Skip to content

Commit

Permalink
added warning for unknown price impact (#5597)
Browse files Browse the repository at this point in the history
* added warning for unknown price impact

* more concise price impact warning

* prop drilling

* added common import

* price impact warning

* null safety
  • Loading branch information
dereknelson authored Apr 9, 2024
1 parent 8decc87 commit cfae287
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 26 deletions.
3 changes: 3 additions & 0 deletions src/components/exchange/ExchangeDetailsRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface ExchangeDetailsRowProps {
priceImpactColor?: string;
priceImpactNativeAmount?: string | null;
priceImpactPercentDisplay?: string | null;
outputCurrencySymbol?: string | null;
type: string;
}

Expand All @@ -32,6 +33,7 @@ export default function ExchangeDetailsRow({
priceImpactColor,
priceImpactNativeAmount,
priceImpactPercentDisplay,
outputCurrencySymbol,
type,
}: ExchangeDetailsRowProps) {
const detailsRowOpacity = useSharedValue(1);
Expand Down Expand Up @@ -83,6 +85,7 @@ export default function ExchangeDetailsRow({
priceImpactColor={priceImpactColor}
priceImpactNativeAmount={priceImpactNativeAmount}
priceImpactPercentDisplay={priceImpactPercentDisplay}
outputCurrencySymbol={outputCurrencySymbol}
style={priceImpactAnimatedStyle}
/>
<Box
Expand Down
31 changes: 21 additions & 10 deletions src/components/exchange/PriceImpactWarning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import Animated from 'react-native-reanimated';
import { ButtonPressAnimation } from '../animations';
import { Box, ColorModeProvider, Inline, Text } from '@/design-system';
import { position } from '@/styles';
import { NO_PRICE_DATA_PERCENTAGE } from '@/hooks/usePriceImpactDetails';

interface PriceImpactWarningProps extends ViewProps {
onPress: () => void;
isHighPriceImpact: boolean;
priceImpactColor?: string;
priceImpactNativeAmount?: string | null;
priceImpactPercentDisplay?: string | null;
outputCurrencySymbol?: string | null;
style?: StyleProp<ViewStyle>;
}

Expand All @@ -21,29 +23,38 @@ export default function PriceImpactWarning({
priceImpactColor = 'primary',
priceImpactNativeAmount,
priceImpactPercentDisplay,
outputCurrencySymbol,
style,
...props
}: PriceImpactWarningProps) {
const headingValue = priceImpactNativeAmount ?? priceImpactPercentDisplay;
const hasPriceData = priceImpactPercentDisplay !== NO_PRICE_DATA_PERCENTAGE;
const impactMsg = !hasPriceData
? `${outputCurrencySymbol} ${lang.t('exchange.price_impact.no_data')}`
: lang.t('exchange.price_impact.small_market');
return (
<ColorModeProvider value="dark">
<Animated.View {...props} style={[style, position.coverAsObject]}>
{isHighPriceImpact && headingValue && (
{!isHighPriceImpact && headingValue && (
<ButtonPressAnimation onPress={onPress} scaleTo={0.94}>
<Box paddingHorizontal="19px (Deprecated)" paddingTop="19px (Deprecated)">
<Inline alignHorizontal="center">
<Text weight="bold" size="17pt" color={{ custom: priceImpactColor }}>{`􀇿 `}</Text>
<Text weight="bold" size="17pt" color="primary (Deprecated)">
{lang.t('exchange.price_impact.small_market')}
</Text>
<Text
weight="bold"
size="17pt"
color={{ custom: priceImpactColor }}
>{` • ${lang.t('exchange.price_impact.losing_prefix')} `}</Text>
<Text weight="bold" size="17pt" color={{ custom: priceImpactColor }}>
{headingValue}
{impactMsg}
</Text>
{hasPriceData && (
<Text
weight="bold"
size="17pt"
color={{ custom: priceImpactColor }}
>{` • ${lang.t('exchange.price_impact.losing_prefix')} `}</Text>
)}
{hasPriceData && (
<Text weight="bold" size="17pt" color={{ custom: priceImpactColor }}>
{headingValue}
</Text>
)}
</Inline>
</Box>
</ButtonPressAnimation>
Expand Down
1 change: 1 addition & 0 deletions src/components/expanded-state/SwapDetailsState.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export default function SwapDetailsState({ confirmButtonProps, restoreFocusOnSwa
/>
<SwapDetailsSlippageMessage
isHighPriceImpact={priceImpact.type !== SwapPriceImpactType.none}
outputCurrencySymbol={outputCurrency?.symbol}
onLayout={setSlippageMessageHeight}
priceImpactColor={priceImpact.color}
priceImpactNativeAmount={priceImpact.impactDisplay}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Centered, Column, ColumnWithMargins, Row } from '../../layout';
import { Emoji, Text } from '../../text';
import styled from '@/styled-thing';
import { padding } from '@/styles';
import { NO_PRICE_DATA_PERCENTAGE } from '@/hooks/usePriceImpactDetails';

const Container = styled(ColumnWithMargins).attrs({
align: 'center',
Expand All @@ -29,24 +30,39 @@ export default function SwapDetailsSlippageMessage({
priceImpactColor,
priceImpactNativeAmount,
priceImpactPercentDisplay,
outputCurrencySymbol,
...props
}) {
const { colors } = useTheme();
const headingValue = priceImpactNativeAmount ?? priceImpactPercentDisplay;
const hasPriceData = priceImpactPercentDisplay !== NO_PRICE_DATA_PERCENTAGE;
const impactMsg = `${outputCurrencySymbol} ${lang.t('exchange.price_impact.no_data')}`;
return isHighPriceImpact ? (
<Column align="center" {...props}>
<Container>
<Row align="center">
<Heading color={priceImpactColor} weight="heavy">
{lang.t('expanded_state.swap.losing')}{' '}
</Heading>
<Heading color={priceImpactColor} letterSpacing="roundedTight" weight="heavy">
{headingValue}
</Heading>
<Emoji size="larger"> 🥵</Emoji>
</Row>
<Message>{lang.t('expanded_state.swap.slippage_message')}</Message>
</Container>
{hasPriceData ? (
<Container>
<Row align="center">
<Heading color={priceImpactColor} weight="heavy">
{lang.t('expanded_state.swap.losing')}{' '}
</Heading>
<Heading color={priceImpactColor} letterSpacing="roundedTight" weight="heavy">
{headingValue}
</Heading>
<Emoji size="larger"> 🥵</Emoji>
</Row>
<Message>{lang.t('expanded_state.swap.slippage_message')}</Message>
</Container>
) : (
<Container>
<Row align="center">
<Text weight="bold" size="17pt" color={{ custom: priceImpactColor }}>{`􀇿 `}</Text>
<Text weight="bold" size="17pt" color="primary (Deprecated)">
{impactMsg}
</Text>
</Row>
<Message>{lang.t('exchange.price_impact.no_data_subtitle')}</Message>
</Container>
)}
<Centered width={139}>
<Divider color={colors.rowDividerExtraLight} inset={false} />
</Centered>
Expand Down
1 change: 1 addition & 0 deletions src/hooks/usePriceImpactDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export enum SwapPriceImpactType {

const PriceImpactWarningThreshold = 0.05;
const SeverePriceImpactThreshold = 0.1;
export const NO_PRICE_DATA_PERCENTAGE = '100.00%';

export default function usePriceImpactDetails(
inputCurrency: SwappableAsset | null,
Expand Down
4 changes: 3 additions & 1 deletion src/languages/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,9 @@
"price_impact": {
"losing_prefix": "Losing",
"small_market": "Small Market",
"label": "Possible loss"
"no_data": "Market Value Unknown",
"label": "Possible loss",
"no_data_subtitle": "If you decide to continue, be sure that you are satisfied with the quoted amount"
},
"source": {
"rainbow": "Auto",
Expand Down
7 changes: 4 additions & 3 deletions src/screens/ExchangeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -681,9 +681,9 @@ export default function ExchangeModal({ fromDiscover, ignoreInitialTypeCheck, te
android && Keyboard.dismiss();
const lastFocusedInputHandleTemporary = lastFocusedInputHandle.current;
android && (lastFocusedInputHandle.current = null);
inputFieldRef?.current?.blur();
outputFieldRef?.current?.blur();
nativeFieldRef?.current?.blur();
inputFieldRef?.current?.blur?.();
outputFieldRef?.current?.blur?.();
nativeFieldRef?.current?.blur?.();
const internalNavigate = () => {
IS_ANDROID && keyboardListenerSubscription.current?.remove();
setParams({ focused: false });
Expand Down Expand Up @@ -847,6 +847,7 @@ export default function ExchangeModal({ fromDiscover, ignoreInitialTypeCheck, te
isHighPriceImpact={
!confirmButtonProps.disabled && !confirmButtonProps.loading && debouncedIsHighPriceImpact && isSufficientBalance
}
outputCurrencySymbol={outputCurrency?.symbol}
onFlipCurrencies={loading ? NOOP : flipCurrencies}
onPressImpactWarning={navigateToSwapDetailsModal}
onPressSettings={navigateToSwapSettingsSheet}
Expand Down

0 comments on commit cfae287

Please sign in to comment.