Skip to content

Commit

Permalink
Retry logic (#320)
Browse files Browse the repository at this point in the history
* initial commit

* remove try/catch around prepareTransactionRequest

* remove unused imports

* add checks for v0.6

* remove console log

* recognize TransactionExecutionErrors

* sync with main + handle tx underpriced errors
  • Loading branch information
mouseless0x authored Oct 14, 2024
1 parent 467529f commit 45a0966
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 5 deletions.
95 changes: 91 additions & 4 deletions src/executor/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,21 @@ import {
isVersion06,
maxBigInt,
parseViemError,
scaleBigIntByPercent,
toPackedUserOperation
} from "@alto/utils"
import * as sentry from "@sentry/node"
import { Mutex } from "async-mutex"
import {
type Account,
FeeCapTooLowError,
InsufficientFundsError,
IntrinsicGasTooLowError,
NonceTooLowError,
encodeFunctionData,
getContract
getContract,
type Account,
type Hex,
TransactionExecutionError
} from "viem"
import {
type CompressedFilterOpsAndEstimateGasParams,
Expand All @@ -50,6 +53,7 @@ import {
flushStuckTransaction,
simulatedOpsToResults
} from "./utils"
import type { SendTransactionErrorType } from "viem"
import type { AltoConfig } from "../createConfig"

export interface GasEstimateResult {
Expand Down Expand Up @@ -497,6 +501,87 @@ export class Executor {
await Promise.all(promises)
}

async sendHandleOpsTransaction(
userOps: PackedUserOperation[],
isUserOpVersion06: boolean,
entryPoint: Address,
opts:
| {
gasPrice: bigint
maxFeePerGas?: undefined
maxPriorityFeePerGas?: undefined
account: Account
gas: bigint
nonce: number
}
| {
maxFeePerGas: bigint
maxPriorityFeePerGas: bigint
gasPrice?: undefined
account: Account
gas: bigint
nonce: number
}
) {
const request =
await this.config.walletClient.prepareTransactionRequest({
to: entryPoint,
data: encodeFunctionData({
abi: isUserOpVersion06
? EntryPointV06Abi
: EntryPointV07Abi,
functionName: "handleOps",
args: [userOps, opts.account.address]
}),
...opts
})

let attempts = 0
let transactionHash: Hex | undefined
const maxAttempts = 3

// Try sending the transaction and updating relevant fields if there is an error.
while (attempts < maxAttempts) {
try {
transactionHash =
await this.config.walletClient.sendTransaction(request)

break
} catch (e: unknown) {
const error = e as SendTransactionErrorType
let isErrorHandled = false

if (error instanceof TransactionExecutionError) {
const cause = error.cause

if (cause instanceof NonceTooLowError) {
this.logger.warn("Nonce too low, retrying")
request.nonce += 1
isErrorHandled = true
}

if (cause instanceof IntrinsicGasTooLowError) {
this.logger.warn("Intrinsic gas too low, retrying")
request.gas = scaleBigIntByPercent(request.gas, 150)
isErrorHandled = true
}
}

attempts++
if (attempts === maxAttempts || !isErrorHandled) {
throw error
}
}
}

// needed for TS
if (!transactionHash) {
throw new Error("Transaction hash not assigned")
}

return transactionHash as Hex
}

async bundle(
entryPoint: Address,
ops: UserOperation[]
Expand Down Expand Up @@ -679,8 +764,10 @@ export class Executor {
)
) as PackedUserOperation[]

transactionHash = await ep.write.handleOps(
[userOps, wallet.address],
transactionHash = await this.sendHandleOpsTransaction(
userOps,
isUserOpVersion06,
entryPoint,
opts
)

Expand Down
6 changes: 5 additions & 1 deletion src/utils/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import {
getContract,
serializeTransaction,
toBytes,
toFunctionSelector
toFunctionSelector,
InternalRpcError
} from "viem"
import { base, baseGoerli, baseSepolia } from "viem/chains"
import { maxBigInt, minBigInt, scaleBigIntByPercent } from "./bigInt"
Expand Down Expand Up @@ -706,6 +707,9 @@ export function parseViemError(err: unknown) {
if (e instanceof EstimateGasExecutionError) {
return e
}
if (e instanceof InternalRpcError) {
return e
}
return
}
return
Expand Down

0 comments on commit 45a0966

Please sign in to comment.