diff --git a/src/components/tx-flow/flows/SafeAppsTx/ReviewSafeAppsTx.tsx b/src/components/tx-flow/flows/SafeAppsTx/ReviewSafeAppsTx.tsx index d83a5d33ef..4580b6021f 100644 --- a/src/components/tx-flow/flows/SafeAppsTx/ReviewSafeAppsTx.tsx +++ b/src/components/tx-flow/flows/SafeAppsTx/ReviewSafeAppsTx.tsx @@ -50,12 +50,12 @@ const ReviewSafeAppsTx = ({ createSafeTx().then(setSafeTx).catch(setSafeTxError) }, [txList, setSafeTx, setSafeTxError, params]) - const handleSubmit = async () => { + const handleSubmit = async (txId: string) => { if (!safeTx || !onboard) return trackSafeAppTxCount(Number(appId)) try { - await dispatchSafeAppsTx(safeTx, requestId, onboard, safe.chainId) + await dispatchSafeAppsTx(safeTx, requestId, onboard, safe.chainId, txId) } catch (error) { setSafeTxError(asError(error)) } diff --git a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx index 3afcb8ca1e..5056e3b5b9 100644 --- a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx +++ b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx @@ -88,9 +88,9 @@ const ExecuteForm = ({ const txOptions = getTxOptions(advancedParams, currentChain) + let executedTxId: string try { - const executedTxId = await executeTx(txOptions, safeTx, txId, origin, willRelay, tx) - setTxFlow(, undefined, false) + executedTxId = await executeTx(txOptions, safeTx, txId, origin, willRelay, tx) } catch (_err) { const err = asError(_err) trackError(Errors._804, err) @@ -99,7 +99,9 @@ const ExecuteForm = ({ return } - onSubmit() + // On success + setTxFlow(, undefined, false) + onSubmit(executedTxId) } const cannotPropose = !isOwner && !onlyExecute diff --git a/src/components/tx/SignOrExecuteForm/SignForm.tsx b/src/components/tx/SignOrExecuteForm/SignForm.tsx index 7f9b48675f..34a96b9246 100644 --- a/src/components/tx/SignOrExecuteForm/SignForm.tsx +++ b/src/components/tx/SignOrExecuteForm/SignForm.tsx @@ -56,8 +56,9 @@ const SignForm = ({ setIsSubmittable(false) setSubmitError(undefined) + let resultTxId: string try { - await (isAddingToBatch ? addToBatch(safeTx, origin) : signTx(safeTx, txId, origin, tx)) + resultTxId = await (isAddingToBatch ? addToBatch(safeTx, origin) : signTx(safeTx, txId, origin, tx)) } catch (_err) { const err = asError(_err) trackError(Errors._805, err) @@ -66,8 +67,9 @@ const SignForm = ({ return } + // On success setTxFlow(undefined) - onSubmit() + onSubmit(resultTxId) } const onBatchClick = (e: SyntheticEvent) => { diff --git a/src/components/tx/SignOrExecuteForm/index.tsx b/src/components/tx/SignOrExecuteForm/index.tsx index 8f843169cf..d64f5fb0aa 100644 --- a/src/components/tx/SignOrExecuteForm/index.tsx +++ b/src/components/tx/SignOrExecuteForm/index.tsx @@ -22,7 +22,7 @@ import { isDelegateCall } from '@/services/tx/tx-sender/sdk' export type SignOrExecuteProps = { txId?: string - onSubmit: () => void + onSubmit: (txId: string) => void children?: ReactNode isExecutable?: boolean isRejection?: boolean diff --git a/src/services/safe-wallet-provider/index.ts b/src/services/safe-wallet-provider/index.ts index 9bf098533c..03177d9b5c 100644 --- a/src/services/safe-wallet-provider/index.ts +++ b/src/services/safe-wallet-provider/index.ts @@ -13,7 +13,10 @@ export type AppInfo = { export type WalletSDK = { signMessage: (message: string, appInfo: AppInfo) => Promise<{ signature?: string }> signTypedMessage: (typedData: unknown, appInfo: AppInfo) => Promise<{ signature?: string }> - send: (params: { txs: unknown[]; params: { safeTxGas: number } }, appInfo: AppInfo) => Promise<{ safeTxHash: string }> + send: ( + params: { txs: unknown[]; params: { safeTxGas: number } }, + appInfo: AppInfo, + ) => Promise<{ safeTxHash: string; txHash?: string }> getBySafeTxHash: (safeTxHash: string) => Promise<{ txHash?: string }> switchChain: (chainId: string, appInfo: AppInfo) => Promise proxy: (method: string, params: unknown[]) => Promise @@ -50,11 +53,11 @@ export class SafeWalletProvider { this.sdk = sdk } - private async makeRequest(id: number, request: RpcRequest, appInfo: AppInfo): Promise { + private async makeRequest(request: RpcRequest, appInfo: AppInfo): Promise { const { method, params = [] } = request switch (method) { - case 'wallet_switchEthereumChain': + case 'wallet_switchEthereumChain': { const [{ chainId }] = params as [{ chainId: string }] try { await this.sdk.switchChain(chainId, appInfo) @@ -62,13 +65,16 @@ export class SafeWalletProvider { throw new RpcError(RpcErrorCode.UNSUPPORTED_CHAIN, 'Unsupported chain') } return null + } - case 'eth_accounts': + case 'eth_accounts': { return [this.safe.safeAddress] + } case 'net_version': - case 'eth_chainId': + case 'eth_chainId': { return `0x${this.safe.chainId.toString(16)}` + } case 'personal_sign': { const [message, address] = params as [string, string] @@ -110,7 +116,7 @@ export class SafeWalletProvider { return signature || '0x' } - case 'eth_sendTransaction': + case 'eth_sendTransaction': { const tx = { value: '0', data: '0x', @@ -124,7 +130,7 @@ export class SafeWalletProvider { tx.gas = parseInt(tx.gas, 16) } - const { safeTxHash } = await this.sdk.send( + const { safeTxHash, txHash } = await this.sdk.send( { txs: [tx], params: { safeTxGas: Number(tx.gas) }, @@ -132,6 +138,8 @@ export class SafeWalletProvider { appInfo, ) + if (txHash) return txHash + // Store fake transaction this.submittedTxs.set(safeTxHash, { from: this.safe.safeAddress, @@ -148,8 +156,9 @@ export class SafeWalletProvider { }) return safeTxHash + } - case 'eth_getTransactionByHash': + case 'eth_getTransactionByHash': { let txHash = params[0] as string try { const resp = await this.sdk.getBySafeTxHash(txHash) @@ -161,6 +170,7 @@ export class SafeWalletProvider { return this.submittedTxs.get(txHash) } return await this.sdk.proxy(method, [txHash]) + } case 'eth_getTransactionReceipt': { let txHash = params[0] as string @@ -171,8 +181,9 @@ export class SafeWalletProvider { return this.sdk.proxy(method, params) } - default: + default: { return await this.sdk.proxy(method, params) + } } } @@ -199,7 +210,7 @@ export class SafeWalletProvider { return { jsonrpc: '2.0', id, - result: await this.makeRequest(id, request, appInfo), + result: await this.makeRequest(request, appInfo), } } catch (e) { return { diff --git a/src/services/safe-wallet-provider/useSafeWalletProvider.tsx b/src/services/safe-wallet-provider/useSafeWalletProvider.tsx index 1f48ef2a2d..5396781ae8 100644 --- a/src/services/safe-wallet-provider/useSafeWalletProvider.tsx +++ b/src/services/safe-wallet-provider/useSafeWalletProvider.tsx @@ -1,4 +1,4 @@ -import { useContext, useMemo } from 'react' +import { useContext, useEffect, useMemo, useRef } from 'react' import { BigNumber } from 'ethers' import { useRouter } from 'next/router' @@ -22,6 +22,15 @@ export const _useTxFlowApi = (chainId: string, safeAddress: string): WalletSDK | const web3ReadOnly = useWeb3ReadOnly() const router = useRouter() const { configs } = useChains() + const pendingTxs = useRef>({}) + + useEffect(() => { + const unsubscribe = txSubscribe(TxEvent.PROCESSING, async ({ txId, txHash }) => { + if (!txId) return + pendingTxs.current[txId] = txHash + }) + return unsubscribe + }, []) return useMemo(() => { if (!chainId || !safeAddress) return @@ -50,7 +59,7 @@ export const _useTxFlowApi = (chainId: string, safeAddress: string): WalletSDK | }, async send(params: { txs: any[]; params: { safeTxGas: number } }, appInfo) { - const id = Math.random().toString(36).slice(2) // TODO: use JsonRpc id + const id = Math.random().toString(36).slice(2) const transactions = params.txs.map(({ to, value, data }) => { return { @@ -77,9 +86,10 @@ export const _useTxFlowApi = (chainId: string, safeAddress: string): WalletSDK | ) return new Promise((resolve) => { - const unsubscribe = txSubscribe(TxEvent.SAFE_APPS_REQUEST, async ({ safeAppRequestId, safeTxHash }) => { + const unsubscribe = txSubscribe(TxEvent.SAFE_APPS_REQUEST, async ({ safeAppRequestId, safeTxHash, txId }) => { if (safeAppRequestId === id) { - resolve({ safeTxHash }) + const txHash = pendingTxs.current[txId] + resolve({ safeTxHash, txHash }) unsubscribe() } }) diff --git a/src/services/tx/tx-sender/dispatch.ts b/src/services/tx/tx-sender/dispatch.ts index a5a885d0e5..81c1938e37 100644 --- a/src/services/tx/tx-sender/dispatch.ts +++ b/src/services/tx/tx-sender/dispatch.ts @@ -316,10 +316,11 @@ export const dispatchSafeAppsTx = async ( safeAppRequestId: RequestId, onboard: OnboardAPI, chainId: SafeInfo['chainId'], + txId: string, ) => { const sdk = await getSafeSDKWithSigner(onboard, chainId) const safeTxHash = await sdk.getTransactionHash(safeTx) - txDispatch(TxEvent.SAFE_APPS_REQUEST, { safeAppRequestId, safeTxHash }) + txDispatch(TxEvent.SAFE_APPS_REQUEST, { safeAppRequestId, safeTxHash, txId }) } export const dispatchTxRelay = async ( diff --git a/src/services/tx/txEvents.ts b/src/services/tx/txEvents.ts index 6e63e527b1..4417a25e62 100644 --- a/src/services/tx/txEvents.ts +++ b/src/services/tx/txEvents.ts @@ -44,7 +44,7 @@ interface TxEvents { [TxEvent.RELAYING]: Id & { taskId: string } [TxEvent.FAILED]: Id & HumanDescription & { error: Error } [TxEvent.SUCCESS]: Id & HumanDescription - [TxEvent.SAFE_APPS_REQUEST]: { safeAppRequestId: RequestId; safeTxHash: string } + [TxEvent.SAFE_APPS_REQUEST]: { txId: string; safeAppRequestId: RequestId; safeTxHash: string } [TxEvent.BATCH_ADD]: Id }