tip: 836
title: harden exchange transaction calculations
author: halibobo1205@gmail.com
status: Draft
type: Standards Track
category: Core
created: 2026-03-19
requires: None
Simple Summary
This proposal hardens the core calculation logic of Exchange trading pairs by replacing floating-point arithmetic with BigDecimal (except for pow operations), and introducing explicit overflow detection for all integer arithmetic and type conversions.
Motivation
The goal is to upgrade the numeric safety model for Exchange trading pair calculations from "implicitly constrained by runtime context" to "explicitly enforced by the language type," ensuring that safety guarantees are actively provided at the implementation level.
Explicit safety mechanisms offer the following engineering advantages:
- Higher readability: Code intent is unambiguous; safety assumptions can be understood without reading comments or surrounding context.
- Deterministic semantics: Overflow behaviour is guaranteed by the language mechanism rather than relying on external constraints.
- Predictable failure: Problems surface immediately as exceptions, making them easier to locate and fix.
Specification
All changes described in this section take effect when a new governance proposal parameter is activated. Until activation, all existing code paths remain completely unchanged.
1. Principles
- No
double/float arithmetic: All floating-point operations are replaced with BigDecimal, except pow (see Section 2).
- Integer overflow detection: All integer arithmetic must use the overflow-detecting methods provided by
StrictMath: addExact, subtractExact, multiplyExact, etc.
- Type conversion overflow checks:
- When converting
BigInteger or BigDecimal to long or int, longValueExact() or intValueExact() must be called. Using longValue() / intValue(), which silently truncates, is prohibited.
- When narrowing
long to int, StrictMath.toIntExact must be used.
2. pow Operations: Hybrid StrictMath.pow + BigDecimal Approach
The Bancor pricing curve uses fractional exponents (0.0005 is the Connector Weight in the Bancor formula, which determines the steepness of the curve). BigDecimal's native pow method supports only integer exponents and cannot be used directly in this context.
This proposal adopts a hybrid approach: StrictMath.pow handles the fractional exponentiation, and the result is wrapped in a BigDecimal for all subsequent operations.
// Before (ExchangeProcessor)
double issuedSupply = -supply * (1.0
- Maths.pow(1.0 + (double) quant / newBalance, 0.0005, this.useStrictMath));
long out = (long) issuedSupply;
// After
BigDecimal bdSupply = BigDecimal.valueOf(supply);
BigDecimal bdNewBalance = BigDecimal.valueOf(newBalance);
BigDecimal bdQuant = BigDecimal.valueOf(quant);
// base = 1 + quant / newBalance, computed precisely with BigDecimal.
// 18 decimal places (HALF_UP) are retained — greater than the effective precision
// of the subsequent StrictMath.pow doubleValue() input (~15–16 digits),
// so no additional rounding error is introduced.
BigDecimal base = BigDecimal.ONE.add(
bdQuant.divide(bdNewBalance, 18, RoundingMode.HALF_UP));
// StrictMath.pow guarantees bit-for-bit identical results across all JVM
// implementations, satisfying the on-chain determinism requirement.
double powResult = StrictMath.pow(base.doubleValue(), 0.0005);
// All subsequent arithmetic is performed at the BigDecimal level,
// preventing floating-point error accumulation.
BigDecimal issuedSupply = bdSupply.negate().multiply(
BigDecimal.ONE.subtract(BigDecimal.valueOf(powResult)));
long out = issuedSupply.setScale(0, RoundingMode.DOWN).longValueExact();
The key distinction between StrictMath.pow and Math.pow is that StrictMath requires all JVM implementations to produce bit-for-bit identical results, independent of the underlying hardware or JVM optimization behavior. This satisfies the determinism requirement for on-chain computation.
3. Non-Negative Validation Before State Write
long newFirstBalance = StrictMathWrapper.addExact(firstTokenBalance, sellTokenQuant);
long newSecondBalance = StrictMathWrapper.subtractExact(secondTokenBalance, buyTokenQuant);
if (newFirstBalance < 0 || newSecondBalance < 0) {
throw new ContractExeException(
"Exchange balance must remain positive after transaction");
}
this.exchange = this.exchange.toBuilder()
.setFirstTokenBalance(newFirstBalance)
.setSecondTokenBalance(newSecondBalance)
.build();
4. Unified Use of Exact-Family Methods for Integer Arithmetic
All integer addition, subtraction, multiplication, and type conversions are replaced with overflow-safe equivalents:
| Original Operation |
Replacement |
a + b |
StrictMathWrapper.addExact(a, b) |
a - b |
StrictMathWrapper.subtractExact(a, b) |
a * b |
StrictMathWrapper.multiplyExact(a, b) |
(int) longVal |
StrictMathWrapper.toIntExact(longVal) |
bigInteger.longValue() |
bigInteger.longValueExact() |
bigDecimal.longValue() |
bigDecimal.longValueExact() |
All of the above methods throw ArithmeticException on overflow or truncation. The exception is caught by the upper-level transaction execution framework and treated as a contract execution failure, causing the transaction to be rolled back.
StrictMathWrapper is an internal utility class that provides a unified wrapper around StrictMath's Exact-family methods.
Rationale
StrictMath.pow + BigDecimal Is the Correct Implementation Path for the Bancor Algorithm
The Bancor pricing curve requires fractional exponentiation. BigDecimal does not natively support fractional powers; implementing ln/exp approximations from scratch or introducing a third-party library would increase implementation complexity and add external dependency risk.
StrictMath.pow guarantees bit-for-bit cross-platform consistency at the JVM specification level, directly satisfying the on-chain determinism requirement without introducing any additional dependencies. By wrapping the pow result in BigDecimal, all subsequent addition, subtraction, and multiplication operations are performed at the BigDecimal level, preventing the accumulation and propagation of floating-point errors.
This approach deliberately confines floating-point precision limits to the single pow step, with StrictMath guaranteeing cross-platform consistency for that step. The overall calculation path achieves both greater determinism and higher precision than the original implementation.
Backwards Compatibility
This proposal is gated behind the Proposal mechanism and is fully backwards compatible.
Simple Summary
This proposal hardens the core calculation logic of
Exchange trading pairsby replacing floating-point arithmetic withBigDecimal(except forpowoperations), and introducing explicit overflow detection for all integer arithmetic and type conversions.Motivation
The goal is to upgrade the numeric safety model for
Exchange trading paircalculations from "implicitly constrained by runtime context" to "explicitly enforced by the language type," ensuring that safety guarantees are actively provided at the implementation level.Explicit safety mechanisms offer the following engineering advantages:
Specification
All changes described in this section take effect when a new governance proposal parameter is activated. Until activation, all existing code paths remain completely unchanged.
1. Principles
double/floatarithmetic: All floating-point operations are replaced withBigDecimal, exceptpow(see Section 2).StrictMath:addExact,subtractExact,multiplyExact, etc.BigIntegerorBigDecimaltolongorint,longValueExact()orintValueExact()must be called. UsinglongValue()/intValue(), which silently truncates, is prohibited.longtoint,StrictMath.toIntExactmust be used.2.
powOperations: HybridStrictMath.pow+BigDecimalApproachThe Bancor pricing curve uses fractional exponents (0.0005 is the Connector Weight in the Bancor formula, which determines the steepness of the curve).
BigDecimal's nativepowmethod supports only integer exponents and cannot be used directly in this context.This proposal adopts a hybrid approach:
StrictMath.powhandles the fractional exponentiation, and the result is wrapped in aBigDecimalfor all subsequent operations.The key distinction between
StrictMath.powandMath.powis thatStrictMathrequires all JVM implementations to produce bit-for-bit identical results, independent of the underlying hardware or JVM optimization behavior. This satisfies the determinism requirement for on-chain computation.3. Non-Negative Validation Before State Write
4. Unified Use of
Exact-Family Methods for Integer ArithmeticAll integer addition, subtraction, multiplication, and type conversions are replaced with overflow-safe equivalents:
a + bStrictMathWrapper.addExact(a, b)a - bStrictMathWrapper.subtractExact(a, b)a * bStrictMathWrapper.multiplyExact(a, b)(int) longValStrictMathWrapper.toIntExact(longVal)bigInteger.longValue()bigInteger.longValueExact()bigDecimal.longValue()bigDecimal.longValueExact()All of the above methods throw
ArithmeticExceptionon overflow or truncation. The exception is caught by the upper-level transaction execution framework and treated as a contract execution failure, causing the transaction to be rolled back.StrictMathWrapperis an internal utility class that provides a unified wrapper aroundStrictMath'sExact-family methods.Rationale
StrictMath.pow+BigDecimalIs the Correct Implementation Path for the Bancor AlgorithmThe Bancor pricing curve requires fractional exponentiation.
BigDecimaldoes not natively support fractional powers; implementingln/expapproximations from scratch or introducing a third-party library would increase implementation complexity and add external dependency risk.StrictMath.powguarantees bit-for-bit cross-platform consistency at the JVM specification level, directly satisfying the on-chain determinism requirement without introducing any additional dependencies. By wrapping thepowresult inBigDecimal, all subsequent addition, subtraction, and multiplication operations are performed at theBigDecimallevel, preventing the accumulation and propagation of floating-point errors.This approach deliberately confines floating-point precision limits to the single
powstep, withStrictMathguaranteeing cross-platform consistency for that step. The overall calculation path achieves both greater determinism and higher precision than the original implementation.Backwards Compatibility
This proposal is gated behind the Proposal mechanism and is fully backwards compatible.