{"record":{"id":"728c2bfd5c821256","repo":"nautechsystems/nautilus_trader","slug":"erc-20-approve-returned-false-for-token-token","errorCode":null,"errorMessage":"ERC-20 approve returned false for token {token}","messagePattern":"ERC-20 approve returned false for token (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":2665,"sourceCode":"                            &approve_call,\n                            block,\n                            |result| {\n                                if result.is_empty() {\n                                    Ok(true)\n                                } else {\n                                    ERC20::approveCall::abi_decode_returns_validate(result)\n                                        .map_err(Into::into)\n                                }\n                            },\n                        )\n                        .await,\n                    \"pre-sign approval simulation\",\n                )?;\n\n                match &simulation.value {\n                    VerifiedSimulation::Succeeded(true) => {}\n                    VerifiedSimulation::Succeeded(false) => {\n                        anyhow::bail!(\"ERC-20 approve returned false for token {token}\")\n                    }\n                    VerifiedSimulation::Denied => {\n                        anyhow::bail!(\"ERC-20 approve simulation reverted for token {token}\")\n                    }\n                }\n                Ok(vec![\n                    verification_decision(&allowance, Some(block), Some(block)),\n                    verification_decision(&simulation, Some(block), Some(block)),\n                ])\n            }\n        }\n    }\n\n    async fn verify_swap_anchors_before_sign(\n        &self,\n        anchors: &SwapQuoteAnchors,\n    ) -> anyhow::Result<Vec<ExecutionVerificationDecision>> {\n        let checkpoint = required_verification(","sourceCodeStart":2647,"sourceCodeEnd":2683,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L2647-L2683","documentation":"Before signing an ERC-20 approve, the client simulates the call and checks its boolean return value. ERC-20 approve returns false on failure in some token implementations; if the simulation succeeds but returns false, the approval will not take effect, so the client bails instead of signing a no-op approval.","triggerScenarios":"Pre-sign approval simulation of approve(spender, amount) returns VerifiedSimulation::Succeeded(false) — the call executes without reverting but the token contract returns false, indicating the approval did not apply.","commonSituations":"Non-standard ERC-20 tokens with balance/allowance conditions in approve; paused token contracts that return false instead of reverting; approving on a fork/simulation backend with stale token state; amount exceeding some token-specific cap.","solutions":["Check the token's implementation: paused, custom approve logic, or blacklist conditions","Verify token state (owner balance, current allowance, pause status) before approving","Use a standard, audited token or upgrade the token contract if you control it","Try approving a smaller/standard amount (e.g. type(uint256).max) if the token imposes limits"],"exampleFix":"// before\nlet ok: bool = token.approve(spender, amount).call().await?;\n// after\nlet paused = token.paused().call().await?;\nanyhow::ensure!(!paused, \"token paused; approve would return false\");\nlet ok: bool = token.approve(spender, amount).call().await?;\nanyhow::ensure!(ok, \"approve returned false for token\");","handlingStrategy":"validation","validationCode":"let paused: bool = token.paused().call().await?;\nanyhow::ensure!(!paused, \"token paused; approve would return false\");\nlet owner_balance: U256 = token.balance_of(owner).call().await?;\nanyhow::ensure!(owner_balance > U256::zero(), \"owner has no token balance\");","typeGuard":"fn approve_will_apply(ret: &VerifiedSimulation) -> bool {\n    matches!(ret, VerifiedSimulation::Succeeded(true))\n}","tryCatchPattern":null,"preventionTips":["Audit non-standard tokens for approve returning false or custom conditions","Check token pause/blacklist status before approval flows","Keep pre-sign simulations enabled for every approval","Prefer standard audited ERC-20 implementations"],"tags":["erc20","approve","simulation","blockchain"],"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-14T05:17:10.506Z"}