diff --git a/src/core/raps/actions/crosschainSwap.ts b/src/core/raps/actions/crosschainSwap.ts index 8feda3a97a..311164a369 100644 --- a/src/core/raps/actions/crosschainSwap.ts +++ b/src/core/raps/actions/crosschainSwap.ts @@ -19,7 +19,7 @@ import { } from '../../types/gas'; import { estimateGasWithPadding } from '../../utils/gas'; import { toHex } from '../../utils/hex'; -import { ActionProps } from '../references'; +import { ActionProps, RapActionResult } from '../references'; import { CHAIN_IDS_WITH_TRACE_SUPPORT, SWAP_GAS_PADDING, @@ -113,7 +113,7 @@ export const crosschainSwap = async ({ index, parameters, baseNonce, -}: ActionProps<'crosschainSwap'>): Promise => { +}: ActionProps<'crosschainSwap'>): Promise => { const { quote, chainId, requiresApprove } = parameters; const { selectedGas, gasFeeParamsBySpeed } = gasStore.getState(); @@ -191,5 +191,8 @@ export const crosschainSwap = async ({ transaction, }); - return swap?.nonce; + return { + nonce: swap?.nonce, + hash: swap?.hash, + }; }; diff --git a/src/core/raps/actions/swap.ts b/src/core/raps/actions/swap.ts index 36d1945bf2..ae47b72f10 100644 --- a/src/core/raps/actions/swap.ts +++ b/src/core/raps/actions/swap.ts @@ -30,7 +30,7 @@ import { } from '../../types/gas'; import { estimateGasWithPadding } from '../../utils/gas'; import { toHex } from '../../utils/hex'; -import { ActionProps } from '../references'; +import { ActionProps, RapActionResult } from '../references'; import { CHAIN_IDS_WITH_TRACE_SUPPORT, SWAP_GAS_PADDING, @@ -192,7 +192,7 @@ export const swap = async ({ index, parameters, baseNonce, -}: ActionProps<'swap'>): Promise => { +}: ActionProps<'swap'>): Promise => { const { selectedGas, gasFeeParamsBySpeed } = gasStore.getState(); const { quote, permit, chainId, requiresApprove } = parameters; @@ -267,5 +267,8 @@ export const swap = async ({ transaction, }); - return swap?.nonce; + return { + nonce: swap?.nonce, + hash: swap?.hash, + }; }; diff --git a/src/core/raps/actions/unlock.ts b/src/core/raps/actions/unlock.ts index 3e68a8c5e0..9de7b4bfb9 100644 --- a/src/core/raps/actions/unlock.ts +++ b/src/core/raps/actions/unlock.ts @@ -18,7 +18,7 @@ import { gasStore } from '../../state'; import { ParsedAsset } from '../../types/assets'; import { toHex } from '../../utils/hex'; import { convertAmountToRawAmount, greaterThan } from '../../utils/numbers'; -import { ActionProps } from '../references'; +import { ActionProps, RapActionResult } from '../references'; import { overrideWithFastSpeedIfNeeded } from './../utils'; @@ -134,7 +134,7 @@ export const unlock = async ({ index, parameters, wallet, -}: ActionProps<'unlock'>): Promise => { +}: ActionProps<'unlock'>): Promise => { const { selectedGas, gasFeeParamsBySpeed } = gasStore.getState(); const { assetToUnlock, contractAddress, chainId } = parameters; @@ -208,5 +208,8 @@ export const unlock = async ({ transaction, }); - return approval?.nonce; + return { + nonce: approval?.nonce, + hash: approval?.hash, + }; }; diff --git a/src/core/raps/execute.ts b/src/core/raps/execute.ts index e527082692..ece422ca9f 100644 --- a/src/core/raps/execute.ts +++ b/src/core/raps/execute.ts @@ -1,3 +1,6 @@ +/* eslint-disable no-await-in-loop */ +/* eslint-disable no-async-promise-executor */ +/* eslint-disable no-promise-executor-return */ import { Signer } from 'ethers'; import { RainbowError, logger } from '~/logger'; @@ -9,6 +12,7 @@ import { Rap, RapAction, RapActionResponse, + RapActionResult, RapActionTypes, RapSwapActionParameters, RapTypes, @@ -66,7 +70,6 @@ export async function executeAction({ flashbots?: boolean; }): Promise { const { type, parameters } = action; - let nonce; try { const actionProps = { wallet, @@ -75,8 +78,11 @@ export async function executeAction({ parameters: { ...parameters, flashbots }, baseNonce, }; - nonce = await typeAction(type, actionProps)(); - return { baseNonce: nonce, errorMessage: null }; + const { nonce, hash } = (await typeAction( + type, + actionProps, + )()) as RapActionResult; + return { baseNonce: nonce, errorMessage: null, hash }; } catch (error) { logger.error(new RainbowError(`rap: ${rapName} - error execute action`), { message: (error as Error)?.message, @@ -93,6 +99,28 @@ function getRapFullName(actions: RapAction[]) { return actionTypes.join(' + '); } +const delay = (ms: number) => new Promise((res) => setTimeout(res, ms)); + +const waitForNodeAck = async ( + hash: string, + provider: Signer['provider'], +): Promise => { + return new Promise(async (resolve) => { + const tx = await provider?.getTransaction(hash); + // This means the node is aware of the tx, we're good to go + if ( + (tx && tx.blockNumber === null) || + (tx && tx?.blockNumber && tx?.blockNumber > 0) + ) { + resolve(); + } else { + // Wait for 1 second and try again + await delay(1000); + return waitForNodeAck(hash, provider); + } + }); +}; + export const walletExecuteRap = async ( wallet: Signer, type: RapTypes, @@ -116,11 +144,16 @@ export const walletExecuteRap = async ( flashbots: parameters?.flashbots, }; - const { baseNonce, errorMessage: error } = await executeAction( - actionParams, - ); + const { + baseNonce, + errorMessage: error, + hash, + } = await executeAction(actionParams); if (typeof baseNonce === 'number') { + actions.length > 1 && + hash && + (await waitForNodeAck(hash, wallet.provider)); for (let index = 1; index < actions.length; index++) { const action = actions[index]; const actionParams = { @@ -132,8 +165,8 @@ export const walletExecuteRap = async ( rapName, flashbots: parameters?.flashbots, }; - // eslint-disable-next-line no-await-in-loop - await executeAction(actionParams); + const { hash } = await executeAction(actionParams); + hash && (await waitForNodeAck(hash, wallet.provider)); } nonce = baseNonce + actions.length - 1; } else { diff --git a/src/core/raps/references.ts b/src/core/raps/references.ts index a32786c74e..f1e0e0547d 100644 --- a/src/core/raps/references.ts +++ b/src/core/raps/references.ts @@ -102,6 +102,12 @@ export type RapTypes = keyof typeof rapTypes; export interface RapActionResponse { baseNonce?: number | null; errorMessage: string | null; + hash?: string | null; +} + +export interface RapActionResult { + nonce?: number | undefined; + hash?: string | undefined; } export interface ActionProps {