nautechsystems/nautilus_trader · error · anyhow::Error
Router allowance after transaction {} does not equal the req
Error message
Router allowance after transaction {} does not equal the requested amount {amount}: was {} What it means
After an approval (approve) transaction finalizes, the adapter reads `allowance(owner=wallet, spender=router)` at the inclusion block and requires it to equal exactly the requested amount. This ensure! fires when the on-chain allowance differs — the approval did not take the expected effect (wrong spender, partial/zero approval, or a non-standard token contract). Failing here prevents subsequent swaps from relying on an incorrect allowance.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:4577
.verification
.verify_decoded_call(
None,
token,
U256::ZERO,
&call,
included.block_number,
|result| ERC20::allowanceCall::abi_decode_returns(result).map_err(Into::into),
)
.await,
"router allowance after finality",
)
.with_context(|| {
format!(
"failed to verify router allowance after included transaction {} at block {}",
included.tx_hash, included.block_number
)
})?;
anyhow::ensure!(
allowance.value == amount,
"Router allowance after transaction {} does not equal the requested amount {amount}: was {}",
included.tx_hash,
allowance.value
);
Ok(vec![verification_decision(
&allowance,
Some(included.block_number),
Some(included.block_number),
)])
}
async fn complete_finalized_swap(
plan: &SwapPlan,
intent_id: i64,
tx_hash: B256,
fill: Option<FinalizedSwapFill>,View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the router (spender) address passed to verification matches the one in the submitted approve call
- Re-read allowance at the inclusion block from an independent RPC to rule out fork/stale state
- Inspect the approve tx receipt logs to confirm spender and value actually written
- If the token is non-standard, account for its allowance semantics before enforcing exact equality
Example fix
// before
verify_approve_allowance(&executor, &token, &router, amount, &included).await?;
// after
anyhow::ensure!(router == plan.router_address, "router mismatch: {}", router);
verify_approve_allowance(&executor, &token, &router, amount, &included).await?; Defensive patterns
Strategy: try-catch
Validate before calling
fn approve_params_match(plan: &SwapPlan, router: Address, amount: U256) -> bool {
plan.router_address == router && plan.approval_amount == amount
} Type guard
fn allowance_is_exact(allowance: U256, requested: U256) -> bool {
allowance == requested
} Try / catch
match verify_approve_allowance(&executor, &token, &router, amount, &included).await {
Ok(d) => apply(d),
Err(e) if e.to_string().contains("does not equal the requested amount") => {
tracing::warn!("allowance mismatch after approve {}", included.tx_hash);
// re-read allowance from canonical RPC; if still wrong, re-issue approve
}
Err(e) => return Err(e),
} Prevention
- Keep router/spender address in one place so tx construction and verification can't diverge
- Avoid race windows: don't submit swaps that consume the allowance between mining and verification
- Screen tokens for non-standard allowance behavior before routing through them
- Verify approvals against an independent RPC if exactness is safety-critical
When it happens
Trigger: `allowance.value != amount` at `included.block_number` after a finalized approve transaction — e.g. the tx approved a different spender or amount, the approval was consumed/changed before verification, or the token's allowance semantics differ from standard ERC20.
Common situations: Router address mismatch between the tx and verification config, verifying an approve that was later partially consumed, non-standard ERC20 tokens (fee-on-transfer, allowance caps), or RPC serving state from a different fork.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- Token {} reports unexpected decimals
- {context} verification disagreed
- {context} verification is locally invalid
- ERC-20 approve returned false for token {token}
- Receipt verification is locally invalid for transaction {tx_
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9187bb937beebe2b.
Report an issue: GitHub.