{"record":{"id":"479db40853318bab","repo":"nautechsystems/nautilus_trader","slug":"pool-fee-is-invalid","errorCode":null,"errorMessage":"Pool fee is invalid","messagePattern":"Pool fee is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/rpc/verification.rs","lineNumber":1383,"sourceCode":"        );\n    }\n\n    for pool in &manifest.pools {\n        for address in [\n            &pool.address,\n            &pool.token0,\n            &pool.token1,\n            &pool.factory,\n            &pool.quote_contract,\n        ] {\n            let address = Address::from_str(address)\n                .map_err(|_| anyhow::anyhow!(\"Pool manifest address is invalid\"))?;\n            anyhow::ensure!(\n                contract_addresses.contains(&address),\n                \"Pool manifest references an unpinned contract\"\n            );\n        }\n        anyhow::ensure!(\n            pool.fee != 0 && pool.fee <= 1_000_000,\n            \"Pool fee is invalid\"\n        );\n    }\n    let mut call_edges = HashSet::new();\n    for edge in &manifest.call_edges {\n        anyhow::ensure!(\n            matches!(\n                edge.purpose.as_str(),\n                \"wrap\" | \"approve\" | \"swap_sell\" | \"swap_buy\"\n            ) && matches!(\n                edge.call_type.as_str(),\n                \"call\" | \"staticcall\" | \"delegatecall\" | \"callcode\"\n            ),\n            \"Deployment manifest call edge is invalid\"\n        );\n        let caller = Address::from_str(&edge.caller)\n            .map_err(|_| anyhow::anyhow!(\"Call edge address is invalid\"))?;","sourceCodeStart":1365,"sourceCodeEnd":1401,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/rpc/verification.rs#L1365-L1401","documentation":"Each pool entry in the deployment manifest must carry a nonzero swap fee that does not exceed 1,000,000 (fee tier in pool-fee units, e.g. Uniswap-style granularity). The library enforces this because a zero fee is nonsensical for a live pool and an out-of-range value indicates a corrupted or fabricated pool record.","triggerScenarios":"Validating a manifest whose pool.fee equals 0 or is greater than 1,000,000; the check runs after the pool address/pinning validation passes.","commonSituations":"Leaving fee at its default 0 when hand-authoring a pool entry; copying a fee from a venue that uses a different unit (e.g. percent 0.3 instead of 3000); a typo like 10000000 instead of 1000000.","solutions":["Set pool.fee to the pool's real fee tier (e.g. 500, 3000, 10000 for Uniswap v3-style tiers)","If the fee was expressed in percent or basis points, convert it to the manifest's fee units before writing it","Remove placeholder pool entries that were never fully populated","Regenerate the manifest from the source of truth (chain data / generator) instead of editing by hand"],"exampleFix":"// before\n{\"address\": \"0xabc...\", \"fee\": 0}\n// after\n{\"address\": \"0xabc...\", \"fee\": 3000}","handlingStrategy":"validation","validationCode":"// Pre-check fee before building the manifest\nif !(pool.fee > 0 && pool.fee <= 1_000_000) {\n    return Err(format!(\"pool {} fee {} out of range (1..=1_000_000)\", pool.address, pool.fee));\n}","typeGuard":"fn is_valid_fee(fee: u64) -> bool { fee != 0 && fee <= 1_000_000 }","tryCatchPattern":"match validate_deployment_manifest(&manifest) {\n    Err(e) if e.to_string().contains(\"Pool fee is invalid\") => {\n        eprintln!(\"Set pool.fee to a nonzero value <= 1_000_000 (fee-tier units)\");\n    }\n    Err(e) => return Err(e),\n    Ok(()) => {}\n}","preventionTips":["Copy fee values directly from chain data (e.g. Uniswap fee tiers 500/3000/10000) rather than converting by hand","Add a unit test that every fixture pool fee is in 1..=1_000_000","Reject fee=0 placeholder entries at manifest authoring time"],"tags":["blockchain","manifest-validation","config"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}