package shreder import ( "encoding/binary" "fmt" "github.com/gagliardetto/solana-go" "github.com/shopspring/decimal" ) var flasProgramID = solana.MustPublicKeyFromBase58("FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9") var ( flasBuyTokensIXs = [][]byte{ {0x00, 0x01, 0x21}, {0x00, 0x01, 0x1b}, } flasSellTokensIXs = [][]byte{ {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 { Amount1 uint64 Amount2 uint64 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) { if instructionIndex >= len(tx.Instructions) { return nil, fmt.Errorf("instruction index out of bounds") } instruction := tx.Instructions[instructionIndex] if len(instruction.Data) == 0 { return nil, fmt.Errorf("data is empty") } if len(instruction.Data) == 10 && instruction.Data[0] == 1 { return nil, nil } if len(instruction.Data) < 20 { return nil, fmt.Errorf("data too short for args flas instruction, len: %d", len(instruction.Data)) } methodData := instruction.Data[17:20] var ( err error txSignal *TxSignal ) if matchFlasMethod(methodData, flasBuyTokensIXs) { txSignal, err = parseFlasBuy(tx, instructionIndex) } else if matchFlasMethod(methodData, flasSellTokensIXs) { txSignal, err = parseFlasSell(tx, instructionIndex) } else if matchFlasMethod(methodData, flasAmmBuyTokensIXs) { txSignal, err = parseFlasAmmBuy(tx, instructionIndex) } else if matchFlasMethod(methodData, flasAmmSellTokensIXs) { txSignal, err = parseFlasAmmSell(tx, instructionIndex) } else if matchFlasMethod(methodData, flasBonkBuyTokensIXs) { txSignal, err = parseFlasBonkBuy(tx, instructionIndex) } else if matchFlasMethod(methodData, flasBonkSellTokensIXs) { txSignal, err = parseFlasBonkSell(tx, instructionIndex) } if txSignal != nil { return TxSignalBatch{txSignal}, err } return nil, err } func parseFlasAmmSell(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) { instruction := tx.Instructions[instructionIndex] if len(instruction.Accounts) < 10 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(instruction.Accounts[9])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[1])) if err != nil { return nil, err } args, err := decodeFlasArgs(instruction.Data) if err != nil { 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{ TxHash: tx.Signatures[0].String(), Label: "flas", Maker: user.String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: token0Amount, Token1Amount: formatSolAmount(args.Amount2), Program: "PumpAMM", Event: "sell", IsToken2022: false, IsMayhemMode: false, ExactSOL: false, Block: tx.Block, Token0AmountUint64: token0AmountUint64, Token1AmountUint64: args.Amount2, }, nil } func parseFlasAmmBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) { instruction := tx.Instructions[instructionIndex] if len(instruction.Accounts) < 10 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(instruction.Accounts[9])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[1])) if err != nil { return nil, err } args, err := decodeFlasArgs(instruction.Data) if err != nil { return nil, fmt.Errorf("failed to parse buy tokens args: %w", err) } return &TxSignal{ TxHash: tx.Signatures[0].String(), Label: "flas", Maker: user.String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: decimal.Zero, Token1Amount: formatSolAmount(args.Amount1), Program: "PumpAMM", Event: "buy", IsToken2022: false, IsMayhemMode: false, ExactSOL: true, Block: tx.Block, Token0AmountUint64: 0, Token1AmountUint64: args.Amount1, }, nil } func parseFlasSell(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) { instruction := tx.Instructions[instructionIndex] if len(instruction.Accounts) < 11 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(instruction.Accounts[10])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[1])) if err != nil { return nil, err } args, err := decodeFlasArgs(instruction.Data) if err != nil { return nil, fmt.Errorf("failed to parse buy tokens args: %w", err) } return &TxSignal{ TxHash: tx.Signatures[0].String(), Label: "flas", Maker: user.String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: formatTokenAmount(args.Amount1), Token1Amount: formatSolAmount(args.Amount2), Program: "Pump", Event: "sell", IsToken2022: false, IsMayhemMode: false, Block: tx.Block, Token0AmountUint64: args.Amount1, Token1AmountUint64: args.Amount2, }, nil } func parseFlasBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) { instruction := tx.Instructions[instructionIndex] if len(instruction.Accounts) < 11 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(instruction.Accounts[10])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[1])) if err != nil { return nil, err } args, err := decodeFlasArgs(instruction.Data) if err != nil { return nil, fmt.Errorf("failed to parse buy tokens args: %w", err) } return &TxSignal{ TxHash: tx.Signatures[0].String(), Label: "flas", Maker: user.String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: formatTokenAmount(args.Amount2), Token1Amount: formatSolAmount(args.Amount1), Program: "Pump", Event: "buy", IsToken2022: false, IsMayhemMode: false, ExactSOL: true, Block: tx.Block, Token0AmountUint64: args.Amount2, Token1AmountUint64: args.Amount1, }, nil } func parseFlasBonkBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) { instruction := tx.Instructions[instructionIndex] if len(instruction.Accounts) < 17 { return nil, fmt.Errorf("accounts too short") } base, err := tx.GetAccount(int(instruction.Accounts[15])) if err != nil { return nil, err } quote, err := tx.GetAccount(int(instruction.Accounts[16])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[1])) if err != nil { return nil, err } if !quote.Equals(wrappedSOL) { // just ignore this return nil, nil } args, err := decodeFlasArgs(instruction.Data) if err != nil { return nil, fmt.Errorf("failed to parse buy tokens args: %w", err) } return &TxSignal{ TxHash: tx.Signatures[0].String(), Label: "flas", Maker: user.String(), Token0Address: base.String(), Token1Address: wsolMint, Token0Amount: formatTokenAmount(args.Amount2), Token1Amount: formatSolAmount(args.Amount1), Program: "RaydiumLaunchLab", Event: "buy", ExactSOL: true, Block: tx.Block, Token0AmountUint64: args.Amount2, Token1AmountUint64: args.Amount1, }, nil } func parseFlasBonkSell(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) { instruction := tx.Instructions[instructionIndex] if len(instruction.Accounts) < 17 { return nil, fmt.Errorf("accounts too short") } base, err := tx.GetAccount(int(instruction.Accounts[15])) if err != nil { return nil, err } quote, err := tx.GetAccount(int(instruction.Accounts[16])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[1])) if err != nil { return nil, err } if !quote.Equals(wrappedSOL) { // just ignore this return nil, nil } args, err := decodeFlasArgs(instruction.Data) if err != nil { return nil, fmt.Errorf("failed to parse buy tokens args: %w", err) } return &TxSignal{ TxHash: tx.Signatures[0].String(), Label: "flas", Maker: user.String(), Token0Address: base.String(), Token1Address: wsolMint, Token0Amount: formatTokenAmount(args.Amount1), Token1Amount: formatSolAmount(args.Amount2), Program: "RaydiumLaunchLab", Event: "sell", Block: tx.Block, Token0AmountUint64: args.Amount1, Token1AmountUint64: args.Amount2, }, nil }