package shreder import ( "encoding/binary" "fmt" "github.com/gagliardetto/solana-go" "github.com/near/borsh-go" "github.com/shopspring/decimal" ) // has no sell function with pump and pump.amm program var azczProgramID = solana.MustPublicKeyFromBase58("AzcZqCRUQgKEg5FTAgY7JacATABEYCEfMbjXEzspLYFB") var ( azczBuyTokensIX = []byte{11} azczAmmBuyTokensIX = []byte{0xf} ) type azczBuyArgs struct { SolAmount uint64 TokenAmount uint64 } func parseAzczInstruction(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") } var ( err error txSignal *TxSignal ) if matchMethod(instruction.Data, azczBuyTokensIX) { txSignal, err = parseAzczBuy(tx, instructionIndex) } else if matchMethod(instruction.Data, azczAmmBuyTokensIX) { txSignal, err = parseAzczAmmBuy(tx, instructionIndex) } if txSignal != nil { return TxSignalBatch{txSignal}, err } return nil, err } func parseAzczAmmBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) { instruction := tx.Instructions[instructionIndex] 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 } if len(instruction.Data) < 17 { return nil, fmt.Errorf("data too short for azcz amm buy args, len=%d", len(instruction.Data)) } solAmount := binary.LittleEndian.Uint64(instruction.Data[1:9]) return &TxSignal{ TxHash: tx.Signatures[0].String(), Label: "azcz", Maker: user.String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: decimal.Zero, Token1Amount: formatSolAmount(solAmount), Program: "Pump", Event: "buy", IsToken2022: false, IsMayhemMode: false, ExactSOL: true, Block: tx.Block, Token0AmountUint64: 0, Token1AmountUint64: solAmount, }, nil } func parseAzczBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) { instruction := tx.Instructions[instructionIndex] 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[7])) if err != nil { return nil, err } if len(instruction.Data) < 2 { return nil, fmt.Errorf("data too short for azcz buy args len=%d", len(instruction.Data)) } var args azczBuyArgs 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: "azcz", Maker: user.String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: formatTokenAmount(args.TokenAmount), Token1Amount: formatSolAmount(args.SolAmount), Program: "Pump", Event: "buy", IsToken2022: false, IsMayhemMode: false, Block: tx.Block, Token0AmountUint64: args.TokenAmount, Token1AmountUint64: args.SolAmount, }, nil }