{"record":{"id":"0b293839fd68a1a5","repo":"nautechsystems/nautilus_trader","slug":"no-deployed-bytecode-at-description-address-add","errorCode":null,"errorMessage":"No deployed bytecode at {description} address {address}","messagePattern":"No deployed bytecode at (.+?) address (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":2401,"sourceCode":"}\n\n/// Runs the read-only pre-trade checks for a swap: deployed bytecode at the pool, router,\n/// and token addresses, and an operator-prepared router allowance and input-token balance\n/// covering the amount. The shared signing pipeline checks the exact maximum native cost.\n/// Never wraps or approves.\nasync fn check_swap_preconditions(\n    plan: &SwapPlan,\n    executor: &TransactionExecutor,\n) -> anyhow::Result<()> {\n    for (address, description) in [\n        (plan.pool_address, \"pool\"),\n        (plan.router, \"router\"),\n        (plan.token_in, \"input token\"),\n        (plan.token_out, \"output token\"),\n    ] {\n        let code = executor.http_rpc_client.get_code(&address).await?;\n        if code.is_empty() {\n            anyhow::bail!(\"No deployed bytecode at {description} address {address}\");\n        }\n    }\n\n    let erc20_contract = Erc20Contract::new_with_timeout(\n        executor.http_rpc_client.clone(),\n        Some(EXECUTION_RPC_TIMEOUT_SECS),\n        true,\n    );\n\n    let allowance = erc20_contract\n        .allowance(&plan.token_in, &executor.wallet_address, &plan.router)\n        .await?;\n\n    if allowance < plan.amount_in {\n        anyhow::bail!(\n            \"Router allowance {allowance} is below the swap amount {} for input token {}; approve the router explicitly before submitting\",\n            plan.amount_in,\n            plan.token_in","sourceCodeStart":2383,"sourceCodeEnd":2419,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/execution/client.rs#L2383-L2419","documentation":"Thrown by check_swap_preconditions before any swap transaction is signed. The client calls eth_getCode for each address in the SwapPlan (pool, router, input token, output token) and requires non-empty bytecode, proving each is a deployed contract on the chain served by the configured RPC. An empty result means the address is an externally owned account (EOA) or simply does not exist, so the swap would fail or send funds to nowhere.","triggerScenarios":"Calling submit/execute of the blockchain execution client with a SwapPlan whose pool_address, router, token_in, or token_out is a mistyped address, an EOA, or a contract that is not deployed on the connected chain (e.g. a mainnet Uniswap pool address used against a Sepolia RPC). Any one of the four get_code calls returning empty triggers the bail.","commonSituations":"RPC URL and chain configuration disagree (testnet RPC with mainnet addresses), copy/paste typo in a token or router address, a deprecated or migrated router address, tokens without real contracts (scam/fake tokens), or an instrument definition carrying an address for the wrong chain fork.","solutions":["Look up each address named in the error on a block explorer for the SAME chain the RPC serves; the failing one will show no contract code","Verify the RPC URL and chain.chain_id in the client configuration match the network where the pool, router, and tokens are actually deployed","Correct the address in the source of the SwapPlan (instrument definitions, router config, or strategy parameters) and retry","If a contract genuinely is not deployed yet (e.g. custom router), deploy it before submitting swaps"],"exampleFix":"// before: chain_id = 1 (Ethereum mainnet) but RPC is Sepolia and\n// plan.router is a mainnet deployment\nlet config = BlockchainExecutionConfig { chain_rpc_http: \"https://sepolia.infura.io/v3/...\".into(), /* chain = Sepolia */ .. };\n\n// after: keep addresses and chain consistent\n// mainnet addresses only with a mainnet RPC and chain_id = 1\nlet config = BlockchainExecutionConfig { chain_rpc_http: \"https://mainnet.infura.io/v3/...\".into(), .. };","handlingStrategy":"validation","validationCode":"// Before building/executing a SwapPlan, prove each address is a contract on this chain\nasync fn all_addresses_are_contracts(rpc: &HttpRpcClient, addrs: &[(&Address, &str)]) -> anyhow::Result<bool> {\n    for (addr, desc) in addrs {\n        if rpc.get_code(addr).await?.is_empty() {\n            log::warn!(\"{desc} address {addr} has no bytecode\");\n            return Ok(false);\n        }\n    }\n    Ok(true)\n}","typeGuard":"fn is_non_empty_code(code: &[u8]) -> bool { !code.is_empty() }","tryCatchPattern":"// check_swap_preconditions already runs pre-signature; treat its Err as terminal for this\n// plan: log the failing address, surface to the operator, and do NOT retry the same plan.\nif let Err(e) = execute_swap(plan).await {\n    if e.to_string().contains(\"No deployed bytecode\") {\n        // config/address bug — fix data, never re-submit unchanged\n        alert_operator(&e.to_string());\n    }\n    return Err(e);\n}","preventionTips":["Keep RPC URL, chain id, and all contract addresses in one per-environment config block","Add a startup smoke test that eth_getCode's every configured pool/router/token","Cross-check addresses against a block explorer for the exact chain before first run"],"tags":["blockchain","evm","swap","preconditions","address-validation","getcode"],"backgroundTag":"evm-address-has-no-contract-code","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}