package shreder import ( "fmt" "github.com/gagliardetto/solana-go" "github.com/near/borsh-go" "github.com/shopspring/decimal" ) var flasProgramID = solana.MustPublicKeyFromBase58("FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9") var ( flasBuyTokensIX = []byte{0x00, 0x1, 0x1b} flasSellTokensIX = []byte{0x01, 0x1, 0x1a} flasAmmBuyTokensIX = []byte{0x00, 0x2, 0x2} flasAmmSellTokensIX = []byte{0x01, 0x2, 0x2} ) type flasArgs struct { Amount1 uint64 Amount2 uint64 Placeholder [3]uint8 } 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] //if !matchMethod(methodData, flasBuyTokensIX) { // return nil, nil //} var ( err error txSignal *TxSignal ) if matchMethod(methodData, flasBuyTokensIX) { txSignal, err = parseFlasBuy(tx, instructionIndex) } else if matchMethod(methodData, flasSellTokensIX) { txSignal, err = parseFlasSell(tx, instructionIndex) } else if matchMethod(methodData, flasAmmBuyTokensIX) { txSignal, err = parseFlasAmmBuy(tx, instructionIndex) } else if matchMethod(methodData, flasAmmSellTokensIX) { txSignal, err = parseFlasAmmSell(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 } 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 &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: "PumpAMM", Event: "sell", IsToken2022: false, IsMayhemMode: false, ExactSOL: false, Block: tx.Block, Token0AmountUint64: args.Amount1, 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 } 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 &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) < 9 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(instruction.Accounts[8])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[1])) if err != nil { return nil, err } 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 &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) < 9 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(instruction.Accounts[8])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[0])) if err != nil { return nil, err } if len(instruction.Data) > 20 { instruction.Data = instruction.Data[:20] } 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 &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 }