Files
precompile/dex/native_pricefloor_precision_test.go
zeekayandHanzo Dev 91b162240d fix(dex/9999): exact-integer ZAP price wire + fold dexcore/lx -> pkg/dex
Bump github.com/luxfi/dex v1.5.20 -> v1.14.0. v1.14.0 (a) folded pkg/lx and
pkg/dexcore into a single pkg/dex, and (b) froze the ZAP wire to EXACT
INTEGERS: price is uint64 fixed-point ×1e8 (the PriceInt grid), no float64.
The 0x9999 EVM surface must speak that same grid or it prices a limit the
native venue reads at a different scale — an interop break.

Package fold (mechanical, behavior-neutral — build + full suite green after):
- import path pkg/dexcore -> pkg/dex (alias dexcore), pkg/lx -> pkg/dex.
- v1.14.0 renames: NewCLOBSource->NewOrderBookSource, SourceCLOB->SourceOrderBook,
  ClassPublicCLOB->ClassPublicDEX.
- collapsed the 4 files that imported the fold under both aliases to a single
  dexcore alias (no redundant same-package import).

Exact-integer price wire (the 7 float-wire sites):
- settle9999.go priceLimitToCLOB: return the CLOB limit as a uint64 FIXED-POINT
  ×priceScale integer computed by EXACT big.Int (round-to-nearest of
  s^2·priceScale/2^192), not math.Float64bits of a float. Round-to-nearest (not
  floor) so a sqrt-derived "50" ceiling still crosses a maker resting AT 50.
- swap_sync.go: limitPrice = lx.PriceInt(limitUnits) directly — no
  PriceToInt(Float64frombits(...)) roundtrip.
- native_dchain_client.go enforceProceedsPriceFloor: the MEV floor compares the
  integer limit (limit = priceLimit/priceScale) by big.Int cross-multiply
  (out·priceScale vs priceLimit·spent), dropping math.Float64frombits +
  big.Rat.SetFloat64. Determinism + no 2^53 truncation preserved.
- new package const priceScale (== dexcore.PriceMultiplier == zapwire.PriceScale);
  the intent/relay PriceLimit is now this fixed-point grid value.

swap_custody.go's runSwapPlace keeps its derived float for dexcore.PlaceOrder —
that is the matcher's in-process crossing-loop API (unchanged signature), a
projection, never a consensus/settlement value.

Tests: MEV-floor / price-limit / exact-precision (>2^53) redteam tests
translated to the fixed-point integer domain without weakening any invariant.
New wire_parity_test.go pins priceScale == dexcore.PriceMultiplier ==
zapwire.PriceScale so the grid can never drift from the venue. 437 pass, 0 fail.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-02 10:56:00 -07:00

120 lines
5.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dex
import (
"math"
"math/big"
"testing"
"github.com/stretchr/testify/require"
)
// exactFloorRef is an INDEPENDENT exact-rational reference for the settlement price floor,
// computed straight from the definition with big.Rat (no float64 on the amounts). The
// priceLimit is a fixed-point ×priceScale integer, so limit = priceLimit / priceScale. The
// production enforceProceedsPriceFloor must agree with it for every amount, including the
// uint256 range above 2^53 where a float64 reconstruction would truncate.
func exactFloorRef(priceLimit uint64, limitIsUpper bool, spent, out uint64) bool /*reject*/ {
if priceLimit == 0 {
return false
}
if spent == 0 || out == 0 {
return true
}
limitRat := new(big.Rat).SetFrac(
new(big.Int).SetUint64(priceLimit),
big.NewInt(priceScale),
) // limit = priceLimit / priceScale
if limitIsUpper {
// BUY ceiling: realized quote/base = spent/out must be <= limit.
realized := new(big.Rat).SetFrac(
new(big.Int).SetUint64(spent),
new(big.Int).SetUint64(out),
)
return realized.Cmp(limitRat) > 0 // reject if spent/out > limit
}
// SELL floor: realized out/spent must be >= limit.
realized := new(big.Rat).SetFrac(
new(big.Int).SetUint64(out),
new(big.Int).SetUint64(spent),
)
return realized.Cmp(limitRat) < 0 // reject if out/spent < limit
}
// TestPriceFloor_Exact_Above2Pow53 is the regression for the consensus hazard: spent/out
// are uint256-domain token amounts, and the OLD float64 reconstruction (float64(spent),
// float64(out)) silently truncated their low bits above 2^53 — so a fill strictly BELOW
// the taker's floor compared EQUAL and was accepted (the precise MEV the floor refuses).
//
// limit == 1.0, SELL: floor demands out/spent >= 1, i.e. out >= spent. With spent = 2^53+1
// and out = 2^53 the realized price is BELOW the floor and MUST be rejected. float64 maps
// both 2^53 and 2^53+1 to the double 2^53, so the old code saw out == spent and PASSED.
func TestPriceFloor_Exact_Above2Pow53(t *testing.T) {
one := uint64(priceScale) // limit 1.0 on the fixed-point grid
const p53 = uint64(1) << 53
// SELL floor: out just under spent past the float64 cliff -> must REJECT.
require.ErrorIs(t,
enforceProceedsPriceFloor(one, false, p53+1, p53),
ErrSettlePriceLimit,
"SELL: out(2^53) < spent(2^53+1) is below the floor and must be rejected exactly")
// BUY ceiling: spent just over out past the float64 cliff -> must REJECT.
require.ErrorIs(t,
enforceProceedsPriceFloor(one, true, p53+1, p53),
ErrSettlePriceLimit,
"BUY: spent(2^53+1) > out(2^53) is above the ceiling and must be rejected exactly")
// Exactly on the floor (out == spent, limit 1.0) is allowed on both sides.
require.NoError(t, enforceProceedsPriceFloor(one, false, p53+1, p53+1))
require.NoError(t, enforceProceedsPriceFloor(one, true, p53+1, p53+1))
}
// TestPriceFloor_MatchesExactReferenceSweep cross-checks the production verdict against the
// independent big.Rat reference across small values AND values straddling 2^53, proving the
// comparison is exact everywhere (and deterministic — pure integer arithmetic).
func TestPriceFloor_MatchesExactReferenceSweep(t *testing.T) {
limits := []float64{0.5, 1.0, 2.0, 1.25, 3.333333333}
const p53 = uint64(1) << 53
amounts := []uint64{
1, 2, 7, 1_000_000, 1e15,
p53 - 1, p53, p53 + 1, p53 + 2, p53 + 3,
2 * p53, 2*p53 + 1, math.MaxUint64 / 2, math.MaxUint64 - 1,
}
for _, lf := range limits {
lb := uint64(lf * priceScale) // the fixed-point ×priceScale grid limit
for _, upper := range []bool{false, true} {
for _, spent := range amounts {
for _, out := range amounts {
wantReject := exactFloorRef(lb, upper, spent, out)
got := enforceProceedsPriceFloor(lb, upper, spent, out)
if wantReject {
require.ErrorIsf(t, got, ErrSettlePriceLimit,
"limit=%v upper=%v spent=%d out=%d: expected reject", lf, upper, spent, out)
} else {
require.NoErrorf(t, got,
"limit=%v upper=%v spent=%d out=%d: expected pass", lf, upper, spent, out)
}
}
}
}
}
}
// TestPriceFloor_EdgeCasesPreserved locks the fail-secure edges unchanged by the rewrite.
func TestPriceFloor_EdgeCasesPreserved(t *testing.T) {
one := uint64(priceScale) // limit 1.0 on the fixed-point grid
// No recorded limit -> no floor.
require.NoError(t, enforceProceedsPriceFloor(0, false, 100, 50))
// Limit set but an amount is zero -> price unprovable -> fail secure.
require.ErrorIs(t, enforceProceedsPriceFloor(one, false, 0, 50), ErrSettlePriceLimit)
require.ErrorIs(t, enforceProceedsPriceFloor(one, false, 50, 0), ErrSettlePriceLimit)
// A large integer limit is a REAL floor (no float degeneracy): a SELL realized below it
// is rejected, one at/above it passes — exact on the fixed-point grid.
big5 := uint64(5 * priceScale)
require.ErrorIs(t, enforceProceedsPriceFloor(big5, false, 100, 400), ErrSettlePriceLimit) // 4.0 < 5.0
require.NoError(t, enforceProceedsPriceFloor(big5, false, 100, 500)) // 5.0 == 5.0
}