diff --git a/src/components/tx-flow/flows/SuccessScreen/index.tsx b/src/components/tx-flow/flows/SuccessScreen/index.tsx index 641a0b51d1..4730927c42 100644 --- a/src/components/tx-flow/flows/SuccessScreen/index.tsx +++ b/src/components/tx-flow/flows/SuccessScreen/index.tsx @@ -71,8 +71,8 @@ export const SuccessScreen = ({ txId }: { txId: string }) => {
- {txLink && ( diff --git a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx index 51b48fa60d..e5acd6fab4 100644 --- a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx +++ b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx @@ -154,7 +154,7 @@ const ExecuteForm = ({ {(isOk) => ( )} diff --git a/src/components/tx/SignOrExecuteForm/SignForm.tsx b/src/components/tx/SignOrExecuteForm/SignForm.tsx index c3d39beb04..2f9c64eb7c 100644 --- a/src/components/tx/SignOrExecuteForm/SignForm.tsx +++ b/src/components/tx/SignOrExecuteForm/SignForm.tsx @@ -5,7 +5,7 @@ import ErrorMessage from '@/components/tx/ErrorMessage' import { logError, Errors } from '@/services/exceptions' import useIsSafeOwner from '@/hooks/useIsSafeOwner' import CheckWallet from '@/components/common/CheckWallet' -import { useTxActions } from './hooks' +import { useAlreadySigned, useTxActions } from './hooks' import type { SignOrExecuteProps } from '.' import type { SafeTransaction } from '@safe-global/safe-core-sdk-types' import { TxModalContext } from '@/components/tx-flow' @@ -32,6 +32,7 @@ const SignForm = ({ const { signTx } = useTxActions() const { setTxFlow } = useContext(TxModalContext) const { needsRiskConfirmation, isRiskConfirmed, setIsRiskIgnored } = useContext(TxSecurityContext) + const hasSigned = useAlreadySigned(safeTx) // On modal submit const handleSubmit = async (e: SyntheticEvent) => { @@ -64,6 +65,8 @@ const SignForm = ({ return (
+ {hasSigned && You have already signed this transaction.} + {cannotPropose ? ( ) : ( @@ -79,7 +82,7 @@ const SignForm = ({ {(isOk) => ( )} diff --git a/src/components/tx/SignOrExecuteForm/hooks.test.ts b/src/components/tx/SignOrExecuteForm/hooks.test.ts index d40e5c1861..3cb72d20e8 100644 --- a/src/components/tx/SignOrExecuteForm/hooks.test.ts +++ b/src/components/tx/SignOrExecuteForm/hooks.test.ts @@ -10,7 +10,7 @@ import * as pending from '@/hooks/usePendingTxs' import * as txSender from '@/services/tx/tx-sender/dispatch' import * as onboardHooks from '@/hooks/wallets/useOnboard' import { type OnboardAPI } from '@web3-onboard/core' -import { useImmediatelyExecutable, useIsExecutionLoop, useTxActions, useValidateNonce } from './hooks' +import { useAlreadySigned, useImmediatelyExecutable, useIsExecutionLoop, useTxActions, useValidateNonce } from './hooks' const createSafeTx = (data = '0x'): SafeTransaction => { return { @@ -542,4 +542,43 @@ describe('SignOrExecute hooks', () => { expect(relaySpy).not.toHaveBeenCalled() }) }) + + describe('useAlreadySigned', () => { + it('should return true if wallet already signed a tx', () => { + // Wallet + jest.spyOn(wallet, 'default').mockReturnValue({ + chainId: '1', + label: 'MetaMask', + address: '0x1234567890000000000000000000000000000000', + } as unknown as ConnectedWallet) + + const tx = createSafeTx() + tx.addSignature({ + signer: '0x1234567890000000000000000000000000000000', + data: '0x0001', + staticPart: () => '', + dynamicPart: () => '', + }) + const { result } = renderHook(() => useAlreadySigned(tx)) + expect(result.current).toEqual(true) + }) + }) + it('should return false if wallet has not signed a tx yet', () => { + // Wallet + jest.spyOn(wallet, 'default').mockReturnValue({ + chainId: '1', + label: 'MetaMask', + address: '0x1234567890000000000000000000000000000000', + } as unknown as ConnectedWallet) + + const tx = createSafeTx() + tx.addSignature({ + signer: '0x00000000000000000000000000000000000000000', + data: '0x0001', + staticPart: () => '', + dynamicPart: () => '', + }) + const { result } = renderHook(() => useAlreadySigned(tx)) + expect(result.current).toEqual(false) + }) }) diff --git a/src/components/tx/SignOrExecuteForm/hooks.ts b/src/components/tx/SignOrExecuteForm/hooks.ts index 09a1d5bfc2..17492530a3 100644 --- a/src/components/tx/SignOrExecuteForm/hooks.ts +++ b/src/components/tx/SignOrExecuteForm/hooks.ts @@ -179,3 +179,10 @@ export const useSafeTxGas = (safeTx: SafeTransaction | undefined): number | unde return safeTxGas } + +export const useAlreadySigned = (safeTx: SafeTransaction | undefined): boolean => { + const wallet = useWallet() + const hasSigned = + safeTx && wallet && (safeTx.signatures.has(wallet.address.toLowerCase()) || safeTx.signatures.has(wallet.address)) + return Boolean(hasSigned) +}