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

@@ -8,6 +8,7 @@ import (
"io"
"iter"
"math"
"math/big"
"sort"
"strconv"
@@ -18,7 +19,9 @@ import (
const (
txBinarySchemaVersionV3 uint16 = 3
txBinarySchemaVersionCurrent uint16 = 4
txBinarySchemaVersionV4 uint16 = 4
txBinarySchemaVersionV5 uint16 = 5
txBinarySchemaVersionCurrent = txBinarySchemaVersionV5
txBinaryEnumVersionV1 uint16 = 1
txBinarySOLScale int32 = 9
@@ -102,6 +105,9 @@ type SwapBinary struct {
LpMint uint32
AfterSOLBalance float64
RealQuoteReserve uint64
VirtualQuoteReserve [16]byte
}
type TxsBinary struct {
@@ -659,7 +665,7 @@ func (tx *TxBinary) ToTx() (*Tx, error) {
if len(tx.Swaps) > 0 {
out.Swaps = make([]Swap, 0, len(tx.Swaps))
for i, swap := range tx.Swaps {
decodedSwap, err := swap.toSwap(tx.AddressTable, i)
decodedSwap, err := swap.toSwap(tx.AddressTable, i, tx.SchemaVersion)
if err != nil {
return nil, err
}
@@ -797,6 +803,12 @@ func newSwapBinary(swap Swap, index int, addressIndex *txBinaryAddressIndex) (Sw
if out.QuoteReserve, err = txBinaryDecimalToFloat64Raw(swap.QuoteReserve, fmt.Sprintf("swap[%d].quote_reserve", index)); err != nil {
return SwapBinary{}, err
}
if out.RealQuoteReserve, err = txBinaryDecimalToUint64(swap.RealQuoteReserve, fmt.Sprintf("swap[%d].real_quote_reserve", index)); err != nil {
return SwapBinary{}, err
}
if out.VirtualQuoteReserve, err = txBinaryDecimalToInt128(swap.VirtualQuoteReserve, fmt.Sprintf("swap[%d].virtual_quote_reserve", index)); err != nil {
return SwapBinary{}, err
}
if out.UserBaseBalance, err = txBinaryDecimalToUint64(swap.UserBaseBalance, fmt.Sprintf("swap[%d].user_base_balance", index)); err != nil {
return SwapBinary{}, err
}
@@ -810,7 +822,7 @@ func newSwapBinary(swap Swap, index int, addressIndex *txBinaryAddressIndex) (Sw
return out, nil
}
func (swap SwapBinary) toSwap(addressTable []solana.PublicKey, index int) (Swap, error) {
func (swap SwapBinary) toSwap(addressTable []solana.PublicKey, index int, schemaVersion uint16) (Swap, error) {
pool, err := txBinaryAddressAt(addressTable, swap.Pool, fmt.Sprintf("swap[%d].pool", index))
if err != nil {
return Swap{}, err
@@ -864,6 +876,20 @@ func (swap SwapBinary) toSwap(addressTable []solana.PublicKey, index int) (Swap,
return Swap{}, err
}
quoteReserve := txBinaryFloat64ToDecimalRaw(swap.QuoteReserve)
realQuoteReserve := quoteReserve
virtualQuoteReserve := decimal.Zero
if schemaVersion >= txBinarySchemaVersionV5 {
realQuoteReserve = decimal.NewFromUint64(swap.RealQuoteReserve)
virtualQuoteReserve = txBinaryInt128ToDecimal(swap.VirtualQuoteReserve)
// A v3/v4 batch upgraded by the streaming merger has no component
// bytes to carry forward. Preserve its legacy meaning after the
// merged output is written as v5.
if realQuoteReserve.IsZero() && virtualQuoteReserve.IsZero() && !quoteReserve.IsZero() {
realQuoteReserve = quoteReserve
}
}
return Swap{
Program: swap.Program,
Event: swap.Event,
@@ -893,7 +919,9 @@ func (swap SwapBinary) toSwap(addressTable []solana.PublicKey, index int) (Swap,
ActualLimitAmountSide: swap.ActualLimitAmountSide,
SlippageBps: decimal.NewFromUint64(swap.SlippageBps),
BaseReserve: txBinaryFloat64ToDecimalRaw(swap.BaseReserve),
QuoteReserve: txBinaryFloat64ToDecimalRaw(swap.QuoteReserve),
QuoteReserve: quoteReserve,
RealQuoteReserve: realQuoteReserve,
VirtualQuoteReserve: virtualQuoteReserve,
Mayhem: swap.Mayhem,
Cashback: swap.Cashback,
UserBaseBalance: decimal.NewFromUint64(swap.UserBaseBalance),
@@ -1071,6 +1099,44 @@ func txBinaryDecimalToUint64(value decimal.Decimal, field string) (uint64, error
return bigInt.Uint64(), nil
}
func txBinaryDecimalToInt128(value decimal.Decimal, field string) ([16]byte, error) {
var out [16]byte
if !value.Equal(value.Truncate(0)) {
return out, fmt.Errorf("%s must be an integer, got %s", field, value.String())
}
integer := value.BigInt()
limit := new(big.Int).Lsh(big.NewInt(1), 127)
minimum := new(big.Int).Neg(new(big.Int).Set(limit))
maximum := new(big.Int).Sub(new(big.Int).Set(limit), big.NewInt(1))
if integer.Cmp(minimum) < 0 || integer.Cmp(maximum) > 0 {
return out, fmt.Errorf("%s overflows int128: %s", field, value.String())
}
unsigned := new(big.Int).Set(integer)
if unsigned.Sign() < 0 {
unsigned.Add(unsigned, new(big.Int).Lsh(big.NewInt(1), 128))
}
var bigEndian [16]byte
unsigned.FillBytes(bigEndian[:])
for i := range out {
out[i] = bigEndian[len(bigEndian)-1-i]
}
return out, nil
}
func txBinaryInt128ToDecimal(raw [16]byte) decimal.Decimal {
var bigEndian [16]byte
for i := range raw {
bigEndian[i] = raw[len(raw)-1-i]
}
integer := new(big.Int).SetBytes(bigEndian[:])
if raw[len(raw)-1]&0x80 != 0 {
integer.Sub(integer, new(big.Int).Lsh(big.NewInt(1), 128))
}
return decimal.NewFromBigInt(integer, 0)
}
func txBinaryScaledDecimalToUint64(value decimal.Decimal, scale int32, field string) (uint64, error) {
return txBinaryDecimalToUint64(value.Shift(scale), field)
}
@@ -1179,7 +1245,7 @@ func (enc *txBinaryEncoder) writeTxBinaryBody(tx *TxBinary, enumTable *txBinaryE
enc.writeUint32(tx.Signer)
enc.writeUint64(tx.Block)
enc.writeUint64(tx.BlockIndex)
if tx.SchemaVersion >= txBinarySchemaVersionCurrent {
if tx.SchemaVersion >= txBinarySchemaVersionV4 {
enc.writeUint64(uint64(tx.BlockAt))
}
enc.writeBool(tx.TxHash != nil)
@@ -1198,7 +1264,7 @@ func (enc *txBinaryEncoder) writeTxBinaryBody(tx *TxBinary, enumTable *txBinaryE
if err := enc.writeMevAgentEntries(tx.MevAgent, enumTable); err != nil {
return err
}
if err := enc.writeSwaps(tx.Swaps, enumTable); err != nil {
if err := enc.writeSwaps(tx.Swaps, enumTable, tx.SchemaVersion); err != nil {
return err
}
return nil
@@ -1230,7 +1296,7 @@ func (enc *txBinaryEncoder) writeMevAgentEntries(entries []MevAgentBinary, enumT
return nil
}
func (enc *txBinaryEncoder) writeSwaps(swaps []SwapBinary, enumTable *txBinaryEnumTable) error {
func (enc *txBinaryEncoder) writeSwaps(swaps []SwapBinary, enumTable *txBinaryEnumTable, schemaVersion uint16) error {
enc.writeUint32(uint32(len(swaps)))
for i, swap := range swaps {
programID, err := enumTable.programs.id(swap.Program)
@@ -1280,6 +1346,10 @@ func (enc *txBinaryEncoder) writeSwaps(swaps []SwapBinary, enumTable *txBinaryEn
enc.writeUint32(swap.MigrateTopProgram)
enc.writeUint32(swap.LpMint)
enc.writeFloat64(swap.AfterSOLBalance)
if schemaVersion >= txBinarySchemaVersionV5 {
enc.writeUint64(swap.RealQuoteReserve)
enc.writeBytes(swap.VirtualQuoteReserve[:])
}
}
return nil
}
@@ -1395,7 +1465,7 @@ func (dec *txBinaryDecoder) readMevAgentEntries(enumTable *txBinaryEnumTable) ([
}
func (dec *txBinaryDecoder) readSwaps(enumTable *txBinaryEnumTable, _ []solana.PublicKey) ([]SwapBinary, error) {
return txBinaryReadSwaps(dec, enumTable)
return txBinaryReadSwaps(dec, enumTable, txBinarySchemaVersionCurrent)
}
func (dec *txBinaryDecoder) readTxBinaryBody(tx *TxBinary, enumTable *txBinaryEnumTable, addressTable []solana.PublicKey) error {
@@ -1651,7 +1721,7 @@ func txBinaryReadMevAgentEntries(dec txBinaryBodyReader, enumTable *txBinaryEnum
return out, nil
}
func txBinaryReadSwaps(dec txBinaryBodyReader, enumTable *txBinaryEnumTable) ([]SwapBinary, error) {
func txBinaryReadSwaps(dec txBinaryBodyReader, enumTable *txBinaryEnumTable, schemaVersion uint16) ([]SwapBinary, error) {
count, err := dec.readUint32()
if err != nil {
return nil, err
@@ -1798,6 +1868,16 @@ func txBinaryReadSwaps(dec txBinaryBodyReader, enumTable *txBinaryEnumTable) ([]
if swap.AfterSOLBalance, err = dec.readFloat64(); err != nil {
return nil, err
}
if schemaVersion >= txBinarySchemaVersionV5 {
if swap.RealQuoteReserve, err = dec.readUint64(); err != nil {
return nil, err
}
rawVirtualQuoteReserve, err := dec.readN(len(swap.VirtualQuoteReserve))
if err != nil {
return nil, err
}
copy(swap.VirtualQuoteReserve[:], rawVirtualQuoteReserve)
}
out = append(out, swap)
}
return out, nil
@@ -1815,7 +1895,7 @@ func txBinaryReadTxBody(dec txBinaryBodyReader, tx *TxBinary, enumTable *txBinar
if tx.BlockIndex, err = dec.readUint64(); err != nil {
return err
}
if tx.SchemaVersion >= txBinarySchemaVersionCurrent {
if tx.SchemaVersion >= txBinarySchemaVersionV4 {
blockAt, err := dec.readUint64()
if err != nil {
return err
@@ -1863,7 +1943,7 @@ func txBinaryReadTxBody(dec txBinaryBodyReader, tx *TxBinary, enumTable *txBinar
if tx.MevAgent, err = txBinaryReadMevAgentEntries(dec, enumTable); err != nil {
return err
}
if tx.Swaps, err = txBinaryReadSwaps(dec, enumTable); err != nil {
if tx.Swaps, err = txBinaryReadSwaps(dec, enumTable, tx.SchemaVersion); err != nil {
return err
}
return nil