From 594c46a1d248eb5c5260e985b6ee73a7e7b8327f Mon Sep 17 00:00:00 2001 From: bijianing97 <826015751@qq.com> Date: Thu, 22 Jan 2026 17:50:26 +0800 Subject: [PATCH] Add bloomrouter pumpfun parse --- cmd/txparse/main.go | 2 +- pkg/shreder/txparser.go | 131 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 119 insertions(+), 14 deletions(-) diff --git a/cmd/txparse/main.go b/cmd/txparse/main.go index f45e1bc..574f6d4 100644 --- a/cmd/txparse/main.go +++ b/cmd/txparse/main.go @@ -15,7 +15,7 @@ import ( const ( rpcURL = "https://staked.helius-rpc.com?api-key=5adcf1f9-5719-43d1-bf3f-c2d4e1e5f94d" - txSignature = "4rkbkLCUQxc89Aq1BZxU1w4LDQtnCtoUJ6VNHmVec8Kqngr5T89xAXahubLFg8DF6iFGzJ39N8V8n6LFtARDUJT9" + txSignature = "4YUQzsQcHxt5jA6qKPVBWCgw8VRuE6bZqAoXeiwptbdLwta3QnDbWHzjwP3mY8hJPPerSf1yGbpdL2SdyWZTJ9e1" labelFilter = "" enableStats = true ) diff --git a/pkg/shreder/txparser.go b/pkg/shreder/txparser.go index 77a2878..37f1307 100644 --- a/pkg/shreder/txparser.go +++ b/pkg/shreder/txparser.go @@ -50,7 +50,8 @@ var ( bonkProgramID = solana.MustPublicKeyFromBase58("BBRouter1cVunVXvkcqeKkZQcBK7ruan37PPm3xzWaXD") - + bloomRouterProgramID = solana.MustPublicKeyFromBase58("b1oomGGqPKGD6errbyfbVMBuzSC8WtAAYo8MwNafWW1") + // For Metaora dlmm dlmmProgramID = solana.MustPublicKeyFromBase58("LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo") ) @@ -107,12 +108,12 @@ var ( bonkBuyAndSellTokensIX = []byte{0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a} - dlmmSwapIX = []byte{248, 198, 158, 145, 225, 117, 135, 200} - dlmmSwap2IX = []byte{65, 75, 63, 76, 235, 91, 91, 136} - dlmmSwapExactOutIX = []byte{250, 73, 101, 33, 38, 207, 75, 184} - dlmmSwapExactOut2IX = []byte{43, 215, 247, 132, 137, 60, 243, 81} - dlmmSwapPriceImpactIX = []byte{56, 173, 230, 208, 173, 228, 156, 205} - dlmmSwapPriceImpact2IX = []byte{74, 98, 192, 214, 177, 51, 75, 51} + dlmmSwapIX = []byte{248, 198, 158, 145, 225, 117, 135, 200} + dlmmSwap2IX = []byte{65, 75, 63, 76, 235, 91, 91, 136} + dlmmSwapExactOutIX = []byte{250, 73, 101, 33, 38, 207, 75, 184} + dlmmSwapExactOut2IX = []byte{43, 215, 247, 132, 137, 60, 243, 81} + dlmmSwapPriceImpactIX = []byte{56, 173, 230, 208, 173, 228, 156, 205} + dlmmSwapPriceImpact2IX = []byte{74, 98, 192, 214, 177, 51, 75, 51} ) type compiledInstruction struct { @@ -186,6 +187,12 @@ type photonSwapPumpAmmArgs struct { ToAmount uint64 } +type bloomRouterArgs struct { + Side uint16 + SolAmount uint64 + TokenAmount uint64 +} + type pumpAmmBuyArgs struct { Amount uint64 MaxSolCost uint64 @@ -360,6 +367,9 @@ func ParseTransaction(update *SubscribeUpdateTransaction, loader *AddressTables, case bonkProgramID: txRes, err := parseBonkInstruction(versioned, i) parsed = appendParsed(now, parsed, txRes, err, txHash, "bonk") + case bloomRouterProgramID: + txRes, err := parseBloomRouterInstruction(versioned, i) + parsed = appendParsed(now, parsed, txRes, err, txHash, "bloomrouter") case dlmmProgramID: txRes, err := parseDlmmInstruction(versioned, i) parsed = appendParsed(now, parsed, txRes, err, txHash, "dlmm") @@ -1378,12 +1388,12 @@ func findAssociatedTokenAddressWithTokenProgram(wallet, mint, tokenProgram solan } type dlmmParsedArgs struct { - AmountIn uint64 - AmountOut uint64 - ExactIn bool - ExactOut bool - ActiveBin int32 - MaxPriceImpactBps uint16 + AmountIn uint64 + AmountOut uint64 + ExactIn bool + ExactOut bool + ActiveBin int32 + MaxPriceImpactBps uint16 } func parseDlmmSwapArgs(disc []byte, payload []byte) (*dlmmParsedArgs, error) { @@ -2033,6 +2043,101 @@ func parseBonkBuyAndSell(tx *versionedTransaction, instruction *compiledInstruct } } +func parseBloomRouterInstruction(tx *versionedTransaction, instructionIndex int) (*TxSignal, error) { + msg := tx.Message + if instructionIndex >= len(msg.Instructions) { + return nil, fmt.Errorf("instruction index out of bounds") + } + + instruction := msg.Instructions[instructionIndex] + if len(instruction.Data) < 26 { + return nil, nil + } + + var ( + amount uint64 + sol uint64 + exactIn bool + event string + ) + + args, err := decodeBloomRouterArgs(instruction.Data) + if err != nil { + return nil, err + } + switch args.Side { + case 0: + event = "buy" + exactIn = true + case 1: + event = "sell" + default: + return nil, nil + } + if args.SolAmount > ^uint64(0)/100 { + return nil, fmt.Errorf("bloomrouter sol amount overflow") + } + // bloomrouter SOL amount has 2 fewer decimals than lamports. + sol = args.SolAmount * 100 + amount = args.TokenAmount + + if len(instruction.Accounts) == 0 { + return nil, fmt.Errorf("accounts too short") + } + maker, err := getStaticKey(msg.StaticAccountKeys, int(instruction.Accounts[0])) + if err != nil { + return nil, err + } + + var ( + mint solana.PublicKey + ok bool + ) + for _, acctIdx := range instruction.Accounts { + key, err := getStaticKey(msg.StaticAccountKeys, int(acctIdx)) + if err != nil { + return nil, err + } + if strings.HasSuffix(key.String(), "pump") { + mint = key + ok = true + break + } + } + if !ok { + return nil, nil + } + + return &TxSignal{ + TxHash: tx.Signatures[0].String(), + Label: "bloomrouter", + Maker: maker.String(), + Token0Address: mint.String(), + Token1Address: wsolMint, + Token0Amount: formatTokenAmount(amount), + Token1Amount: formatSolAmount(sol), + Program: "Pump", + Event: event, + ExactSOL: exactIn, + IsToken2022: false, + IsMayhemMode: false, + Block: tx.Block, + Token0AmountUint64: amount, + Token1AmountUint64: sol, + }, nil +} + +func decodeBloomRouterArgs(data []byte) (bloomRouterArgs, error) { + if len(data) < 26 { + return bloomRouterArgs{}, fmt.Errorf("data too short for bloomrouter args, len=%d", len(data)) + } + return bloomRouterArgs{ + Side: binary.BigEndian.Uint16(data[8:10]), + SolAmount: binary.LittleEndian.Uint64(data[10:18]), + TokenAmount: binary.LittleEndian.Uint64(data[18:26]), + }, nil +} + func matchMethod(data []byte, methods []byte) bool { if len(data) < len(methods) { return false