Skip to content

Commit 00e74ed

Browse files
authored
feat(checkout): Show price impact message (#2648)
1 parent 29ec917 commit 00e74ed

File tree

1 file changed

+26
-6
lines changed
  • packages/checkout/widgets-lib/src/widgets/swap/components

1 file changed

+26
-6
lines changed

packages/checkout/widgets-lib/src/widgets/swap/components/SwapForm.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ import { TransactionRejected } from '../../../components/TransactionRejected/Tra
5454
import { Fees } from './Fees';
5555
import { useCryptoUSDConversion } from '../../../lib/hooks/useCryptoUSDConversion';
5656

57+
const MAX_PRICE_IMPACT_PERCENTAGE = 15;
58+
5759
enum SwapDirection {
5860
FROM = 'FROM',
5961
TO = 'TO',
@@ -75,6 +77,13 @@ export interface SwapFromProps {
7577
cancelAutoProceed: () => void;
7678
}
7779

80+
class PriceImpactError extends Error {
81+
constructor(readonly priceImpact: number) {
82+
super(`Price impact is too high: ${priceImpact}`);
83+
this.name = 'PriceImpactError';
84+
}
85+
}
86+
7887
export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
7988
const { t } = useTranslation();
8089
const {
@@ -122,7 +131,7 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
122131

123132
// Quote
124133
const [quote, setQuote] = useState<TransactionResponse | null>(null);
125-
const [quoteError, setQuoteError] = useState<string>('');
134+
const [quoteError, setQuoteError] = useState<Error | null>(null);
126135
const [gasFeeValue, setGasFeeValue] = useState<string>('');
127136
const [gasFeeToken, setGasFeeToken] = useState<TokenInfo | undefined>(undefined);
128137

@@ -223,7 +232,7 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
223232
]);
224233

225234
const onQuoteError = useCallback((error: any) => {
226-
setQuoteError(error.message);
235+
setQuoteError(error);
227236
track({
228237
userJourney: UserJourney.SWAP,
229238
screen: 'SwapCoins',
@@ -257,7 +266,7 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
257266
setFromTokenError('');
258267
setToAmountError('');
259268
setToTokenError('');
260-
setQuoteError('');
269+
setQuoteError(null);
261270
};
262271

263272
const resetQuote = () => {
@@ -332,6 +341,10 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
332341
),
333342
);
334343

344+
if (Math.abs(quoteResult.quote.priceImpact) >= MAX_PRICE_IMPACT_PERCENTAGE) {
345+
throw new PriceImpactError(quoteResult.quote.priceImpact);
346+
}
347+
335348
resetFormErrors();
336349
} catch (error: any) {
337350
if (!error.cancelled) {
@@ -405,11 +418,15 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
405418
),
406419
);
407420

421+
if (Math.abs(quoteResult.quote.priceImpact) >= MAX_PRICE_IMPACT_PERCENTAGE) {
422+
throw new PriceImpactError(quoteResult.quote.priceImpact);
423+
}
424+
408425
resetFormErrors();
409426
} catch (error: any) {
410427
if (!error.cancelled) {
411428
resetQuote();
412-
onQuoteError(error);
429+
onQuoteError(error instanceof Error ? error : new Error(error));
413430
}
414431
}
415432

@@ -1078,10 +1095,13 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
10781095
}}
10791096
rc={<div />}
10801097
>
1081-
Unable to swap this token
1098+
{quoteError instanceof PriceImpactError ? 'High Price impact' : 'Unable to swap this token'}
10821099
</Body>
10831100
<Body size="xxSmall">
1084-
This token pairing isn&apos;t available to swap right now. Try another selection.
1101+
{quoteError instanceof PriceImpactError
1102+
// eslint-disable-next-line max-len, @typescript-eslint/quotes
1103+
? `Your swap amount is too large for current market conditions. This means you'd get a less favorable exchange rate. Try a smaller amount.`
1104+
: 'This token pairing is not available to swap right now. Try another selection.'}
10851105
</Body>
10861106
</Box>
10871107
)}

0 commit comments

Comments
 (0)