diff --git a/libs/web3/src/lib/use-ethereum-transaction-manager.spec.tsx b/libs/web3/src/lib/use-ethereum-transaction-manager.spec.tsx index 57f6421b1..761444a94 100644 --- a/libs/web3/src/lib/use-ethereum-transaction-manager.spec.tsx +++ b/libs/web3/src/lib/use-ethereum-transaction-manager.spec.tsx @@ -15,6 +15,7 @@ const requestedTransactionUpdate = { status: EthTxStatus.Requested, error: null, confirmations: 0, + notify: true, }; const mockDepositAsset = jest.fn(); @@ -57,6 +58,7 @@ const createTransaction = ( dialogOpen: false, txHash: null, receipt: null, + notify: true, ...transaction, }); @@ -158,6 +160,7 @@ describe('useVegaTransactionManager', () => { expect(update.mock.calls[1][1]).toEqual({ status: EthTxStatus.Pending, txHash, + notify: true, }); }); @@ -197,6 +200,7 @@ describe('useVegaTransactionManager', () => { expect(update.mock.calls[3][1]).toEqual({ status: EthTxStatus.Confirmed, receipt, + notify: true, }); }); diff --git a/libs/web3/src/lib/use-ethereum-transaction-manager.tsx b/libs/web3/src/lib/use-ethereum-transaction-manager.tsx index af1ce499e..8bcc136ae 100644 --- a/libs/web3/src/lib/use-ethereum-transaction-manager.tsx +++ b/libs/web3/src/lib/use-ethereum-transaction-manager.tsx @@ -25,6 +25,7 @@ export const useEthTransactionManager = () => { status: EthTxStatus.Requested, error: null, confirmations: 0, + notify: true, }); const { contract, @@ -48,6 +49,7 @@ export const useEthTransactionManager = () => { update(transaction.id, { status: EthTxStatus.Error, error: err as EthereumError, + notify: true, }); return; } @@ -61,6 +63,7 @@ export const useEthTransactionManager = () => { update(transaction.id, { status: EthTxStatus.Pending, txHash: tx.hash, + notify: true, }); for (let i = 1; i <= requiredConfirmations; i++) { @@ -77,19 +80,31 @@ export const useEthTransactionManager = () => { } if (requiresConfirmation) { - update(transaction.id, { status: EthTxStatus.Complete, receipt }); + update(transaction.id, { + status: EthTxStatus.Complete, + receipt, + }); } else { - update(transaction.id, { status: EthTxStatus.Confirmed, receipt }); + update(transaction.id, { + status: EthTxStatus.Confirmed, + receipt, + notify: true, + }); } } catch (err) { if (err instanceof Error || isEthereumError(err)) { if (!isExpectedEthereumError(err)) { - update(transaction.id, { status: EthTxStatus.Error, error: err }); + update(transaction.id, { + status: EthTxStatus.Error, + error: err, + notify: true, + }); } } else { update(transaction.id, { status: EthTxStatus.Error, error: new Error('Something went wrong'), + notify: true, }); } return; diff --git a/libs/web3/src/lib/use-ethereum-transaction-store.tsx b/libs/web3/src/lib/use-ethereum-transaction-store.tsx index 2647d4619..386a86044 100644 --- a/libs/web3/src/lib/use-ethereum-transaction-store.tsx +++ b/libs/web3/src/lib/use-ethereum-transaction-store.tsx @@ -27,7 +27,13 @@ export interface EthStoredTxState extends EthTxState { methodName: ContractMethod; args: string[]; requiredConfirmations: number; - requiresConfirmation: boolean; // whether or not the tx needs external confirmation (IE from a subscription even) + // whether or not the tx needs external confirmation (IE from a subscription even) + requiresConfirmation: boolean; + // whether or not to notify via toast + // true = force open toast + // false = force close toast + // undefined = leave alone + notify: boolean | undefined; assetId?: string; deposit?: DepositBusEventFieldsFragment; withdrawal?: WithdrawalBusEventFieldsFragment; @@ -49,7 +55,7 @@ export interface EthTransactionStore { update?: Partial< Pick< EthStoredTxState, - 'status' | 'error' | 'receipt' | 'confirmations' | 'txHash' + 'status' | 'error' | 'receipt' | 'confirmations' | 'txHash' | 'notify' > > ) => void; @@ -89,6 +95,7 @@ export const useEthTransactionStore = create()( requiresConfirmation, assetId, withdrawal, + notify: true, }; set({ transactions: transactions.concat(transaction) }); return transaction.id; @@ -135,6 +142,7 @@ export const useEthTransactionStore = create()( transaction.deposit = deposit; transaction.dialogOpen = true; transaction.updatedAt = new Date(); + transaction.notify = true; }) ); }, diff --git a/libs/web3/src/lib/use-ethereum-transaction-toasts.tsx b/libs/web3/src/lib/use-ethereum-transaction-toasts.tsx index f0e49b482..84e4d0e1f 100644 --- a/libs/web3/src/lib/use-ethereum-transaction-toasts.tsx +++ b/libs/web3/src/lib/use-ethereum-transaction-toasts.tsx @@ -1,4 +1,5 @@ import type { ReactNode } from 'react'; +import { useEffect } from 'react'; import { useAssetsDataProvider } from '@vegaprotocol/assets'; import { EtherscanLink } from '@vegaprotocol/environment'; import { formatNumber, toBigNum } from '@vegaprotocol/utils'; @@ -169,11 +170,13 @@ export const useEthereumTransactionToasts = () => { ]); const dismissTx = useEthTransactionStore((state) => state.dismiss); + const updateTx = useEthTransactionStore((state) => state.update); const onClose = useCallback( (tx: EthStoredTxState) => () => { dismissTx(tx.id); removeToast(`eth-${tx.id}`); + updateTx(tx.id, { notify: false }); // closes related "Funds released" toast after successful withdrawal if ( isWithdrawTransaction(tx) && @@ -183,7 +186,7 @@ export const useEthereumTransactionToasts = () => { closeToastBy({ withdrawalId: tx.withdrawal.id }); } }, - [closeToastBy, dismissTx, removeToast] + [closeToastBy, dismissTx, removeToast, updateTx] ); const fromEthTransaction = useCallback( @@ -213,17 +216,25 @@ export const useEthereumTransactionToasts = () => { loader: [EthTxStatus.Pending, EthTxStatus.Complete].includes(tx.status), content, closeAfter, + hidden: !tx.notify, }; }, [onClose] ); - useEthTransactionStore.subscribe( - (state) => compact(state.transactions.filter((tx) => tx?.dialogOpen)), - (txs) => { - txs.forEach((tx) => { - setToast(fromEthTransaction(tx)); - }); - } - ); + // Only register a subscription once + useEffect(() => { + const unsubscribe = useEthTransactionStore.subscribe( + (state) => compact(state.transactions.filter((tx) => tx?.dialogOpen)), + (txs) => { + txs.forEach((tx) => { + setToast(fromEthTransaction(tx)); + }); + } + ); + + return () => { + unsubscribe(); + }; + }, [fromEthTransaction, setToast]); };