nautechsystems/nautilus_trader · error · anyhow::Error

Finalized transaction {} emitted {} Swap logs from expected

Error message

Finalized transaction {} emitted {} Swap logs from expected pool {}; expected exactly one

What it means

After confirming a swap transaction is finalized, the library locates the single Swap log emitted by the expected pool address in the transaction receipt. If zero or multiple matching logs are found, the receipt cannot be mapped unambiguously to one swap event, so verification fails.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:4734

}

fn validate_finalized_swap_fill(
    plan: &SwapPlan,
    included: &IncludedTransaction,
) -> anyhow::Result<Option<FinalizedSwapFill>> {
    let signature =
        keccak256("Swap(address,address,int256,int256,uint160,uint128,int24)").to_string();
    let swap_logs = included
        .receipt
        .logs
        .iter()
        .filter(|log| {
            !log.removed
                && log.topics.first().is_some_and(|topic| topic == &signature)
                && Address::from_str(&log.address).ok() == Some(plan.pool_address)
        })
        .collect::<Vec<_>>();
    anyhow::ensure!(
        swap_logs.len() == 1,
        "Finalized transaction {} emitted {} Swap logs from expected pool {}; expected exactly one",
        included.tx_hash,
        swap_logs.len(),
        plan.pool_address
    );
    let log = swap_logs[0];
    let log_transaction_hash = B256::from_str(&rpc_log::extract_transaction_hash(log)?)
        .with_context(|| "Invalid finalized Swap log transaction hash")?;
    let log_block_hash = log
        .block_hash
        .as_deref()
        .ok_or_else(|| anyhow::anyhow!("Finalized Swap log has no block hash"))?;
    anyhow::ensure!(
        log_transaction_hash == included.tx_hash
            && rpc_log::extract_block_number(log)? == included.block_number
            && u64::from(rpc_log::extract_transaction_index(log)?)
                == included.receipt.transaction_index

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Confirm plan.pool_address matches the pool the router actually used for this tx (inspect the receipt logs)
  2. If the transaction legitimately contains multiple swaps, process each log individually instead of requiring exactly one
  3. Re-check the plan construction: ensure the pool chosen at quote time is the one the execution route targets
  4. Exclude aggregator intermediate logs by matching expected topic0 plus pool address, as done here, and verify the tx hash is the intended one

Example fix

// before
anyhow::ensure!(swap_logs.len() == 1, "expected exactly one");
// after
let log = swap_logs.first().ok_or_else(|| anyhow!("no Swap log"))?;
// or iterate swap_logs if multi-swap txs are expected
Defensive patterns

Strategy: validation

Validate before calling

let swap_logs: Vec<_> = receipt.logs.iter().filter(|l| !l.removed && l.topics.first() == Some(&signature) && l.address == plan.pool_address).collect();
if swap_logs.len() != 1 { return Err(anyhow!("expected 1 Swap log, got {}", swap_logs.len())); }

Try / catch

match verify_finalized_swap(plan, included).await {
    Ok(swap) => handle_swap(swap),
    Err(e) if e.to_string().contains("expected exactly one") => recheck_pool_route(e),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A finalized transaction whose receipt contains no Swap log from plan.pool_address (wrong pool configured in the plan, aggregator router swapped via a different pool) or more than one Swap log from the same pool (multihop/multi-swap transaction, flash-swap callback plus swap).

Common situations: Plan built against one pool but router executed the trade on another; transaction bundles several swaps through the same pool; MEV bot transaction with multiple swaps; pool address recorded with wrong case/chain that Address::from_str resolves differently.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/8b6592933d35360b. Report an issue: GitHub.