nautechsystems/nautilus_trader · error
ERC-20 approve simulation reverted for token {token}
Error message
ERC-20 approve simulation reverted for token {token} What it means
During the pre-sign approval flow, the simulation of the ERC-20 approve call reverted (VerifiedSimulation::Denied). This means executing approve on current state would revert on-chain, so the client refuses to sign and spend gas on a doomed transaction.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:2668
if result.is_empty() {
Ok(true)
} else {
ERC20::approveCall::abi_decode_returns_validate(result)
.map_err(Into::into)
}
},
)
.await,
"pre-sign approval simulation",
)?;
match &simulation.value {
VerifiedSimulation::Succeeded(true) => {}
VerifiedSimulation::Succeeded(false) => {
anyhow::bail!("ERC-20 approve returned false for token {token}")
}
VerifiedSimulation::Denied => {
anyhow::bail!("ERC-20 approve simulation reverted for token {token}")
}
}
Ok(vec![
verification_decision(&allowance, Some(block), Some(block)),
verification_decision(&simulation, Some(block), Some(block)),
])
}
}
}
async fn verify_swap_anchors_before_sign(
&self,
anchors: &SwapQuoteAnchors,
) -> anyhow::Result<Vec<ExecutionVerificationDecision>> {
let checkpoint = required_verification(
self.verification.verify_checkpoint().await,
"pre-sign checkpoint reread",
)?;View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the simulation revert reason to find the failing condition
- Check token pause/freeze/blacklist status before approving
- Retry after the token state changes (unpause) or use a different spender
- Re-run simulation against a current, correctly configured fork/RPC state
Example fix
// before
token.approve(spender, amount).send().await?; // reverts on-chain, gas lost
// after
match client.simulate_approve(token, spender, amount).await {
Ok(_) => token.approve(spender, amount).send().await?,
Err(e) => log::error("approve would revert: {e}"),
} Defensive patterns
Strategy: validation
Validate before calling
// Simulate the approve before sending; bail if it would revert
let sim = client.simulate_approve(&token, spender, amount).await?;
anyhow::ensure!(sim.succeeded(), "approve would revert: {:?}", sim.reason); Try / catch
match res {
Err(e) if e.to_string().contains("approve simulation reverted") => {
let reason = client.last_simulation_revert_reason().await?;
// check paused/blacklist state, then decide
}
r => r?,
} Prevention
- Always run pre-sign simulation for approvals
- Check token pause/freeze status before approving
- Inspect revert reasons and record them for token diagnostics
- Avoid extreme approval amounts on tokens with custom limits
When it happens
Trigger: Pre-sign approval simulation returns VerifiedSimulation::Denied — the approve call would revert, e.g. because the token is paused, the owner lacks balance/roles, or the token contract enforces conditions that fail at simulation time.
Common situations: Token contract paused or frozen; approval amount violates contract rules (e.g. some tokens cap max approval); simulation fork state diverges from mainnet; spender address blacklisted by the token.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ERC-20 approve returned false for token {token}
- Router allowance {allowance} is below the swap amount {} for
- Input token {} balance {balance} is below the swap amount {}
- Transaction {} reverted on-chain
- Router allowance {} is below the swap amount {} for input to
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b4aca5ef8baf3809.
Report an issue: GitHub.