From bf574eedb8bab16375b82b1067985e95a4580f8d Mon Sep 17 00:00:00 2001 From: Ji Young Lee <641712+jiyounglee@users.noreply.github.com> Date: Tue, 26 Nov 2024 09:58:14 +1100 Subject: [PATCH] [NO CHANGELOG] [Add Tokens Widget] Add more metrics (#2417) --- .../checkout/widgets-lib/src/lib/metrics.ts | 17 +++++++++----- .../widgets/add-tokens/functions/errorType.ts | 6 +++++ .../widgets/add-tokens/hooks/useExecute.ts | 22 ++++++++++++++++--- .../src/widgets/add-tokens/views/Review.tsx | 8 +++---- 4 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 packages/checkout/widgets-lib/src/widgets/add-tokens/functions/errorType.ts diff --git a/packages/checkout/widgets-lib/src/lib/metrics.ts b/packages/checkout/widgets-lib/src/lib/metrics.ts index a7eaeba7f8..6fea13cf40 100644 --- a/packages/checkout/widgets-lib/src/lib/metrics.ts +++ b/packages/checkout/widgets-lib/src/lib/metrics.ts @@ -4,13 +4,13 @@ export const withMetrics = ( fn: (flow: Flow) => T, flowName: string, ): T => { - const flow: Flow = trackFlow('checkout', flowName); + const flow: Flow = trackFlow('commerce', flowName); try { return fn(flow); } catch (error) { if (error instanceof Error) { - trackError('checkout', flowName, error); + trackError('commerce', flowName, error); } flow.addEvent('errored'); throw error; @@ -22,16 +22,21 @@ export const withMetrics = ( export const withMetricsAsync = async ( fn: (flow: Flow) => Promise, flowName: string, + errorType?: (error:any)=>string, ): Promise => { - const flow: Flow = trackFlow('checkout', flowName); + const flow: Flow = trackFlow('commerce', flowName); try { return await fn(flow); - } catch (error) { + } catch (error:any) { if (error instanceof Error) { - trackError('checkout', flowName, error); + trackError('commerce', flowName, error); + } + if (errorType && errorType(error)) { + flow.addEvent(`errored_${errorType(error)}`); + } else { + flow.addEvent('errored'); } - flow.addEvent('errored'); throw error; } finally { flow.addEvent('End'); diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/errorType.ts b/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/errorType.ts new file mode 100644 index 0000000000..59fb125eef --- /dev/null +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/functions/errorType.ts @@ -0,0 +1,6 @@ +export function isRejectedError(err: unknown): boolean { + const reason = `${ + (err as any)?.reason || (err as any)?.message || '' + }`.toLowerCase(); + return reason.includes('rejected') && reason.includes('user'); +} 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 8d3d50b704..daad2bff85 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 @@ -6,6 +6,8 @@ import { ethers } from 'ethers'; 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 { useError } from './useError'; import { AddTokensError, AddTokensErrorTypes } from '../types'; @@ -14,6 +16,7 @@ import { sendAddTokensFailedEvent } from '../AddTokensWidgetEvents'; import { retry } from '../../../lib/retry'; import { withMetricsAsync } from '../../../lib/metrics'; import { UserJourney } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; +import { isRejectedError } from '../functions/errorType'; const TRANSACTION_NOT_COMPLETED = 'transaction not completed'; @@ -26,7 +29,7 @@ export const useExecute = (contextId: string, environment: Environment) => { const waitForReceipt = async ( provider: Web3Provider, txHash: string, - maxAttempts = 60, + maxAttempts = 120, ) => { const result = await retry( async () => { @@ -167,9 +170,12 @@ export const useExecute = (contextId: string, environment: Environment) => { }; const callApprove = async ( + flow:Flow, + fromProviderInfo: EIP6963ProviderInfo, provider: Web3Provider, routeResponse: RouteResponse, ): Promise => { + flow.addEvent(`provider_${fromProviderInfo.name}`); const erc20Abi = [ 'function approve(address spender, uint256 amount) public returns (bool)', ]; @@ -191,18 +197,22 @@ export const useExecute = (contextId: string, environment: Environment) => { transactionRequestTarget, fromAmount, ); + flow.addEvent('transactionSent'); + return await waitForReceipt(provider, tx.hash); }; const approve = async ( + fromProviderInfo: EIP6963ProviderInfo, provider: Web3Provider, routeResponse: RouteResponse, ): Promise => { try { if (!isSquidNativeToken(routeResponse?.route?.params.fromToken)) { return await withMetricsAsync( - () => callApprove(provider, routeResponse), + (flow) => callApprove(flow, fromProviderInfo, provider, routeResponse), `${UserJourney.ADD_TOKENS}_Approve`, + (error) => (isRejectedError(error) ? 'rejected' : ''), ); } return undefined; @@ -213,19 +223,24 @@ export const useExecute = (contextId: string, environment: Environment) => { }; const callExecute = async ( + flow: Flow, squid: Squid, + fromProviderInfo: EIP6963ProviderInfo, provider: Web3Provider, routeResponse: RouteResponse, ): Promise => { + flow.addEvent(`provider_${fromProviderInfo.name}`); const tx = (await squid.executeRoute({ signer: provider.getSigner(), route: routeResponse.route, })) as unknown as ethers.providers.TransactionResponse; + flow.addEvent('transactionSent'); return await waitForReceipt(provider, tx.hash); }; const execute = async ( squid: Squid, + fromProviderInfo: EIP6963ProviderInfo, provider: Web3Provider, routeResponse: RouteResponse, ): Promise => { @@ -234,8 +249,9 @@ export const useExecute = (contextId: string, environment: Environment) => { } try { return await withMetricsAsync( - () => callExecute(squid, provider, routeResponse), + (flow) => callExecute(flow, squid, fromProviderInfo, provider, routeResponse), `${UserJourney.ADD_TOKENS}_Execute`, + (error) => (isRejectedError(error) ? 'rejected' : ''), ); } catch (error) { handleTransactionError(error); 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 627d929d75..3109ca4d29 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 @@ -108,7 +108,7 @@ export function Review({ const { providersState: { - checkout, fromProvider, fromAddress, toAddress, + checkout, fromProvider, fromAddress, toAddress, fromProviderInfo, }, } = useProvidersContext(); @@ -277,7 +277,7 @@ export function Review({ ); const handleTransaction = useCallback(async () => { - if (!squid || !fromProvider || !route) { + if (!squid || !fromProvider || !route || !fromProviderInfo) { return; } @@ -351,7 +351,7 @@ export function Review({ ), }); - const approveTxnReceipt = await approve(changeableProvider, route); + const approveTxnReceipt = await approve(fromProviderInfo, changeableProvider, route); if (!approveTxnReceipt) { return; @@ -373,7 +373,7 @@ export function Review({ ), }); - const executeTxnReceipt = await execute(squid, changeableProvider, route); + const executeTxnReceipt = await execute(squid, fromProviderInfo, changeableProvider, route); if (executeTxnReceipt) { track({ userJourney: UserJourney.ADD_TOKENS,