feat(common): overflow-safe time-weighted average rate (#2)#45
Merged
elizabetheonoja-art merged 1 commit intoJun 25, 2026
Merged
Conversation
…col#2) Time-weighted tariff averaging computes sum(rate_i * duration_i) / sum(duration_i). A naive u128 implementation can overflow the product/sum and truncates on division; the tariff calculator used saturating_mul (silently clamps to a wrong value) plus integer division (precision loss). Add contracts/common/src/weighted_rate.rs (pure no_std, no deps): - mul_full: exact 128x128 -> 256-bit multiply - div_256_by_128: exact restoring long division (quotient + remainder) - mul_div_floor / mul_div_round (ROUND_HALF_UP) - weighted_average(&[(rate, duration)]): accumulates the numerator in full 256-bit precision and divides exactly -> zero precision loss, no intermediate overflow (returns None instead of silently wrong on the unreachable >2^256 numerator / >u128 quotient cases) - interval_product_fits_u128: optional per-interval pre-validation Tests: mul_full vs wrapping_mul + known high products, half-up rounding, zero-divisor/quotient-overflow None, constant/two-window/duration-weighted averages, 18-decimal 30-day scale, beyond-u128 numerator, and a 2000-iter deterministic property sweep over rate in [1,1e18], duration in [60,2.59e6], intervals in [1,2880] asserting exact equality with a native reference. docs/specs/tariff-precision.md documents the strategy, overflow guarantees, and why full-width integers beat a rounding Decimal128. Note: the production consumer (TariffOracle::calculate_flow_for_period in utility_contracts) does not compile today (pre-existing SDK-23 errors), so the verified algorithm lands in the common crate for it to delegate to once that crate builds again.
elizabetheonoja-art
approved these changes
Jun 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat(common): overflow-safe, precision-preserving time-weighted average rate
Closes #2
(
TariffOracle::calculate_flow_for_period) does this with:saturating_mulforrate_i × duration_i— on overflow it silently clampsto a wrong (capped) value instead of failing, and
integer division
Σ / total— which truncates, losing precision.mul_full(a, b) -> (hi, lo)— exact 128×128 → 256-bit multiply.add_256— 256-bit accumulation with overflow detection.div_256_by_128(hi, lo, d)— exact restoring long division (quotient +remainder);
Noneif the quotient exceedsu128.round_half_up—ROUND_HALF_UPvia the remainder (overflow-safe2r ≥ d).mul_div_floor/mul_div_round—a*b/dwith no intermediate overflow.weighted_average(&[(rate, duration)])— accumulates the numerator in full256-bit precision and divides exactly → zero precision loss, no intermediate
overflow. Returns
None(never silently wrong) on the unreachable> 2²⁵⁶numerator /> u128quotient cases.interval_product_fits_u128— optional per-interval pre-validation(blueprint step 3).
Files
contracts/common/src/weighted_rate.rs(new)contracts/common/src/lib.rs(register module)contracts/docs/specs/tariff-precision.md(new — strategy & overflow guarantees)