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

  1. Verify the router (spender) address passed to verification matches the one in the submitted approve call
  2. Re-read allowance at the inclusion block from an independent RPC to rule out fork/stale state
  3. Inspect the approve tx receipt logs to confirm spender and value actually written
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/9187bb937beebe2b. Report an issue: GitHub.