package shreder import ( "bytes" "encoding/binary" "fmt" "github.com/gagliardetto/solana-go" ) var terminalProgramID = solana.MustPublicKeyFromBase58("term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3") var ( terminalBuyTokensIX = []byte{0x14, 0xfe, 0x38, 0xc9, 0x3d, 0x37, 0x17, 0x27} terminalSellTokensIX = []byte{0xcd, 0xaa, 0x10, 0x49, 0x20, 0xd6, 0x62, 0xd6} terminalAmmSellTokensIX = []byte{0x40, 0x64, 0x97, 0xb9, 0x16, 0xfa, 0xec, 0xb1} ) func parseTermInstruction(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) < 24 { return nil, nil } var ( err error txSignal *TxSignal ) switch { case bytes.Equal(instruction.Data[:8], terminalBuyTokensIX): txSignal, err = parseTermBuy(tx, instruction) case bytes.Equal(instruction.Data[:8], terminalSellTokensIX): txSignal, err = parseTermSell(tx, instruction) case bytes.Equal(instruction.Data[:8], terminalAmmSellTokensIX): txSignal, err = parseTermAmmSell(tx, instruction) default: return nil, nil } if txSignal != nil { return TxSignalBatch{txSignal}, err } return nil, err } func parseTermAmmSell(tx VersionedTransaction, instruction Instructions) (*TxSignal, error) { if len(instruction.Accounts) < 8 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(instruction.Accounts[3])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[1])) if err != nil { return nil, err } solAmount := binary.LittleEndian.Uint64(instruction.Data[8:16]) tokenAmount := binary.LittleEndian.Uint64(instruction.Data[16:24]) return &TxSignal{ TxHash: tx.Signatures[0].String(), Label: "term", Maker: user.String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: formatTokenAmount(tokenAmount), Token1Amount: formatSolAmount(solAmount), Program: "Pump", Event: "buy", IsToken2022: false, IsMayhemMode: false, ExactSOL: true, Block: tx.Block, Token0AmountUint64: tokenAmount, Token1AmountUint64: solAmount, }, nil } func parseTermBuy(tx VersionedTransaction, instruction Instructions) (*TxSignal, error) { if len(instruction.Accounts) < 8 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(instruction.Accounts[2])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[6])) if err != nil { return nil, err } solAmount := binary.LittleEndian.Uint64(instruction.Data[8:16]) tokenAmount := binary.LittleEndian.Uint64(instruction.Data[16:24]) return &TxSignal{ TxHash: tx.Signatures[0].String(), Label: "term", Maker: user.String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: formatTokenAmount(tokenAmount), Token1Amount: formatSolAmount(solAmount), Program: "Pump", Event: "buy", IsToken2022: false, IsMayhemMode: false, ExactSOL: true, Block: tx.Block, Token0AmountUint64: tokenAmount, Token1AmountUint64: solAmount, }, nil } func parseTermSell(tx VersionedTransaction, instruction Instructions) (*TxSignal, error) { if len(instruction.Accounts) < 8 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(instruction.Accounts[2])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[6])) if err != nil { return nil, err } tokenAmount := binary.LittleEndian.Uint64(instruction.Data[8:16]) solAmount := binary.LittleEndian.Uint64(instruction.Data[16:24]) return &TxSignal{ TxHash: tx.Signatures[0].String(), Label: "term", Maker: user.String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: formatTokenAmount(tokenAmount), Token1Amount: formatSolAmount(solAmount), Program: "Pump", Event: "sell", IsToken2022: false, IsMayhemMode: false, ExactSOL: false, Block: tx.Block, Token0AmountUint64: tokenAmount, Token1AmountUint64: solAmount, }, nil }