Skip to content

Commit f0a28fc

Browse files
committed
SD-81: Add toast for locked wallet during shielding
1 parent 3c41a98 commit f0a28fc

File tree

2 files changed

+62
-28
lines changed

2 files changed

+62
-28
lines changed

src/domains/shielder/utils/useShield.ts

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { erc20Token, nativeToken } from '@cardinal-cryptography/shielder-sdk';
22
import { useMutation, useQueryClient } from '@tanstack/react-query';
3-
import { useRef } from 'react';
4-
import { erc20Abi, TransactionExecutionError, UserRejectedRequestError } from 'viem';
3+
import { erc20Abi } from 'viem';
54
import { useAccount, usePublicClient, useSendTransaction, useWalletClient } from 'wagmi';
65

76
import { Token } from 'src/domains/chains/types/misc';
87
import useChain from 'src/domains/chains/utils/useChain';
98
import { useToast } from 'src/domains/misc/components/Toast';
109
import getQueryKey from 'src/domains/misc/utils/getQueryKey';
10+
import { getWalletErrorName, handleWalletError } from 'src/domains/shielder/utils/walletErrors';
1111

1212
import useShielderClient from './useShielderClient';
1313

@@ -20,7 +20,6 @@ export const useShield = () => {
2020
const queryClient = useQueryClient();
2121
const chainConfig = useChain();
2222
const { showToast } = useToast();
23-
const rejectedTxRef = useRef(false);
2423

2524
const sendTransactionWithToast = async (params: Parameters<typeof sendTransactionAsync>[0]) => {
2625
const toast = showToast({
@@ -34,36 +33,20 @@ export const useShield = () => {
3433
toast.updateToast({
3534
subtitle: 'Still waiting? Make sure you signed the transaction from your wallet.',
3635
});
37-
}, 30_000);
36+
}, 10_000);
3837

3938
try {
40-
const tx = await sendTransactionAsync(params);
41-
clearTimeout(timeoutId);
42-
toast.dismissToast();
43-
return tx;
39+
return await sendTransactionAsync(params);
4440
} catch (error) {
41+
return handleWalletError(error);
42+
} finally {
4543
clearTimeout(timeoutId);
4644
toast.dismissToast();
47-
48-
const isRejected = error instanceof TransactionExecutionError && error.cause instanceof UserRejectedRequestError;
49-
50-
if(isRejected) {
51-
rejectedTxRef.current = true;
52-
showToast({
53-
status: 'error',
54-
title: 'Transaction rejected',
55-
subtitle: 'Transaction has been rejected in the wallet',
56-
});
57-
}
58-
59-
throw error;
6045
}
6146
};
6247

6348
const { mutateAsync: shield, isPending: isShielding, ...meta } = useMutation({
6449
mutationFn: async ({ token, amount }: { token: Token, amount: bigint, onSuccess?: () => void }) => {
65-
rejectedTxRef.current = false;
66-
6750
if (!shielderClient) throw new Error('Shielder is not ready');
6851
if (!walletAddress) throw new Error('Address is not available');
6952

@@ -120,11 +103,30 @@ export const useShield = () => {
120103
queryKey: getQueryKey.tokenPublicBalance('native', chainId.toString(), walletAddress),
121104
});
122105

123-
if (!rejectedTxRef.current) {
124-
showToast({
125-
status: 'error',
126-
title: 'Shielding failed',
127-
});
106+
const knowErrorName = getWalletErrorName(error);
107+
108+
switch (knowErrorName) {
109+
case 'USER_REJECTED_REQUEST':
110+
showToast({
111+
status: 'error',
112+
title: 'Transaction rejected',
113+
subtitle: 'Transaction has been rejected in the wallet',
114+
});
115+
break;
116+
117+
case 'LOCKED_OR_UNAUTHORIZED':
118+
showToast({
119+
status: 'error',
120+
title: 'Transaction not initiated',
121+
subtitle: 'Make sure your wallet is unlocked and your account is authorized.',
122+
});
123+
break;
124+
125+
default:
126+
showToast({
127+
status: 'error',
128+
title: 'Shielding failed',
129+
});
128130
}
129131
},
130132
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { DefaultError } from '@tanstack/react-query';
2+
import { TransactionExecutionError } from 'viem';
3+
4+
const ERROR_NAME_BY_CODE = {
5+
4001: 'USER_REJECTED_REQUEST',
6+
4100: 'LOCKED_OR_UNAUTHORIZED',
7+
} as const;
8+
9+
type KnownErrorCode = keyof typeof ERROR_NAME_BY_CODE;
10+
type KnownErrorName = (typeof ERROR_NAME_BY_CODE)[keyof typeof ERROR_NAME_BY_CODE];
11+
12+
export const handleWalletError = (error: unknown): never => {
13+
if (error instanceof TransactionExecutionError) {
14+
const cause = error.cause as { code?: number };
15+
const code = cause.code?.toString() as KnownErrorCode | undefined;
16+
const knownErrorName = code ? ERROR_NAME_BY_CODE[code] : undefined;
17+
18+
if (knownErrorName) {
19+
throw new Error(knownErrorName);
20+
}
21+
throw error;
22+
}
23+
throw error;
24+
};
25+
26+
export const getWalletErrorName = (error: DefaultError): KnownErrorName | null => {
27+
const matches = Object.values(ERROR_NAME_BY_CODE).find(name =>
28+
error.message.includes(name)
29+
);
30+
31+
return matches ?? null;
32+
};

0 commit comments

Comments
 (0)