update amm virtual quotes reserves

This commit is contained in:
thloyi
2026-07-17 16:56:44 +08:00
parent 44eecac087
commit f40c548fc9
7 changed files with 528 additions and 69 deletions

View File

@@ -82,6 +82,8 @@ func TestTxBinaryRoundTrip(t *testing.T) {
SlippageBps: decimal.RequireFromString("833.3333"),
BaseReserve: decimal.NewFromInt(5555),
QuoteReserve: decimal.NewFromInt(9999),
RealQuoteReserve: decimal.NewFromInt(10122),
VirtualQuoteReserve: decimal.NewFromInt(-123),
Mayhem: true,
Cashback: false,
UserBaseBalance: decimal.NewFromInt(777),
@@ -202,6 +204,12 @@ func TestTxBinaryRoundTrip(t *testing.T) {
if !swap.QuoteReserve.Equal(original.Swaps[0].QuoteReserve) {
t.Fatalf("swap.QuoteReserve = %s, want %s", swap.QuoteReserve, original.Swaps[0].QuoteReserve)
}
if !swap.RealQuoteReserve.Equal(original.Swaps[0].RealQuoteReserve) {
t.Fatalf("swap.RealQuoteReserve = %s, want %s", swap.RealQuoteReserve, original.Swaps[0].RealQuoteReserve)
}
if !swap.VirtualQuoteReserve.Equal(original.Swaps[0].VirtualQuoteReserve) {
t.Fatalf("swap.VirtualQuoteReserve = %s, want %s", swap.VirtualQuoteReserve, original.Swaps[0].VirtualQuoteReserve)
}
if !swap.UserBaseBalance.Equal(original.Swaps[0].UserBaseBalance) {
t.Fatalf("swap.UserBaseBalance = %s, want %s", swap.UserBaseBalance, original.Swaps[0].UserBaseBalance)
}
@@ -1017,6 +1025,89 @@ func TestTxBinaryDecodeSchemaV3LeavesBlockAtZero(t *testing.T) {
}
}
func TestTxBinaryDecodeSchemaV4DefaultsQuoteReserveComponents(t *testing.T) {
original := &Tx{
Signer: mustPubKey("So11111111111111111111111111111111111111112"),
Block: 42,
BlockIndex: 2,
BlockAt: 1710000042,
Swaps: []Swap{
{
Program: SolProgramPumpAMM,
Event: TxEventBuy,
QuoteReserve: decimal.NewFromInt(123456789),
RealQuoteReserve: decimal.NewFromInt(123000000),
VirtualQuoteReserve: decimal.NewFromInt(456789),
},
},
}
binaryTx, err := NewTxBinary(original)
if err != nil {
t.Fatalf("NewTxBinary() error = %v", err)
}
binaryTx.SchemaVersion = txBinarySchemaVersionV4
encoded, err := binaryTx.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary(v4) error = %v", err)
}
decoded, err := DecodeTxBinary(encoded)
if err != nil {
t.Fatalf("DecodeTxBinary(v4) error = %v", err)
}
if decoded.BlockAt != original.BlockAt {
t.Fatalf("BlockAt = %d, want %d", decoded.BlockAt, original.BlockAt)
}
if len(decoded.Swaps) != 1 {
t.Fatalf("Swaps len = %d, want 1", len(decoded.Swaps))
}
swap := decoded.Swaps[0]
if !swap.QuoteReserve.Equal(original.Swaps[0].QuoteReserve) {
t.Fatalf("QuoteReserve = %s, want %s", swap.QuoteReserve, original.Swaps[0].QuoteReserve)
}
if !swap.RealQuoteReserve.Equal(swap.QuoteReserve) {
t.Fatalf("RealQuoteReserve = %s, want legacy QuoteReserve %s", swap.RealQuoteReserve, swap.QuoteReserve)
}
if !swap.VirtualQuoteReserve.IsZero() {
t.Fatalf("VirtualQuoteReserve = %s, want 0", swap.VirtualQuoteReserve)
}
}
func TestTxBinarySignedInt128RoundTrip(t *testing.T) {
values := []string{
"-170141183460469231731687303715884105728",
"-123",
"-1",
"0",
"1",
"123",
"170141183460469231731687303715884105727",
}
for _, value := range values {
t.Run(value, func(t *testing.T) {
want := decimal.RequireFromString(value)
raw, err := txBinaryDecimalToInt128(want, "value")
if err != nil {
t.Fatalf("txBinaryDecimalToInt128() error = %v", err)
}
if got := txBinaryInt128ToDecimal(raw); !got.Equal(want) {
t.Fatalf("round trip = %s, want %s", got, want)
}
})
}
invalid := []string{
"-170141183460469231731687303715884105729",
"170141183460469231731687303715884105728",
"1.5",
}
for _, value := range invalid {
if _, err := txBinaryDecimalToInt128(decimal.RequireFromString(value), "value"); err == nil {
t.Fatalf("txBinaryDecimalToInt128(%s) error = nil", value)
}
}
}
func TestMergeTxsBinaryBytesUpgradesSchemaV3AndPreservesV4BlockAt(t *testing.T) {
legacyTx := Tx{
Signer: mustPubKey("So11111111111111111111111111111111111111112"),
@@ -1029,11 +1120,18 @@ func TestMergeTxsBinaryBytesUpgradesSchemaV3AndPreservesV4BlockAt(t *testing.T)
Block: 52,
BlockIndex: 2,
BlockAt: 1710000052,
Swaps: []Swap{
{
Program: SolProgramPumpAMM,
Event: TxEventBuy,
QuoteReserve: decimal.NewFromInt(222),
},
},
}
merged, err := MergeTxsBinaryBytes([][]byte{
mustEncodeTxsBinaryV3(t, []Tx{legacyTx}),
mustEncodeTxsBinary(t, []Tx{currentTx}),
mustEncodeTxsBinaryV4(t, []Tx{currentTx}),
})
if err != nil {
t.Fatalf("MergeTxsBinaryBytes(v3,v4) error = %v", err)
@@ -1060,6 +1158,9 @@ func TestMergeTxsBinaryBytesUpgradesSchemaV3AndPreservesV4BlockAt(t *testing.T)
if decoded[1].BlockAt != currentTx.BlockAt {
t.Fatalf("current BlockAt = %d, want %d", decoded[1].BlockAt, currentTx.BlockAt)
}
if len(decoded[1].Swaps) != 1 || !decoded[1].Swaps[0].RealQuoteReserve.Equal(currentTx.Swaps[0].QuoteReserve) || !decoded[1].Swaps[0].VirtualQuoteReserve.IsZero() {
t.Fatalf("v4 quote reserve components were not preserved: %+v", decoded[1].Swaps)
}
}
func mustPubKey(value string) solana.PublicKey {
@@ -1109,6 +1210,24 @@ func mustEncodeTxsBinaryV3(t *testing.T, txs []Tx) []byte {
return encoded
}
func mustEncodeTxsBinaryV4(t *testing.T, txs []Tx) []byte {
t.Helper()
binaryTxs, err := NewTxsBinary(txs)
if err != nil {
t.Fatalf("NewTxsBinary() error = %v", err)
}
binaryTxs.SchemaVersion = txBinarySchemaVersionV4
for i := range binaryTxs.Txs {
binaryTxs.Txs[i].SchemaVersion = txBinarySchemaVersionV4
}
encoded, err := binaryTxs.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary(v4) error = %v", err)
}
return encoded
}
func mustTxBinary(t *testing.T, data []byte) *TxsBinary {
t.Helper()