{"record":{"id":"350a74ff3aca05a5","repo":"nautechsystems/nautilus_trader","slug":"factory-resolves-an-unexpected-pool-for-the-swap-t","errorCode":null,"errorMessage":"Factory resolves an unexpected pool for the swap token pair and fee","messagePattern":"Factory resolves an unexpected pool for the swap token pair and fee","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":5099,"sourceCode":"    }\n    .abi_encode();\n    let registered_pool = required_verification(\n        executor\n            .verification\n            .verify_decoded_call(\n                None,\n                &plan.factory,\n                U256::ZERO,\n                &pool_call,\n                block,\n                |result| {\n                    UniswapV3Factory::getPoolCall::abi_decode_returns(result).map_err(Into::into)\n                },\n            )\n            .await,\n        \"swap factory pool\",\n    )?;\n    anyhow::ensure!(\n        registered_pool.value == plan.pool_address,\n        \"Factory resolves an unexpected pool for the swap token pair and fee\"\n    );\n    decisions.push(verification_decision(\n        &registered_pool,\n        Some(block),\n        Some(block),\n    ));\n\n    for token in [&plan.pool.token0, &plan.pool.token1] {\n        let decimals_call = ERC20::decimalsCall.abi_encode();\n        let decimals = required_verification(\n            executor\n                .verification\n                .verify_decoded_call(\n                    None,\n                    &token.address,\n                    U256::ZERO,","sourceCodeStart":5081,"sourceCodeEnd":5117,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L5081-L5117","documentation":"Raised during pre-trade verification when the Uniswap V3 factory's getPool(token0, token1, fee) returns an address different from plan.pool_address. This confirms the pool recorded in the plan is actually the canonical pool the factory computes for that token pair and fee tier. A mismatch aborts the swap because the plan targets a non-canonical or nonexistent pool.","triggerScenarios":"Executing a swap plan where factory.getPool(tokenIn, tokenOut, fee) != plan.pool_address — e.g. the plan's pool was created via createPool with unusual parameters, or the pool address was computed/hardcoded incorrectly.","commonSituations":"Hardcoded pool address from a different fee tier, pool deployed by a different factory than plan.factory, plan built on one chain and replayed on another, or a malicious fork pool address entered in the plan.","solutions":["Rebuild the execution plan and set plan.pool_address from factory.getPool(token0, token1, fee) at plan time","Verify the pool exists (getPool returned non-zero) for the chosen token pair and fee tier","Confirm plan.factory matches the factory that actually deployed the pool","If multiple fee tiers exist, pick the intended tier explicitly and regenerate the plan"],"exampleFix":"// before\nplan.pool_address = \"0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640\"; // hardcoded 0.3% USDC/WETH\n// after\nplan.pool_address = factory.get_pool(token0, token1, plan.fee).await?; // canonical pool from factory","handlingStrategy":"validation","validationCode":"async fn check_pool_canonical(factory: Address, token0: Address, token1: Address, fee: u32, plan_pool: Address) -> Result<(), String> {\n    let actual: Address = factory_get_pool(factory, token0, token1, fee).await?;\n    if actual.is_zero() { return Err(\"pool does not exist for this pair and fee\".into()); }\n    if actual != plan_pool { return Err(format!(\"pool mismatch: {actual} != {plan_pool}\")); }\n    Ok(())\n}","typeGuard":"fn pool_matches(plan_pool: Address, actual: Address) -> bool { !actual.is_zero() && plan_pool == actual }","tryCatchPattern":null,"preventionTips":["Always derive pool addresses via factory.getPool, never hardcode","Verify the pool exists (non-zero address) before planning a swap","Pin the fee tier explicitly and confirm the canonical pool for it","Detect token0/token1 ordering (sort by address) before calling getPool"],"tags":["blockchain","verification","uniswap-v3","contract-mismatch"],"backgroundTag":"unexpected-api-response-shape","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"}