Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
738e417167 | ||
|
|
51f1511c8f | ||
|
|
7dfe003e5b |
13
enum.go
13
enum.go
@@ -126,4 +126,17 @@ const (
|
||||
TxEventBuyFailed = "buy_failed"
|
||||
TxEventSellFailed = "sell_failed"
|
||||
TxEventBurn = "burn"
|
||||
TxEventCreate = "create"
|
||||
TxEventComplete = "complete"
|
||||
TxEventMigrate = "migrate"
|
||||
TxEventDeposit = "deposit"
|
||||
TxEventWithdraw = "withdraw"
|
||||
TxEventOpen = "open"
|
||||
TxEventClose = "close"
|
||||
TxEventClaimFee = "claim_fee"
|
||||
|
||||
TxEventAddLiquidity = "add_liquidity"
|
||||
TxEventAddLiquidityOneSide = "add_liquidity_one_side"
|
||||
TxEventRemoveLiquidity = "remove_liquidity"
|
||||
TxEventRemoveLiquidityOneSide = "remove_liquidity_one_side"
|
||||
)
|
||||
|
||||
@@ -62,6 +62,12 @@ func main() {
|
||||
swap.BaseAmount.Div(decimal.NewFromInt(1e6)), swap.QuoteAmount.Div(decimal.NewFromInt(1e9)), swap.FixedAmount.String(), swap.LimitAmount.String())
|
||||
}
|
||||
}
|
||||
if len(ptx.Swaps) > 0 {
|
||||
_, err := parser.EncodeTxBinary(ptx)
|
||||
if err != nil {
|
||||
fmt.Printf("success tx : %s, , block: %d, tx: %s, err: %s \n", time.Now().Format("2006-01-02 15:04:05"), ptx.Block, ptx.GetTxHash(), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// currentBlock = ptx.Block
|
||||
|
||||
@@ -281,7 +281,7 @@ func orcaWhirPoolLiquidityParser(tx *Tx, instruction Instruction, innerInstructi
|
||||
return nil, increaseOffset(offset), InstructionIgnoredError
|
||||
}
|
||||
if baseAmount.Equal(decimal.Zero) || quoteAmount.Equal(decimal.Zero) {
|
||||
instructionName += "_on_side"
|
||||
instructionName += "_one_side"
|
||||
}
|
||||
if (baseTokenBalance == nil && !baseAmount.Equal(decimal.Zero)) || (quoteTokenBalance == nil && !quoteAmount.Equal(decimal.Zero)) {
|
||||
return nil, offset, fmt.Errorf("token balance is nil but amount is not zero")
|
||||
@@ -388,7 +388,7 @@ func orcaWhirPoolLiquidityV2Parser(tx *Tx, instruction Instruction, innerInstruc
|
||||
return nil, offset, InstructionIgnoredError
|
||||
}
|
||||
if baseAmount.Equal(decimal.Zero) || quoteAmount.Equal(decimal.Zero) {
|
||||
instructionName += "_on_side"
|
||||
instructionName += "_one_side"
|
||||
}
|
||||
if (baseTokenBalance == nil && !baseAmount.Equal(decimal.Zero)) || (quoteTokenBalance == nil && !quoteAmount.Equal(decimal.Zero)) {
|
||||
return nil, offset, fmt.Errorf("token balance is nil but amount is not zero")
|
||||
@@ -493,7 +493,7 @@ func orcaWhirPoolCollectFeeParser(tx *Tx, instruction Instruction, innerInstruct
|
||||
return nil, offset, InstructionIgnoredError
|
||||
}
|
||||
if baseAmount.Equal(decimal.Zero) || quoteAmount.Equal(decimal.Zero) {
|
||||
instructionName += "_on_side"
|
||||
instructionName += "_one_side"
|
||||
}
|
||||
if (baseTokenBalance == nil && !baseAmount.Equal(decimal.Zero)) || (quoteTokenBalance == nil && !quoteAmount.Equal(decimal.Zero)) {
|
||||
return nil, offset, fmt.Errorf("token balance is nil but amount is not zero")
|
||||
@@ -595,7 +595,7 @@ func orcaWhirPoolCollectFeeV2Parser(tx *Tx, instruction Instruction, innerInstru
|
||||
return nil, offset, InstructionIgnoredError
|
||||
}
|
||||
if baseAmount.Equal(decimal.Zero) || quoteAmount.Equal(decimal.Zero) {
|
||||
instructionName += "_on_side"
|
||||
instructionName += "_one_side"
|
||||
}
|
||||
if (baseTokenBalance == nil && !baseAmount.Equal(decimal.Zero)) || (quoteTokenBalance == nil && !quoteAmount.Equal(decimal.Zero)) {
|
||||
return nil, offset, fmt.Errorf("token balance is nil but amount is not zero")
|
||||
@@ -697,7 +697,7 @@ func orcaWhirPoolCollectProtocolFeeV2Parser(tx *Tx, instruction Instruction, inn
|
||||
return nil, offset, InstructionIgnoredError
|
||||
}
|
||||
if baseAmount.Equal(decimal.Zero) || quoteAmount.Equal(decimal.Zero) {
|
||||
instructionName += "_on_side"
|
||||
instructionName += "_one_side"
|
||||
}
|
||||
if (baseTokenBalance == nil && !baseAmount.Equal(decimal.Zero)) || (quoteTokenBalance == nil && !quoteAmount.Equal(decimal.Zero)) {
|
||||
return nil, offset, fmt.Errorf("token balance is nil but amount is not zero")
|
||||
|
||||
62
tx_binary.go
62
tx_binary.go
@@ -80,8 +80,8 @@ type SwapBinary struct {
|
||||
ActualLimitAmountSide SwapAmountSide
|
||||
SlippageBps uint64
|
||||
|
||||
BaseReserve uint64
|
||||
QuoteReserve uint64
|
||||
BaseReserve float64
|
||||
QuoteReserve float64
|
||||
Mayhem bool
|
||||
Cashback bool
|
||||
|
||||
@@ -728,7 +728,7 @@ func newSwapBinary(swap Swap, index int, addressIndex *txBinaryAddressIndex) (Sw
|
||||
|
||||
out := SwapBinary{
|
||||
Program: swap.Program,
|
||||
Event: swap.Event,
|
||||
Event: txBinaryCanonicalEvent(swap.Event),
|
||||
TxIndex: int32(swap.TxIndex),
|
||||
InstrIdx: swap.InstrIdx,
|
||||
InnerIdx: swap.InnerIdx,
|
||||
@@ -777,10 +777,10 @@ func newSwapBinary(swap Swap, index int, addressIndex *txBinaryAddressIndex) (Sw
|
||||
if out.SlippageBps, err = txBinaryRoundedDecimalToUint64(swap.SlippageBps, fmt.Sprintf("swap[%d].slippage_bps", index)); err != nil {
|
||||
return SwapBinary{}, err
|
||||
}
|
||||
if out.BaseReserve, err = txBinaryDecimalToUint64(swap.BaseReserve, fmt.Sprintf("swap[%d].base_reserve", index)); err != nil {
|
||||
if out.BaseReserve, err = txBinaryDecimalToFloat64Raw(swap.BaseReserve, fmt.Sprintf("swap[%d].base_reserve", index)); err != nil {
|
||||
return SwapBinary{}, err
|
||||
}
|
||||
if out.QuoteReserve, err = txBinaryDecimalToUint64(swap.QuoteReserve, fmt.Sprintf("swap[%d].quote_reserve", index)); err != nil {
|
||||
if out.QuoteReserve, err = txBinaryDecimalToFloat64Raw(swap.QuoteReserve, fmt.Sprintf("swap[%d].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 {
|
||||
@@ -878,8 +878,8 @@ func (swap SwapBinary) toSwap(addressTable []solana.PublicKey, index int) (Swap,
|
||||
ActualLimitAmount: decimal.NewFromUint64(swap.ActualLimitAmount),
|
||||
ActualLimitAmountSide: swap.ActualLimitAmountSide,
|
||||
SlippageBps: decimal.NewFromUint64(swap.SlippageBps),
|
||||
BaseReserve: decimal.NewFromUint64(swap.BaseReserve),
|
||||
QuoteReserve: decimal.NewFromUint64(swap.QuoteReserve),
|
||||
BaseReserve: txBinaryFloat64ToDecimalRaw(swap.BaseReserve),
|
||||
QuoteReserve: txBinaryFloat64ToDecimalRaw(swap.QuoteReserve),
|
||||
Mayhem: swap.Mayhem,
|
||||
Cashback: swap.Cashback,
|
||||
UserBaseBalance: decimal.NewFromUint64(swap.UserBaseBalance),
|
||||
@@ -918,6 +918,17 @@ func txBinaryPlatformsFromTx(platforms map[string]platformInfo) ([]PlatformBinar
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func txBinaryCanonicalEvent(event string) string {
|
||||
switch event {
|
||||
case "add_liquidity_on_side":
|
||||
return TxEventAddLiquidityOneSide
|
||||
case "remove_liquidity_on_side":
|
||||
return TxEventRemoveLiquidityOneSide
|
||||
default:
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
func txBinaryMevAgentsFromTx(mevAgents map[string]mevInfo) ([]MevAgentBinary, error) {
|
||||
if len(mevAgents) == 0 {
|
||||
return nil, nil
|
||||
@@ -1063,6 +1074,14 @@ func txBinaryDecimalToFloat64(value decimal.Decimal, scale int32, field string)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func txBinaryDecimalToFloat64Raw(value decimal.Decimal, field string) (float64, error) {
|
||||
f, exact := value.Float64()
|
||||
if !exact && math.IsInf(f, 0) {
|
||||
return 0, fmt.Errorf("%s cannot be represented as float64: %s", field, value.String())
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func txBinaryFloat64ToDecimal(value float64, scale int32) decimal.Decimal {
|
||||
formatted := strconv.FormatFloat(value, 'f', int(scale), 64)
|
||||
out, err := decimal.NewFromString(formatted)
|
||||
@@ -1072,6 +1091,15 @@ func txBinaryFloat64ToDecimal(value float64, scale int32) decimal.Decimal {
|
||||
return out
|
||||
}
|
||||
|
||||
func txBinaryFloat64ToDecimalRaw(value float64) decimal.Decimal {
|
||||
formatted := strconv.FormatFloat(value, 'f', -1, 64)
|
||||
out, err := decimal.NewFromString(formatted)
|
||||
if err != nil {
|
||||
return decimal.Zero
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type txBinaryEncoder struct {
|
||||
buf bytes.Buffer
|
||||
}
|
||||
@@ -1224,8 +1252,8 @@ func (enc *txBinaryEncoder) writeSwaps(swaps []SwapBinary, enumTable *txBinaryEn
|
||||
enc.writeUint64(swap.ActualLimitAmount)
|
||||
enc.writeUint8(uint8(swap.ActualLimitAmountSide))
|
||||
enc.writeUint64(swap.SlippageBps)
|
||||
enc.writeUint64(swap.BaseReserve)
|
||||
enc.writeUint64(swap.QuoteReserve)
|
||||
enc.writeFloat64(swap.BaseReserve)
|
||||
enc.writeFloat64(swap.QuoteReserve)
|
||||
enc.writeBool(swap.Mayhem)
|
||||
enc.writeBool(swap.Cashback)
|
||||
enc.writeUint64(swap.UserBaseBalance)
|
||||
@@ -1720,10 +1748,10 @@ func txBinaryReadSwaps(dec txBinaryBodyReader, enumTable *txBinaryEnumTable) ([]
|
||||
if swap.SlippageBps, err = dec.readUint64(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if swap.BaseReserve, err = dec.readUint64(); err != nil {
|
||||
if swap.BaseReserve, err = dec.readFloat64(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if swap.QuoteReserve, err = dec.readUint64(); err != nil {
|
||||
if swap.QuoteReserve, err = dec.readFloat64(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if swap.Mayhem, err = dec.readBool(); err != nil {
|
||||
@@ -2055,6 +2083,18 @@ var txBinaryEnumTables = map[uint16]*txBinaryEnumTable{
|
||||
TxEventBuyFailed,
|
||||
TxEventSellFailed,
|
||||
TxEventBurn,
|
||||
TxEventCreate,
|
||||
TxEventComplete,
|
||||
TxEventMigrate,
|
||||
TxEventDeposit,
|
||||
TxEventWithdraw,
|
||||
TxEventOpen,
|
||||
TxEventClose,
|
||||
TxEventClaimFee,
|
||||
TxEventAddLiquidity,
|
||||
TxEventAddLiquidityOneSide,
|
||||
TxEventRemoveLiquidity,
|
||||
TxEventRemoveLiquidityOneSide,
|
||||
},
|
||||
"platform",
|
||||
[]string{
|
||||
|
||||
@@ -225,6 +225,191 @@ func TestTxBinaryRejectsUnknownProgramEnum(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxBinaryAcceptsKnownEventEnums(t *testing.T) {
|
||||
events := []string{
|
||||
TxEventAddLP,
|
||||
TxEventRemoveLP,
|
||||
TxEventBuy,
|
||||
TxEventSell,
|
||||
TxEventBuyFailed,
|
||||
TxEventSellFailed,
|
||||
TxEventBurn,
|
||||
TxEventCreate,
|
||||
TxEventComplete,
|
||||
TxEventMigrate,
|
||||
TxEventDeposit,
|
||||
TxEventWithdraw,
|
||||
TxEventOpen,
|
||||
TxEventClose,
|
||||
TxEventClaimFee,
|
||||
TxEventAddLiquidity,
|
||||
TxEventAddLiquidityOneSide,
|
||||
TxEventRemoveLiquidity,
|
||||
TxEventRemoveLiquidityOneSide,
|
||||
}
|
||||
|
||||
for _, event := range events {
|
||||
t.Run(event, func(t *testing.T) {
|
||||
txBinary := &TxBinary{
|
||||
SchemaVersion: txBinarySchemaVersionCurrent,
|
||||
EnumVersion: txBinaryEnumVersionV1,
|
||||
AddressTable: []solana.PublicKey{
|
||||
mustPubKey("11111111111111111111111111111111"),
|
||||
mustPubKey("So11111111111111111111111111111111111111112"),
|
||||
solana.TokenProgramID,
|
||||
mustPubKey("BPFLoader1111111111111111111111111111111111"),
|
||||
mustPubKey("SysvarRent111111111111111111111111111111111"),
|
||||
},
|
||||
Swaps: []SwapBinary{
|
||||
{
|
||||
Program: SolProgramPump,
|
||||
Event: event,
|
||||
Pool: 0,
|
||||
BaseMint: 1,
|
||||
QuoteMint: 1,
|
||||
BaseTokenProgram: 2,
|
||||
QuoteTokenProgram: 2,
|
||||
Creator: 3,
|
||||
User: 4,
|
||||
FixedMint: 1,
|
||||
LimitMint: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
encoded, err := txBinary.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatalf("MarshalBinary() error = %v", err)
|
||||
}
|
||||
|
||||
var decoded TxBinary
|
||||
if err := decoded.UnmarshalBinary(encoded); err != nil {
|
||||
t.Fatalf("UnmarshalBinary() error = %v", err)
|
||||
}
|
||||
if got := decoded.Swaps[0].Event; got != event {
|
||||
t.Fatalf("decoded event = %q, want %q", got, event)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxBinaryPreservesFractionalReserves(t *testing.T) {
|
||||
tx := &Tx{
|
||||
Signer: mustPubKey("So11111111111111111111111111111111111111112"),
|
||||
Block: 1,
|
||||
BlockIndex: 1,
|
||||
CuFee: decimal.NewFromInt(1),
|
||||
CUPrice: decimal.RequireFromString("0.000001"),
|
||||
BeforeSolBalance: decimal.RequireFromString("1.000000000"),
|
||||
AfterSOLBalance: decimal.RequireFromString("0.900000000"),
|
||||
ComputeUnitsConsumed: 1,
|
||||
CuLimit: 1,
|
||||
Swaps: []Swap{
|
||||
{
|
||||
Program: SolProgramMeteoraPools,
|
||||
Event: TxEventAddLiquidity,
|
||||
Pool: mustPubKey("11111111111111111111111111111111"),
|
||||
BaseMint: mustPubKey("3wyAj7RtG72wM1Wv9DkYfL7RAx9X3Jx1sC6E6mN4jWeL"),
|
||||
QuoteMint: solana.WrappedSol,
|
||||
BaseTokenProgram: solana.TokenProgramID,
|
||||
QuoteTokenProgram: solana.TokenProgramID,
|
||||
Creator: mustPubKey("BPFLoader1111111111111111111111111111111111"),
|
||||
BaseMintDecimals: 6,
|
||||
QuoteMintDecimals: 9,
|
||||
User: mustPubKey("SysvarRent111111111111111111111111111111111"),
|
||||
BaseAmount: decimal.NewFromInt(10),
|
||||
QuoteAmount: decimal.NewFromInt(20),
|
||||
SwapMode: SwapModeExactIn,
|
||||
FixedAmount: decimal.NewFromInt(20),
|
||||
FixedAmountSide: SwapAmountSideQuote,
|
||||
FixedMint: solana.WrappedSol,
|
||||
LimitAmountType: SwapLimitTypeMinOut,
|
||||
LimitAmount: decimal.NewFromInt(9),
|
||||
LimitAmountSide: SwapAmountSideBase,
|
||||
LimitMint: mustPubKey("3wyAj7RtG72wM1Wv9DkYfL7RAx9X3Jx1sC6E6mN4jWeL"),
|
||||
ActualLimitAmount: decimal.NewFromInt(10),
|
||||
ActualLimitAmountSide: SwapAmountSideBase,
|
||||
BaseReserve: decimal.RequireFromString("123.4"),
|
||||
QuoteReserve: decimal.RequireFromString("710079483.625409498"),
|
||||
AfterSOLBalance: decimal.RequireFromString("0.800000000"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
encoded, err := EncodeTxBinary(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("EncodeTxBinary() error = %v", err)
|
||||
}
|
||||
|
||||
decoded, err := DecodeTxBinary(encoded)
|
||||
if err != nil {
|
||||
t.Fatalf("DecodeTxBinary() error = %v", err)
|
||||
}
|
||||
if got := decoded.Swaps[0].BaseReserve.String(); got != "123.4" {
|
||||
t.Fatalf("BaseReserve = %s, want 123.4", got)
|
||||
}
|
||||
diff := decoded.Swaps[0].QuoteReserve.Sub(decimal.RequireFromString("710079483.625409498")).Abs()
|
||||
if diff.GreaterThan(decimal.RequireFromString("0.0000001")) {
|
||||
t.Fatalf("QuoteReserve diff = %s, want <= 0.0000001", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxBinaryCanonicalizesOnSideEventAlias(t *testing.T) {
|
||||
tx := &Tx{
|
||||
Signer: mustPubKey("So11111111111111111111111111111111111111112"),
|
||||
Block: 1,
|
||||
BlockIndex: 1,
|
||||
CuFee: decimal.NewFromInt(1),
|
||||
CUPrice: decimal.RequireFromString("0.000001"),
|
||||
BeforeSolBalance: decimal.RequireFromString("1.000000000"),
|
||||
AfterSOLBalance: decimal.RequireFromString("0.900000000"),
|
||||
ComputeUnitsConsumed: 1,
|
||||
CuLimit: 1,
|
||||
Swaps: []Swap{
|
||||
{
|
||||
Program: SolProgramOrcaWhirPool,
|
||||
Event: "remove_liquidity_on_side",
|
||||
Pool: mustPubKey("11111111111111111111111111111111"),
|
||||
BaseMint: mustPubKey("3wyAj7RtG72wM1Wv9DkYfL7RAx9X3Jx1sC6E6mN4jWeL"),
|
||||
QuoteMint: solana.WrappedSol,
|
||||
BaseTokenProgram: solana.TokenProgramID,
|
||||
QuoteTokenProgram: solana.TokenProgramID,
|
||||
Creator: mustPubKey("BPFLoader1111111111111111111111111111111111"),
|
||||
BaseMintDecimals: 6,
|
||||
QuoteMintDecimals: 9,
|
||||
User: mustPubKey("SysvarRent111111111111111111111111111111111"),
|
||||
BaseAmount: decimal.NewFromInt(10),
|
||||
QuoteAmount: decimal.Zero,
|
||||
SwapMode: SwapModeExactIn,
|
||||
FixedAmount: decimal.NewFromInt(10),
|
||||
FixedAmountSide: SwapAmountSideBase,
|
||||
FixedMint: mustPubKey("3wyAj7RtG72wM1Wv9DkYfL7RAx9X3Jx1sC6E6mN4jWeL"),
|
||||
LimitAmountType: SwapLimitTypeMinOut,
|
||||
LimitAmount: decimal.Zero,
|
||||
LimitAmountSide: SwapAmountSideQuote,
|
||||
ActualLimitAmount: decimal.Zero,
|
||||
ActualLimitAmountSide: SwapAmountSideQuote,
|
||||
BaseReserve: decimal.RequireFromString("123.4"),
|
||||
QuoteReserve: decimal.RequireFromString("456.7"),
|
||||
AfterSOLBalance: decimal.RequireFromString("0.800000000"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
encoded, err := EncodeTxBinary(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("EncodeTxBinary() error = %v", err)
|
||||
}
|
||||
|
||||
decoded, err := DecodeTxBinary(encoded)
|
||||
if err != nil {
|
||||
t.Fatalf("DecodeTxBinary() error = %v", err)
|
||||
}
|
||||
if got := decoded.Swaps[0].Event; got != TxEventRemoveLiquidityOneSide {
|
||||
t.Fatalf("Event = %q, want %q", got, TxEventRemoveLiquidityOneSide)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxsBinaryRoundTripWithSharedAddressTable(t *testing.T) {
|
||||
tx1 := Tx{
|
||||
Signer: mustPubKey("So11111111111111111111111111111111111111112"),
|
||||
|
||||
Reference in New Issue
Block a user