{"record":{"id":"93ac09ee2ea7e9c9","repo":"nautechsystems/nautilus_trader","slug":"quote-spend-limit-for-token-uses-decimals-e","errorCode":null,"errorMessage":"Quote spend limit for token {} uses {} decimals, expected pool quote-token decimals {}","messagePattern":"Quote spend limit for token (.+?) uses (.+?) decimals, expected pool quote-token decimals (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":1641,"sourceCode":"        }\n\n        let quote_spend_ceiling = if order.order_side() == OrderSide::Buy {\n            let ceiling = self\n                .transaction_limits\n                .quote_spend_limits\n                .get(&(token_in, token_out))\n                .ok_or_else(|| {\n                    anyhow::anyhow!(\n                        \"No `quote_spend_limits` entry for BUY token pair {token_in} -> {token_out}\"\n                    )\n                })?;\n            anyhow::ensure!(\n                ceiling.spend_token == quote_token.address,\n                \"Quote spend limit for {token_in} -> {token_out} is denominated in {}, expected quote token {}\",\n                ceiling.spend_token,\n                quote_token.address\n            );\n            anyhow::ensure!(\n                ceiling.spend_token_decimals == quote_token.decimals,\n                \"Quote spend limit for token {} uses {} decimals, expected pool quote-token decimals {}\",\n                ceiling.spend_token,\n                ceiling.spend_token_decimals,\n                quote_token.decimals\n            );\n            Some(ceiling)\n        } else {\n            None\n        };\n\n        let profiler = self\n            .core\n            .cache()\n            .pool_profiler(&instrument_id)\n            .cloned()\n            .ok_or_else(|| {\n                anyhow::anyhow!(","sourceCodeStart":1623,"sourceCodeEnd":1659,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L1623-L1659","documentation":"The quote-spend ceiling's decimal precision must match the pool quote token's decimals so the cap amount is interpreted in the same units as the spend. A mismatch would silently under/over-cap, so it is rejected.","triggerScenarios":"`prepare_swap()` on a BUY order where `ceiling.spend_token_decimals != quote_token.decimals` (token matched by address but decimals configured wrong, or ceiling reused across wrapped/underlying variants).","commonSituations":"Configured 18 decimals for USDC/USDT (6); ceiling entry copied from a wrapped token (WETH 18) to base token; upstream token contract changed decimals metadata.","solutions":["Set `spend_token_decimals` to the pool quote token's actual decimals in the spend-limit config","Re-derive decimals from the token contract/metadata instead of hardcoding","If the address matched but decimals differ, suspect a proxy/scam token — verify the token before trading"],"exampleFix":"// before\nspend_token_decimals: 18 // USDC\n// after\nspend_token_decimals: 6","handlingStrategy":"validation","validationCode":"let ceiling = limits.get(&(token_in, token_out)).unwrap();\nif ceiling.spend_token_decimals != quote_token.decimals {\n    return Err(format!(\"decimals {} != {}\", ceiling.spend_token_decimals, quote_token.decimals));\n}","typeGuard":"fn decimals_match(ceiling: &Ceiling, quote: &Token) -> bool {\n    ceiling.spend_token_decimals == quote.decimals\n}","tryCatchPattern":"match client.submit_order(buy_order).await {\n    Err(e) if e.to_string().contains(\"decimals\") => {\n        // refetch token metadata and regenerate the ceiling, then retry\n        regenerate_spend_limit(&quote_token)?;\n        client.submit_order(buy_order).await\n    }\n    r => r,\n}","preventionTips":["Derive decimals from token contract metadata instead of hardcoding","Remember stablecoins often use 6 decimals, not 18","Cross-check ceiling decimals against quote_token.decimals at config load"],"tags":["configuration","decimals","risk-limits","swap"],"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"}