Skip to content

Commit

Permalink
Merge pull request #420 from reservoirprotocol/fix/chain-mismatch-race
Browse files Browse the repository at this point in the history
Chain mismatch race condition fix
  • Loading branch information
pedromcunha authored Jan 7, 2025
2 parents 48f37e2 + 4ef26d6 commit dfb5ce5
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/kind-horses-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@reservoir0x/relay-sdk': patch
---

Improve robustness of pre tx chain id check
1 change: 1 addition & 0 deletions packages/sdk/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export {
isSimulateContractRequest
} from './simulateContract.js'
export { safeStructuredClone } from './structuredClone.js'
export { repeatUntilOk } from './repeatUntilOk.js'
33 changes: 33 additions & 0 deletions packages/sdk/src/utils/repeatUntilOk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Repeat a function until the function returns true for a maximum set of attempts with a fixed interval
* @param callback A function that returns true to exit the loop
* @param maximumAttempts The maximum amount of tries for this poll
* @param attemptCount The amount of attempts already done by the poll, should be left blank
* @param pollingInterval The frequency of the loop
* @returns When it has finished polling
*/
export async function repeatUntilOk(
callback: () => Promise<boolean>,
maximumAttempts: number = 15,
attemptCount: number = 0,
pollingInterval: number = 5000
) {
if (attemptCount >= maximumAttempts) {
throw `Failed to get an ok response after ${attemptCount} attempt(s), aborting`
}

const response = await callback()

if (response) {
return true
} else {
await new Promise((resolve) => setTimeout(resolve, pollingInterval))
attemptCount++
await repeatUntilOk(
callback,
maximumAttempts,
attemptCount,
pollingInterval
)
}
}
17 changes: 15 additions & 2 deletions packages/sdk/src/utils/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
} from 'axios'
import { getClient } from '../client.js'
import { SolverStatusTimeoutError } from '../errors/index.js'
import { repeatUntilOk } from '../utils/repeatUntilOk.js'

/**
* Safe txhash.wait which handles replacements when users speed up the transaction
Expand All @@ -39,8 +40,20 @@ export async function sendTransactionSafely(
details?: Execute['details']
) {
const client = getClient()
const walletChainId = await wallet.getChainId()
if (chainId !== walletChainId) {
try {
//In some cases wallets can be delayed when switching chains, causing this check to fail.
//To work around this we check the chain id of the active wallet a few times before declaring it a failure
await repeatUntilOk(
async () => {
const walletChainId = await wallet.getChainId()
return walletChainId === chainId
},
10,
undefined,
250
)
} catch (e) {
const walletChainId = await wallet.getChainId()
throw `Current chain id: ${walletChainId} does not match expected chain id: ${chainId} `
}
let receipt: TransactionReceipt | SvmReceipt | undefined
Expand Down

0 comments on commit dfb5ce5

Please sign in to comment.