3 Commits

Author SHA1 Message Date
bijianing97
f41e086028 Fix bloomrouter parser 2026-02-05 14:13:40 +08:00
77c8c0aad3 chore: add cu price 2026-02-03 17:36:59 +08:00
bijianing97
a0e46ec83e Add tradewiz parser 2026-02-03 14:06:43 +08:00
6 changed files with 98 additions and 14 deletions

View File

@@ -94,7 +94,7 @@ func main() {
return return
case tx := <-txCh: case tx := <-txCh:
if tx.Label == "dbot" || tx.Label == "okxdexroutev2" { if tx.Label == "dbot" || tx.Label == "okxdexroutev2" {
fmt.Println("===============", tx.TxHash, tx.Label,tx.Program ,tx.Event, tx.Token0Address, tx.Token1Address,"token0amount:", tx.Token0Amount, "token1amount:",tx.Token1Amount ,"parse time:", tx.ParseEnd.Sub(tx.ParseStart)) fmt.Println("===============", tx.TxHash, tx.Label, tx.Program, tx.Event, tx.Token0Address, tx.Token1Address, "token0amount:", tx.Token0Amount, "token1amount:", tx.Token1Amount, "parse time:", tx.ParseEnd.Sub(tx.ParseStart), "cu price:", tx.CUPrice, "cu price uint64:", tx.CUPriceUint64)
} }
} }
} }

View File

@@ -15,7 +15,7 @@ import (
const ( const (
rpcURL = "https://staked.helius-rpc.com?api-key=5adcf1f9-5719-43d1-bf3f-c2d4e1e5f94d" rpcURL = "https://staked.helius-rpc.com?api-key=5adcf1f9-5719-43d1-bf3f-c2d4e1e5f94d"
txSignature = "4tcpUCVUZtUFDKGwZVBexkQpYiPhFgW4wfnrTEQgPrkQxpfsDEVMWN2UBfYxpy1EsDzuatuP1wgsUowTqeh2fnie" txSignature = "4gzWkLRWNLbkBdvyCqg2M4unWA7yg4DdMg8dGTnapw2USsefd9TjXVArhv22qJE9gtex46NwXC4xp1FtNZ1TmjAM"
labelFilter = "" labelFilter = ""
) )

View File

@@ -3,12 +3,12 @@ package shreder
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"strings"
"github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go"
) )
var bloomRouterProgramID = solana.MustPublicKeyFromBase58("b1oomGGqPKGD6errbyfbVMBuzSC8WtAAYo8MwNafWW1") var bloomRouterProgramID = solana.MustPublicKeyFromBase58("b1oomGGqPKGD6errbyfbVMBuzSC8WtAAYo8MwNafWW1")
var pumpFunAccount = solana.MustPublicKeyFromBase58("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf")
type bloomRouterArgs struct { type bloomRouterArgs struct {
Side uint16 Side uint16
@@ -61,22 +61,27 @@ func parseBloomRouterInstruction(tx VersionedTransaction, instructionIndex int)
return nil, err return nil, err
} }
var ( var mint solana.PublicKey
mint solana.PublicKey foundPumpFun := false
ok bool for i, acctIdx := range instruction.Accounts {
)
for _, acctIdx := range instruction.Accounts {
key, err := tx.GetAccount(int(acctIdx)) key, err := tx.GetAccount(int(acctIdx))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if strings.HasSuffix(key.String(), "pump") { if key.Equals(pumpFunAccount) {
mint = key if i+2 >= len(instruction.Accounts) {
ok = true return nil, fmt.Errorf("accounts too short for pumpfun mint, idx=%d len=%d", i, len(instruction.Accounts))
}
mintKey, err := tx.GetAccount(int(instruction.Accounts[i+2]))
if err != nil {
return nil, err
}
mint = mintKey
foundPumpFun = true
break break
} }
} }
if !ok { if !foundPumpFun {
return nil, nil return nil, nil
} }

View File

@@ -0,0 +1,50 @@
package shreder
import (
"encoding/binary"
"fmt"
"github.com/gagliardetto/solana-go"
"github.com/shopspring/decimal"
)
var tradewizProgramID = solana.MustPublicKeyFromBase58("B3jytJa6Tzpn4Ly7GNnDm3dMGqUin5aMRm5aPsJGU5G7")
func parseTradewizInstruction(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) < 9 {
return nil, fmt.Errorf("data too short for tradewiz buy args, len=%d", len(ix.Data))
}
if len(ix.Accounts) < 3 {
return nil, fmt.Errorf("accounts too short")
}
// data format: 0x00 + u64(wsol amount) + u64(...)
wsolAmount := binary.LittleEndian.Uint64(ix.Data[1:9])
mint, err := tx.GetAccount(int(ix.Accounts[2]))
if err != nil {
return nil, err
}
return TxSignalBatch{&TxSignal{
TxHash: tx.Signatures[0].String(),
Label: "tradewiz",
Maker: tx.StaticAccountKeys[0].String(),
Token0Address: mint.String(),
Token1Address: wsolMint,
Token0Amount: decimal.Zero,
Token1Amount: formatSolAmount(wsolAmount),
Program: "Pump",
Event: "buy",
IsToken2022: false,
IsMayhemMode: false,
ExactSOL: true,
Block: tx.Block,
Token0AmountUint64: 0,
Token1AmountUint64: wsolAmount,
}}, nil
}

