{"record":{"id":"a7e6cb97a1e26d6a","repo":"nautechsystems/nautilus_trader","slug":"quote-spend-limit-for-token-in-token-out-is","errorCode":null,"errorMessage":"Quote spend limit for {token_in} -> {token_out} is denominated in {spend_token}; `spend_token` must match `token_in`","messagePattern":"Quote spend limit for (.+?) -> (.+?) is denominated in (.+?); `spend_token` must match `token_in`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":303,"sourceCode":"                validate_address(token_out.as_str())?,\n            ));\n        }\n\n        let quote_spend_limits = config.quote_spend_limits.as_deref().unwrap_or_default();\n        let mut parsed_quote_spend_limits = HashMap::with_capacity(quote_spend_limits.len());\n        for limit in quote_spend_limits {\n            let token_in = validate_address(limit.token_in.as_str())?;\n            let token_out = validate_address(limit.token_out.as_str())?;\n            let spend_token = validate_address(limit.spend_token.as_str())?;\n\n            if !parsed_pairs.contains(&(token_in, token_out)) {\n                anyhow::bail!(\n                    \"Quote spend limit pair {token_in} -> {token_out} is not in the `allowed_token_pairs` allowlist\"\n                );\n            }\n\n            if spend_token != token_in {\n                anyhow::bail!(\n                    \"Quote spend limit for {token_in} -> {token_out} is denominated in {spend_token}; `spend_token` must match `token_in`\"\n                );\n            }\n\n            if limit.max_amount.is_empty()\n                || !limit.max_amount.bytes().all(|byte| byte.is_ascii_digit())\n            {\n                anyhow::bail!(\n                    \"Quote spend limit `max_amount` '{}' must be a base-10 unsigned integer string\",\n                    limit.max_amount\n                );\n            }\n            let max_amount = U256::from_str(&limit.max_amount).map_err(|_| {\n                anyhow::anyhow!(\n                    \"Quote spend limit `max_amount` '{}' exceeds the U256 range\",\n                    limit.max_amount\n                )\n            })?;","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L285-L321","documentation":"Quote spend limits must be denominated in the input token: spend_token must equal token_in. The library throws this when a limit's spend_token address differs from its token_in, since the client caps spend of the token being sold into the swap.","triggerScenarios":"Calling new/transaction_limits with a config.quote_spend_limits entry where validate_address(limit.spend_token) != validate_address(limit.token_in).","commonSituations":"Setting spend_token to the output token (USDC) instead of the input token (WETH); copy-paste of addresses in the wrong field; assuming the limit applies to proceeds rather than spend.","solutions":["Set spend_token in the limit entry to the same address as token_in","Re-check the limit's semantics: it caps the amount of token_in spent per quote","Fix any address copy-paste mix-ups between fields"],"exampleFix":"// before\n{ token_in = \"0xWETH\", token_out = \"0xUSDC\", spend_token = \"0xUSDC\", max_amount = \"1000000000\" }\n// after\n{ token_in = \"0xWETH\", token_out = \"0xUSDC\", spend_token = \"0xWETH\", max_amount = \"1000000000000000000\" }","handlingStrategy":"validation","validationCode":"for l in &cfg.quote_spend_limits {\n    if !l.spend_token.eq_ignore_ascii_case(&l.token_in) {\n        return Err(format!(\"spend_token {} must equal token_in {}\", l.spend_token, l.token_in));\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember the limit caps the input token spent, not the output received","Build limits via a helper that derives spend_token from token_in automatically","Add a config-lint unit test asserting spend_token == token_in for all entries"],"tags":["config","validation","blockchain"],"backgroundTag":"invalid-config-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}