fix flas
This commit is contained in:
@@ -1,21 +1,36 @@
|
|||||||
package shreder
|
package shreder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/gagliardetto/solana-go"
|
"github.com/gagliardetto/solana-go"
|
||||||
"github.com/near/borsh-go"
|
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var flasProgramID = solana.MustPublicKeyFromBase58("FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9")
|
var flasProgramID = solana.MustPublicKeyFromBase58("FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9")
|
||||||
var (
|
var (
|
||||||
flasBuyTokensIX = []byte{0x00, 0x1, 0x1b}
|
flasBuyTokensIXs = [][]byte{
|
||||||
flasSellTokensIX = []byte{0x01, 0x1, 0x1a}
|
{0x00, 0x01, 0x21},
|
||||||
flasAmmBuyTokensIX = []byte{0x00, 0x2, 0x2}
|
{0x00, 0x01, 0x1b},
|
||||||
flasAmmSellTokensIX = []byte{0x01, 0x2, 0x2}
|
}
|
||||||
flasBonkBuyTokensIX = []byte{0x00, 0x2, 0x7}
|
flasSellTokensIXs = [][]byte{
|
||||||
flasBonkSellTokensIX = []byte{0x01, 0x2, 0x7}
|
{0x01, 0x01, 0x1a},
|
||||||
|
}
|
||||||
|
flasAmmBuyTokensIXs = [][]byte{
|
||||||
|
{0x00, 0x02, 0x1f},
|
||||||
|
{0x00, 0x02, 0x02},
|
||||||
|
}
|
||||||
|
flasAmmSellTokensIXs = [][]byte{
|
||||||
|
{0x01, 0x02, 0x1f},
|
||||||
|
{0x01, 0x02, 0x02},
|
||||||
|
}
|
||||||
|
flasBonkBuyTokensIXs = [][]byte{
|
||||||
|
{0x00, 0x02, 0x07},
|
||||||
|
}
|
||||||
|
flasBonkSellTokensIXs = [][]byte{
|
||||||
|
{0x01, 0x02, 0x07},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type flasArgs struct {
|
type flasArgs struct {
|
||||||
@@ -24,6 +39,26 @@ type flasArgs struct {
|
|||||||
Placeholder [3]uint8
|
Placeholder [3]uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeFlasArgs(data []byte) (flasArgs, error) {
|
||||||
|
if len(data) < 20 {
|
||||||
|
return flasArgs{}, fmt.Errorf("data too short for args flas instruction, len: %d", len(data))
|
||||||
|
}
|
||||||
|
return flasArgs{
|
||||||
|
Amount1: binary.LittleEndian.Uint64(data[1:9]),
|
||||||
|
Amount2: binary.LittleEndian.Uint64(data[9:17]),
|
||||||
|
Placeholder: [3]uint8{data[17], data[18], data[19]},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchFlasMethod(data []byte, methods [][]byte) bool {
|
||||||
|
for _, method := range methods {
|
||||||
|
if matchMethod(data, method) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func parseFlasInstruction(tx VersionedTransaction, instructionIndex int) (TxSignalBatch, error) {
|
func parseFlasInstruction(tx VersionedTransaction, instructionIndex int) (TxSignalBatch, error) {
|
||||||
if instructionIndex >= len(tx.Instructions) {
|
if instructionIndex >= len(tx.Instructions) {
|
||||||
return nil, fmt.Errorf("instruction index out of bounds")
|
return nil, fmt.Errorf("instruction index out of bounds")
|
||||||
@@ -40,24 +75,21 @@ func parseFlasInstruction(tx VersionedTransaction, instructionIndex int) (TxSign
|
|||||||
return nil, fmt.Errorf("data too short for args flas instruction, len: %d", len(instruction.Data))
|
return nil, fmt.Errorf("data too short for args flas instruction, len: %d", len(instruction.Data))
|
||||||
}
|
}
|
||||||
methodData := instruction.Data[17:20]
|
methodData := instruction.Data[17:20]
|
||||||
//if !matchMethod(methodData, flasBuyTokensIX) {
|
|
||||||
// return nil, nil
|
|
||||||
//}
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
txSignal *TxSignal
|
txSignal *TxSignal
|
||||||
)
|
)
|
||||||
if matchMethod(methodData, flasBuyTokensIX) {
|
if matchFlasMethod(methodData, flasBuyTokensIXs) {
|
||||||
txSignal, err = parseFlasBuy(tx, instructionIndex)
|
txSignal, err = parseFlasBuy(tx, instructionIndex)
|
||||||
} else if matchMethod(methodData, flasSellTokensIX) {
|
} else if matchFlasMethod(methodData, flasSellTokensIXs) {
|
||||||
txSignal, err = parseFlasSell(tx, instructionIndex)
|
txSignal, err = parseFlasSell(tx, instructionIndex)
|
||||||
} else if matchMethod(methodData, flasAmmBuyTokensIX) {
|
} else if matchFlasMethod(methodData, flasAmmBuyTokensIXs) {
|
||||||
txSignal, err = parseFlasAmmBuy(tx, instructionIndex)
|
txSignal, err = parseFlasAmmBuy(tx, instructionIndex)
|
||||||
} else if matchMethod(methodData, flasAmmSellTokensIX) {
|
} else if matchFlasMethod(methodData, flasAmmSellTokensIXs) {
|
||||||
txSignal, err = parseFlasAmmSell(tx, instructionIndex)
|
txSignal, err = parseFlasAmmSell(tx, instructionIndex)
|
||||||
} else if matchMethod(methodData, flasBonkBuyTokensIX) {
|
} else if matchFlasMethod(methodData, flasBonkBuyTokensIXs) {
|
||||||
txSignal, err = parseFlasBonkBuy(tx, instructionIndex)
|
txSignal, err = parseFlasBonkBuy(tx, instructionIndex)
|
||||||
} else if matchMethod(methodData, flasBonkSellTokensIX) {
|
} else if matchFlasMethod(methodData, flasBonkSellTokensIXs) {
|
||||||
txSignal, err = parseFlasBonkSell(tx, instructionIndex)
|
txSignal, err = parseFlasBonkSell(tx, instructionIndex)
|
||||||
}
|
}
|
||||||
if txSignal != nil {
|
if txSignal != nil {
|
||||||
@@ -81,10 +113,16 @@ func parseFlasAmmSell(tx VersionedTransaction, instructionIndex int) (*TxSignal,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var args flasArgs
|
args, err := decodeFlasArgs(instruction.Data)
|
||||||
if err := borsh.Deserialize(&args, instruction.Data[1:]); err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
||||||
}
|
}
|
||||||
|
token0Amount := formatTokenAmount(args.Amount1)
|
||||||
|
token0AmountUint64 := args.Amount1
|
||||||
|
if len(instruction.Accounts) == 52 {
|
||||||
|
token0Amount = decimal.Zero
|
||||||
|
token0AmountUint64 = 0
|
||||||
|
}
|
||||||
|
|
||||||
return &TxSignal{
|
return &TxSignal{
|
||||||
TxHash: tx.Signatures[0].String(),
|
TxHash: tx.Signatures[0].String(),
|
||||||
@@ -92,7 +130,7 @@ func parseFlasAmmSell(tx VersionedTransaction, instructionIndex int) (*TxSignal,
|
|||||||
Maker: user.String(),
|
Maker: user.String(),
|
||||||
Token0Address: mint.String(),
|
Token0Address: mint.String(),
|
||||||
Token1Address: wsolMint,
|
Token1Address: wsolMint,
|
||||||
Token0Amount: formatTokenAmount(args.Amount1),
|
Token0Amount: token0Amount,
|
||||||
Token1Amount: formatSolAmount(args.Amount2),
|
Token1Amount: formatSolAmount(args.Amount2),
|
||||||
Program: "PumpAMM",
|
Program: "PumpAMM",
|
||||||
Event: "sell",
|
Event: "sell",
|
||||||
@@ -100,7 +138,7 @@ func parseFlasAmmSell(tx VersionedTransaction, instructionIndex int) (*TxSignal,
|
|||||||
IsMayhemMode: false,
|
IsMayhemMode: false,
|
||||||
ExactSOL: false,
|
ExactSOL: false,
|
||||||
Block: tx.Block,
|
Block: tx.Block,
|
||||||
Token0AmountUint64: args.Amount1,
|
Token0AmountUint64: token0AmountUint64,
|
||||||
Token1AmountUint64: args.Amount2,
|
Token1AmountUint64: args.Amount2,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -120,8 +158,8 @@ func parseFlasAmmBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var args flasArgs
|
args, err := decodeFlasArgs(instruction.Data)
|
||||||
if err := borsh.Deserialize(&args, instruction.Data[1:]); err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,8 +197,8 @@ func parseFlasSell(tx VersionedTransaction, instructionIndex int) (*TxSignal, er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var args flasArgs
|
args, err := decodeFlasArgs(instruction.Data)
|
||||||
if err := borsh.Deserialize(&args, instruction.Data[1:]); err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,11 +234,8 @@ func parseFlasBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(instruction.Data) > 20 {
|
args, err := decodeFlasArgs(instruction.Data)
|
||||||
instruction.Data = instruction.Data[:20]
|
if err != nil {
|
||||||
}
|
|
||||||
var args flasArgs
|
|
||||||
if err := borsh.Deserialize(&args, instruction.Data[1:]); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +260,7 @@ func parseFlasBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, err
|
|||||||
|
|
||||||
func parseFlasBonkBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) {
|
func parseFlasBonkBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) {
|
||||||
instruction := tx.Instructions[instructionIndex]
|
instruction := tx.Instructions[instructionIndex]
|
||||||
if len(instruction.Accounts) < 16 {
|
if len(instruction.Accounts) < 17 {
|
||||||
return nil, fmt.Errorf("accounts too short")
|
return nil, fmt.Errorf("accounts too short")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,11 +282,8 @@ func parseFlasBonkBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal,
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(instruction.Data) > 20 {
|
args, err := decodeFlasArgs(instruction.Data)
|
||||||
instruction.Data = instruction.Data[:20]
|
if err != nil {
|
||||||
}
|
|
||||||
var args flasArgs
|
|
||||||
if err := borsh.Deserialize(&args, instruction.Data[1:]); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +306,7 @@ func parseFlasBonkBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal,
|
|||||||
|
|
||||||
func parseFlasBonkSell(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) {
|
func parseFlasBonkSell(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) {
|
||||||
instruction := tx.Instructions[instructionIndex]
|
instruction := tx.Instructions[instructionIndex]
|
||||||
if len(instruction.Accounts) < 16 {
|
if len(instruction.Accounts) < 17 {
|
||||||
return nil, fmt.Errorf("accounts too short")
|
return nil, fmt.Errorf("accounts too short")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,8 +328,8 @@ func parseFlasBonkSell(tx VersionedTransaction, instructionIndex int) (*TxSignal
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var args flasArgs
|
args, err := decodeFlasArgs(instruction.Data)
|
||||||
if err := borsh.Deserialize(&args, instruction.Data[1:]); err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/gagliardetto/solana-go"
|
"github.com/gagliardetto/solana-go"
|
||||||
"github.com/gagliardetto/solana-go/rpc"
|
"github.com/gagliardetto/solana-go/rpc"
|
||||||
"github.com/near/borsh-go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDecodeAxiomArgs(t *testing.T) {
|
func TestDecodeAxiomArgs(t *testing.T) {
|
||||||
@@ -49,8 +48,8 @@ func TestDecodeAxiomArgs(t *testing.T) {
|
|||||||
t.Fatalf("failed to decode hex string: %v", err)
|
t.Fatalf("failed to decode hex string: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var args flasArgs
|
args, err := decodeFlasArgs(data)
|
||||||
if err := borsh.Deserialize(&args, data[1:]); err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to decode Axiom args: %v", err)
|
t.Fatalf("failed to decode Axiom args: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -59,6 +58,41 @@ func TestDecodeAxiomArgs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDecodeAxiomUpdatedRouteMarkers(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
marker []byte
|
||||||
|
match func([]byte) bool
|
||||||
|
}{
|
||||||
|
{name: "pump buy 0021", marker: []byte{0x00, 0x01, 0x21}, match: func(marker []byte) bool { return matchFlasMethod(marker, flasBuyTokensIXs) }},
|
||||||
|
{name: "pump buy 001b", marker: []byte{0x00, 0x01, 0x1b}, match: func(marker []byte) bool { return matchFlasMethod(marker, flasBuyTokensIXs) }},
|
||||||
|
{name: "pump sell", marker: []byte{0x01, 0x01, 0x1a}, match: func(marker []byte) bool { return matchFlasMethod(marker, flasSellTokensIXs) }},
|
||||||
|
{name: "pump amm buy", marker: []byte{0x00, 0x02, 0x1f}, match: func(marker []byte) bool { return matchFlasMethod(marker, flasAmmBuyTokensIXs) }},
|
||||||
|
{name: "pump amm sell", marker: []byte{0x01, 0x02, 0x1f}, match: func(marker []byte) bool { return matchFlasMethod(marker, flasAmmSellTokensIXs) }},
|
||||||
|
{name: "legacy bonk buy", marker: []byte{0x00, 0x02, 0x07}, match: func(marker []byte) bool { return matchFlasMethod(marker, flasBonkBuyTokensIXs) }},
|
||||||
|
{name: "legacy bonk sell", marker: []byte{0x01, 0x02, 0x07}, match: func(marker []byte) bool { return matchFlasMethod(marker, flasBonkSellTokensIXs) }},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
data := make([]byte, 20)
|
||||||
|
data[0] = 0
|
||||||
|
copy(data[17:20], tt.marker)
|
||||||
|
args, err := decodeFlasArgs(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to decode args: %v", err)
|
||||||
|
}
|
||||||
|
expected := [3]uint8{tt.marker[0], tt.marker[1], tt.marker[2]}
|
||||||
|
if args.Placeholder != expected {
|
||||||
|
t.Fatalf("expected marker %x, got %x", tt.marker, args.Placeholder)
|
||||||
|
}
|
||||||
|
if !tt.match(tt.marker) {
|
||||||
|
t.Fatalf("marker %x did not match route", tt.marker)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func toUpdata(slot uint64, tx *solana.Transaction) *SubscribeUpdateTransaction {
|
func toUpdata(slot uint64, tx *solana.Transaction) *SubscribeUpdateTransaction {
|
||||||
signatures := make([][]byte, len(tx.Signatures))
|
signatures := make([][]byte, len(tx.Signatures))
|
||||||
for i, sig := range tx.Signatures {
|
for i, sig := range tx.Signatures {
|
||||||
|
|||||||
Reference in New Issue
Block a user