From 18c88407f4b2055a2d4d3689405d8bf359a35d11 Mon Sep 17 00:00:00 2001 From: Mimi Tran <80493680+mimi-imtbl@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:13:15 +1100 Subject: [PATCH] [NO CHANGELOGS] [Add Funds Widget] Add Funds Error Handling (#2301) --- .../src/widgets/add-funds/AddFundsWidget.tsx | 15 ++ .../src/widgets/add-funds/hooks/useError.tsx | 146 ++++++++++++++++++ .../src/widgets/add-funds/hooks/useExecute.ts | 109 +++++++++---- .../src/widgets/add-funds/types.ts | 16 ++ .../src/widgets/add-funds/utils/config.ts | 6 + .../src/widgets/add-funds/views/AddFunds.tsx | 35 +---- .../src/widgets/add-funds/views/Review.tsx | 116 +++++++------- 7 files changed, 325 insertions(+), 118 deletions(-) create mode 100644 packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useError.tsx diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/AddFundsWidget.tsx b/packages/checkout/widgets-lib/src/widgets/add-funds/AddFundsWidget.tsx index 05107bfdb0..fd64139e3e 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/AddFundsWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/AddFundsWidget.tsx @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'; import { AddFundsWidgetParams } from '@imtbl/checkout-sdk'; import { Stack, CloudImage } from '@biom3/react'; +import { Environment } from '@imtbl/config'; import { sendAddFundsCloseEvent } from './AddFundsWidgetEvents'; import { EventTargetContext } from '../../context/event-target-context/EventTargetContext'; import { @@ -37,6 +38,10 @@ import { useProvidersContext } from '../../context/providers-context/ProvidersCo import { ServiceUnavailableErrorView } from '../../views/error/ServiceUnavailableErrorView'; import { ServiceType } from '../../views/error/serviceTypes'; import { getRemoteImage } from '../../lib/utils'; +import { isValidAddress } from '../../lib/validations/widgetValidators'; +import { amountInputValidation } from '../../lib/validations/amountInputValidations'; +import { useError } from './hooks/useError'; +import { AddFundsErrorTypes } from './types'; export type AddFundsWidgetInputs = AddFundsWidgetParams & { config: StrongCheckoutWidgetsConfig; @@ -90,6 +95,16 @@ export default function AddFundsWidget({ const squidSdk = useSquid(checkout); const tokensResponse = useTokens(checkout); + const { showErrorHandover } = useError(checkout.config.environment ?? Environment.SANDBOX); + + useEffect(() => { + const isInvalidToTokenAddress = toTokenAddress && !isValidAddress(toTokenAddress); + const isInvalidToAmount = toAmount && !amountInputValidation(toAmount); + + if (isInvalidToTokenAddress || isInvalidToAmount) { + showErrorHandover(AddFundsErrorTypes.INVALID_PARAMETERS); + } + }, [toTokenAddress, toAmount]); useEffect(() => { (async () => { diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useError.tsx b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useError.tsx new file mode 100644 index 0000000000..3c5e340f0f --- /dev/null +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useError.tsx @@ -0,0 +1,146 @@ +import { Environment } from '@imtbl/config'; +import { useContext } from 'react'; +import { AddFundsErrorTypes, RiveStateMachineInput } from '../types'; +import { useHandover } from '../../../lib/hooks/useHandover'; +import { HandoverTarget } from '../../../context/handover-context/HandoverContext'; +import { getRemoteRive } from '../../../lib/utils'; +import { APPROVE_TXN_ANIMATION } from '../utils/config'; +import { HandoverContent } from '../../../components/Handover/HandoverContent'; +import { sendAddFundsCloseEvent } from '../AddFundsWidgetEvents'; +import { EventTargetContext } from '../../../context/event-target-context/EventTargetContext'; +import { ViewActions, ViewContext } from '../../../context/view-context/ViewContext'; +import { AddFundsWidgetViews } from '../../../context/view-context/AddFundsViewContextTypes'; +import { useAnalytics, UserJourney } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; + +interface ErrorConfig { + headingText: string; + subHeadingText?: string; + primaryButtonText?: string; + onPrimaryButtonClick?: () => void; + secondaryButtonText?: string; + onSecondaryButtonClick?: () => void; +} + +export const useError = (environment: Environment) => { + const { viewDispatch } = useContext(ViewContext); + + const { page } = useAnalytics(); + const { addHandover, closeHandover } = useHandover({ + id: HandoverTarget.GLOBAL, + }); + + const { + eventTargetState: { eventTarget }, + } = useContext(EventTargetContext); + + const closeWidget = () => { + sendAddFundsCloseEvent(eventTarget); + }; + + const goBackToAddFundsView = () => { + closeHandover(); + + viewDispatch({ + payload: { + type: ViewActions.UPDATE_VIEW, + view: { + type: AddFundsWidgetViews.ADD_FUNDS, + }, + }, + }); + }; + + const errorConfig: Record = { + [AddFundsErrorTypes.DEFAULT]: { + headingText: 'Unknown error', + subHeadingText: 'An unknown error occurred. Please try again later.', + secondaryButtonText: 'Close', + onSecondaryButtonClick: closeWidget, + }, + [AddFundsErrorTypes.INVALID_PARAMETERS]: { + headingText: 'Invalid parameters', + subHeadingText: 'The parameters provided are invalid. Please check again.', + secondaryButtonText: 'Close', + onSecondaryButtonClick: closeWidget, + }, + [AddFundsErrorTypes.SERVICE_BREAKDOWN]: { + headingText: 'Our system is currently down', + subHeadingText: 'We are currently experiencing technical difficulties. Please try again later.', + secondaryButtonText: 'Close', + onSecondaryButtonClick: closeWidget, + }, + [AddFundsErrorTypes.TRANSACTION_FAILED]: { + headingText: 'Transaction failed', + subHeadingText: 'The transaction failed. Please try again.', + primaryButtonText: 'Retry', + onPrimaryButtonClick: goBackToAddFundsView, + secondaryButtonText: 'Close', + onSecondaryButtonClick: closeWidget, + }, + [AddFundsErrorTypes.WALLET_FAILED]: { + headingText: 'Transaction failed', + subHeadingText: 'The transaction failed. Please try again.', + primaryButtonText: 'Retry', + onPrimaryButtonClick: goBackToAddFundsView, + secondaryButtonText: 'Close', + onSecondaryButtonClick: goBackToAddFundsView, + }, + [AddFundsErrorTypes.WALLET_REJECTED]: { + headingText: 'Transaction rejected', + subHeadingText: 'The transaction was rejected. Please try again.', + primaryButtonText: 'Retry', + onPrimaryButtonClick: goBackToAddFundsView, + secondaryButtonText: 'Close', + onSecondaryButtonClick: closeWidget, + }, + [AddFundsErrorTypes.WALLET_REJECTED_NO_FUNDS]: { + headingText: 'Insufficient funds', + subHeadingText: 'You do not have enough funds to complete the transaction.', + primaryButtonText: 'Retry', + onPrimaryButtonClick: goBackToAddFundsView, + secondaryButtonText: 'Close', + onSecondaryButtonClick: closeWidget, + }, + [AddFundsErrorTypes.WALLET_POPUP_BLOCKED]: { + headingText: "Browser's popup blocked", + subHeadingText: 'Please enable popups in your browser to proceed.', + primaryButtonText: 'Retry', + onPrimaryButtonClick: goBackToAddFundsView, + secondaryButtonText: 'Close', + onSecondaryButtonClick: goBackToAddFundsView, + }, + }; + + const getErrorConfig = (errorType: AddFundsErrorTypes) => errorConfig[errorType]; + + const showErrorHandover = (errorType: AddFundsErrorTypes, data?: Record) => { + page({ + userJourney: UserJourney.ADD_FUNDS, + screen: 'Error', + extras: { + errorType, + data, + }, + }); + + addHandover({ + animationUrl: getRemoteRive( + environment, + APPROVE_TXN_ANIMATION, + ), + inputValue: RiveStateMachineInput.ERROR, + children: , + }); + }; + + return { + showErrorHandover, + }; +}; diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useExecute.ts b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useExecute.ts index 6369d23f55..59e5d10914 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useExecute.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useExecute.ts @@ -2,9 +2,43 @@ import { Web3Provider } from '@ethersproject/providers'; import { RouteResponse } from '@0xsquid/squid-types'; import { Squid } from '@0xsquid/sdk'; import { ethers } from 'ethers'; +import { Environment } from '@imtbl/config'; import { isSquidNativeToken } from '../functions/isSquidNativeToken'; +import { useError } from './useError'; +import { AddFundsError, AddFundsErrorTypes } from '../types'; + +export const useExecute = (environment: Environment) => { + const { showErrorHandover } = useError(environment); + + const handleTransactionError = (err: unknown) => { + const reason = `${(err as any)?.reason || (err as any)?.message || ''}`.toLowerCase(); + + let errorType = AddFundsErrorTypes.WALLET_FAILED; + + if (reason.includes('failed') && reason.includes('open confirmation')) { + errorType = AddFundsErrorTypes.WALLET_POPUP_BLOCKED; + } + + if (reason.includes('rejected') && reason.includes('user')) { + errorType = AddFundsErrorTypes.WALLET_REJECTED; + } + + if (reason.includes('failed to submit') && reason.includes('highest gas limit')) { + errorType = AddFundsErrorTypes.WALLET_REJECTED_NO_FUNDS; + } + + if (reason.includes('status failed') || reason.includes('transaction failed')) { + errorType = AddFundsErrorTypes.TRANSACTION_FAILED; + } + + const error: AddFundsError = { + type: errorType, + data: { error: err }, + }; + + showErrorHandover(errorType, { error }); + }; -export const useExecute = () => { const convertToNetworkChangeableProvider = async ( provider: Web3Provider, ): Promise => new ethers.providers.Web3Provider(provider.provider, 'any'); @@ -12,16 +46,16 @@ export const useExecute = () => { const checkProviderChain = async ( provider: Web3Provider, chainId: string, - ): Promise => { + ): Promise => { if (!provider.provider.request) { throw new Error('provider does not have request method'); } - try { const fromChainHex = `0x${parseInt(chainId, 10).toString(16)}`; const providerChainId = await provider.provider.request({ method: 'eth_chainId', }); + if (fromChainHex !== providerChainId) { await provider.provider.request({ method: 'wallet_switchEthereumChain', @@ -31,9 +65,12 @@ export const useExecute = () => { }, ], }); + return true; } - } catch (e) { - throw new Error('Error checking provider'); + return true; + } catch (error) { + handleTransactionError(error); + return false; } }; @@ -41,35 +78,40 @@ export const useExecute = () => { provider: Web3Provider, routeResponse: RouteResponse, ): Promise => { - if (!isSquidNativeToken(routeResponse?.route?.params.fromToken)) { - const erc20Abi = [ - 'function allowance(address owner, address spender) public view returns (uint256)', - ]; - const fromToken = routeResponse?.route.params.fromToken; - const signer = provider.getSigner(); - const tokenContract = new ethers.Contract(fromToken, erc20Abi, signer); - - const ownerAddress = await signer.getAddress(); - const transactionRequestTarget = routeResponse?.route?.transactionRequest?.target; - - if (!transactionRequestTarget) { - throw new Error('transactionRequest target is undefined'); + try { + if (!isSquidNativeToken(routeResponse?.route?.params.fromToken)) { + const erc20Abi = [ + 'function allowance(address owner, address spender) public view returns (uint256)', + ]; + const fromToken = routeResponse?.route.params.fromToken; + const signer = provider.getSigner(); + const tokenContract = new ethers.Contract(fromToken, erc20Abi, signer); + + const ownerAddress = await signer.getAddress(); + const transactionRequestTarget = routeResponse?.route?.transactionRequest?.target; + + if (!transactionRequestTarget) { + throw new Error('transactionRequest target is undefined'); + } + + const allowance = await tokenContract.allowance( + ownerAddress, + transactionRequestTarget, + ); + return allowance; } - const allowance = await tokenContract.allowance( - ownerAddress, - transactionRequestTarget, - ); - return allowance; + return ethers.constants.MaxUint256; // no approval is needed for native tokens + } catch (error) { + showErrorHandover(AddFundsErrorTypes.DEFAULT, { error }); + return undefined; } - - return ethers.constants.MaxUint256; // no approval is needed for native tokens }; const approve = async ( provider: Web3Provider, routeResponse: RouteResponse, - ): Promise => { + ): Promise => { try { if (!isSquidNativeToken(routeResponse?.route?.params.fromToken)) { const erc20Abi = [ @@ -93,10 +135,12 @@ export const useExecute = () => { transactionRequestTarget, fromAmount, ); - await tx.wait(); + return tx.wait(); } - } catch (e) { - throw new Error('Error approving tokens'); + return undefined; + } catch (error) { + handleTransactionError(error); + return undefined; } }; @@ -104,7 +148,7 @@ export const useExecute = () => { squid: Squid, provider: Web3Provider, routeResponse: RouteResponse, - ): Promise => { + ): Promise => { if (!provider.provider.request) { throw new Error('provider does not have request method'); } @@ -115,8 +159,9 @@ export const useExecute = () => { route: routeResponse.route, })) as unknown as ethers.providers.TransactionResponse; return tx.wait(); - } catch (e) { - throw new Error('Error executing route'); + } catch (error) { + handleTransactionError(error); + return undefined; } }; 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 e5ac17c834..bf9a553693 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts @@ -51,3 +51,19 @@ export enum RiveStateMachineInput { COMPLETED = 3, ERROR = 4, } + +export type AddFundsError = { + type: AddFundsErrorTypes; + data?: Record; +}; + +export enum AddFundsErrorTypes { + DEFAULT = 'DEFAULT_ERROR', + INVALID_PARAMETERS = 'INVALID_PARAMETERS', + SERVICE_BREAKDOWN = 'SERVICE_BREAKDOWN', + TRANSACTION_FAILED = 'TRANSACTION_FAILED', + WALLET_FAILED = 'WALLET_FAILED', + WALLET_REJECTED = 'WALLET_REJECTED', + WALLET_REJECTED_NO_FUNDS = 'WALLET_REJECTED_NO_FUNDS', + WALLET_POPUP_BLOCKED = 'WALLET_POPUP_BLOCKED', +} diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/utils/config.ts b/packages/checkout/widgets-lib/src/widgets/add-funds/utils/config.ts index 7289a7c2d4..e94778c8bd 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/utils/config.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/utils/config.ts @@ -3,3 +3,9 @@ export const SQUID_SDK_BASE_URL = 'https://apiplus.squidrouter.com'; export const SQUID_API_BASE_URL = 'https://api.squidrouter.com/v1'; export const SQUID_NATIVE_TOKEN = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; + +export const FIXED_HANDOVER_DURATION = 2000; + +export const APPROVE_TXN_ANIMATION = '/access_coins.riv'; + +export const EXECUTE_TXN_ANIMATION = '/swapping_coins.riv'; 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 0aceb49186..dbf05d66ef 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 @@ -32,7 +32,6 @@ import { Web3Provider } from '@ethersproject/providers'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { EventTargetContext } from '../../../context/event-target-context/EventTargetContext'; import { - SharedViews, ViewActions, ViewContext, } from '../../../context/view-context/ViewContext'; @@ -46,7 +45,7 @@ import type { StrongCheckoutWidgetsConfig } from '../../../lib/withDefaultWidget import { useRoutes } from '../hooks/useRoutes'; import { SQUID_NATIVE_TOKEN } from '../utils/config'; import { AddFundsWidgetViews } from '../../../context/view-context/AddFundsViewContextTypes'; -import type { RouteData } from '../types'; +import { AddFundsErrorTypes, type RouteData } from '../types'; import { SelectedRouteOption } from '../components/SelectedRouteOption'; import { SelectedWallet } from '../components/SelectedWallet'; import { DeliverToWalletDrawer } from '../../../components/WalletDrawer/DeliverToWalletDrawer'; @@ -62,6 +61,7 @@ import { } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; import { validateToAmount } from '../functions/amountValidation'; import { OnboardingDrawer } from '../components/OnboardingDrawer'; +import { useError } from '../hooks/useError'; interface AddFundsProps { checkout: Checkout | null; @@ -89,6 +89,8 @@ export function AddFunds({ onBackButtonClick, }: AddFundsProps) { const { fetchRoutesWithRateLimit, resetRoutes } = useRoutes(); + const { showErrorHandover } = useError(config.environment); + const { addFundsState: { squid, @@ -232,21 +234,6 @@ export function AddFunds({ [providers], ); - const showErrorView = useCallback( - (error: Error) => { - viewDispatch({ - payload: { - type: ViewActions.UPDATE_VIEW, - view: { - type: SharedViews.ERROR_VIEW, - error, - }, - }, - }); - }, - [viewDispatch], - ); - useEffect(() => { page({ userJourney: UserJourney.ADD_FUNDS, @@ -312,10 +299,7 @@ export function AddFunds({ }, [routes]); useEffect(() => { - if (!checkout) { - showErrorView(new Error('Checkout object is missing')); - return; - } + if (!checkout) return; const fetchTokens = async () => { try { @@ -345,7 +329,7 @@ export function AddFunds({ }); } } catch (error) { - showErrorView(new Error('Failed to fetch tokens')); + showErrorHandover(AddFundsErrorTypes.SERVICE_BREAKDOWN); } }; @@ -353,10 +337,7 @@ export function AddFunds({ }, [checkout, toTokenAddress]); useEffect(() => { - if (!checkout) { - showErrorView(new Error('Checkout object is missing')); - return; - } + if (!checkout) return; const fetchOnRampTokens = async () => { try { @@ -369,7 +350,7 @@ export function AddFunds({ setOnRampAllowedTokens(tokenResponse.tokens); } } catch (error) { - showErrorView(new Error('Failed to fetch onramp tokens')); + showErrorHandover(AddFundsErrorTypes.SERVICE_BREAKDOWN); } }; fetchOnRampTokens(); 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 fd2a9d2cb1..7b1dc75632 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 @@ -24,6 +24,7 @@ import { } from '@biom3/react'; import { RouteResponse } from '@0xsquid/squid-types'; import { t } from 'i18next'; +import { Environment } from '@imtbl/config'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { AddFundsContext } from '../context/AddFundsContext'; import { useRoutes } from '../hooks/useRoutes'; @@ -31,8 +32,6 @@ import { AddFundsReviewData } from '../../../context/view-context/AddFundsViewCo import { RiveStateMachineInput } from '../types'; import { useExecute } from '../hooks/useExecute'; import { - SharedViews, - ViewActions, ViewContext, } from '../../../context/view-context/ViewContext'; import { SquidIcon } from '../components/SquidIcon'; @@ -40,7 +39,12 @@ import { useHandover } from '../../../lib/hooks/useHandover'; import { HandoverTarget } from '../../../context/handover-context/HandoverContext'; import { HandoverContent } from '../../../components/Handover/HandoverContent'; import { getRemoteRive } from '../../../lib/utils'; -import { SQUID_NATIVE_TOKEN } from '../utils/config'; +import { + APPROVE_TXN_ANIMATION, + EXECUTE_TXN_ANIMATION, + FIXED_HANDOVER_DURATION, + SQUID_NATIVE_TOKEN, +} from '../utils/config'; import { useAnalytics, UserJourney, @@ -63,10 +67,6 @@ interface ReviewProps { onCloseButtonClick?: () => void; } -const FIXED_HANDOVER_DURATION = 2000; -const APPROVE_TXN_ANIMATION = '/access_coins.riv'; -const EXECUTE_TXN_ANIMATION = '/swapping_coins.riv'; - const dividerSx = { content: "''", pos: 'absolute', @@ -108,7 +108,7 @@ export function Review({ getAllowance, approve, execute, - } = useExecute(); + } = useExecute(checkout?.config.environment || Environment.SANDBOX); useEffect(() => { page({ @@ -234,60 +234,70 @@ export function Review({ return; } - try { - clearInterval(getRouteIntervalIdRef.current); - setProceedDisabled(true); + clearInterval(getRouteIntervalIdRef.current); + setProceedDisabled(true); + + showHandover( + APPROVE_TXN_ANIMATION, + RiveStateMachineInput.START, + 'Preparing', + ); + + const changeableProvider = await convertToNetworkChangeableProvider( + fromProvider, + ); + + const isValidNetwork = await checkProviderChain( + changeableProvider, + route.route.params.fromChain, + ); + if (!isValidNetwork) { + return; + } + + const allowance = await getAllowance(changeableProvider, route); + + const { fromAmount } = route.route.params; + if (allowance?.lt(fromAmount)) { showHandover( APPROVE_TXN_ANIMATION, - RiveStateMachineInput.START, - 'Preparing', + RiveStateMachineInput.WAITING, + 'Waiting for access approval in your wallet', + 'Approve the transaction request to complete this transaction', ); - const changeableProvider = await convertToNetworkChangeableProvider( - fromProvider, - ); - await checkProviderChain( - changeableProvider, - route.route.params.fromChain, - ); + const approveTxnReceipt = await approve(changeableProvider, route); - const allowance = await getAllowance(changeableProvider, route); - const { fromAmount } = route.route.params; - - if (allowance?.lt(fromAmount)) { - showHandover( - APPROVE_TXN_ANIMATION, - RiveStateMachineInput.WAITING, - 'Waiting for access approval in your wallet', - 'Approve the transaction request to complete this transaction', - ); - - await approve(changeableProvider, route); - - showHandover( - APPROVE_TXN_ANIMATION, - RiveStateMachineInput.COMPLETED, - 'Granted access to your tokens', - '', - FIXED_HANDOVER_DURATION, - ); + if (!approveTxnReceipt) { + return; } showHandover( - EXECUTE_TXN_ANIMATION, - RiveStateMachineInput.WAITING, - 'Waiting for transaction approval in wallet', - 'Approve the transaction request to complete this transaction', + APPROVE_TXN_ANIMATION, + RiveStateMachineInput.COMPLETED, + 'Granted access to your tokens', + '', + FIXED_HANDOVER_DURATION, ); + } + + showHandover( + EXECUTE_TXN_ANIMATION, + RiveStateMachineInput.WAITING, + 'Waiting for transaction approval in wallet', + 'Approve the transaction request to complete this transaction', + ); - const txReceipt = await execute(squid, changeableProvider, route); + const executeTxnReceipt = await execute(squid, changeableProvider, route); + + if (executeTxnReceipt) { track({ userJourney: UserJourney.ADD_FUNDS, screen: 'FundsAdded', action: 'Succeeded', extras: { - txHash: txReceipt.transactionHash, + txHash: executeTxnReceipt.transactionHash, }, }); @@ -311,7 +321,7 @@ export function Review({ rc={( )} @@ -322,18 +332,6 @@ export function Review({ for transaction details , ); - } catch (e) { - closeHandover(); - - viewDispatch({ - payload: { - type: ViewActions.UPDATE_VIEW, - view: { - type: SharedViews.ERROR_VIEW, - error: e as Error, - }, - }, - }); } }, [ route,