diff --git a/packages/checkout/widgets-lib/src/context/squid-provider/SquidContext.tsx b/packages/checkout/widgets-lib/src/context/squid-provider/SquidContext.tsx new file mode 100644 index 0000000000..56df2a5555 --- /dev/null +++ b/packages/checkout/widgets-lib/src/context/squid-provider/SquidContext.tsx @@ -0,0 +1,112 @@ +import { createContext } from 'react'; +import { Squid } from '@0xsquid/sdk'; +import { TokenBalance } from '@0xsquid/sdk/dist/types'; +import { Chain, RouteData, Token } from '../../lib/squid/types'; + +export interface SquidState { + squid: Squid | null; + chains: Chain[] | null; + balances: TokenBalance[] | null; + tokens: Token[] | null; + routes: RouteData[]; +} + +export const initialSquidState: SquidState = { + squid: null, + chains: null, + balances: null, + tokens: null, + routes: [], +}; + +export interface SquidContextState { + squidState: SquidState; + squidDispatch: React.Dispatch; +} + +export interface SquidAction { + payload: SquidActionPayload; +} + +type SquidActionPayload = + | SetSquidPayload + | SetChainsPayload + | SetBalancesPayload + | SetTokensPayload + | SetRoutesPayload; + +export enum SquidActions { + SET_SQUID = 'SET_SQUID', + SET_CHAINS = 'SET_CHAINS', + SET_BALANCES = 'SET_BALANCES', + SET_TOKENS = 'SET_TOKENS', + SET_ROUTES = 'SET_ROUTES', +} + +export interface SetSquidPayload { + type: SquidActions.SET_SQUID; + squid: Squid; +} + +export interface SetChainsPayload { + type: SquidActions.SET_CHAINS; + chains: Chain[]; +} + +export interface SetBalancesPayload { + type: SquidActions.SET_BALANCES; + balances: TokenBalance[]; +} + +export interface SetTokensPayload { + type: SquidActions.SET_TOKENS; + tokens: Token[]; +} + +export interface SetRoutesPayload { + type: SquidActions.SET_ROUTES; + routes: RouteData[]; +} + +// eslint-disable-next-line @typescript-eslint/naming-convention +export const SquidContext = createContext({ + squidState: initialSquidState, + squidDispatch: () => {}, +}); + +export type Reducer = (prevState: S, action: A) => S; + +export const squidReducer: Reducer = ( + state: SquidState, + action: SquidAction, +) => { + switch (action.payload.type) { + case SquidActions.SET_SQUID: + return { + ...state, + squid: action.payload.squid, + }; + case SquidActions.SET_CHAINS: + return { + ...state, + chains: action.payload.chains, + }; + case SquidActions.SET_BALANCES: + return { + ...state, + balances: action.payload.balances, + }; + case SquidActions.SET_TOKENS: + return { + ...state, + tokens: action.payload.tokens, + }; + case SquidActions.SET_ROUTES: + return { + ...state, + routes: action.payload.routes, + }; + default: + return state; + } +}; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/delay.ts b/packages/checkout/widgets-lib/src/lib/delay.ts similarity index 100% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/delay.ts rename to packages/checkout/widgets-lib/src/lib/delay.ts diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getFormattedNumber.ts b/packages/checkout/widgets-lib/src/lib/getFormattedNumber.ts similarity index 91% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getFormattedNumber.ts rename to packages/checkout/widgets-lib/src/lib/getFormattedNumber.ts index edbcbe6cb4..44433101cb 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getFormattedNumber.ts +++ b/packages/checkout/widgets-lib/src/lib/getFormattedNumber.ts @@ -1,7 +1,6 @@ import { BigNumber, utils } from 'ethers'; - -import { tokenValueFormat } from '../../../lib/utils'; -import { DEFAULT_TOKEN_FORMATTING_DECIMALS } from '../../../lib/constants'; +import { DEFAULT_TOKEN_FORMATTING_DECIMALS } from './constants'; +import { tokenValueFormat } from './utils'; /** * Formats a number to a string with a maximum number of decimals diff --git a/packages/checkout/widgets-lib/src/lib/squid/config.ts b/packages/checkout/widgets-lib/src/lib/squid/config.ts new file mode 100644 index 0000000000..75339de528 --- /dev/null +++ b/packages/checkout/widgets-lib/src/lib/squid/config.ts @@ -0,0 +1,3 @@ +export const SQUID_SDK_BASE_URL = 'https://apiplus.squidrouter.com'; + +export const SQUID_NATIVE_TOKEN = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/convertToUsd.ts b/packages/checkout/widgets-lib/src/lib/squid/convertToUsd.ts similarity index 86% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/convertToUsd.ts rename to packages/checkout/widgets-lib/src/lib/squid/convertToUsd.ts index 34111506d0..e0d548132c 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/convertToUsd.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/convertToUsd.ts @@ -1,6 +1,6 @@ import { ChainId, type TokenInfo } from '@imtbl/checkout-sdk'; -import { Token } from '../types'; -import { SQUID_NATIVE_TOKEN } from '../utils/config'; +import { Token } from './types'; +import { SQUID_NATIVE_TOKEN } from './config'; export function convertToUsd( tokens: Token[] | null, diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/fetchBalances.ts b/packages/checkout/widgets-lib/src/lib/squid/fetchBalances.ts similarity index 96% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/fetchBalances.ts rename to packages/checkout/widgets-lib/src/lib/squid/fetchBalances.ts index 2d900a6d91..e41304b118 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/fetchBalances.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/fetchBalances.ts @@ -1,7 +1,7 @@ import { Web3Provider } from '@ethersproject/providers'; import { Squid } from '@0xsquid/sdk'; import { CosmosBalance, TokenBalance } from '@0xsquid/sdk/dist/types'; -import { Chain } from '../types'; +import { Chain } from './types'; export const fetchBalances = async ( squid: Squid, diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/fetchChains.ts b/packages/checkout/widgets-lib/src/lib/squid/fetchChains.ts similarity index 93% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/fetchChains.ts rename to packages/checkout/widgets-lib/src/lib/squid/fetchChains.ts index 35a2441cb6..d11c36d16d 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/fetchChains.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/fetchChains.ts @@ -1,5 +1,5 @@ import { Squid } from '@0xsquid/sdk'; -import { Chain } from '../types'; +import { Chain } from '../../widgets/add-tokens/types'; type SquidChain = { chainId: string; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/fetchTokens.ts b/packages/checkout/widgets-lib/src/lib/squid/fetchTokens.ts similarity index 92% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/fetchTokens.ts rename to packages/checkout/widgets-lib/src/lib/squid/fetchTokens.ts index 055346303d..badd6bffff 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/fetchTokens.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/fetchTokens.ts @@ -1,5 +1,5 @@ -import { Token } from '../types'; -import { SQUID_SDK_BASE_URL } from '../utils/config'; +import { Token } from './types'; +import { SQUID_SDK_BASE_URL } from './config'; type SquidTokenResponse = { chainId: number; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getDurationFormatted.ts b/packages/checkout/widgets-lib/src/lib/squid/getDurationFormatted.ts similarity index 100% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getDurationFormatted.ts rename to packages/checkout/widgets-lib/src/lib/squid/getDurationFormatted.ts diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getRouteAndTokenBalances.ts b/packages/checkout/widgets-lib/src/lib/squid/getRouteAndTokenBalances.ts similarity index 91% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getRouteAndTokenBalances.ts rename to packages/checkout/widgets-lib/src/lib/squid/getRouteAndTokenBalances.ts index 0e6fcde7b6..1d8cb8d31e 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getRouteAndTokenBalances.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/getRouteAndTokenBalances.ts @@ -1,5 +1,5 @@ -import { RouteData } from '../types'; -import { getFormattedAmounts, getFormattedNumber } from './getFormattedNumber'; +import { RouteData } from './types'; +import { getFormattedAmounts, getFormattedNumber } from '../getFormattedNumber'; export type RouteBalance = { routeBalance: string; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getRouteChains.ts b/packages/checkout/widgets-lib/src/lib/squid/getRouteChains.ts similarity index 96% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getRouteChains.ts rename to packages/checkout/widgets-lib/src/lib/squid/getRouteChains.ts index 12d6f6c48a..30c072b60e 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getRouteChains.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/getRouteChains.ts @@ -1,5 +1,5 @@ import { RouteResponse } from '@0xsquid/squid-types'; -import { Chain } from '../types'; +import { Chain } from './types'; /** * Find a chain by its id diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getTotalRouteFees.ts b/packages/checkout/widgets-lib/src/lib/squid/getTotalRouteFees.ts similarity index 100% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/getTotalRouteFees.ts rename to packages/checkout/widgets-lib/src/lib/squid/getTotalRouteFees.ts diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useRoutes.ts b/packages/checkout/widgets-lib/src/lib/squid/hooks/useRoutes.ts similarity index 89% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useRoutes.ts rename to packages/checkout/widgets-lib/src/lib/squid/hooks/useRoutes.ts index 47e86f8088..b61c3f7c83 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useRoutes.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/hooks/useRoutes.ts @@ -1,25 +1,26 @@ import { TokenBalance } from '@0xsquid/sdk/dist/types'; -import { RouteResponse, ActionType } from '@0xsquid/squid-types'; -import { Squid } from '@0xsquid/sdk'; +import { RouteResponse, ActionType, Hook } from '@0xsquid/squid-types'; import { BigNumber, utils } from 'ethers'; import { useContext, useRef } from 'react'; -import { delay } from '../functions/delay'; +import { delay } from '../../delay'; import { AmountData, RouteData, RouteResponseData, Token, } from '../types'; -import { sortRoutesByFastestTime } from '../functions/sortRoutesByFastestTime'; -import { AddTokensActions, AddTokensContext } from '../context/AddTokensContext'; -import { retry } from '../../../lib/retry'; +import { sortRoutesByFastestTime } from '../sortRoutesByFastestTime'; +import { retry } from '../../retry'; import { useAnalytics, UserJourney } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; import { useProvidersContext } from '../../../context/providers-context/ProvidersContext'; -import { isPassportProvider } from '../../../lib/provider'; +import { isPassportProvider } from '../../provider'; +import { SquidActions, SquidContext } from '../../../context/squid-provider/SquidContext'; const BASE_SLIPPAGE = 0.02; +type SquidPostHook = Omit; + export const useRoutes = () => { const latestRequestIdRef = useRef(0); - const { addTokensState: { id }, addTokensDispatch } = useContext(AddTokensContext); + const { squidDispatch } = useContext(SquidContext); const { providersState: { @@ -27,12 +28,14 @@ export const useRoutes = () => { }, } = useProvidersContext(); + const { squidState: { squid } } = useContext(SquidContext); + const { track } = useAnalytics(); const setRoutes = (routes: RouteData[]) => { - addTokensDispatch({ + squidDispatch({ payload: { - type: AddTokensActions.SET_ROUTES, + type: SquidActions.SET_ROUTES, routes, }, }); @@ -148,15 +151,15 @@ export const useRoutes = () => { }; const getRouteWithRetry = async ( - squid: Squid, fromToken: Token, toToken: Token, toAddress: string, fromAmount: string, fromAddress?: string, quoteOnly = true, + postHook?: SquidPostHook, ): Promise => await retry( - () => squid.getRoute({ + () => squid?.getRoute({ fromChain: fromToken.chainId, fromToken: fromToken.address, fromAmount: convertToFormattedAmount(fromAmount, fromToken.decimals), @@ -167,6 +170,7 @@ export const useRoutes = () => { quoteOnly, enableBoost: true, receiveGasOnDestination: !isPassportProvider(toProvider), + postHook, }), { retryIntervalMs: 1000, @@ -189,7 +193,10 @@ export const useRoutes = () => { }; const getRoute = async ( - squid: Squid, + context: { + id: string, + userJourney: UserJourney, + }, fromToken: Token, toToken: Token, toAddress: string, @@ -197,16 +204,17 @@ export const useRoutes = () => { toAmount: string, fromAddress?: string, quoteOnly = true, + postHook?: SquidPostHook, ): Promise => { try { const routeResponse = await getRouteWithRetry( - squid, fromToken, toToken, toAddress, fromAmount, fromAddress, quoteOnly, + postHook, ); if (!routeResponse?.route) { @@ -223,13 +231,13 @@ export const useRoutes = () => { ); const newRoute = await getRouteWithRetry( - squid, fromToken, toToken, toAddress, newFromAmount, fromAddress, quoteOnly, + postHook, ); if (!newRoute?.route) { @@ -241,11 +249,11 @@ export const useRoutes = () => { } track({ - userJourney: UserJourney.ADD_TOKENS, + userJourney: context.userJourney, screen: 'Routes', action: 'Failed', extras: { - contextId: id, + contextId: context.id, fromToken: fromToken.symbol, toToken: toToken.symbol, fromChain: fromToken.chainId, @@ -273,12 +281,15 @@ export const useRoutes = () => { }; const getRoutes = async ( - squid: Squid, + context: { + id: string, + userJourney: UserJourney, + }, amountDataArray: AmountData[], toTokenAddress: string, ): Promise => { const routePromises = amountDataArray.map((data) => getRoute( - squid, + context, data.fromToken, data.toToken, toTokenAddress, @@ -297,7 +308,10 @@ export const useRoutes = () => { }; const fetchRoutesWithRateLimit = async ( - squid: Squid, + context: { + id: string, + userJourney: UserJourney, + }, tokens: Token[], balances: TokenBalance[], toChanId: string, @@ -334,7 +348,7 @@ export const useRoutes = () => { }, [] as (typeof amountDataArray)[]) .map(async (slicedAmountDataArray) => { allRoutes.push( - ...(await getRoutes(squid, slicedAmountDataArray, toTokenAddress)), + ...(await getRoutes(context, slicedAmountDataArray, toTokenAddress)), ); await delay(delayMs); }), diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useSquid.ts b/packages/checkout/widgets-lib/src/lib/squid/hooks/useSquid.ts similarity index 95% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useSquid.ts rename to packages/checkout/widgets-lib/src/lib/squid/hooks/useSquid.ts index 90bce7ce6c..009965ff52 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useSquid.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/hooks/useSquid.ts @@ -1,7 +1,7 @@ import { Squid } from '@0xsquid/sdk'; import { Checkout, SquidConfig } from '@imtbl/checkout-sdk'; import { useCallback, useEffect, useState } from 'react'; -import { SQUID_SDK_BASE_URL } from '../utils/config'; +import { SQUID_SDK_BASE_URL } from '../config'; export const useSquid = (checkout: Checkout) => { const [squid, setSquid] = useState(null); diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useTokens.ts b/packages/checkout/widgets-lib/src/lib/squid/hooks/useTokens.ts similarity index 95% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useTokens.ts rename to packages/checkout/widgets-lib/src/lib/squid/hooks/useTokens.ts index 196338514f..0de19175b6 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useTokens.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/hooks/useTokens.ts @@ -1,6 +1,6 @@ import { Checkout, SquidConfig } from '@imtbl/checkout-sdk'; import { useCallback, useEffect, useState } from 'react'; -import { fetchTokens } from '../functions/fetchTokens'; +import { fetchTokens } from '../fetchTokens'; import { Token } from '../types'; export const useTokens = (checkout: Checkout) => { diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/isSquidNativeToken.ts b/packages/checkout/widgets-lib/src/lib/squid/isSquidNativeToken.ts similarity index 67% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/isSquidNativeToken.ts rename to packages/checkout/widgets-lib/src/lib/squid/isSquidNativeToken.ts index 36560b1d89..88c89927b1 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/isSquidNativeToken.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/isSquidNativeToken.ts @@ -1,3 +1,3 @@ -import { SQUID_NATIVE_TOKEN } from '../utils/config'; +import { SQUID_NATIVE_TOKEN } from './config'; export const isSquidNativeToken = (token: string) => token.toLowerCase() === SQUID_NATIVE_TOKEN.toLowerCase(); diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/sortRoutesByFastestTime.ts b/packages/checkout/widgets-lib/src/lib/squid/sortRoutesByFastestTime.ts similarity index 89% rename from packages/checkout/widgets-lib/src/widgets/add-tokens/functions/sortRoutesByFastestTime.ts rename to packages/checkout/widgets-lib/src/lib/squid/sortRoutesByFastestTime.ts index 2d425fc91e..c51d895949 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/sortRoutesByFastestTime.ts +++ b/packages/checkout/widgets-lib/src/lib/squid/sortRoutesByFastestTime.ts @@ -1,4 +1,4 @@ -import { RouteData } from '../types'; +import { RouteData } from './types'; export const sortRoutesByFastestTime = (routes: RouteData[]): RouteData[] => { if (!routes) return []; diff --git a/packages/checkout/widgets-lib/src/lib/squid/types.ts b/packages/checkout/widgets-lib/src/lib/squid/types.ts new file mode 100644 index 0000000000..82ddfb0bef --- /dev/null +++ b/packages/checkout/widgets-lib/src/lib/squid/types.ts @@ -0,0 +1,46 @@ +import { TokenBalance } from '@0xsquid/sdk/dist/types'; +import { RouteResponse } from '@0xsquid/squid-types'; + +export type NativeCurrency = { + name: string; + symbol: string; + decimals: number; + iconUrl: string; +}; + +export type Chain = { + id: string; + type: string; + name: string; + iconUrl: string; + nativeCurrency: NativeCurrency; +}; + +export type Token = { + chainId: string; + address: string; + decimals: number; + symbol?: string; + name?: string; + usdPrice: number; + iconUrl: string; +}; + +export type AmountData = { + fromToken: Token; + fromAmount: string; + toToken: Token; + toAmount: string; + balance: TokenBalance; + additionalBuffer: number; +}; + +export type RouteData = { + amountData: AmountData; + route: RouteResponse; +}; + +export type RouteResponseData = { + route?: RouteResponse; + additionalBuffer?: number; +}; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/AddTokensWidget.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/AddTokensWidget.tsx index 43922556e4..76834f6f68 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/AddTokensWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/AddTokensWidget.tsx @@ -24,16 +24,16 @@ import { } from '../../context/view-context/ViewContext'; import { AddTokens } from './views/AddTokens'; import { ErrorView } from '../../views/error/ErrorView'; -import { useSquid } from './hooks/useSquid'; +import { useSquid } from '../../lib/squid/hooks/useSquid'; import { useAnalytics, UserJourney, } from '../../context/analytics-provider/SegmentAnalyticsProvider'; -import { fetchChains } from './functions/fetchChains'; +import { fetchChains } from '../../lib/squid/fetchChains'; import { StrongCheckoutWidgetsConfig } from '../../lib/withDefaultWidgetConfig'; import { Review } from './views/Review'; -import { fetchBalances } from './functions/fetchBalances'; -import { useTokens } from './hooks/useTokens'; +import { fetchBalances } from '../../lib/squid/fetchBalances'; +import { useTokens } from '../../lib/squid/hooks/useTokens'; import { useProvidersContext } from '../../context/providers-context/ProvidersContext'; import { orchestrationEvents } from '../../lib/orchestrationEvents'; import { getRemoteImage } from '../../lib/utils'; @@ -42,6 +42,9 @@ import { amountInputValidation } from '../../lib/validations/amountInputValidati import { useError } from './hooks/useError'; import { AddTokensErrorTypes } from './types'; import { ServiceUnavailableErrorView } from '../../views/error/ServiceUnavailableErrorView'; +import { + initialSquidState, SquidActions, SquidContext, squidReducer, +} from '../../context/squid-provider/SquidContext'; export type AddTokensWidgetInputs = Omit & { config: StrongCheckoutWidgetsConfig; @@ -66,6 +69,17 @@ export default function AddTokensWidget({ const { t } = useTranslation(); const { page } = useAnalytics(); + const [squidState, squidDispatch] = useReducer(squidReducer, initialSquidState); + const squidReducerValues = useMemo( + () => ({ + squidState, + squidDispatch, + }), + [squidState, squidDispatch], + ); + + const { squid, chains } = squidState; + const viewReducerValues = useMemo( () => ({ viewState, @@ -83,7 +97,7 @@ export default function AddTokensWidget({ providersState: { checkout, fromProvider }, } = useProvidersContext(); - const { id, squid, chains } = addTokensState; + const { id } = addTokensState; const addTokensReducerValues = useMemo( () => ({ @@ -136,9 +150,9 @@ export default function AddTokensWidget({ useEffect(() => { if (!squid) return; - addTokensDispatch({ + squidDispatch({ payload: { - type: AddTokensActions.SET_CHAINS, + type: SquidActions.SET_CHAINS, chains: fetchChains(squid), }, }); @@ -153,9 +167,9 @@ export default function AddTokensWidget({ const evmChains = chains.filter((chain) => chain.type === 'evm'); const balances = await fetchBalances(squid, evmChains, fromProvider); - addTokensDispatch({ + squidDispatch({ payload: { - type: AddTokensActions.SET_BALANCES, + type: SquidActions.SET_BALANCES, balances, }, }); @@ -168,9 +182,9 @@ export default function AddTokensWidget({ useEffect(() => { if (!squidSdk) return; - addTokensDispatch({ + squidDispatch({ payload: { - type: AddTokensActions.SET_SQUID, + type: SquidActions.SET_SQUID, squid: squidSdk, }, }); @@ -178,9 +192,9 @@ export default function AddTokensWidget({ useEffect(() => { if (!tokensResponse) return; - addTokensDispatch({ + squidDispatch({ payload: { - type: AddTokensActions.SET_TOKENS, + type: SquidActions.SET_TOKENS, tokens: tokensResponse, }, }); @@ -200,92 +214,94 @@ export default function AddTokensWidget({ }; return ( - - - - - )} - sx={{ - pos: 'absolute', - h: '100%', - w: '100%', - objectFit: 'cover', - objectPosition: 'center', - }} - /> - {viewState.view.type === AddTokensWidgetViews.ADD_TOKENS && ( - sendAddTokensCloseEvent(eventTarget)} - onBackButtonClick={() => { - orchestrationEvents.sendRequestGoBackEvent( - eventTarget, - IMTBLWidgetEvents.IMTBL_ADD_TOKENS_WIDGET_EVENT, - {}, - ); - }} - /> - )} - {viewState.view.type === AddTokensWidgetViews.REVIEW && ( - sendAddTokensCloseEvent(eventTarget)} - onBackButtonClick={() => { - viewDispatch({ - payload: { - type: ViewActions.GO_BACK, - }, - }); + + + + + + )} + sx={{ + pos: 'absolute', + h: '100%', + w: '100%', + objectFit: 'cover', + objectPosition: 'center', }} - showBackButton /> - )} - {viewState.view.type === SharedViews.ERROR_VIEW && ( - sendAddTokensCloseEvent(eventTarget)} - errorEventAction={() => { - page({ - userJourney: UserJourney.ADD_TOKENS, - screen: 'Error', - extras: { - contextId: id, - }, - }); - }} - /> - )} - {viewState.view.type - === SharedViews.SERVICE_UNAVAILABLE_ERROR_VIEW && ( - sendAddTokensCloseEvent(eventTarget)} - onBackButtonClick={() => { - viewDispatch({ - payload: { - type: ViewActions.GO_BACK, - }, - }); - }} - /> - )} - - - + {viewState.view.type === AddTokensWidgetViews.ADD_TOKENS && ( + sendAddTokensCloseEvent(eventTarget)} + onBackButtonClick={() => { + orchestrationEvents.sendRequestGoBackEvent( + eventTarget, + IMTBLWidgetEvents.IMTBL_ADD_TOKENS_WIDGET_EVENT, + {}, + ); + }} + /> + )} + {viewState.view.type === AddTokensWidgetViews.REVIEW && ( + sendAddTokensCloseEvent(eventTarget)} + onBackButtonClick={() => { + viewDispatch({ + payload: { + type: ViewActions.GO_BACK, + }, + }); + }} + showBackButton + /> + )} + {viewState.view.type === SharedViews.ERROR_VIEW && ( + sendAddTokensCloseEvent(eventTarget)} + errorEventAction={() => { + page({ + userJourney: UserJourney.ADD_TOKENS, + screen: 'Error', + extras: { + contextId: id, + }, + }); + }} + /> + )} + {viewState.view.type + === SharedViews.SERVICE_UNAVAILABLE_ERROR_VIEW && ( + sendAddTokensCloseEvent(eventTarget)} + onBackButtonClick={() => { + viewDispatch({ + payload: { + type: ViewActions.GO_BACK, + }, + }); + }} + /> + )} + + + + ); } diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/Options.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/Options.tsx index 9b8d09b860..d97de0fe11 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/Options.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/Options.tsx @@ -6,7 +6,8 @@ import { Checkout } from '@imtbl/checkout-sdk'; import { useTranslation } from 'react-i18next'; import { listItemVariants, listVariants } from '../../../lib/animation/listAnimation'; import { FiatOption } from './FiatOption'; -import { Chain, FiatOptionType, RouteData } from '../types'; +import { FiatOptionType } from '../types'; +import { Chain, RouteData } from '../../../lib/squid/types'; import { RouteOption } from './RouteOption'; import { getRemoteVideo } from '../../../lib/utils'; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/OptionsDrawer.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/OptionsDrawer.tsx index 0a3f042feb..406b2c20c2 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/OptionsDrawer.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/OptionsDrawer.tsx @@ -6,9 +6,10 @@ import { Checkout } from '@imtbl/checkout-sdk'; import { useTranslation } from 'react-i18next'; import { listVariants } from '../../../lib/animation/listAnimation'; import { Options } from './Options'; -import { FiatOptionType, RouteData } from '../types'; -import { AddTokensContext } from '../context/AddTokensContext'; +import { FiatOptionType } from '../types'; +import { RouteData } from '../../../lib/squid/types'; import { useProvidersContext } from '../../../context/providers-context/ProvidersContext'; +import { SquidContext } from '../../../context/squid-provider/SquidContext'; type OptionsDrawerProps = { checkout: Checkout; @@ -39,8 +40,8 @@ export function OptionsDrawer({ }: OptionsDrawerProps) { const { t } = useTranslation(); const { - addTokensState: { chains }, - } = useContext(AddTokensContext); + squidState: { chains }, + } = useContext(SquidContext); const { providersState: { fromProviderInfo, fromAddress }, diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/RouteFees.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/RouteFees.tsx index 12cd7f3572..0aa8d61bf9 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/RouteFees.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/RouteFees.tsx @@ -4,10 +4,7 @@ import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { FeesBreakdown } from '../../../components/FeesBreakdown/FeesBreakdown'; import { FormattedFee } from '../../swap/functions/swapFees'; -import { - getFormattedNumber, - getFormattedAmounts, -} from '../functions/getFormattedNumber'; +import { getFormattedAmounts, getFormattedNumber } from '../../../lib/getFormattedNumber'; export type RouteFeesProps = { visible: boolean; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/RouteOption.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/RouteOption.tsx index 8fb834c658..d059649878 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/RouteOption.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/RouteOption.tsx @@ -11,11 +11,11 @@ import { } from '@biom3/react'; import { ReactElement, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { Chain, RouteData } from '../types'; -import { getDurationFormatted } from '../functions/getDurationFormatted'; -import { getTotalRouteFees } from '../functions/getTotalRouteFees'; -import { getFormattedAmounts } from '../functions/getFormattedNumber'; -import { getRouteAndTokenBalances } from '../functions/getRouteAndTokenBalances'; +import { Chain, RouteData } from '../../../lib/squid/types'; +import { getDurationFormatted } from '../../../lib/squid/getDurationFormatted'; +import { getTotalRouteFees } from '../../../lib/squid/getTotalRouteFees'; +import { getFormattedAmounts } from '../../../lib/getFormattedNumber'; +import { getRouteAndTokenBalances } from '../../../lib/squid/getRouteAndTokenBalances'; export interface RouteOptionProps< RC extends ReactElement | undefined = undefined, @@ -144,7 +144,7 @@ export function RouteOption({ /> )} { - `${t('views.ADD_TOKENS.fees.fee')} ${t('views.ADD_TOKENS.fees.fiatPricePrefix')} + `${t('views.ADD_TOKENS.fees.fee')} ${t('views.ADD_TOKENS.fees.fiatPricePrefix')} $${getFormattedAmounts(totalFeesUsd)}` } diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/SelectedRouteOption.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/SelectedRouteOption.tsx index 4aa47d2680..fc73ff9a0a 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/SelectedRouteOption.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/SelectedRouteOption.tsx @@ -11,8 +11,8 @@ import { import { Checkout } from '@imtbl/checkout-sdk'; import { useTranslation } from 'react-i18next'; -import { Chain, RouteData } from '../types'; -import { getRouteAndTokenBalances } from '../functions/getRouteAndTokenBalances'; +import { Chain, RouteData } from '../../../lib/squid/types'; +import { getRouteAndTokenBalances } from '../../../lib/squid/getRouteAndTokenBalances'; import { getRemoteVideo } from '../../../lib/utils'; export interface SelectedRouteOptionProps { diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/TokenDrawerMenu.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/TokenDrawerMenu.tsx index e362882deb..bb115126c2 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/components/TokenDrawerMenu.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/components/TokenDrawerMenu.tsx @@ -40,10 +40,12 @@ import { AddTokensErrorTypes } from '../types'; import { TokenImage } from '../../../components/TokenImage/TokenImage'; import { TOKEN_PRIORITY_ORDER } from '../utils/config'; import { PULSE_SHADOW } from '../utils/animation'; +import { Token } from '../../../lib/squid/types'; export interface TokenDrawerMenuProps { checkout: Checkout; config: StrongCheckoutWidgetsConfig; + tokens: Token[] | null; toTokenAddress?: string; addTokensState: AddTokensState; addTokensDispatch: Dispatch; @@ -52,6 +54,7 @@ export interface TokenDrawerMenuProps { export function TokenDrawerMenu({ checkout, config, + tokens, toTokenAddress, addTokensState, addTokensDispatch, @@ -106,7 +109,7 @@ export function TokenDrawerMenu({ }), [ addTokensState.allowedTokens, - addTokensState.tokens, + tokens, handleTokenChange, isSelected, defaultTokenImage, @@ -126,7 +129,7 @@ export function TokenDrawerMenu({ }, [setVisible, setSearchValue]); useEffect(() => { - if (!checkout || addTokensState.tokens != null) return; + if (!checkout || tokens != null) return; (async () => { try { @@ -191,7 +194,7 @@ export function TokenDrawerMenu({ showErrorHandover(AddTokensErrorTypes.SERVICE_BREAKDOWN, { contextId: addTokensState.id, error }); } })(); - }, [addTokensState.tokens, checkout, toTokenAddress]); + }, [tokens, checkout, toTokenAddress]); return ( = ( ...state, allowedTokens: action.payload.allowedTokens, }; - case AddTokensActions.SET_SQUID: - return { - ...state, - squid: action.payload.squid, - }; - case AddTokensActions.SET_CHAINS: - return { - ...state, - chains: action.payload.chains, - }; - case AddTokensActions.SET_BALANCES: - return { - ...state, - balances: action.payload.balances, - }; - case AddTokensActions.SET_TOKENS: - return { - ...state, - tokens: action.payload.tokens, - }; - case AddTokensActions.SET_ROUTES: - return { - ...state, - routes: action.payload.routes, - }; case AddTokensActions.SET_SELECTED_ROUTE_DATA: return { ...state, diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useExecute.ts b/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useExecute.ts index daad2bff85..ccf604fefd 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useExecute.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useExecute.ts @@ -8,7 +8,7 @@ import { Environment } from '@imtbl/config'; import { StatusResponse } from '@0xsquid/sdk/dist/types'; import { Flow } from '@imtbl/metrics'; import { EIP6963ProviderInfo } from '@imtbl/checkout-sdk'; -import { isSquidNativeToken } from '../functions/isSquidNativeToken'; +import { isSquidNativeToken } from '../../../lib/squid/isSquidNativeToken'; import { useError } from './useError'; import { AddTokensError, AddTokensErrorTypes } from '../types'; import { EventTargetContext } from '../../../context/event-target-context/EventTargetContext'; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/types.ts b/packages/checkout/widgets-lib/src/widgets/add-tokens/types.ts index f31067c996..244cc526bf 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/types.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/types.ts @@ -1,50 +1,3 @@ -import { TokenBalance } from '@0xsquid/sdk/dist/types'; -import { RouteResponse } from '@0xsquid/squid-types'; - -export type Token = { - chainId: string; - address: string; - decimals: number; - symbol?: string; - name?: string; - usdPrice: number; - iconUrl: string; -}; - -export type Chain = { - id: string; - type: string; - name: string; - iconUrl: string; - nativeCurrency: NativeCurrency; -}; - -export type NativeCurrency = { - name: string; - symbol: string; - decimals: number; - iconUrl: string; -}; - -export type AmountData = { - fromToken: Token; - fromAmount: string; - toToken: Token; - toAmount: string; - balance: TokenBalance; - additionalBuffer: number; -}; - -export type RouteData = { - amountData: AmountData; - 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-tokens/utils/config.ts b/packages/checkout/widgets-lib/src/widgets/add-tokens/utils/config.ts index e6d18f9152..467e9629b6 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/utils/config.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/utils/config.ts @@ -1,7 +1,3 @@ -export const SQUID_SDK_BASE_URL = 'https://apiplus.squidrouter.com'; - -export const SQUID_NATIVE_TOKEN = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; - export const FIXED_HANDOVER_DURATION = 2000; export const APPROVE_TXN_ANIMATION = '/access_coins.riv'; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/views/AddTokens.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/views/AddTokens.tsx index f6bf343687..9d288a20fb 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/views/AddTokens.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/views/AddTokens.tsx @@ -44,10 +44,9 @@ import { AddTokensContext, } from '../context/AddTokensContext'; import type { StrongCheckoutWidgetsConfig } from '../../../lib/withDefaultWidgetConfig'; -import { useRoutes } from '../hooks/useRoutes'; -import { SQUID_NATIVE_TOKEN } from '../utils/config'; +import { useRoutes } from '../../../lib/squid/hooks/useRoutes'; import { AddTokensWidgetViews } from '../../../context/view-context/AddTokensViewContextTypes'; -import { AddTokensErrorTypes, type RouteData } from '../types'; +import { AddTokensErrorTypes } from '../types'; import { SelectedRouteOption } from '../components/SelectedRouteOption'; import { SelectedWallet } from '../components/SelectedWallet'; import { DeliverToWalletDrawer } from '../../../components/WalletDrawer/DeliverToWalletDrawer'; @@ -56,7 +55,7 @@ import { useInjectedProviders } from '../../../lib/hooks/useInjectedProviders'; import { getProviderSlugFromRdns } from '../../../lib/provider'; import { useProvidersContext } from '../../../context/providers-context/ProvidersContext'; import { sendConnectProviderSuccessEvent } from '../AddTokensWidgetEvents'; -import { convertToUsd } from '../functions/convertToUsd'; +import { convertToUsd } from '../../../lib/squid/convertToUsd'; import { useAnalytics, UserJourney, @@ -65,10 +64,13 @@ import { validateToAmount } from '../functions/amountValidation'; import { OnboardingDrawer } from '../components/OnboardingDrawer'; import { useError } from '../hooks/useError'; import { SquidFooter } from '../components/SquidFooter'; -import { getFormattedNumberWithDecimalPlaces } from '../functions/getFormattedNumber'; +import { getFormattedNumberWithDecimalPlaces } from '../../../lib/getFormattedNumber'; import { TokenDrawerMenu } from '../components/TokenDrawerMenu'; import { PULSE_SHADOW } from '../utils/animation'; import { checkSanctionedAddresses } from '../functions/checkSanctionedAddresses'; +import { type RouteData } from '../../../lib/squid/types'; +import { SQUID_NATIVE_TOKEN } from '../../../lib/squid/config'; +import { SquidContext } from '../../../context/squid-provider/SquidContext'; interface AddTokensProps { checkout: Checkout; @@ -100,18 +102,22 @@ export function AddTokens({ const { fetchRoutesWithRateLimit, resetRoutes } = useRoutes(); const { showErrorHandover } = useError(config.environment); + const { squidState } = useContext(SquidContext); + const { + squid, + chains, + balances, + tokens, + routes, + } = squidState; + const { addTokensState, addTokensDispatch, } = useContext(AddTokensContext); const { id, - squid, - chains, - balances, - tokens, selectedAmount, - routes, selectedRouteData, selectedToken, isSwapAvailable, @@ -299,7 +305,10 @@ export function AddTokens({ ) { setFetchingRoutes(true); const availableRoutes = await fetchRoutesWithRateLimit( - squid, + { + id, + userJourney: UserJourney.ADD_TOKENS, + }, tokens, balances, ChainId.IMTBL_ZKEVM_MAINNET.toString(), @@ -580,6 +589,7 @@ export function AddTokens({ - {`${t('views.ADD_TOKENS.fees.fiatPricePrefix')} + {`${t('views.ADD_TOKENS.fees.fiatPricePrefix')} $${getFormattedNumberWithDecimalPlaces(selectedAmountUsd)}`} diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/views/Review.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/views/Review.tsx index 3109ca4d29..bb0129a22e 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/views/Review.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/views/Review.tsx @@ -28,7 +28,7 @@ import { Trans } from 'react-i18next'; import { Environment } from '@imtbl/config'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { AddTokensContext } from '../context/AddTokensContext'; -import { useRoutes } from '../hooks/useRoutes'; +import { useRoutes } from '../../../lib/squid/hooks/useRoutes'; import { AddTokensReviewData, AddTokensWidgetViews, @@ -48,7 +48,6 @@ import { APPROVE_TXN_ANIMATION, EXECUTE_TXN_ANIMATION, FIXED_HANDOVER_DURATION, - SQUID_NATIVE_TOKEN, } from '../utils/config'; import { useAnalytics, @@ -56,16 +55,13 @@ import { } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; import { useProvidersContext } from '../../../context/providers-context/ProvidersContext'; import { LoadingView } from '../../../views/loading/LoadingView'; -import { getDurationFormatted } from '../functions/getDurationFormatted'; import { RouteFees } from '../components/RouteFees'; import { AddressMissmatchDrawer } from '../components/AddressMissmatchDrawer'; -import { getTotalRouteFees } from '../functions/getTotalRouteFees'; -import { getRouteChains } from '../functions/getRouteChains'; import { getFormattedAmounts, getFormattedNumber, getFormattedNumberWithDecimalPlaces, -} from '../functions/getFormattedNumber'; +} from '../../../lib/getFormattedNumber'; import { SquidFooter } from '../components/SquidFooter'; import { useError } from '../hooks/useError'; import { @@ -74,6 +70,11 @@ import { } from '../AddTokensWidgetEvents'; import { EventTargetContext } from '../../../context/event-target-context/EventTargetContext'; import { convertToNetworkChangeableProvider } from '../functions/convertToNetworkChangeableProvider'; +import { SQUID_NATIVE_TOKEN } from '../../../lib/squid/config'; +import { getDurationFormatted } from '../../../lib/squid/getDurationFormatted'; +import { getRouteChains } from '../../../lib/squid/getRouteChains'; +import { getTotalRouteFees } from '../../../lib/squid/getTotalRouteFees'; +import { SquidContext } from '../../../context/squid-provider/SquidContext'; interface ReviewProps { data: AddTokensReviewData; @@ -101,11 +102,15 @@ export function Review({ const { track, page } = useAnalytics(); const { - addTokensState: { - id, squid, chains, tokens, - }, + addTokensState: { id }, } = useContext(AddTokensContext); + const { + squidState: { + squid, chains, tokens, + }, + } = useContext(SquidContext); + const { providersState: { checkout, fromProvider, fromAddress, toAddress, fromProviderInfo, @@ -162,7 +167,10 @@ export function Review({ if (!amountData) return; const routeResponse = await getRoute( - squid, + { + id, + userJourney: UserJourney.ADD_TOKENS, + }, amountData?.fromToken, amountData?.toToken, toAddress,