Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions apps/submitter/lib/handlers/createAccount/createAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import { CreateAccount, type CreateAccountInput, type CreateAccountOutput } from

const WaitForReceiptError = Symbol("WaitForReceiptError")

async function createAccount({ salt, owner }: CreateAccountInput): Promise<CreateAccountOutput> {
async function createAccount(
{ salt, owner }: CreateAccountInput,
noNonceRetry?: "noNonceRetry",
): Promise<CreateAccountOutput> {
assertDef(salt) // from validator
let evmTxInfo: Optional<EvmTxInfo, "evmTxHash"> | undefined
const predictedAddress = computeHappyAccountAddress(salt, owner)
Expand Down Expand Up @@ -75,7 +78,14 @@ async function createAccount({ salt, owner }: CreateAccountInput): Promise<Creat
logger.trace("Successfully created account", address, owner, salt)
return { status: CreateAccount.Success, owner, salt, address }
} catch (error) {
if (isNonceTooLowError(error)) evmNonceManager.resyncIfTooLow(accountDeployer.address)
if (isNonceTooLowError(error)) {
evmNonceManager.resyncIfTooLow(accountDeployer.address)
if (!noNonceRetry) {
logger.warn("EVM nonce too low, retrying account creation", { salt, owner })
return await createAccount({ salt, owner }, "noNonceRetry")
}
return { ...outputForGenericError(error), owner, salt }
}

if (evmTxInfo) {
// The nonce has been consumed. A transaction must occur with that nonce because other other transactions
Expand Down
13 changes: 9 additions & 4 deletions apps/submitter/lib/handlers/submit/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ type SubmitInternalInput = SubmitInput & {
timeout?: number
earlyExit?: boolean
replacedTx?: EvmTxInfo
noNonceRetry?: boolean
}

type SubmitInternalOutput =
| (SubmitSuccess & { evmTxHash?: Hash; receiptPromise?: Promise<WaitForReceiptOutput> })
| (SubmitError & { evmTxHash?: undefined; receiptPromise?: undefined })

async function submitInternal(input: SubmitInternalInput): Promise<SubmitInternalOutput> {
const { entryPoint = deployment.EntryPoint, timeout, earlyExit, replacedTx } = input
const { entryPoint = deployment.EntryPoint, timeout, earlyExit, replacedTx, noNonceRetry } = input
let boop = input.boop

const boopHash = computeHash(boop)
Expand Down Expand Up @@ -164,9 +165,13 @@ async function submitInternal(input: SubmitInternalInput): Promise<SubmitInterna
const receiptPromise = boopReceiptService.waitForInclusion(args)
return { status: Onchain.Success, boopHash, entryPoint, evmTxHash, receiptPromise }
} catch (error) {
if (isNonceTooLowError(error)) evmNonceManager.resyncIfTooLow(accountDeployer.address)

if ((error as BaseError)?.walk((e) => e instanceof InsufficientFundsError)) {
if (isNonceTooLowError(error)) {
evmNonceManager.resyncIfTooLow(accountDeployer.address)
if (!noNonceRetry) {
logger.warn("EVM nonce too low, retrying submit", boopHash)
return await submitInternal({ ...input, noNonceRetry: true })
}
} else if ((error as BaseError)?.walk((e) => e instanceof InsufficientFundsError)) {
return {
status: SubmitterError.UnexpectedError,
error: "Submitter failed to pay for the boop.",
Expand Down