package shreder import ( "bytes" "encoding/binary" "fmt" "github.com/gagliardetto/solana-go" "github.com/shopspring/decimal" ) var dbotProgramID = solana.MustPublicKeyFromBase58("DBotWvSso9oD1ZB3aHx2LiD2ZoFpF8PbKjaT4uHKLLVs") var ( dbotPumpFunBuyIX = []byte{0x4e, 0x13, 0x6d, 0x72, 0x3d, 0x72, 0xbe, 0x9d} dbotPumpAmmBuyIX = []byte{0x99, 0x76, 0xb6, 0x1e, 0xe4, 0x03, 0xdc, 0xf4} ) func parseDbotInstruction(tx VersionedTransaction, instructionIndex int) (TxSignalBatch, error) { if instructionIndex >= len(tx.Instructions) { return nil, fmt.Errorf("instruction index out of bounds") } ix := tx.Instructions[instructionIndex] if len(ix.Data) < 8 { return nil, nil } isPumpFun := false isPumpAmm := false if len(ix.Accounts) > 11 { key, err := tx.GetAccount(int(ix.Accounts[11])) if err != nil { return nil, err } if key.Equals(pumpProgramID) { isPumpFun = true } } if len(ix.Accounts) > 16 { key, err := tx.GetAccount(int(ix.Accounts[16])) if err != nil { return nil, err } if key.Equals(pumpAmmProgramID) { isPumpAmm = true } } disc := ix.Data[:8] if isPumpFun { if !bytes.Equal(disc, dbotPumpFunBuyIX) { return nil, nil } if len(ix.Data) < 16 { return nil, fmt.Errorf("data too short for dbot pumpfun buy args, len=%d", len(ix.Data)) } if len(ix.Accounts) < 3 { return nil, fmt.Errorf("accounts too short") } mint, err := tx.GetAccount(int(ix.Accounts[2])) if err != nil { return nil, err } solAmount := binary.LittleEndian.Uint64(ix.Data[8:16]) return TxSignalBatch{&TxSignal{ TxHash: tx.Signatures[0].String(), Label: "dbot", Maker: tx.StaticAccountKeys[0].String(), Token0Address: mint.String(), Token1Address: wsolMint, Token0Amount: decimal.Zero, Token1Amount: formatSolAmount(solAmount), Program: "Pump", Event: "buy", ExactSOL: true, IsToken2022: false, IsMayhemMode: false, Block: tx.Block, Token0AmountUint64: 0, Token1AmountUint64: solAmount, }}, nil } if isPumpAmm { if !bytes.Equal(disc, dbotPumpAmmBuyIX) { return nil, nil } if len(ix.Data) < 16 { return nil, fmt.Errorf("data too short for dbot pumpamm buy args, len=%d", len(ix.Data)) } if len(ix.Accounts) < 5 { return nil, fmt.Errorf("accounts too short") } base, err := tx.GetAccount(int(ix.Accounts[3])) if err != nil { return nil, err } quote, err := tx.GetAccount(int(ix.Accounts[4])) if err != nil { return nil, err } if !quote.Equals(solana.WrappedSol) { return nil, nil } solAmount := binary.LittleEndian.Uint64(ix.Data[8:16]) return TxSignalBatch{&TxSignal{ TxHash: tx.Signatures[0].String(), Label: "dbot", Maker: tx.StaticAccountKeys[0].String(), Token0Address: base.String(), Token1Address: wsolMint, Token0Amount: decimal.Zero, Token1Amount: formatSolAmount(solAmount), Program: "PumpAMM", Event: "buy", ExactSOL: true, IsToken2022: false, IsMayhemMode: false, Block: tx.Block, Token0AmountUint64: 0, Token1AmountUint64: solAmount, }}, nil } return nil, nil }