{"record":{"id":"9855afdad72e2148","repo":"nautechsystems/nautilus_trader","slug":"div-rounding-up-failed","errorCode":null,"errorMessage":"div_rounding_up failed","messagePattern":"div_rounding_up failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/defi/tick_map/sqrt_price_math.rs","lineNumber":116,"sourceCode":"    let numerator = U256::from(liquidity) << 96;\n    let sqrt_price_x96 = U256::from(sqrt_price_x96);\n    let product = amount * sqrt_price_x96;\n\n    if add {\n        if product / amount == sqrt_price_x96 {\n            let denominator = numerator + product;\n            if denominator >= numerator {\n                // always fit to 160bits\n                let result = FullMath::mul_div_rounding_up(numerator, sqrt_price_x96, denominator)\n                    .expect(\"mul_div_rounding_up failed\");\n                return U160::from(result);\n            }\n        }\n\n        // Fallback: divRoundingUp(numerator1, (numerator1 / sqrtPX96).add(amount))\n        let fallback_denominator = (numerator / sqrt_price_x96) + amount;\n        let result = FullMath::div_rounding_up(numerator, fallback_denominator)\n            .expect(\"div_rounding_up failed\");\n\n        // Check if result fits in U160\n        assert!(result <= U256::from(U160::MAX), \"Result overflows U160\");\n        U160::from(result)\n    } else {\n        // require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product);\n        assert!(\n            (product / amount) == sqrt_price_x96 && numerator > product,\n            \"Invalid conditions for amount0 removal: overflow or underflow detected\"\n        );\n\n        let denominator = numerator - product;\n        let result = FullMath::mul_div_rounding_up(numerator, sqrt_price_x96, denominator)\n            .expect(\"mul_div_rounding_up failed\");\n        U160::from(result)\n    }\n}\n","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/defi/tick_map/sqrt_price_math.rs#L98-L134","documentation":"In the fallback path of get_next_sqrt_price_from_amount0_rounding_up, div_rounding_up(numerator, fallback_denominator) computes the next price as divRoundingUp(numerator1, numerator1/sqrtPX96 + amount). The expect panics when the division fails — i.e. fallback_denominator is zero, which happens when numerator/sqrt_price_x96 + amount wraps or evaluates to zero due to extreme inputs.","triggerScenarios":"Calling get_next_sqrt_price_from_input/output with amount0 values where (numerator / sqrt_price_x96) + amount overflows U256 or yields zero, typically with maximum-size amounts or degenerate sqrt_price_x96 values reaching this branch.","commonSituations":"Simulating swaps with amounts near U256::MAX; fuzz tests probing the overflow-safe fallback; pools with malformed sqrt prices making numerator/sqrtPX96 huge.","solutions":["Clamp swap amounts so the computed next price remains within valid bounds before invoking the function.","Propagate the failure as an error instead of expect, letting swap simulation reject the quote.","Pre-check fallback_denominator != 0 (and no U256 addition overflow) with checked_add."],"exampleFix":"// before\nlet result = FullMath::div_rounding_up(numerator, fallback_denominator)\n    .expect(\"div_rounding_up failed\");\n// after\nlet result = FullMath::div_rounding_up(numerator, fallback_denominator)\n    .ok_or_else(|| anyhow::anyhow!(\"fallback next-sqrt-price division failed (zero denominator)\"))?;","handlingStrategy":"validation","validationCode":"let fallback_denominator = (numerator / sqrt_price_x96).checked_add(amount)\n    .filter(|d| !d.is_zero())\n    .ok_or_else(|| anyhow!(\"degenerate fallback denominator\"))?;","typeGuard":"fn fallback_div_safe(numerator: U256, sqrt_price_x96: U160, amount: U256) -> bool {\n    (numerator / U256::from(sqrt_price_x96)).checked_add(amount).map_or(false, |d| !d.is_zero())\n}","tryCatchPattern":"match FullMath::div_rounding_up(numerator, fallback_denominator) {\n    Some(r) => U160::from(r),\n    None => return Err(anyhow!(\"fallback division failed\")),\n}","preventionTips":["Use checked_add when forming the fallback denominator.","Bound input amounts before entering the overflow-safe fallback.","Keep simulation errors recoverable rather than panicking."],"tags":["rust","panic","division-by-zero","arithmetic-overflow","uniswap-v3"],"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-14T00:17:10.932Z"}