{"record":{"id":"5850c6dfd47cff36","repo":"nautechsystems/nautilus_trader","slug":"router-allowance-allowance-is-below-the-swap-amo","errorCode":null,"errorMessage":"Router allowance {allowance} is below the swap amount {} for input token {}; approve the router explicitly before submitting","messagePattern":"Router allowance (.+?) is below the swap amount (.+?) for input token (.+?); approve the router explicitly before submitting","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":2416,"sourceCode":"    ] {\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\n        );\n    }\n\n    let balance = erc20_contract\n        .balance_of(&plan.token_in, &executor.wallet_address)\n        .await?;\n\n    if balance < plan.amount_in {\n        anyhow::bail!(\n            \"Input token {} balance {balance} is below the swap amount {}\",\n            plan.token_in,\n            plan.amount_in\n        );\n    }\n","sourceCodeStart":2398,"sourceCodeEnd":2434,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/execution/client.rs#L2398-L2434","documentation":"Pre-trade check that reads the ERC-20 allowance of the configured wallet for the swap router on the input token, and rejects when allowance < plan.amount_in. The blockchain execution client deliberately never auto-approves, because an on-chain approval is a state-changing transaction that costs gas and widens token access; the caller must approve the router explicitly.","triggerScenarios":"Submitting a swap when allowance(owner=wallet_address, spender=plan.router) on plan.token_in is zero or below plan.amount_in: first-ever swap with a token, a previously granted exact-size allowance consumed by earlier swaps, an allowance granted to a different router address than plan.router, or an increased order size beyond the approved amount.","commonSituations":"Fresh wallet or fresh deployment with no approvals yet; switching the plan to a new router (aggregator/uniswap version) while approvals still point at the old one; allowance used down by repeated swaps; approval performed on the wrong chain or for the wrong token.","solutions":["Send an ERC-20 approve(plan.router, amount >= plan.amount_in) transaction from the configured wallet for plan.token_in, then retry the swap","Grant a larger or max allowance if frequent swaps are expected, accepting the standard approval-risk tradeoff","Verify the approval is on the same chain and for the exact router address in the SwapPlan","Reduce plan.amount_in to fit within the existing allowance"],"exampleFix":"// before: no approval, swap fails precheck with\n// 'Router allowance 0 is below the swap amount ...'\n\n// after: approve the router once from the wallet\nlet erc20 = Erc20Contract::new(http_rpc_client.clone());\nlet _receipt = erc20\n    .approve(&token_in, &router, U256::MAX)\n    .await?; // or the exact swap amount","handlingStrategy":"validation","validationCode":"// Before submitting, confirm allowance >= amount_in and approve if needed\nlet allowance = erc20.allowance(&token_in, &wallet, &router).await?;\nif allowance < amount_in {\n    erc20.approve(&token_in, &router, amount_in).await?; // explicit approval tx\n}","typeGuard":"fn has_sufficient_allowance(allowance: U256, amount_in: U256) -> bool { allowance >= amount_in }","tryCatchPattern":"match execute_swap(plan).await {\n    Err(e) if e.to_string().contains(\"Router allowance\") => {\n        // deterministic precondition: approve, then retry once with a fresh plan\n        approve_router(&plan.token_in, &plan.router, plan.amount_in).await?;\n        execute_swap(plan).await\n    }\n    other => other,\n}","preventionTips":["Approve the router once during deployment rather than per swap","Track granted allowances alongside wallet state and re-approve before they are exhausted","Approve on the same chain and for the exact router address the plan will use"],"tags":["erc20","allowance","approval","defi","swap","preconditions"],"backgroundTag":"erc20-insufficient-allowance","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}