Skip to content

Commit

Permalink
Fix/handle tx underpriced (#360)
Browse files Browse the repository at this point in the history
* resubmit conflicting userOps when underpriced error occurs

* fix

* fix

* fix

---------

Co-authored-by: mouseless <[email protected]>
  • Loading branch information
mouseless0x and mouseless0x authored Nov 19, 2024
1 parent 5b0d804 commit bfa607c
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/cli/setupServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const getCompressionHandler = async (
}

const getExecutor = ({
mempool,
config,
senderManager,
reputationManager,
Expand All @@ -124,6 +125,7 @@ const getExecutor = ({
gasPriceManager,
eventManager
}: {
mempool: MemoryMempool
config: AltoConfig
senderManager: SenderManager
reputationManager: InterfaceReputationManager
Expand All @@ -133,6 +135,7 @@ const getExecutor = ({
eventManager: EventManager
}): Executor => {
return new Executor({
mempool,
config,
senderManager,
reputationManager,
Expand Down Expand Up @@ -299,6 +302,7 @@ export const setupServer = async ({
})

const executor = getExecutor({
mempool,
config,
senderManager,
reputationManager,
Expand Down
44 changes: 43 additions & 1 deletion src/executor/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
EventManager,
GasPriceManager
} from "@alto/handlers"
import type { InterfaceReputationManager } from "@alto/mempool"
import type { InterfaceReputationManager, MemoryMempool } from "@alto/mempool"
import {
type Address,
type BundleResult,
Expand Down Expand Up @@ -87,10 +87,12 @@ export class Executor {
compressionHandler: CompressionHandler | null
gasPriceManager: GasPriceManager
mutex: Mutex
mempool: MemoryMempool
eventManager: EventManager

constructor({
config,
mempool,
senderManager,
reputationManager,
metrics,
Expand All @@ -99,6 +101,7 @@ export class Executor {
eventManager
}: {
config: AltoConfig
mempool: MemoryMempool
senderManager: SenderManager
reputationManager: InterfaceReputationManager
metrics: Metrics
Expand All @@ -107,6 +110,7 @@ export class Executor {
eventManager: EventManager
}) {
this.config = config
this.mempool = mempool
this.senderManager = senderManager
this.reputationManager = reputationManager
this.logger = config.getLogger(
Expand Down Expand Up @@ -540,6 +544,7 @@ export class Executor {
...opts
})

let isTransactionUnderPriced = false
let attempts = 0
let transactionHash: Hex | undefined
const maxAttempts = 3
Expand All @@ -552,11 +557,13 @@ export class Executor {

break
} catch (e: unknown) {
isTransactionUnderPriced = false
let isErrorHandled = false

if (e instanceof BaseError) {
if (isTransactionUnderpricedError(e)) {
this.logger.warn("Transaction underpriced, retrying")

request.maxFeePerGas = scaleBigIntByPercent(
request.maxFeePerGas,
150
Expand All @@ -566,6 +573,7 @@ export class Executor {
150
)
isErrorHandled = true
isTransactionUnderPriced = true
}
}

Expand Down Expand Up @@ -612,6 +620,13 @@ export class Executor {
}
}

if (isTransactionUnderPriced) {
await this.handleTransactionUnderPriced({
nonce: request.nonce,
executor: request.from
})
}

// needed for TS
if (!transactionHash) {
throw new Error("Transaction hash not assigned")
Expand All @@ -620,6 +635,33 @@ export class Executor {
return transactionHash as Hex
}

// Occurs when tx was sent with conflicting nonce, we want to resubmit all conflicting ops
async handleTransactionUnderPriced({
nonce,
executor
}: { nonce: number; executor: Address }) {
const submitted = this.mempool.dumpSubmittedOps()

const conflictingOps = submitted
.filter((submitted) => {
const tx = submitted.transactionInfo

return (
tx.executor.address === executor &&
tx.transactionRequest.nonce === nonce
)
})
.map(({ userOperation }) => userOperation)

conflictingOps.map((op) => {
this.logger.info(
`Resubmitting ${op.userOperationHash} due to transaction underpriced`
)
this.mempool.removeSubmitted(op.userOperationHash)
this.mempool.add(op.mempoolUserOperation, op.entryPoint)
})
}

async bundle(
entryPoint: Address,
ops: UserOperation[]
Expand Down

0 comments on commit bfa607c

Please sign in to comment.