11import { erc20Token , nativeToken } from '@cardinal-cryptography/shielder-sdk' ;
22import { useMutation , useQueryClient } from '@tanstack/react-query' ;
3- import { erc20Abi } from 'viem' ;
3+ import { useRef } from 'react' ;
4+ import { erc20Abi , TransactionExecutionError , UserRejectedRequestError } from 'viem' ;
45import { useAccount , usePublicClient , useSendTransaction , useWalletClient } from 'wagmi' ;
56
67import { Token } from 'src/domains/chains/types/misc' ;
78import useChain from 'src/domains/chains/utils/useChain' ;
9+ import { useToast } from 'src/domains/misc/components/Toast' ;
810import getQueryKey from 'src/domains/misc/utils/getQueryKey' ;
911
1012import useShielderClient from './useShielderClient' ;
@@ -17,9 +19,51 @@ export const useShield = () => {
1719 const { sendTransactionAsync } = useSendTransaction ( ) ;
1820 const queryClient = useQueryClient ( ) ;
1921 const chainConfig = useChain ( ) ;
22+ const { showToast } = useToast ( ) ;
23+ const rejectedTxRef = useRef ( false ) ;
24+
25+ const sendTransactionWithToast = async ( params : Parameters < typeof sendTransactionAsync > [ 0 ] ) => {
26+ const toast = showToast ( {
27+ status : 'inProgress' ,
28+ title : 'Transaction pending' ,
29+ subtitle : 'Waiting to be signed by user.' ,
30+ ttlMs : Infinity ,
31+ } ) ;
32+
33+ const timeoutId = setTimeout ( ( ) => {
34+ toast . updateToast ( {
35+ subtitle : 'Still waiting? Make sure you signed the transaction from your wallet.' ,
36+ } ) ;
37+ } , 30_000 ) ;
38+
39+ try {
40+ const tx = await sendTransactionAsync ( params ) ;
41+ clearTimeout ( timeoutId ) ;
42+ toast . dismissToast ( ) ;
43+ return tx ;
44+ } catch ( error ) {
45+ clearTimeout ( timeoutId ) ;
46+ 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 ;
60+ }
61+ } ;
2062
2163 const { mutateAsync : shield , isPending : isShielding , ...meta } = useMutation ( {
2264 mutationFn : async ( { token, amount } : { token : Token , amount : bigint , onSuccess ?: ( ) => void } ) => {
65+ rejectedTxRef . current = false ;
66+
2367 if ( ! shielderClient ) throw new Error ( 'Shielder is not ready' ) ;
2468 if ( ! walletAddress ) throw new Error ( 'Address is not available' ) ;
2569
@@ -50,7 +94,7 @@ export const useShield = () => {
5094 await shielderClient . shield (
5195 sdkToken ,
5296 amount ,
53- async params => await sendTransactionAsync ( params ) ,
97+ sendTransactionWithToast ,
5498 walletAddress
5599 ) ;
56100 } ,
@@ -75,6 +119,13 @@ export const useShield = () => {
75119 void queryClient . invalidateQueries ( {
76120 queryKey : getQueryKey . tokenPublicBalance ( 'native' , chainId . toString ( ) , walletAddress ) ,
77121 } ) ;
122+
123+ if ( ! rejectedTxRef . current ) {
124+ showToast ( {
125+ status : 'error' ,
126+ title : 'Shielding failed' ,
127+ } ) ;
128+ }
78129 } ,
79130 } ) ;
80131
0 commit comments