diff --git a/src/logic/safe/store/actions/createTransaction.ts b/src/logic/safe/store/actions/createTransaction.ts index 76ded3a5..95ea40e5 100644 --- a/src/logic/safe/store/actions/createTransaction.ts +++ b/src/logic/safe/store/actions/createTransaction.ts @@ -111,7 +111,7 @@ interface CreateTransactionArgs { type CreateTransactionAction = ThunkAction, AppReduxState, undefined, AnyAction> type ConfirmEventHandler = (safeTxHash: string) => void -type RejectEventHandler = () => void +type ErrorEventHandler = () => void const createTransaction = ( { @@ -126,7 +126,7 @@ const createTransaction = ( origin = null, }: CreateTransactionArgs, onUserConfirm?: ConfirmEventHandler, - onUserReject?: RejectEventHandler, + onError?: ErrorEventHandler, ): CreateTransactionAction => async (dispatch: Dispatch, getState: () => AppReduxState): Promise => { const state = getState() @@ -172,6 +172,7 @@ const createTransaction = ( sender: from, sigs, } + const safeTxHash = generateSafeTxHash(safeAddress, txArgs) try { // Here we're checking that safe contract version is greater or equal 1.1.1, but @@ -179,20 +180,19 @@ const createTransaction = ( const canTryOffchainSigning = !isExecution && !smartContractWallet && semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES) if (canTryOffchainSigning) { - const signature = await tryOffchainSigning({ ...txArgs, safeAddress }, hardwareWallet) + const signature = await tryOffchainSigning(safeTxHash, { ...txArgs, safeAddress }, hardwareWallet) if (signature) { dispatch(closeSnackbarAction({ key: beforeExecutionKey })) + dispatch(enqueueSnackbar(notificationsQueue.afterExecution.moreConfirmationsNeeded)) + dispatch(fetchTransactions(safeAddress)) await saveTxToHistory({ ...txArgs, signature, origin }) - dispatch(enqueueSnackbar(notificationsQueue.afterExecution.moreConfirmationsNeeded)) - - dispatch(fetchTransactions(safeAddress)) + onUserConfirm?.(safeTxHash) return } } - const safeTxHash = generateSafeTxHash(safeAddress, txArgs) const tx = isExecution ? await getExecutionTransaction(txArgs) : await getApprovalTransaction(safeInstance, safeTxHash) @@ -245,20 +245,7 @@ const createTransaction = ( removeTxFromStore(mockedTx, safeAddress, dispatch, state) console.error('Tx error: ', error) - // Different wallets return different error messages in this case. This is an assumption that if - // error message includes "user" word, the tx was rejected by user - - let errorIncludesUserWord = false - if (typeof error === 'string') { - errorIncludesUserWord = (error as string).includes('User') || (error as string).includes('user') - } - if (error.message) { - errorIncludesUserWord = error.message.includes('User') || error.message.includes('user') - } - - if (errorIncludesUserWord) { - onUserReject?.() - } + onError?.() }) .then(async (receipt) => { if (pendingExecutionKey) { diff --git a/src/logic/safe/store/actions/processTransaction.ts b/src/logic/safe/store/actions/processTransaction.ts index ffe0b2d2..a4e2aa6e 100644 --- a/src/logic/safe/store/actions/processTransaction.ts +++ b/src/logic/safe/store/actions/processTransaction.ts @@ -78,7 +78,7 @@ const processTransaction = ({ approveAndExecute, notifiedTransaction, safeAddres const canTryOffchainSigning = !isExecution && !smartContractWallet && semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES) if (canTryOffchainSigning) { - const signature = await tryOffchainSigning({ ...txArgs, safeAddress }, hardwareWallet) + const signature = await tryOffchainSigning(tx.safeTxHash, { ...txArgs, safeAddress }, hardwareWallet) if (signature) { dispatch(closeSnackbarAction(beforeExecutionKey)) diff --git a/src/logic/safe/store/middleware/notificationsMiddleware.ts b/src/logic/safe/store/middleware/notificationsMiddleware.ts index a9fbf648..617bdd3d 100644 --- a/src/logic/safe/store/middleware/notificationsMiddleware.ts +++ b/src/logic/safe/store/middleware/notificationsMiddleware.ts @@ -103,7 +103,7 @@ const notificationsMiddleware = (store) => (next) => async (action) => { } case ADD_INCOMING_TRANSACTIONS: { action.payload.forEach((incomingTransactions, safeAddress) => { - const { latestIncomingTxBlock } = state.safes.get('safes').get(safeAddress) + const { latestIncomingTxBlock } = state.safes.get('safes').get(safeAddress, {}) const viewedSafes = state.currentSession['viewedSafes'] const recurringUser = viewedSafes?.includes(safeAddress) diff --git a/src/logic/safe/transactions/offchainSigner/EIP712Signer.ts b/src/logic/safe/transactions/offchainSigner/EIP712Signer.ts index 9b77ae2f..55fe61d7 100644 --- a/src/logic/safe/transactions/offchainSigner/EIP712Signer.ts +++ b/src/logic/safe/transactions/offchainSigner/EIP712Signer.ts @@ -1,5 +1,6 @@ -import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions' +import { AbstractProvider } from 'web3-core' import { getWeb3 } from 'src/logic/wallets/getWeb3' +import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions' const EIP712_NOT_SUPPORTED_ERROR_MSG = "EIP712 is not supported by user's wallet" @@ -59,7 +60,7 @@ const generateTypedDataFrom = async ({ } export const getEIP712Signer = (version?: string) => async (txArgs) => { - const web3: any = getWeb3() + const web3 = getWeb3() const typedData = await generateTypedDataFrom(txArgs) let method = 'eth_signTypedData_v3' @@ -80,13 +81,14 @@ export const getEIP712Signer = (version?: string) => async (txArgs) => { } return new Promise((resolve, reject) => { - web3.currentProvider.sendAsync(signedTypedData, (err, signature) => { + const provider = web3.currentProvider as AbstractProvider + provider.sendAsync(signedTypedData, (err, signature) => { if (err) { reject(err) return } - if (signature.result == null) { + if (signature?.result == null) { reject(new Error(EIP712_NOT_SUPPORTED_ERROR_MSG)) return } diff --git a/src/logic/safe/transactions/offchainSigner/ethSigner.ts b/src/logic/safe/transactions/offchainSigner/ethSigner.ts index 08f0dc86..5daeedba 100644 --- a/src/logic/safe/transactions/offchainSigner/ethSigner.ts +++ b/src/logic/safe/transactions/offchainSigner/ethSigner.ts @@ -4,26 +4,13 @@ import { AbstractProvider } from 'web3-core/types' const ETH_SIGN_NOT_SUPPORTED_ERROR_MSG = 'ETH_SIGN_NOT_SUPPORTED' -export const ethSigner = async ({ - baseGas, - data, - gasPrice, - gasToken, - nonce, - operation, - refundReceiver, - safeInstance, - safeTxGas, - sender, - to, - valueInWei, -}): Promise => { +type EthSignerArgs = { + safeTxHash: string + sender: string +} + +export const ethSigner = async ({ safeTxHash, sender }: EthSignerArgs): Promise => { const web3 = await getWeb3() - const txHash = await safeInstance.methods - .getTransactionHash(to, valueInWei, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, nonce) - .call({ - from: sender, - }) return new Promise(function (resolve, reject) { const provider = web3.currentProvider as AbstractProvider @@ -31,7 +18,7 @@ export const ethSigner = async ({ { jsonrpc: '2.0', method: 'eth_sign', - params: [sender, txHash], + params: [sender, safeTxHash], id: new Date().getTime(), }, async function (err, signature) { diff --git a/src/logic/safe/transactions/offchainSigner/index.ts b/src/logic/safe/transactions/offchainSigner/index.ts index 047c04d7..6113d568 100644 --- a/src/logic/safe/transactions/offchainSigner/index.ts +++ b/src/logic/safe/transactions/offchainSigner/index.ts @@ -8,7 +8,7 @@ import { ethSigner } from './ethSigner' const SIGNERS = { EIP712_V3: getEIP712Signer('v3'), EIP712_V4: getEIP712Signer('v4'), - EIP712: getEIP712Signer() as any, + EIP712: getEIP712Signer(), ETH_SIGN: ethSigner, } @@ -18,13 +18,13 @@ const getSignersByWallet = (isHW) => export const SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES = '>=1.1.1' -export const tryOffchainSigning = async (txArgs, isHW) => { +export const tryOffchainSigning = async (safeTxHash: string, txArgs, isHW: boolean): Promise => { let signature const signerByWallet = getSignersByWallet(isHW) for (const signingFunc of signerByWallet) { try { - signature = await signingFunc(txArgs) + signature = await signingFunc({ ...txArgs, safeTxHash }) break } catch (err) { diff --git a/src/routes/safe/components/Apps/components/ConfirmTransactionModal.tsx b/src/routes/safe/components/Apps/components/ConfirmTransactionModal.tsx index c9e279db..01353288 100644 --- a/src/routes/safe/components/Apps/components/ConfirmTransactionModal.tsx +++ b/src/routes/safe/components/Apps/components/ConfirmTransactionModal.tsx @@ -69,9 +69,8 @@ type OwnProps = { safeAddress: string safeName: string ethBalance: string - onCancel: () => void onUserConfirm: (safeTxHash: string) => void - onUserTxReject: () => void + onTxReject: () => void onClose: () => void } @@ -82,16 +81,20 @@ const ConfirmTransactionModal = ({ safeAddress, ethBalance, safeName, - onCancel, onUserConfirm, onClose, - onUserTxReject, + onTxReject, }: OwnProps): React.ReactElement | null => { const dispatch = useDispatch() if (!isOpen) { return null } + const handleTxRejection = () => { + onTxReject() + onClose() + } + const handleUserConfirmation = (safeTxHash: string): void => { onUserConfirm(safeTxHash) onClose() @@ -113,10 +116,9 @@ const ConfirmTransactionModal = ({ navigateToTransactionsTab: false, }, handleUserConfirmation, - onUserTxReject, + handleTxRejection, ), ) - onClose() } const areTxsMalformed = txs.some((t) => !isTxValid(t)) @@ -165,13 +167,13 @@ const ConfirmTransactionModal = ({ footer={ } - onClose={onClose} + onClose={handleTxRejection} /> ) } diff --git a/src/routes/safe/components/Apps/hooks/useIframeMessageHandler.ts b/src/routes/safe/components/Apps/hooks/useIframeMessageHandler.ts index aa165f4d..8f751a39 100644 --- a/src/routes/safe/components/Apps/hooks/useIframeMessageHandler.ts +++ b/src/routes/safe/components/Apps/hooks/useIframeMessageHandler.ts @@ -12,6 +12,7 @@ import { } from '@gnosis.pm/safe-apps-sdk' import { useDispatch, useSelector } from 'react-redux' import { useEffect, useCallback, MutableRefObject } from 'react' +import { getTxServiceHost } from 'src/config/' import { safeEthBalanceSelector, safeNameSelector, @@ -85,7 +86,7 @@ const useIframeMessageHandler = ( } case SDK_MESSAGES.SAFE_APP_SDK_INITIALIZED: { - const message = { + const safeInfoMessage = { messageId: INTERFACE_MESSAGES.ON_SAFE_INFO, data: { safeAddress: safeAddress as string, @@ -93,8 +94,15 @@ const useIframeMessageHandler = ( ethBalance: ethBalance as string, }, } + const envInfoMessage = { + messageId: INTERFACE_MESSAGES.ENV_INFO, + data: { + txServiceUrl: getTxServiceHost(), + }, + } - sendMessageToIframe(message) + sendMessageToIframe(safeInfoMessage) + sendMessageToIframe(envInfoMessage) break } default: { diff --git a/src/routes/safe/components/Apps/index.tsx b/src/routes/safe/components/Apps/index.tsx index 3d7acdd1..d34d8dd4 100644 --- a/src/routes/safe/components/Apps/index.tsx +++ b/src/routes/safe/components/Apps/index.tsx @@ -102,7 +102,7 @@ const Apps = (): React.ReactElement => { ) } - const onUserTxReject = () => { + const onTxReject = () => { sendMessageToIframe( { messageId: INTERFACE_MESSAGES.TRANSACTION_REJECTED, data: {} }, confirmTransactionModal.requestId, @@ -212,10 +212,9 @@ const Apps = (): React.ReactElement => { ethBalance={ethBalance as string} safeName={safeName as string} txs={confirmTransactionModal.txs} - onCancel={closeConfirmationModal} onClose={closeConfirmationModal} onUserConfirm={onUserTxConfirm} - onUserTxReject={onUserTxReject} + onTxReject={onTxReject} /> )