{"record":{"id":"8b6592933d35360b","repo":"nautechsystems/nautilus_trader","slug":"finalized-transaction-emitted-swap-logs-from","errorCode":null,"errorMessage":"Finalized transaction {} emitted {} Swap logs from expected pool {}; expected exactly one","messagePattern":"Finalized transaction (.+?) emitted (.+?) Swap logs from expected pool (.+?); expected exactly one","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":4734,"sourceCode":"}\n\nfn validate_finalized_swap_fill(\n    plan: &SwapPlan,\n    included: &IncludedTransaction,\n) -> anyhow::Result<Option<FinalizedSwapFill>> {\n    let signature =\n        keccak256(\"Swap(address,address,int256,int256,uint160,uint128,int24)\").to_string();\n    let swap_logs = included\n        .receipt\n        .logs\n        .iter()\n        .filter(|log| {\n            !log.removed\n                && log.topics.first().is_some_and(|topic| topic == &signature)\n                && Address::from_str(&log.address).ok() == Some(plan.pool_address)\n        })\n        .collect::<Vec<_>>();\n    anyhow::ensure!(\n        swap_logs.len() == 1,\n        \"Finalized transaction {} emitted {} Swap logs from expected pool {}; expected exactly one\",\n        included.tx_hash,\n        swap_logs.len(),\n        plan.pool_address\n    );\n    let log = swap_logs[0];\n    let log_transaction_hash = B256::from_str(&rpc_log::extract_transaction_hash(log)?)\n        .with_context(|| \"Invalid finalized Swap log transaction hash\")?;\n    let log_block_hash = log\n        .block_hash\n        .as_deref()\n        .ok_or_else(|| anyhow::anyhow!(\"Finalized Swap log has no block hash\"))?;\n    anyhow::ensure!(\n        log_transaction_hash == included.tx_hash\n            && rpc_log::extract_block_number(log)? == included.block_number\n            && u64::from(rpc_log::extract_transaction_index(log)?)\n                == included.receipt.transaction_index","sourceCodeStart":4716,"sourceCodeEnd":4752,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L4716-L4752","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Confirm plan.pool_address matches the pool the router actually used for this tx (inspect the receipt logs)","If the transaction legitimately contains multiple swaps, process each log individually instead of requiring exactly one","Re-check the plan construction: ensure the pool chosen at quote time is the one the execution route targets","Exclude aggregator intermediate logs by matching expected topic0 plus pool address, as done here, and verify the tx hash is the intended one"],"exampleFix":"// before\nanyhow::ensure!(swap_logs.len() == 1, \"expected exactly one\");\n// after\nlet log = swap_logs.first().ok_or_else(|| anyhow!(\"no Swap log\"))?;\n// or iterate swap_logs if multi-swap txs are expected","handlingStrategy":"validation","validationCode":"let swap_logs: Vec<_> = receipt.logs.iter().filter(|l| !l.removed && l.topics.first() == Some(&signature) && l.address == plan.pool_address).collect();\nif swap_logs.len() != 1 { return Err(anyhow!(\"expected 1 Swap log, got {}\", swap_logs.len())); }","typeGuard":null,"tryCatchPattern":"match verify_finalized_swap(plan, included).await {\n    Ok(swap) => handle_swap(swap),\n    Err(e) if e.to_string().contains(\"expected exactly one\") => recheck_pool_route(e),\n    Err(e) => return Err(e),\n}","preventionTips":["Record the exact pool address used by the execution route in the plan","Reject multi-swap transactions at submission time or handle logs per-swap","Log all receipt topics/addresses on mismatch to diagnose routing","Keep pool addresses checksummed and chain-scoped in configuration"],"tags":["blockchain","receipt","swap","invariant"],"backgroundTag":"empty-result-set","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}