{"record":{"id":"f60abd07972130eb","repo":"nautechsystems/nautilus_trader","slug":"router-reports-an-unexpected-factory","errorCode":null,"errorMessage":"Router {} reports an unexpected factory","messagePattern":"Router (.+?) reports an unexpected factory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":5038,"sourceCode":"    let factory_call = UniswapV3RouterState::factoryCall.abi_encode();\n    let router_factory = required_verification(\n        executor\n            .verification\n            .verify_decoded_call(\n                None,\n                &plan.router,\n                U256::ZERO,\n                &factory_call,\n                block,\n                |result| {\n                    UniswapV3RouterState::factoryCall::abi_decode_returns(result)\n                        .map_err(Into::into)\n                },\n            )\n            .await,\n        \"swap router factory\",\n    )?;\n    anyhow::ensure!(\n        router_factory.value == plan.factory,\n        \"Router {} reports an unexpected factory\",\n        plan.router,\n    );\n    decisions.push(verification_decision(\n        &router_factory,\n        Some(block),\n        Some(block),\n    ));\n\n    let weth_call = UniswapV3RouterState::WETH9Call.abi_encode();\n    let router_weth = required_verification(\n        executor\n            .verification\n            .verify_decoded_call(\n                None,\n                &plan.router,\n                U256::ZERO,","sourceCodeStart":5020,"sourceCodeEnd":5056,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L5020-L5056","documentation":"Raised during pre-trade router verification when the swap router's factory() call returns an address different from the plan.factory recorded in the execution plan. This guards against the router not being the expected Uniswap V3 router or pointing to a cloned/malicious factory. Verification fails before any swap is submitted.","triggerScenarios":"Executing a swap plan where on-chain router.factory() != plan.factory, e.g. the plan was built against a different router deployment or the router contract was upgraded/replaced at plan.router.","commonSituations":"Stale execution plan reused after a router redeploy, plan built on one network and replayed on another (different contract addresses), router address typo'd in the plan, or a malicious/proxy router.","solutions":["Rebuild the execution plan so plan.factory matches the factory reported by the router currently deployed at plan.router","Confirm plan.router and plan.factory are from the same network/deployment (chain ID check)","Re-fetch canonical Uniswap V3 router and factory addresses from official deployments rather than manual entry","If the router is behind a proxy, verify the proxy admin/upgrades did not change factory()"],"exampleFix":"// before\nplan.router = \"0xE592427A0AEce92De3Edee1F18E0157C05861564\"; // plan stale after redeploy\n// after\nlet plan = build_execution_plan(chain_id).await?; // re-derive router/factory/weth for current deployment","handlingStrategy":"validation","validationCode":"async fn check_router_factory(router: Address, plan_factory: Address) -> Result<(), String> {\n    let actual: Address = call_router_factory(router).await?;\n    if actual != plan_factory { return Err(format!(\"router {router} factory mismatch: {actual} != {plan_factory}\")); }\n    Ok(())\n}","typeGuard":"fn factory_matches(plan_factory: Address, actual: Address) -> bool { plan_factory == actual }","tryCatchPattern":null,"preventionTips":["Always build plans from a trusted deployment registry for the exact chain ID","Never reuse execution plans across chains or after contract redeploys","Cache canonical router/factory/WETH addresses with chain-id keys","Treat any factory mismatch as a potential malicious router and halt trading"],"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"}