-
Notifications
You must be signed in to change notification settings - Fork 302
TIP-836: harden exchange transaction calculations #836
Description
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/floatarithmetic: All floating-point operations are replaced withBigDecimal, exceptpow(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
BigIntegerorBigDecimaltolongorint,longValueExact()orintValueExact()must be called. UsinglongValue()/intValue(), which silently truncates, is prohibited. - When narrowing
longtoint,StrictMath.toIntExactmust be used.
- When converting
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.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status