Skip to content

[executor] build_tx fetches latest nonce — concurrent builds produce duplicate nonces #159

@obchain

Description

@obchain

PR: #41 (feat/executor: transaction builder + eth_call simulator)
File: crates/charon-executor/src/builder.rs — build_tx()
Refs #41

Problem

build_tx fetches the nonce with:

let nonce = provider
    .get_transaction_count(from)
    .await
    .context("tx builder: failed to fetch nonce")?;

alloy's get_transaction_count defaults to BlockId::latest() — the count of confirmed transactions, not pending. If two build_tx calls execute before either broadcast (two opportunities dequeued from OpportunityQueue in the same block), both receive the same nonce. The second broadcast is rejected with nonce too low and the opportunity silently drops.

Impact

Loss of liquidation revenue in any burst scenario (multiple liquidatable positions in one block). The race window is inherent in the flash-loan-per-block model.

Fix

Use the pending nonce:

use alloy::rpc::types::BlockNumberOrTag;

let nonce = provider
    .get_transaction_count(from)
    .block_id(BlockId::Number(BlockNumberOrTag::Pending))
    .await
    .context("tx builder: failed to fetch pending nonce")?;

Note: PR #43 (feat/18-gas-and-nonce) introduces a nonce manager that supersedes this. Until PR #43 merges, pending is the correct interim fix. Add a TODO referencing #43.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglayer:rustRust crates (core / scanner / protocols / executor / cli)pr-reviewFindings from PR review processpriority:p1-coreCore MVP scopestatus:readyScoped and ready to pick up

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions