1package pair23import (4 "testing"56 "gno.land/p/nt/uassert/v0"7)89// The pricing function, on its own, is the part worth pinning numerically: it10// is pure, it is where the 128-bit arithmetic lives, and every instance in the11// ecosystem runs this exact code.12func TestAmountOut(t *testing.T) {13 cases := []struct {14 name string15 in, resIn, resOut, want int6416 }{17 {"balanced pool, small trade", 1_000, 1_000_000, 1_000_000, 996},18 {"balanced pool, 1%", 10_000, 1_000_000, 1_000_000, 9_871},19 {"balanced pool, 10%", 100_000, 1_000_000, 1_000_000, 90_661},20 {"balanced pool, 50%", 500_000, 1_000_000, 1_000_000, 332_665},21 {"skewed pool", 100_000, 1_000_000, 4_000_000, 362_644},22 {"near drain", 1_000, 1, 1_000_000, 998_997},23 {"dust rounds to zero", 1, 1_000_000, 1_000_000, 0},24 {"reserves at the cap", MaxReserve / 2, MaxReserve / 2, MaxReserve, 4_604_758_097_518_382},25 }26 for _, tc := range cases {27 got := AmountOut(tc.in, tc.resIn, tc.resOut)28 uassert.Equal(t, tc.want, got, tc.name)29 }30}3132// The fee is what stays behind: k must never decrease across a swap.33func TestConstantProductNeverRegresses(t *testing.T) {34 resIn, resOut := int64(1_000_000), int64(4_000_000)35 for _, in := range []int64{1, 1_000, 100_000, 999_999} {36 out := AmountOut(in, resIn, resOut)37 uassert.True(t, cmpProd(resIn+in, resOut-out, resIn, resOut) >= 0,38 "k must not regress")39 }40}4142func TestAmountOutGuards(t *testing.T) {43 mustPanic(t, "pair: amountIn must be > 0", func() {44 AmountOut(0, 1_000, 1_000)45 })46 mustPanic(t, "pair: pair has an empty reserve", func() {47 AmountOut(1, 0, 1_000)48 })49 mustPanic(t, "pair: reserve above cap", func() {50 AmountOut(1, MaxReserve+1, 1_000)51 })52 mustPanic(t, "pair: reserve cap exceeded", func() {53 AmountOut(2, MaxReserve-1, 1_000)54 })55}5657// mulDiv is the only place a 128-bit intermediate is required, and the only58// place bits.Div64 could panic. Both ends are asserted rather than argued.59func TestMulDiv(t *testing.T) {60 uassert.Equal(t, int64(2), mulDiv(4, 3, 6))61 uassert.Equal(t, int64(0), mulDiv(1, 1, 3), "floors")62 uassert.Equal(t, int64(4_611_686_018_427_387_903), mulDiv(9_223_372_036_854_775_807, 1, 2),63 "operands near MaxInt64 stay exact through the 128-bit path")6465 mustPanic(t, "pair: division by a non-positive value", func() {66 mulDiv(1, 1, 0)67 })68 mustPanic(t, "pair: quotient overflows int64", func() {69 mulDiv(9_223_372_036_854_775_807, 9_223_372_036_854_775_807, 1)70 })71}7273func TestCmpProd(t *testing.T) {74 uassert.Equal(t, 0, cmpProd(6, 7, 42, 1))75 uassert.Equal(t, -1, cmpProd(6, 6, 42, 1))76 uassert.Equal(t, 1, cmpProd(7, 7, 42, 1))77 // Both products exceed int64 and differ only in the low word.78 uassert.Equal(t, -1, cmpProd(4_000_000_000, 4_000_000_000, 4_000_000_000, 4_000_000_001))79}8081// mustPanic is uassert.PanicsWithMessage without the realm argument: a pure82// package cannot produce a `cur` to hand it, since it can never declare a83// crossing function in the first place.84func mustPanic(t *testing.T, want string, f func()) {85 t.Helper()86 defer func() {87 r := recover()88 if r == nil {89 t.Errorf("expected panic %q, got none", want)90 return91 }92 got, ok := r.(string)93 if !ok {94 t.Errorf("expected a string panic %q, got %v", want, r)95 return96 }97 if got != want {98 t.Errorf("expected panic %q, got %q", want, got)99 }100 }()101 f()102}103Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.