View File

@@ -44,7 +44,7 @@ type TxSignal struct {
IsProcessed bool `json:"is_processed"` IsProcessed bool `json:"is_processed"`
IsToken2022 bool `json:"is_token2022"` IsToken2022 bool `json:"is_token2022"`
IsMayhemMode bool `json:"is_mayhem_mode"` IsMayhemMode bool `json:"is_mayhem_mode"`
TxFee decimal.Decimal `json:"tx_fee"` CUPrice decimal.Decimal `json:"cu_price"`
ExactSOL bool `json:"exact_in"` ExactSOL bool `json:"exact_in"`
@@ -55,6 +55,7 @@ type TxSignal struct {
MaxPriceImpactBps uint16 `json:"max_price_impact_bps"` MaxPriceImpactBps uint16 `json:"max_price_impact_bps"`
// parsed values // parsed values
CUPriceUint64 uint64 `json:"-"`
Token0AmountUint64 uint64 `json:"-"` Token0AmountUint64 uint64 `json:"-"`
Token1AmountUint64 uint64 `json:"-"` Token1AmountUint64 uint64 `json:"-"`

View File

@@ -3,6 +3,7 @@ package shreder
import ( import (
"bytes" "bytes"
"context" "context"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
@@ -73,6 +74,7 @@ var (
bloomRouterProgramID: {parseBloomRouterInstruction, "bloomrouter"}, bloomRouterProgramID: {parseBloomRouterInstruction, "bloomrouter"},
dlmmProgramID: {parseDlmmInstruction, "dlmm"}, dlmmProgramID: {parseDlmmInstruction, "dlmm"},
dbotProgramID: {parseDbotInstruction, "dbot"}, dbotProgramID: {parseDbotInstruction, "dbot"},
tradewizProgramID: {parseTradewizInstruction, "tradewiz"},
} }
) )
@@ -91,7 +93,10 @@ func ParseTransactionForSubscribe(ctx context.Context, update *SubscribeUpdateTr
} }
} }
var VoteProgram = solana.MustPublicKeyFromBase58("Vote111111111111111111111111111111111111111") var (
ComputeBudgetProgram = solana.MustPublicKeyFromBase58("ComputeBudget111111111111111111111111111111")
VoteProgram = solana.MustPublicKeyFromBase58("Vote111111111111111111111111111111111111111")
)
func FilterTransactionForEntries(versioned VersionedTransaction) bool { func FilterTransactionForEntries(versioned VersionedTransaction) bool {
if len(versioned.Instructions) >= 1 { if len(versioned.Instructions) >= 1 {
@@ -194,6 +199,22 @@ func ParseTransactionWithHandler(ctx context.Context, versioned VersionedTransac
} }
} }
cuPrice := decimal.Zero
cuPriceUint64 := uint64(0)
for _, instruction := range versioned.Instructions {
program, err := versioned.GetAccount(int(instruction.ProgramIDIndex))
if err != nil {
continue
}
if program.Equals(ComputeBudgetProgram) &&
len(instruction.Data) == 9 &&
instruction.Data[0] == 0x03 {
cuPriceUint64 = binary.LittleEndian.Uint64(instruction.Data[1:9])
cuPrice = formatCUPrice(cuPriceUint64)
break
}
}
for i, instruction := range versioned.Instructions { for i, instruction := range versioned.Instructions {
//load from address table //load from address table
program, err := versioned.GetAccount(int(instruction.ProgramIDIndex)) program, err := versioned.GetAccount(int(instruction.ProgramIDIndex))
@@ -218,6 +239,8 @@ func ParseTransactionWithHandler(ctx context.Context, versioned VersionedTransac
} }
one.Label = handler.Label one.Label = handler.Label
one.Block = versioned.Block one.Block = versioned.Block
one.CUPrice = cuPrice
one.CUPriceUint64 = cuPriceUint64
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
@@ -287,6 +310,11 @@ func toVersionedTransaction(update *SubscribeUpdateTransaction) (VersionedTransa
return versioned, nil return versioned, nil
} }
func formatCUPrice(cuPrice uint64) decimal.Decimal {
val := decimal.NewFromBigInt(new(big.Int).SetUint64(cuPrice), 0)
return val.Div(decimal.NewFromInt(1_000_000))
}
func formatTokenAmount(amount uint64) decimal.Decimal { func formatTokenAmount(amount uint64) decimal.Decimal {
val := decimal.NewFromBigInt(new(big.Int).SetUint64(amount), 0) val := decimal.NewFromBigInt(new(big.Int).SetUint64(amount), 0)
return val.Div(decimal.NewFromInt(1_000_000)) return val.Div(decimal.NewFromInt(1_000_000))