{"record":{"id":"692550a776a46cf1","repo":"nautechsystems/nautilus_trader","slug":"inverted-price-numerator-exceeds-u256-range","errorCode":null,"errorMessage":"Inverted price numerator exceeds U256 range","messagePattern":"Inverted price numerator exceeds U256 range","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/defi/tick_map/sqrt_price_math.rs","lineNumber":395,"sourceCode":"    invert: bool,\n) -> anyhow::Result<Price> {\n    let sqrt_price = U256::from(sqrt_price_x96);\n    let decimal_diff = i32::from(token0_decimals) - i32::from(token1_decimals);\n    let token0_scalar = FullMath::pow10(token0_decimals)?;\n    let token1_scalar = FullMath::pow10(token1_decimals)?;\n    let decimal_adjustment = if decimal_diff >= 0 {\n        token0_scalar / token1_scalar\n    } else {\n        token1_scalar / token0_scalar\n    };\n    let fixed_scalar = FullMath::pow10(FIXED_PRECISION)?;\n    let divisor_base: U256 = U256::from(1u128) << 192;\n\n    let price_raw = if invert {\n        if decimal_diff >= 0 {\n            let numerator = divisor_base\n                .checked_mul(fixed_scalar)\n                .ok_or_else(|| anyhow::anyhow!(\"Inverted price numerator exceeds U256 range\"))?;\n            let price_square: U512 = sqrt_price.widening_mul(sqrt_price);\n            let max_square = U512::from(numerator / decimal_adjustment);\n\n            if price_square > max_square {\n                U256::ZERO\n            } else {\n                let price_square = U256::checked_from_limbs_slice(price_square.as_limbs())\n                    .ok_or_else(|| {\n                        anyhow::anyhow!(\"Inverted price denominator exceeds U256 range\")\n                    })?;\n                let denominator =\n                    price_square\n                        .checked_mul(decimal_adjustment)\n                        .ok_or_else(|| {\n                            anyhow::anyhow!(\"Inverted price denominator exceeds U256 range\")\n                        })?;\n                FullMath::mul_div(numerator, U256::from(1), denominator)?\n            }","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/defi/tick_map/sqrt_price_math.rs#L377-L413","documentation":"In `decode_sqrt_price_x96_to_price_tokens_adjusted`, when the price must be inverted (token0/token1 direction swap) and the decimal difference is non-negative, the numerator `divisor_base * fixed_scalar` is computed with checked multiplication. The library throws this error when that product exceeds the U256 range, i.e. the fixed scalar is too large for the inversion path.","triggerScenarios":"Calling the decode/spot-price function with `invert=true` and a large `decimal_diff` whose adjustment scalar, multiplied by 2^192, overflows U256 — e.g. very asymmetric token decimals combined with inversion.","commonSituations":"Pools pairing tokens with wildly different decimals (e.g. 18 vs 0-2 decimals) where quote-direction inversion is requested; misreported token decimals inflating `decimal_diff`.","solutions":["Verify token decimals metadata is correct; a wrong decimals field inflates decimal_diff.","Handle inversion by swapping the numerator/denominator arguments instead of requesting invert with a huge scalar.","Pre-check `decimal_diff` bounds before calling and clamp the adjustment.","Compute the scalar in U512 and only narrow after division."],"exampleFix":"// before\nlet price = decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price, base_dec, quote_dec, true)?;\n// after\nensure!((base_dec - quote_dec).abs() <= 36, \"decimal diff too large for inversion\");\nlet price = decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price, base_dec, quote_dec, true)?;","handlingStrategy":"validation","validationCode":"fn inversion_safe(decimal_diff: i32) -> bool {\n    // divisor_base = 2^192; require scalar = 10^decimal_diff to fit alongside it in U256\n    decimal_diff <= 19\n}","typeGuard":null,"tryCatchPattern":"match decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price, base, quote, invert) {\n    Ok(p) if p.is_zero() => handle_extreme_price(),\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"numerator exceeds U256\") => recompute_without_inversion(),\n    Err(e) => return Err(e),\n}","preventionTips":["Verify token decimals from a trusted source before pool math","Prefer swapping numerator/denominator over requesting inversion with large decimal diffs","Clamp or reject pools with extreme decimal asymmetry at pool-registration time"],"tags":["math","u256-overflow","sqrt-price","defi"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}