From 0337336fb93cf722c52c6eb0db4e945bb8374929 Mon Sep 17 00:00:00 2001 From: Keith Broughton Date: Fri, 15 Aug 2025 13:13:37 +1000 Subject: [PATCH 1/4] GFI-995: Point users to AxelarScan --- .../Transactions/SupportMessage.tsx | 114 ++++-- .../components/Transactions/Transactions.tsx | 339 +----------------- .../checkout/widgets-lib/src/locales/en.json | 2 +- 3 files changed, 92 insertions(+), 363 deletions(-) diff --git a/packages/checkout/widgets-lib/src/components/Transactions/SupportMessage.tsx b/packages/checkout/widgets-lib/src/components/Transactions/SupportMessage.tsx index 1b485e6381..8add0e488a 100644 --- a/packages/checkout/widgets-lib/src/components/Transactions/SupportMessage.tsx +++ b/packages/checkout/widgets-lib/src/components/Transactions/SupportMessage.tsx @@ -1,26 +1,91 @@ import { Body, Box, Link } from '@biom3/react'; import { Checkout } from '@imtbl/checkout-sdk'; -import { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { PASSPORT_URL } from '../../lib'; import { supportMessageBoxStyle, bodyStyle } from './SupportMessageStyles'; +import { useAnalytics, UserJourney } from '../../context/analytics-provider/SegmentAnalyticsProvider'; type SupportMessageProps = { checkout: Checkout, isPassport: boolean, }; +function NeedHelpContactSupport() { + const { t } = useTranslation(); + const { track } = useAnalytics(); + + return ( + + + {t('views.TRANSACTIONS.support.body1')} + + + {t('views.TRANSACTIONS.support.body2')} + track({ + userJourney: UserJourney.BRIDGE, + screen: 'Transactions', + control: 'Support', + controlType: 'Link', + })} + href={t('views.TRANSACTIONS.support.supportLink')} + rel="noreferrer" + /> + )} + > + {t('views.TRANSACTIONS.support.body3')} + + + + ); +} + +function LookingForPastTransactions() { + const { track } = useAnalytics(); + + return ( + + + In progress and historical bridge transactions can be found on + {' '} + track({ + userJourney: UserJourney.BRIDGE, + screen: 'Transactions', + control: 'Axelarscan', + controlType: 'Link', + })} + href="https://axelarscan.io/" + rel="noreferrer" + /> + )} + > + Axelarscan + + . Search there using a non-Passport wallet address. + + + ); +} + export function SupportMessage({ checkout, isPassport, }: SupportMessageProps) { + const { track } = useAnalytics(); const { t } = useTranslation(); - const [passportLink, setPassportLink] = useState(''); - - useEffect(() => { - if (!checkout) return; - setPassportLink(PASSPORT_URL[checkout.config.environment]); - }, [checkout]); + const passportLink = PASSPORT_URL[checkout.config.environment]; return ( - - - {t('views.TRANSACTIONS.support.body1')} - - - {t('views.TRANSACTIONS.support.body2')} - } - > - {t('views.TRANSACTIONS.support.body3')} - - - + + {isPassport && ( } + rc={( + track({ + userJourney: UserJourney.BRIDGE, + screen: 'Transactions', + control: 'Passport', + controlType: 'Link', + })} + href={passportLink} + rel="noreferrer" + /> + )} > {t('views.TRANSACTIONS.support.passport.body2')} diff --git a/packages/checkout/widgets-lib/src/components/Transactions/Transactions.tsx b/packages/checkout/widgets-lib/src/components/Transactions/Transactions.tsx index 3d33ba4557..5f1508e6ee 100644 --- a/packages/checkout/widgets-lib/src/components/Transactions/Transactions.tsx +++ b/packages/checkout/widgets-lib/src/components/Transactions/Transactions.tsx @@ -1,35 +1,16 @@ import { - useCallback, useContext, useEffect, useMemo, useState, + useContext, useEffect, } from 'react'; import { Box } from '@biom3/react'; -import { - ChainId, - WrappedBrowserProvider, - TokenFilterTypes, - TokenInfo, - WalletProviderRdns, -} from '@imtbl/checkout-sdk'; -import { Environment } from '@imtbl/config'; + import { useTranslation } from 'react-i18next'; -import { JsonRpcProvider } from 'ethers'; import { HeaderNavigation } from '../Header/HeaderNavigation'; import { SimpleLayout } from '../SimpleLayout/SimpleLayout'; import { FooterLogo } from '../Footer/FooterLogo'; import { EventTargetContext } from '../../context/event-target-context/EventTargetContext'; import { - connectToProvider, isPassportProvider, } from '../../lib/provider'; -import { - DEFAULT_TRANSACTIONS_RETRY_POLICY, -} from '../../lib'; -import { CheckoutApi, Transaction, TransactionType } from '../../lib/clients'; -import { retry } from '../../lib/retry'; -import { getChainSlugById } from '../../lib/chains'; -import { - CryptoFiatActions, - CryptoFiatContext, -} from '../../context/crypto-fiat-context/CryptoFiatContext'; import { UserJourney, useAnalytics, @@ -38,253 +19,33 @@ import { BridgeActions, BridgeContext, } from '../../widgets/bridge/context/BridgeContext'; -import { WalletDrawer } from '../WalletDrawer/WalletDrawer'; import { sendBridgeWidgetCloseEvent } from '../../widgets/bridge/BridgeWidgetEvents'; -import { Shimmer } from './Shimmer'; import { supportBoxContainerStyle, transactionsContainerStyle, - transactionsListContainerStyle, } from './TransactionsStyles'; -import { EmptyStateNotConnected } from './EmptyStateNotConnected'; import { SupportMessage } from './SupportMessage'; -import { KnownNetworkMap } from './transactionsType'; -import { TransactionList } from './TransactionList'; -import { NoTransactions } from './NoTransactions'; -import { useInjectedProviders } from '../../lib/hooks/useInjectedProviders'; -import { WalletChangeEvent } from '../WalletDrawer/WalletDrawerEvents'; type TransactionsProps = { - defaultTokenImage: string; onBackButtonClick: () => void; }; export function Transactions({ - defaultTokenImage, onBackButtonClick, }: TransactionsProps) { const { eventTargetState: { eventTarget }, } = useContext(EventTargetContext); - const { cryptoFiatDispatch } = useContext(CryptoFiatContext); const { bridgeDispatch, bridgeState: { checkout, from }, } = useContext(BridgeContext); const { page } = useAnalytics(); const { t } = useTranslation(); - const { track } = useAnalytics(); - - const [loading, setLoading] = useState(true); - const [knownTokenMap, setKnownTokenMap] = useState< - KnownNetworkMap | undefined - >(undefined); - const [txs, setTxs] = useState([]); - const [showWalletDrawer, setShowWalletDrawer] = useState(false); const isPassport = isPassportProvider(from?.browserProvider); - // Fetch the tokens for the root chain using the allowed tokens. - // In case this list does not have all the tokens, there is logic - // built into the component to fetch the - // the missing data. - const rootChainTokensHashmap = useCallback(async () => { - if (!checkout) return {}; - - const rootChainId = checkout.config.l1ChainId; - try { - const tokens = ( - await checkout.getTokenAllowList({ - type: TokenFilterTypes.BRIDGE, - chainId: rootChainId, - }) - ).tokens ?? []; - return tokens.reduce((out, current) => { - // eslint-disable-next-line no-param-reassign - out[current.address!.toLowerCase()] = current; - return out; - }, {}); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - return []; - } - }, [checkout]); - - // Fetch the tokens for the root chain using the user balances tokens. - // In case this list does not have all the tokens, there is logic - // built into the component to fetch the - // the missing data. - const childChainTokensHashmap = useCallback(async () => { - if (!from?.browserProvider) return {}; - - if (!from?.walletAddress) return {}; - - const childChainId = checkout.config.l2ChainId; - - try { - const data = await checkout.getAllBalances({ - provider: from?.browserProvider, - walletAddress: from?.walletAddress, - chainId: childChainId, - }); - return data.balances.reduce((out, current) => { - // eslint-disable-next-line no-param-reassign - out[current.token.address!.toLowerCase()] = current.token; - return out; - }, {}); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - return []; - } - }, [checkout, from]); - - const getTokensDetails = async (tokensWithChainSlug: { - [p: string]: string; - }) => { - const rootChainName = getChainSlugById(checkout.config.l1ChainId); - const childChainName = getChainSlugById(checkout.config.l2ChainId); - - const [rootData, childData] = await Promise.all([ - rootChainTokensHashmap(), - childChainTokensHashmap(), - ]); - - // Fetch the data for the missing tokens: tokensWithChainSlug - const missingTokens: { [k: string]: string } = {}; - Object.entries(tokensWithChainSlug).forEach(([key, value]) => { - if ( - (tokensWithChainSlug[key] === rootChainName && !rootData[key]) - || (tokensWithChainSlug[key] === childChainName && !childData[key]) - ) missingTokens[key] = value; - }); - // Root provider is always L1 - const rootProvider = new JsonRpcProvider( - checkout.config.networkMap.get(checkout.config.l1ChainId)?.rpcUrls[0], - ); - - // Child provider is always L2 - const childProvider = new JsonRpcProvider( - checkout.config.networkMap.get(checkout.config.l2ChainId)?.rpcUrls[0], - ); - - const rootTokenInfoPromises: Promise[] = []; - const childTokenInfoPromises: Promise[] = []; - - Object.entries(missingTokens).forEach(([tokenAddress, chainName]) => { - if (chainName === rootChainName) { - // Root provider - rootTokenInfoPromises.push( - checkout.getTokenInfo({ - provider: rootProvider, - tokenAddress, - }), - ); - } else { - // child provider - childTokenInfoPromises.push( - checkout.getTokenInfo({ - provider: childProvider, - tokenAddress, - }), - ); - } - }); - const rootTokenInfo = await Promise.allSettled(rootTokenInfoPromises); - const childTokenInfo = await Promise.allSettled(childTokenInfoPromises); - - ( - rootTokenInfo.filter( - (result) => result.status === 'fulfilled', - ) as PromiseFulfilledResult[] - ).forEach((result) => { - const resp = result; - rootData[resp.value.address!.toLowerCase()] = resp.value; - }); - - ( - childTokenInfo.filter( - (result) => result.status === 'fulfilled', - ) as PromiseFulfilledResult[] - ).forEach((result) => { - const resp = result; - childData[resp.value.address!.toLowerCase()] = resp.value; - }); - - const allTokenSymbols: string[] = []; - Object.values(rootData).forEach((token) => allTokenSymbols.push((token as TokenInfo).symbol.toLowerCase())); - Object.values(childData).forEach((token) => allTokenSymbols.push((token as TokenInfo).symbol.toLowerCase())); - - cryptoFiatDispatch({ - payload: { - type: CryptoFiatActions.SET_TOKEN_SYMBOLS, - tokenSymbols: allTokenSymbols, - }, - }); - - return { [rootChainName]: rootData, [childChainName]: childData }; - }; - - const getTransactionsDetails = useCallback( - async (env: Environment, address: string) => { - const client = new CheckoutApi({ env }); - return client.getTransactions({ - txType: TransactionType.BRIDGE, - fromAddress: address, - }); - }, - [], - ); - - const handleWalletChange = useCallback( - async (event: WalletChangeEvent) => { - track({ - userJourney: UserJourney.BRIDGE, - screen: 'EmptyStateNotConnected', - control: 'WalletProvider', - controlType: 'Select', - extras: { - walletProviderName: event.providerDetail.info.name, - }, - }); - - try { - let changeAccount = false; - if (event.providerDetail.info.rdns === WalletProviderRdns.METAMASK) { - changeAccount = true; - } - const browserProvider = new WrappedBrowserProvider(event.provider); - const connectedProvider = await connectToProvider(checkout, browserProvider, changeAccount); - const network = await connectedProvider.getNetwork(); - const address = await (await connectedProvider.getSigner()).getAddress(); - - setTxs([]); - bridgeDispatch({ - payload: { - type: BridgeActions.SET_WALLETS_AND_NETWORKS, - from: { - browserProvider: connectedProvider, - walletProviderInfo: { - ...event.providerDetail.info, - }, - walletAddress: address.toLowerCase(), - network: network.chainId as unknown as ChainId, - }, - to: null, - }, - }); - } catch (error) { - // eslint-disable-next-line no-console - console.error(error); - } finally { - setShowWalletDrawer(false); - } - }, - [checkout], - ); - const handleBackButtonClick = () => { if (from) { bridgeDispatch({ @@ -311,55 +72,6 @@ export function Transactions({ onBackButtonClick(); }; - const fetchData = useCallback(async () => { - if (!from?.walletAddress) return undefined; - - const localTxs = await getTransactionsDetails( - checkout.config.environment, - from?.walletAddress, - ); - - const tokensWithChainSlug: { [k: string]: string } = {}; - localTxs.result.forEach((txn) => { - tokensWithChainSlug[txn.details.from_token_address] = txn.details.from_chain; - }); - - return { - tokens: await getTokensDetails(tokensWithChainSlug), - transactions: localTxs.result, - }; - }, [from, getTransactionsDetails]); - - const { providers } = useInjectedProviders({ checkout }); - const walletOptions = useMemo(() => providers, [providers]); - - // Fetch all the data at once - useEffect(() => { - (async () => { - setLoading(true); - const data = await retry(fetchData, DEFAULT_TRANSACTIONS_RETRY_POLICY); - if (!data) { - setLoading(false); - return; - } - - const knownTxs = data.transactions.filter((txn) => { - const tokens = data.tokens[txn.details.from_chain]; - if (!tokens) return false; - - const token = tokens[txn.details.from_token_address.toLowerCase()]; - if (!token) return false; - - return true; - }); - - setKnownTokenMap(data.tokens); - setTxs(knownTxs); - - setLoading(false); - })(); - }, [from, checkout]); - useEffect(() => { page({ userJourney: UserJourney.BRIDGE, @@ -381,52 +93,9 @@ export function Transactions({ footer={} > - - {!from?.browserProvider && ( - setShowWalletDrawer(true)} - /> - )} - {from?.browserProvider && loading && } - {from?.browserProvider - && !loading - && txs.length > 0 - && knownTokenMap && ( - setShowWalletDrawer(true)} - /> - )} - {from?.browserProvider && !loading && txs.length === 0 && ( - setShowWalletDrawer(true)} - /> - )} + + - {from?.browserProvider && txs.length > 0 && ( - - - - )} - { - setShowWalletDrawer(show); - }} - onWalletChange={handleWalletChange} - /> ); diff --git a/packages/checkout/widgets-lib/src/locales/en.json b/packages/checkout/widgets-lib/src/locales/en.json index b1bddf0436..47b0d014e4 100644 --- a/packages/checkout/widgets-lib/src/locales/en.json +++ b/packages/checkout/widgets-lib/src/locales/en.json @@ -636,7 +636,7 @@ }, "fiatPricePrefix": "≈ USD $", "support": { - "body1": "Need help?", + "body1": "Need additional help?", "body2": " Contact ", "body3": "support", "supportLink": "https://support.immutable.com/hc/en-us", From f7d3f872c64e7dc998e33c40a58f1ee616994dc5 Mon Sep 17 00:00:00 2001 From: Keith Broughton Date: Fri, 15 Aug 2025 13:19:05 +1000 Subject: [PATCH 2/4] Delete fiels --- .../Transactions/TransactionDetails.tsx | 91 -------- .../Transactions/TransactionItem.tsx | 137 ------------ .../TransactionItemWithdrawPending.tsx | 196 ------------------ .../Transactions/TransactionList.tsx | 119 ----------- .../Transactions/TransactionListStyles.ts | 25 --- .../Transactions/transactionItemStyles.ts | 33 --- .../Transactions/transactionsType.ts | 7 - .../src/widgets/bridge/BridgeWidget.tsx | 2 +- 8 files changed, 1 insertion(+), 609 deletions(-) delete mode 100644 packages/checkout/widgets-lib/src/components/Transactions/TransactionDetails.tsx delete mode 100644 packages/checkout/widgets-lib/src/components/Transactions/TransactionItem.tsx delete mode 100644 packages/checkout/widgets-lib/src/components/Transactions/TransactionItemWithdrawPending.tsx delete mode 100644 packages/checkout/widgets-lib/src/components/Transactions/TransactionList.tsx delete mode 100644 packages/checkout/widgets-lib/src/components/Transactions/TransactionListStyles.ts delete mode 100644 packages/checkout/widgets-lib/src/components/Transactions/transactionItemStyles.ts delete mode 100644 packages/checkout/widgets-lib/src/components/Transactions/transactionsType.ts diff --git a/packages/checkout/widgets-lib/src/components/Transactions/TransactionDetails.tsx b/packages/checkout/widgets-lib/src/components/Transactions/TransactionDetails.tsx deleted file mode 100644 index 6a24e90645..0000000000 --- a/packages/checkout/widgets-lib/src/components/Transactions/TransactionDetails.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { - Box, Icon, Body, EllipsizedText, FramedImage, -} from '@biom3/react'; -import { ChainSlug } from '@imtbl/checkout-sdk'; -import { Environment } from '@imtbl/config'; -import { networkName } from '../../lib'; -import { getChainIdBySlug } from '../../lib/chains'; -import { Transaction } from '../../lib/clients'; -import { getChainImage } from '../../lib/utils'; - -export interface TransactionDetailsProps { - transaction: Transaction; - environment: Environment; -} - -export function TransactionDetails({ transaction, environment }: TransactionDetailsProps) { - const fromChain = getChainIdBySlug(transaction.details.from_chain as ChainSlug); - const toChain = getChainIdBySlug(transaction.details.to_chain as ChainSlug); - return ( - - - )} - /> - - - {networkName[fromChain]} - - - - - - - - )} - /> - - - {networkName[toChain]} - - - - - ); -} diff --git a/packages/checkout/widgets-lib/src/components/Transactions/TransactionItem.tsx b/packages/checkout/widgets-lib/src/components/Transactions/TransactionItem.tsx deleted file mode 100644 index be70a39b0c..0000000000 --- a/packages/checkout/widgets-lib/src/components/Transactions/TransactionItem.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { - Accordion, - Box, - Divider, - MenuItem, - Link, -} from '@biom3/react'; -import { MouseEvent, useMemo } from 'react'; -import { Environment } from '@imtbl/config'; -import { UserJourney, useAnalytics } from '../../context/analytics-provider/SegmentAnalyticsProvider'; -import { Transaction } from '../../lib/clients/checkoutApiType'; -import { TokenImage } from '../TokenImage/TokenImage'; -import { containerStyles } from './transactionItemStyles'; -import { TransactionDetails } from './TransactionDetails'; - -type TransactionItemProps = { - label: string - details: { - text: string, - link: string, - hash: string, - }, - transaction: Transaction, - fiatAmount: string, - amount: string, - icon: string, - defaultTokenImage: string, - environment: Environment, -}; - -export function TransactionItem({ - label, - details, - transaction, - fiatAmount, - amount, - icon, - defaultTokenImage, - environment, -}: TransactionItemProps) { - const { track } = useAnalytics(); - const txnDetailsLink = useMemo(() => `${details.link}${details.hash}`, [details]); - - const handleDetailsLinkClick = ( - event: MouseEvent, - linkDetail: { text: string, link: string, hash: string }, - ) => { - event.stopPropagation(); // prevent expanding accordian - - track({ - userJourney: UserJourney.BRIDGE, - screen: 'TransactionItem', - control: 'Details', - controlType: 'Link', - extras: { - linkDetail, - }, - }); - }; - - return ( - - expanded - && track({ - userJourney: UserJourney.BRIDGE, - screen: 'TransactionItem', - control: 'Accordion', - controlType: 'Button', - }) - } - > - - - - )} - /> - - {label} - - - handleDetailsLinkClick(e, details)} - /> - )} - > - {details.text} - - - - - - - - - - - - ); -} diff --git a/packages/checkout/widgets-lib/src/components/Transactions/TransactionItemWithdrawPending.tsx b/packages/checkout/widgets-lib/src/components/Transactions/TransactionItemWithdrawPending.tsx deleted file mode 100644 index 7139d9d6fb..0000000000 --- a/packages/checkout/widgets-lib/src/components/Transactions/TransactionItemWithdrawPending.tsx +++ /dev/null @@ -1,196 +0,0 @@ -import { - Accordion, - Body, - Box, - Button, - Divider, - Icon, - MenuItem, -} from '@biom3/react'; -import { useContext, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Environment } from '@imtbl/config'; -import { UserJourney, useAnalytics } from '../../context/analytics-provider/SegmentAnalyticsProvider'; -import { Transaction, TransactionStatus } from '../../lib/clients/checkoutApiType'; -import { BridgeWidgetViews } from '../../context/view-context/BridgeViewContextTypes'; -import { ViewActions, ViewContext } from '../../context/view-context/ViewContext'; -import { TokenImage } from '../TokenImage/TokenImage'; -import { actionsContainerStyles, actionsLayoutStyles, containerStyles } from './transactionItemStyles'; -import { TransactionDetails } from './TransactionDetails'; - -type TransactionItemWithdrawPendingProps = { - label: string, - transaction: Transaction, - fiatAmount: string, - amount: string, - icon: string, - defaultTokenImage: string, - environment: Environment, -}; - -export function TransactionItemWithdrawPending({ - label, - transaction, - fiatAmount, - amount, - icon, - defaultTokenImage, - environment, -}: TransactionItemWithdrawPendingProps) { - const { viewDispatch } = useContext(ViewContext); - const { track } = useAnalytics(); - const translation = useTranslation(); - const dateNowUnixMs = useMemo(() => new Date().getTime(), []); - const withdrawalReadyDate = useMemo( - () => (transaction.details.current_status.withdrawal_ready_at - ? new Date(transaction.details.current_status.withdrawal_ready_at) - : undefined), - [transaction], - ); - - const requiresWithdrawalClaim = transaction.details.current_status.status === TransactionStatus.WITHDRAWAL_PENDING; - - const relativeTimeFormat = new Intl.RelativeTimeFormat(translation[1].language || 'en', { numeric: 'auto' }); - - const delayTimeString = useMemo(() => { - if (!requiresWithdrawalClaim || withdrawalReadyDate === undefined) return ''; - - const timeDiffMins = (withdrawalReadyDate!.getTime() - dateNowUnixMs) / (60 * 1000); - - if (timeDiffMins <= 1) return 'in 1 minute'; - - if (timeDiffMins < 60) { - return relativeTimeFormat.format(Math.ceil(timeDiffMins), 'minute'); - } - const timeDiffHours = timeDiffMins / 60; // hours - if (timeDiffMins < 60 * 24) { - return relativeTimeFormat.format(Math.ceil(timeDiffHours), 'hour'); - } - const timeDiffDays = timeDiffHours / 24; // days - return relativeTimeFormat.format(Math.ceil(timeDiffDays), 'day'); - }, [dateNowUnixMs, translation[1].language]); - - const withdrawalReadyToClaim = withdrawalReadyDate ? withdrawalReadyDate.getTime() < dateNowUnixMs : false; - const actionMessage = useMemo( - () => (withdrawalReadyToClaim === true - ? translation.t('views.TRANSACTIONS.status.withdrawalPending.withdrawalReadyText') - : `${translation.t('views.TRANSACTIONS.status.withdrawalPending.withdrawalDelayText')} ${delayTimeString}`), - [delayTimeString, translation[1].language], - ); - - const handleWithdrawalClaimClick = () => { - viewDispatch({ - payload: { - type: ViewActions.UPDATE_VIEW, - view: { - type: BridgeWidgetViews.CLAIM_WITHDRAWAL, - transaction, - }, - }, - }); - }; - - return ( - - {requiresWithdrawalClaim && ( - <> - - - - - {actionMessage} - - - {requiresWithdrawalClaim && withdrawalReadyToClaim && ( - - )} - - - - )} - - expanded - && track({ - userJourney: UserJourney.BRIDGE, - screen: 'TransactionItem', - control: 'Accordion', - controlType: 'Button', - }) - } - > - - - - )} - /> - - {label} - - - {translation.t('views.TRANSACTIONS.status.withdrawalPending.caption')} - - - - - - - - - - - ); -} diff --git a/packages/checkout/widgets-lib/src/components/Transactions/TransactionList.tsx b/packages/checkout/widgets-lib/src/components/Transactions/TransactionList.tsx deleted file mode 100644 index e6826e7c59..0000000000 --- a/packages/checkout/widgets-lib/src/components/Transactions/TransactionList.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { - Box, -} from '@biom3/react'; -import { Checkout } from '@imtbl/checkout-sdk'; -import { - useCallback, - useContext, - useEffect, - useState, -} from 'react'; -import { useTranslation } from 'react-i18next'; -import { formatUnits } from 'ethers'; -import { AXELAR_SCAN_URL } from '../../lib'; -import { Transaction, TransactionStatus } from '../../lib/clients'; -import { CryptoFiatContext } from '../../context/crypto-fiat-context/CryptoFiatContext'; -import { calculateCryptoToFiat, getTokenImageByAddress, isNativeToken } from '../../lib/utils'; -import { TransactionItem } from './TransactionItem'; -import { KnownNetworkMap } from './transactionsType'; -import { containerStyles, transactionsListStyle } from './TransactionListStyles'; -import { TransactionItemWithdrawPending } from './TransactionItemWithdrawPending'; -import { ChangeWallet } from './ChangeWallet'; -import { getNativeSymbolByChainSlug } from '../../lib/chains'; - -type TransactionListProps = { - checkout: Checkout, - transactions: Transaction[], - knownTokenMap: KnownNetworkMap, - isPassport: boolean; - defaultTokenImage: string; - changeWallet: () => void, -}; - -export function TransactionList({ - checkout, - transactions, - knownTokenMap, - isPassport, - defaultTokenImage, - changeWallet, -}: TransactionListProps) { - const { cryptoFiatState } = useContext(CryptoFiatContext); - const { t } = useTranslation(); - const [link, setLink] = useState(''); - const { environment } = checkout.config; - - useEffect(() => { - if (!checkout) return; - setLink(AXELAR_SCAN_URL[checkout.config.environment]); - }, [checkout]); - - const sortWithdrawalPendingFirst = useCallback((txnA, txnB) => { - if ( - txnA.details.current_status.status === TransactionStatus.WITHDRAWAL_PENDING - && txnB.details.current_status.status !== TransactionStatus.WITHDRAWAL_PENDING) return -1; - if (txnA.details.current_status.status === txnB.details.current_status.status) return 0; - - return 1; - }, []); - - const getTransactionItemIcon = useCallback((transaction) => { - if (isNativeToken(transaction.details.from_token_address)) { - // Map transaction chain slug to native symbol icon asset - return getTokenImageByAddress( - checkout.config.environment, - getNativeSymbolByChainSlug(transaction.details.from_chain), - ); - } - return getTokenImageByAddress(checkout.config.environment, transaction.details.from_token_address); - }, [checkout]); - - return ( - - - - {transactions - .sort(sortWithdrawalPendingFirst) - .map((transaction) => { - const hash = transaction.blockchain_metadata.transaction_hash; - const tokens = knownTokenMap[transaction.details.from_chain]; - const token = tokens[transaction.details.from_token_address.toLowerCase()]; - const amount = formatUnits(transaction.details.amount, token.decimals); - const fiat = calculateCryptoToFiat(amount, token.symbol, cryptoFiatState.conversions); - - if (transaction.details.current_status.status === TransactionStatus.WITHDRAWAL_PENDING) { - return ( - - ); - } - - return ( - - ); - })} - - - ); -} diff --git a/packages/checkout/widgets-lib/src/components/Transactions/TransactionListStyles.ts b/packages/checkout/widgets-lib/src/components/Transactions/TransactionListStyles.ts deleted file mode 100644 index 1b90876a24..0000000000 --- a/packages/checkout/widgets-lib/src/components/Transactions/TransactionListStyles.ts +++ /dev/null @@ -1,25 +0,0 @@ -export const transactionsListStyle = (showPassportLink: boolean) => { - let height = 440; - - if (showPassportLink) { - height -= 20; - } - - return { - backgroundColor: 'base.color.neutral.800', - px: 'base.spacing.x4', - pt: 'base.spacing.x5', - pb: 'base.spacing.x4', - borderRadius: 'base.borderRadius.x6', - h: `${height}px`, - w: '100%', - overflowY: 'scroll', - }; -}; - -export const containerStyles = { - borderRadius: 'base.borderRadius.x4', - display: 'flex', - flexDirection: 'column', - gap: 'base.spacing.x5', -}; diff --git a/packages/checkout/widgets-lib/src/components/Transactions/transactionItemStyles.ts b/packages/checkout/widgets-lib/src/components/Transactions/transactionItemStyles.ts deleted file mode 100644 index e9764a19ee..0000000000 --- a/packages/checkout/widgets-lib/src/components/Transactions/transactionItemStyles.ts +++ /dev/null @@ -1,33 +0,0 @@ -export const containerStyles = { - display: 'flex', - flexDirection: 'column', - borderRadius: 'base.borderRadius.x4', - bg: 'base.color.translucent.emphasis.100', -}; -export const headingStyles = { - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', - paddingLeft: 'base.spacing.x2', - alignItems: 'center', -}; - -export const actionsContainerStyles = { - p: 'base.spacing.x3', - d: 'flex', - justifyContent: 'space-between', - position: 'relative', -}; - -export const actionsLayoutStyles = { - display: 'flex', - flexGrow: '1', - alignItems: 'center', - gap: 'base.spacing.x2', -}; - -export const actionsBadgeStyles = { - position: 'absolute', - right: 'base.spacing.x2', - top: 'base.spacing.x2', -}; diff --git a/packages/checkout/widgets-lib/src/components/Transactions/transactionsType.ts b/packages/checkout/widgets-lib/src/components/Transactions/transactionsType.ts deleted file mode 100644 index 201acae771..0000000000 --- a/packages/checkout/widgets-lib/src/components/Transactions/transactionsType.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { TokenInfo } from '@imtbl/checkout-sdk'; - -export type KnownNetworkMap = { - [chainName: string]: { - [address: string]: TokenInfo - } -}; diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx index deb7399e43..a1730058f3 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx @@ -257,7 +257,7 @@ export default function BridgeWidget({ /> )} {viewState.view.type === BridgeWidgetViews.TRANSACTIONS && ( - + )} {viewState.view.type === BridgeWidgetViews.CLAIM_WITHDRAWAL && ( From a097087f4d18d9f4df6af2e88e0154400201836d Mon Sep 17 00:00:00 2001 From: Keith Broughton Date: Fri, 15 Aug 2025 13:27:40 +1000 Subject: [PATCH 3/4] Remove clients --- .../Transactions/SupportMessage.tsx | 2 +- .../src/lib/clients/checkoutApi.test.ts | 169 ------------------ .../src/lib/clients/checkoutApi.ts | 102 ----------- .../src/lib/clients/checkoutApiType.ts | 41 ----- .../widgets-lib/src/lib/clients/index.ts | 2 - 5 files changed, 1 insertion(+), 315 deletions(-) delete mode 100644 packages/checkout/widgets-lib/src/lib/clients/checkoutApi.test.ts delete mode 100644 packages/checkout/widgets-lib/src/lib/clients/checkoutApi.ts delete mode 100644 packages/checkout/widgets-lib/src/lib/clients/checkoutApiType.ts delete mode 100644 packages/checkout/widgets-lib/src/lib/clients/index.ts diff --git a/packages/checkout/widgets-lib/src/components/Transactions/SupportMessage.tsx b/packages/checkout/widgets-lib/src/components/Transactions/SupportMessage.tsx index 8add0e488a..01187a65a5 100644 --- a/packages/checkout/widgets-lib/src/components/Transactions/SupportMessage.tsx +++ b/packages/checkout/widgets-lib/src/components/Transactions/SupportMessage.tsx @@ -73,7 +73,7 @@ function LookingForPastTransactions() { > Axelarscan - . Search there using a non-Passport wallet address. + . Search there with the non-Passport wallet address used in the transaction. ); diff --git a/packages/checkout/widgets-lib/src/lib/clients/checkoutApi.test.ts b/packages/checkout/widgets-lib/src/lib/clients/checkoutApi.test.ts deleted file mode 100644 index f7a165d4d2..0000000000 --- a/packages/checkout/widgets-lib/src/lib/clients/checkoutApi.test.ts +++ /dev/null @@ -1,169 +0,0 @@ -/* eslint @typescript-eslint/naming-convention: off */ -import axios, { AxiosError, HttpStatusCode } from 'axios'; -import { Environment } from '@imtbl/config'; -import { TransactionType } from './checkoutApiType'; -import { CheckoutApi } from './checkoutApi'; - -jest.mock('axios'); -const mockedAxios = axios as jest.Mocked; - -describe('CheckoutApi', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('getTransactions', () => { - it('success', async () => { - const mockResponse = { - status: 200, - data: - { - result: [ - { - type: 'bridge', - details: { - from_address: '0x1234567890', - from_chain: 'imtbl-zkevm-testnet', - amount: '100000000000000000', - from_token_address: 'native', - to_address: '0x1e8dc77bed0da06621e819fa0afb59d50f76cfdf', - to_chain: 'sepolia', - to_token_address: '0x60466acb9e525ae1e9978fd14197c8c419ba65e6', - current_status: { - status: 'in_progress', - }, - }, - blockchain_metadata: { - transaction_hash: '0x68d9eac5e3b3c3580404989a4030c948a78e1b07b2b5ea5688d8c38a6c61c93e', - }, - updated_at: '2022-08-16T17:43:26.991388Z', - }, - ], - }, - }; - mockedAxios.get.mockResolvedValueOnce(mockResponse); - - const txType = TransactionType.BRIDGE; - const fromAddress = '0x1234567890'; - const client = new CheckoutApi({ env: Environment.SANDBOX }); - const resp = await client.getTransactions({ fromAddress, txType }); - - // should not contain native token data - expect(resp.result.length).toEqual(1); - expect( - resp.result[0].blockchain_metadata.transaction_hash, - ).toEqual('0x68d9eac5e3b3c3580404989a4030c948a78e1b07b2b5ea5688d8c38a6c61c93e'); - expect(resp.result[0].details.from_address).toEqual('0x1234567890'); - expect(resp.result[0].details.from_chain).toEqual('imtbl-zkevm-testnet'); - expect(resp.result[0].details.current_status.status).toEqual('in_progress'); - - expect(mockedAxios.get).toHaveBeenNthCalledWith( - 1, - `${client.url}/v1/transactions?from_address=${fromAddress}&tx_type=${txType}`, - ); - }); - - it('success cached', async () => { - const mockResponse = { - status: 200, - data: - { - result: [], - }, - }; - mockedAxios.get.mockResolvedValue(mockResponse); - - const txType = TransactionType.BRIDGE; - const fromAddress = '0x1234567890'; - const client = new CheckoutApi({ env: Environment.SANDBOX }); - const precache = await client.getTransactions({ fromAddress, txType }); - const cached = await client.getTransactions({ fromAddress, txType }); - - expect(cached).toEqual(precache); - - expect(mockedAxios.get).toHaveBeenNthCalledWith( - 1, - `${client.url}/v1/transactions?from_address=${fromAddress}&tx_type=${txType}`, - ); - }); - - it('success zero TTL', async () => { - const mockResponse = { - status: 200, - data: - { - result: [], - }, - }; - mockedAxios.get.mockResolvedValue(mockResponse); - - const txType = TransactionType.BRIDGE; - const fromAddress = '0x1234567890'; - const client = new CheckoutApi({ env: Environment.SANDBOX, ttl: 0 }); - const precache = await client.getTransactions({ fromAddress, txType }); - const cached = await client.getTransactions({ fromAddress, txType }); - - expect(cached).toEqual(precache); - - expect(mockedAxios.get).toHaveBeenNthCalledWith( - 2, - `${client.url}/v1/transactions?from_address=${fromAddress}&tx_type=${txType}`, - ); - }); - - it('fails 400', async () => { - const mockResponse = { - status: HttpStatusCode.BadRequest, - statusText: 'error', - data: {}, - }; - mockedAxios.get.mockResolvedValueOnce(mockResponse); - - const txType = TransactionType.BRIDGE; - const fromAddress = '0x1234567890'; - const client = new CheckoutApi({ env: Environment.SANDBOX }); - try { - await client.getTransactions({ fromAddress, txType }); - } catch (error: any) { - expect(CheckoutApi.isHttpError(error)).toBe(true); - expect((error as AxiosError).code).toEqual(HttpStatusCode.BadRequest); - expect((error as AxiosError).message).toEqual('error'); - } - }); - - it('fails 500', async () => { - const mockResponse = { - status: HttpStatusCode.InternalServerError, - statusText: 'error', - data: {}, - }; - mockedAxios.get.mockResolvedValueOnce(mockResponse); - - const txType = TransactionType.BRIDGE; - const fromAddress = '0x1234567890'; - const client = new CheckoutApi({ env: Environment.SANDBOX }); - try { - await client.getTransactions({ fromAddress, txType }); - } catch (error: any) { - expect(CheckoutApi.isHttpError(error)).toBe(true); - expect((error as AxiosError).code).toEqual(HttpStatusCode.InternalServerError); - expect((error as AxiosError).message).toEqual('error'); - } - }); - - it('throws', async () => { - mockedAxios.get.mockRejectedValueOnce('error'); - - const txType = TransactionType.BRIDGE; - const fromAddress = '0x1234567890'; - const client = new CheckoutApi({ env: Environment.SANDBOX }); - try { - await client.getTransactions({ fromAddress, txType }); - } catch (error: any) { - expect(CheckoutApi.isHttpError(error)).toBe(true); - expect((error as AxiosError).code).toEqual(HttpStatusCode.InternalServerError); - expect((error as AxiosError).message).toEqual('InternalServerError'); - } - }); - }); -}); diff --git a/packages/checkout/widgets-lib/src/lib/clients/checkoutApi.ts b/packages/checkout/widgets-lib/src/lib/clients/checkoutApi.ts deleted file mode 100644 index 8ea17b5bbc..0000000000 --- a/packages/checkout/widgets-lib/src/lib/clients/checkoutApi.ts +++ /dev/null @@ -1,102 +0,0 @@ -import axios, { AxiosError, HttpStatusCode } from 'axios'; -import { Environment } from '@imtbl/config'; -import { IMMUTABLE_API_BASE_URL } from '@imtbl/checkout-sdk'; -import { ENV_DEVELOPMENT } from '../constants'; -import { TransactionType, Transactions } from './checkoutApiType'; - -type CacheData = { - data: any, - ttl: number -}; - -type GetTransactions = { - txType: TransactionType, - fromAddress: string, -}; - -const CACHE_DATA_TTL = 60; // seconds - -/** - * Checkout API class provides a client abstraction for the Checkout API. - */ -export class CheckoutApi { - readonly url: string; - - readonly ttl: number; - - readonly env: Environment; - - private cacheMap: { [key: string]: CacheData }; - - private setCache(key: string, data: any) { - this.cacheMap[key] = { data, ttl: new Date().getTime() + this.ttl * 1000 }; - } - - private getCache(key: string): any { - const d = this.cacheMap[key]; - if (!d || d.ttl <= new Date().getTime()) return null; - return d.data; - } - - /** - * Checkout API constructor - * @param env target chain - * @param ttl cache TTL - */ - constructor(params: { - env: Environment | typeof ENV_DEVELOPMENT; - ttl?: number - }) { - this.env = params.env; - this.url = `${IMMUTABLE_API_BASE_URL[this.env]}/checkout`; - - this.cacheMap = {}; - this.ttl = params.ttl !== undefined ? params.ttl : CACHE_DATA_TTL; - } - - /** - * isHttpError verifies if the error is a HTTP error - * @param err error to evaluate - */ - public static isHttpError = (err: any): boolean => 'code' in err; - - /** - * getTransactions fetches a list of blockchain transactions. - * @param txType transaction type - * @param fromAddress transactions executed from address - */ - public async getTransactions(params: GetTransactions): Promise { - const { txType, fromAddress } = params; - - try { - const url = `${this.url}/v1/transactions?from_address=${fromAddress}&tx_type=${txType}`; - - // Cache response data to prevent unnecessary requests - const cached = this.getCache(url); - if (cached) return Promise.resolve(cached); - - const response = await axios.get(url); - if (response.status >= 400) { - return Promise.reject({ - code: response.status, - message: response.statusText, - }); - } - - const { data } = response; - - this.setCache(url, data); - return Promise.resolve(data); - } catch (err: any) { - let code: number = HttpStatusCode.InternalServerError; - let message = 'InternalServerError'; - - if (axios.isAxiosError(err)) { - code = (err as AxiosError).response?.status || code; - message = (err as AxiosError).message; - } - - return Promise.reject({ code, message }); - } - } -} diff --git a/packages/checkout/widgets-lib/src/lib/clients/checkoutApiType.ts b/packages/checkout/widgets-lib/src/lib/clients/checkoutApiType.ts deleted file mode 100644 index 4fb76a9392..0000000000 --- a/packages/checkout/widgets-lib/src/lib/clients/checkoutApiType.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -export enum TransactionType { - BRIDGE = 'bridge', -} - -export const TransactionStatus = { - IN_PROGRESS: 'in_progress', - WITHDRAWAL_PENDING: 'withdrawal_pending', -} as const; - -export type Transactions = { - result: Transaction[] -}; - -export type CurrentStatus = { - status: string; - withdrawal_ready_at?: string; - index?: number; -}; - -export type TransactionDetails = { - amount: string - from_address: string - from_chain: string - from_token_address: string - to_address: string - to_chain: string - to_token_address: string - current_status: CurrentStatus -}; - -export type BlockchainMetadata = { - transaction_hash: string -}; - -export type Transaction = { - tx_type: TransactionType - details: TransactionDetails - blockchain_metadata: BlockchainMetadata - created_at: string -}; diff --git a/packages/checkout/widgets-lib/src/lib/clients/index.ts b/packages/checkout/widgets-lib/src/lib/clients/index.ts deleted file mode 100644 index 59d3c26721..0000000000 --- a/packages/checkout/widgets-lib/src/lib/clients/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './checkoutApi'; -export * from './checkoutApiType'; From 228f21862c2e3606852549ced3323ccdc15a933d Mon Sep 17 00:00:00 2001 From: Keith Broughton Date: Fri, 15 Aug 2025 13:30:33 +1000 Subject: [PATCH 4/4] rm --- .../view-context/BridgeViewContextTypes.ts | 7 - .../src/widgets/bridge/BridgeWidget.tsx | 4 - .../widgets/bridge/views/ClaimWithdrawal.tsx | 284 ------------------ 3 files changed, 295 deletions(-) delete mode 100644 packages/checkout/widgets-lib/src/widgets/bridge/views/ClaimWithdrawal.tsx diff --git a/packages/checkout/widgets-lib/src/context/view-context/BridgeViewContextTypes.ts b/packages/checkout/widgets-lib/src/context/view-context/BridgeViewContextTypes.ts index 5de81216b5..df87fcecbb 100644 --- a/packages/checkout/widgets-lib/src/context/view-context/BridgeViewContextTypes.ts +++ b/packages/checkout/widgets-lib/src/context/view-context/BridgeViewContextTypes.ts @@ -1,6 +1,5 @@ import { ApproveBridgeResponse, BridgeTxResponse } from '@imtbl/bridge-sdk'; import { TransactionResponse } from 'ethers'; -import { Transaction } from '../../lib/clients'; import { ViewType } from './ViewType'; export enum BridgeWidgetViews { @@ -26,7 +25,6 @@ export type BridgeWidgetView = | BridgeFailure | BridgeApproveTransaction | BridgeTransactions - | BridgeClaimWithdrawal | BridgeClaimWithdrawalInProgress | BridgeClaimWithdrawalSuccess | BridgeClaimWithdrawalFailure @@ -65,11 +63,6 @@ interface BridgeTransactions extends ViewType { type: BridgeWidgetViews.TRANSACTIONS, } -interface BridgeClaimWithdrawal extends ViewType { - type: BridgeWidgetViews.CLAIM_WITHDRAWAL, - transaction: Transaction -} - interface BridgeClaimWithdrawalInProgress extends ViewType { type: BridgeWidgetViews.CLAIM_WITHDRAWAL_IN_PROGRESS, transactionResponse: TransactionResponse; diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx index a1730058f3..9cc4330834 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx @@ -61,7 +61,6 @@ import { BridgeClaimWithdrawalFailure, BridgeWidgetViews, } from '../../context/view-context/BridgeViewContextTypes'; -import { ClaimWithdrawal } from './views/ClaimWithdrawal'; import { ServiceUnavailableErrorView } from '../../views/error/ServiceUnavailableErrorView'; export type BridgeWidgetInputs = BridgeWidgetParams & { @@ -259,9 +258,6 @@ export default function BridgeWidget({ {viewState.view.type === BridgeWidgetViews.TRANSACTIONS && ( )} - {viewState.view.type === BridgeWidgetViews.CLAIM_WITHDRAWAL && ( - - )} {viewState.view.type === SharedViews.ERROR_VIEW && ( { - page({ - userJourney: UserJourney.BRIDGE, - screen: 'ClaimWithdrawal', - }); - }, []); - - const [txProcessing, setTxProcessing] = useState(false); - const [loading, setLoading] = useState(false); - const [hasWithdrawError, setHasWithdrawError] = useState(false); - const [withdrawalResponse, setWithdrawalResponse] = useState(); - const [showNotEnoughEthDrawer, setShowNotEnoughEthDrawer] = useState(false); - - const goBack = useCallback(() => { - viewDispatch({ - payload: { - type: ViewActions.GO_BACK, - }, - }); - }, [viewDispatch]); - - /** - * This effect should load the transaction that should be ready to be withdrawn. - * There should be a receiver -> details.to_address AND - * there should be an index -> details.current_status.index - */ - useEffect(() => { - const getWithdrawalTxn = async () => { - if (!tokenBridge || !transaction || transaction.details.current_status?.index === undefined) return; - // get withdrawal transaction from the token bridge by receipient address and index - setLoading(true); - try { - const flowRateWithdrawTxnResponse = await tokenBridge?.getFlowRateWithdrawTx({ - recipient: transaction.details.to_address, - index: transaction.details.current_status.index!, - }); - setWithdrawalResponse(flowRateWithdrawTxnResponse); - } catch (err) { - // eslint-disable-next-line no-console - console.log(err); - } finally { - setLoading(false); - } - }; - getWithdrawalTxn(); - }, [tokenBridge, transaction]); - - const handleWithdrawalClaimClick = useCallback(async ({ forceChangeAccount }: { forceChangeAccount: boolean }) => { - if (!checkout || !tokenBridge || !from?.browserProvider || !withdrawalResponse) return; - - if (!withdrawalResponse.pendingWithdrawal.canWithdraw || !withdrawalResponse.unsignedTx) { - // eslint-disable-next-line max-len, no-console - console.log(`Unable to process withdrawal transaction as it is not ready yet. Delay timeout at ${withdrawalResponse.pendingWithdrawal.timeoutEnd} `); - return; - } - - let providerToUse = from?.browserProvider; - const { l1ChainId } = checkout.config; - - setTxProcessing(true); - - if (isPassportProvider(from?.browserProvider) || forceChangeAccount) { - // user should switch to MetaMask - try { - const createProviderResult = await checkout.createProvider({ walletProviderName: WalletProviderName.METAMASK }); - const connectResult = await checkout.connect({ - provider: createProviderResult.provider, - requestWalletPermissions: true, - }); - providerToUse = connectResult.provider; - setShowNotEnoughEthDrawer(false); - } catch (err) { - // eslint-disable-next-line no-console - console.log(err); - setHasWithdrawError(true); - setTxProcessing(false); - return; - } - } - - /** - * Gas fee estimation and balance checks are done on a best effort basis. - * If for some reason the balance calls fail or gas fee data calls fail - * don't block the transaction from being submitted. - */ - - let gasEstimate: bigint; - let ethGasCostWei: bigint | null = null; - try { - try { - gasEstimate = await providerToUse.estimateGas(withdrawalResponse.unsignedTx); - } catch (err) { - gasEstimate = BigInt(WITHDRAWAL_CLAIM_GAS_LIMIT); - } - - let feeData: FeeData | null = null; - try { - feeData = await providerToUse.getFeeData(); - } catch (err) { - // eslint-disable-next-line no-console - console.log(err); - } - - let gasPriceInWei: bigint | null = null; - if (feeData) gasPriceInWei = getGasPriceInWei(feeData); - if (gasPriceInWei) { - ethGasCostWei = gasEstimate * gasPriceInWei; - } - } catch (err) { - // eslint-disable-next-line no-console - console.log(err); - } - - // get L1 balances and do check for enough ETH to cover gas - try { - const balancesResult = await checkout.getAllBalances({ - provider: providerToUse, - chainId: l1ChainId, - }); - - const ethBalance = balancesResult.balances.find((balance) => isNativeToken(balance.token.address)); - - if (!ethBalance || (ethBalance.balance < ethGasCostWei!)) { - setShowNotEnoughEthDrawer(true); - setTxProcessing(false); - return; - } - } catch (err) { - // eslint-disable-next-line no-console - console.log(err); - } - - // check that provider is connected to L1 - const network = await providerToUse.getNetwork(); - - if (Number(network.chainId) !== l1ChainId) { - try { - const switchNetworkResult = await checkout.switchNetwork({ - provider: providerToUse, - chainId: l1ChainId, - }); - providerToUse = switchNetworkResult.provider; - } catch (err) { - setHasWithdrawError(true); - setLoading(false); - // eslint-disable-next-line no-console - console.log(err); - return; - } - } - - // send transaction to wallet for signing - try { - const response = await checkout.sendTransaction({ - provider: providerToUse, - transaction: withdrawalResponse.unsignedTx, - }); - - viewDispatch({ - payload: { - type: ViewActions.UPDATE_VIEW, - view: { - type: BridgeWidgetViews.CLAIM_WITHDRAWAL_IN_PROGRESS, - transactionResponse: response.transactionResponse, - }, - }, - }); - } catch (err) { - // eslint-disable-next-line no-console - console.log(err); - setHasWithdrawError(true); - setTxProcessing(false); - } finally { - setTxProcessing(false); - } - }, [tokenBridge, from, withdrawalResponse]); - - return ( - sendBridgeWidgetCloseEvent(eventTarget)} - onBackButtonClick={goBack} - /> - )} - floatHeader - heroContent={} - footer={( - - - - - - - )} - > - - - {t('views.CLAIM_WITHDRAWAL.content.body')} - - - {t('views.CLAIM_WITHDRAWAL.content.body2')} - - - - setShowNotEnoughEthDrawer(false)} - onChangeAccount={() => handleWithdrawalClaimClick({ forceChangeAccount: true })} - /> - - ); -}