diff --git a/src/logic/safe/store/actions/__tests__/TxSender.test.ts b/src/logic/safe/store/actions/__tests__/TxSender.test.ts index 355ea8dbea..e2e1854c56 100644 --- a/src/logic/safe/store/actions/__tests__/TxSender.test.ts +++ b/src/logic/safe/store/actions/__tests__/TxSender.test.ts @@ -15,6 +15,7 @@ import * as pendingTransactions from 'src/logic/safe/store/actions/pendingTransa import * as fetchTransactions from 'src/logic/safe/store/actions/transactions/fetchTransactions' import * as aboutToExecuteTx from 'src/logic/safe/utils/aboutToExecuteTx' import * as send from 'src/logic/safe/transactions/send' +import * as getWeb3 from 'src/logic/wallets/getWeb3' import { waitFor } from '@testing-library/react' import { addPendingTransaction } from 'src/logic/safe/store/actions/pendingTransactions' import { LocalTransactionStatus } from 'src/logic/safe/store/models/types/gateway.d' @@ -103,7 +104,10 @@ describe('TxSender', () => { jest.spyOn(walletSelectors, 'providerSelector') jest.spyOn(safeContracts, 'getGnosisSafeInstanceAt') jest.spyOn(notificationBuilder, 'createTxNotifications') - tryOffChainSigningSpy = jest.spyOn(offChainSigner, 'tryOffChainSigning') + jest.spyOn(getWeb3, 'isSmartContractWallet') + tryOffChainSigningSpy = jest + .spyOn(offChainSigner, 'tryOffChainSigning') + .mockImplementation(() => Promise.resolve('mocksignature')) saveTxToHistorySpy = jest .spyOn(txHistory, 'saveTxToHistory') .mockImplementation(() => Promise.resolve(mockTransactionDetails as any)) diff --git a/src/logic/safe/store/actions/createTransaction.ts b/src/logic/safe/store/actions/createTransaction.ts index 2c89f16c1c..c710020276 100644 --- a/src/logic/safe/store/actions/createTransaction.ts +++ b/src/logic/safe/store/actions/createTransaction.ts @@ -3,6 +3,7 @@ import { AnyAction } from 'redux' import { ThunkAction } from 'redux-thunk' import { onboardUser } from 'src/components/ConnectButton' +import { isSmartContractWallet } from 'src/logic/wallets/getWeb3' import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts' import { createTxNotifications } from 'src/logic/notifications' import { @@ -207,22 +208,42 @@ export class TxSender { .then(({ transactionHash }) => transactionHash) } + async canSignOffchain(state: AppReduxState): Promise { + const { isFinalization, safeVersion } = this + const { account, smartContractWallet } = providerSelector(state) + let isSmart = smartContractWallet + + // WalletConnect/Mobile App aren't smart contracts per se but the connected account can be + if (!isSmart) { + isSmart = await isSmartContractWallet(account) // never throws + } + + return checkIfOffChainSignatureIsPossible(isFinalization, isSmart, safeVersion) + } + async submitTx( state: AppReduxState, confirmCallback?: ConfirmEventHandler, errorCallback?: ErrorEventHandler, ): Promise { - const { isFinalization, safeVersion } = this - const { hardwareWallet, smartContractWallet } = providerSelector(state) - const canSignOffChain = checkIfOffChainSignatureIsPossible(isFinalization, smartContractWallet, safeVersion) + const isOffchain = await this.canSignOffchain(state) + // Off-chain signature - if (!isFinalization && canSignOffChain) { + if (!this.isFinalization && isOffchain) { try { + const { hardwareWallet } = providerSelector(state) const signature = await this.onlyConfirm(hardwareWallet) - this.onComplete(signature, confirmCallback) + + // WC + Safe receives "NaN" as a string instead of a sig + if (signature && signature !== 'NaN') { + this.onComplete(signature, confirmCallback) + } else { + throw Error('No signature received') + } } catch (err) { // User likely rejected transaction logError(Errors._814, err.message) + this.onError(err, errorCallback) } return }