From 7557414fff5c9b0c0fe330648a01c48a7ae11676 Mon Sep 17 00:00:00 2001 From: bijianing97 <826015751@qq.com> Date: Mon, 2 Feb 2026 11:02:10 +0800 Subject: [PATCH] Add Dbot parser --- pkg/shreder/program_dbot.go | 134 ++++++++++++++++++++++++++++++++++++ pkg/shreder/txparser.go | 1 + 2 files changed, 135 insertions(+) create mode 100644 pkg/shreder/program_dbot.go diff --git a/pkg/shreder/program_dbot.go b/pkg/shreder/program_dbot.go new file mode 100644 index 0000000..04da7cc --- /dev/null +++ b/pkg/shreder/program_dbot.go @@ -0,0 +1,134 @@ +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 +} diff --git a/pkg/shreder/txparser.go b/pkg/shreder/txparser.go index db4f3b8..5ce97b3 100644 --- a/pkg/shreder/txparser.go +++ b/pkg/shreder/txparser.go @@ -72,6 +72,7 @@ var ( bonkProgramID: {parseBonkInstruction, "bonk"}, bloomRouterProgramID: {parseBloomRouterInstruction, "bloomrouter"}, dlmmProgramID: {parseDlmmInstruction, "dlmm"}, + dbotProgramID: {parseDbotInstruction, "dbot"}, } )