From 1bbfa18839eaaccf9f9ec10232343786e38bdb32 Mon Sep 17 00:00:00 2001 From: Ji Young Lee <641712+jiyounglee@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:18:30 +1100 Subject: [PATCH] [NO CHANGELOGS] [Add funds Widget] Add additional buffer using aggregatePriceImpact (#2307) --- .../view-context/AddFundsViewContextTypes.ts | 1 + .../src/widgets/add-funds/hooks/useRoutes.ts | 123 +++++++++++++----- .../src/widgets/add-funds/types.ts | 6 + .../src/widgets/add-funds/views/AddFunds.tsx | 1 + .../src/widgets/add-funds/views/Review.tsx | 5 +- 5 files changed, 105 insertions(+), 31 deletions(-) diff --git a/packages/checkout/widgets-lib/src/context/view-context/AddFundsViewContextTypes.ts b/packages/checkout/widgets-lib/src/context/view-context/AddFundsViewContextTypes.ts index e68db1e85b..6819154679 100644 --- a/packages/checkout/widgets-lib/src/context/view-context/AddFundsViewContextTypes.ts +++ b/packages/checkout/widgets-lib/src/context/view-context/AddFundsViewContextTypes.ts @@ -22,6 +22,7 @@ export interface AddFundsReviewData { toAmount: string; toChainId: string; toTokenAddress: string; + additionalBuffer: number; } export interface AddFundsConfirmationData { diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useRoutes.ts b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useRoutes.ts index 13b4dbf0a3..0099f3b245 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useRoutes.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useRoutes.ts @@ -4,10 +4,13 @@ import { Squid } from '@0xsquid/sdk'; import { utils } from 'ethers'; import { useContext, useRef } from 'react'; import { delay } from '../functions/delay'; -import { AmountData, RouteData, Token } from '../types'; +import { + AmountData, RouteData, RouteResponseData, Token, +} from '../types'; import { sortRoutesByFastestTime } from '../functions/sortRoutesByFastestTime'; import { AddFundsActions, AddFundsContext } from '../context/AddFundsContext'; import { retry } from '../../../lib/retry'; +import { getFormattedNumber } from '../functions/getFormattedNumber'; export const useRoutes = () => { const latestRequestIdRef = useRef(0); @@ -40,11 +43,12 @@ export const useRoutes = () => { fromToken: Token, toToken: Token, toAmount: string, + additionalBuffer: number = 0, ) => { const toAmountNumber = Number(toAmount); const toAmountInUsd = toAmountNumber * toToken.usdPrice; const baseFromAmount = toAmountInUsd / fromToken.usdPrice; - const fromAmountWithBuffer = baseFromAmount * 1.015; + const fromAmountWithBuffer = baseFromAmount * (1.02 + additionalBuffer); return fromAmountWithBuffer.toString(); }; @@ -54,6 +58,7 @@ export const useRoutes = () => { toAmount: string, toChainId: string, toTokenAddress: string, + additionalBuffer: number = 0, ): AmountData | undefined => { const fromToken = findToken( tokens, @@ -66,10 +71,11 @@ export const useRoutes = () => { } return { fromToken, - fromAmount: calculateFromAmount(fromToken, toToken, toAmount), + fromAmount: calculateFromAmount(fromToken, toToken, toAmount, additionalBuffer), toToken, toAmount, balance, + additionalBuffer, }; }; @@ -101,43 +107,101 @@ export const useRoutes = () => { }); }; + const convertToFormattedAmount = (amount : string, decimals:number) => { + const parsedFromAmount = parseFloat(amount).toFixed( + decimals, + ); + const formattedFromAmount = utils.parseUnits( + parsedFromAmount, + decimals, + ); + return formattedFromAmount.toString(); + }; + + const getRouteWithRetry = async ( + squid: Squid, + fromToken: Token, + toToken: Token, + toAddress: string, + fromAmount: string, + fromAddress?: string, + quoteOnly = true, + ): Promise => await retry( + () => squid.getRoute({ + fromChain: fromToken.chainId, + fromToken: fromToken.address, + fromAmount: convertToFormattedAmount(fromAmount, fromToken.decimals), + toChain: toToken.chainId, + toToken: toToken.address, + fromAddress, + toAddress, + quoteOnly, + enableBoost: true, + }), + { + retryIntervalMs: 1000, + retries: 5, + nonRetryable: (err: any) => err.response.status !== 429, + }, + ); + + const isRouteToAmountGreaterThanToAmount = (routeResponse:RouteResponse, toAmount :string) => { + const routeToAmount = getFormattedNumber( + routeResponse?.route.estimate.toAmount, + routeResponse?.route.estimate.toToken.decimals, + ); + return Number(routeToAmount) > Number(toAmount); + }; + const getRoute = async ( squid: Squid, fromToken: Token, toToken: Token, toAddress: string, fromAmount: string, + toAmount: string, fromAddress?: string, quoteOnly = true, - ): Promise => { + ): Promise => { try { - const parsedFromAmount = parseFloat(fromAmount).toFixed( - fromToken.decimals, + const routeResponse = await getRouteWithRetry( + squid, + fromToken, + toToken, + toAddress, + fromAmount, + fromAddress, + quoteOnly, ); - const formattedFromAmount = utils.parseUnits( - parsedFromAmount, - fromToken.decimals, + + if (!routeResponse?.route) { + return {}; + } + if (isRouteToAmountGreaterThanToAmount(routeResponse, toAmount)) { return { route: routeResponse }; } + + const additionalBuffer = Math.abs(Number(routeResponse?.route.estimate.aggregatePriceImpact)); + const newFromAmount = calculateFromAmount( + fromToken, + toToken, + toAmount, + additionalBuffer, ); - return await retry( - () => squid.getRoute({ - fromChain: fromToken.chainId, - fromToken: fromToken.address, - fromAmount: formattedFromAmount.toString(), - toChain: toToken.chainId, - toToken: toToken.address, - fromAddress, - toAddress, - quoteOnly, - enableBoost: true, - }), - { - retryIntervalMs: 1000, - retries: 5, - nonRetryable: (err: any) => err.response.status !== 429, - }, + + const routeWithBufferResponse = await getRouteWithRetry( + squid, + fromToken, + toToken, + toAddress, + newFromAmount, + fromAddress, + quoteOnly, ); + if (isRouteToAmountGreaterThanToAmount(routeResponse, toAmount)) { + return { route: routeWithBufferResponse, additionalBuffer }; + } + return {}; } catch (error) { - return undefined; + return {}; } }; @@ -152,9 +216,10 @@ export const useRoutes = () => { data.toToken, toTokenAddress, data.fromAmount, + data.toAmount, ).then((route) => ({ - amountData: data, - route, + amountData: { ...data, additionalBuffer: route.additionalBuffer }, + route: route.route, }))); const routesData = await Promise.all(routePromises); diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts b/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts index bf9a553693..56dfe77e0b 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts @@ -32,6 +32,7 @@ export type AmountData = { toToken: Token; toAmount: string; balance: TokenBalance; + additionalBuffer: number; }; export type RouteData = { @@ -39,6 +40,11 @@ export type RouteData = { route: RouteResponse; }; +export type RouteResponseData = { + route?: RouteResponse; + additionalBuffer?: number; +}; + export enum FiatOptionType { CREDIT = 'credit', DEBIT = 'debit', diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/views/AddFunds.tsx b/packages/checkout/widgets-lib/src/widgets/add-funds/views/AddFunds.tsx index 0bb33c39bc..16eed2a2e8 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/views/AddFunds.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/views/AddFunds.tsx @@ -423,6 +423,7 @@ export function AddFunds({ toChainId: ChainId.IMTBL_ZKEVM_MAINNET.toString(), toTokenAddress: selectedToken.address, toAmount: selectedAmount, + additionalBuffer: selectedRouteData.amountData.additionalBuffer, }, }, }, diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/views/Review.tsx b/packages/checkout/widgets-lib/src/widgets/add-funds/views/Review.tsx index 04d8cdad11..4f7cf90a50 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/views/Review.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/views/Review.tsx @@ -135,8 +135,8 @@ export function Review({ data.toTokenAddress === 'native' ? SQUID_NATIVE_TOKEN : data.toTokenAddress, + data.additionalBuffer, ); - if (!amountData) return; const routeResponse = await getRoute( @@ -145,10 +145,11 @@ export function Review({ amountData?.toToken, toAddress, amountData.fromAmount, + amountData.toAmount, fromAddress, false, ); - setRoute(routeResponse); + setRoute(routeResponse.route); setProceedDisabled(false); };