pump buy_exact_sol_in parsered

This commit is contained in:
thloyi
2025-11-24 17:47:56 +08:00
parent f86c5591c1
commit 1f63a3a18f
6 changed files with 72 additions and 10 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/shopspring/decimal"
parser "github.com/thloyi/pump-parser" parser "github.com/thloyi/pump-parser"
example "github.com/thloyi/pump-parser/example" example "github.com/thloyi/pump-parser/example"
"github.com/thloyi/pump-parser/example/geyser" "github.com/thloyi/pump-parser/example/geyser"
@@ -21,7 +22,7 @@ func main() {
ch := make(chan geyser.SubscriptionMessage, 1) ch := make(chan geyser.SubscriptionMessage, 1)
go geyser.RunLoopWithReConnect(context.Background(), "127.0.0.1:10001", parser.SolProgramPump, ch) go geyser.RunLoopWithReConnect(context.Background(), "127.0.0.1:10001", parser.SolProgramPump, ch)
// var tokenTxs = make(map[string]*types.Tx) // var tokenTxs = make(map[string]*types.Tx)
currentBlock := uint64(0) // currentBlock := uint64(0)
for msg := range ch { for msg := range ch {
if msg.Tx == nil { if msg.Tx == nil {
block := msg.Block block := msg.Block
@@ -42,9 +43,9 @@ func main() {
//if tx.Program != parser.SolProgramPump { //if tx.Program != parser.SolProgramPump {
// continue // continue
//} //}
if currentBlock == ptx.Block { //if currentBlock == ptx.Block {
continue // continue
} //}
// 处理交易 // 处理交易
txErr, ok := ptx.Err.(*geyser.TransactionError) txErr, ok := ptx.Err.(*geyser.TransactionError)
@@ -64,11 +65,14 @@ func main() {
if tx.Program != parser.SolProgramPump { if tx.Program != parser.SolProgramPump {
continue continue
} }
if tx.Token1Amount.GreaterThanOrEqual(decimal.NewFromFloat(0.1)) || tx.Event != "buy" {
continue
}
printed = true printed = true
fmt.Printf("t: %s, block: %d, hash: %s, signer: %s, program: %s, event: %s, token1: %s, cuPrice: %s, mevAgent: %s, mevFee: %s, platform: %s, platformFee: %s, entryContract: %s, mayhem: %t\n", fmt.Printf("t: %s, block: %d, hash: %s, signer: %s, program: %s, event: %s, token1: %s, cuPrice: %s, mevAgent: %s, mevFee: %s, platform: %s, platformFee: %s, entryContract: %s, mayhem: %t\n",
time.Now().Format(time.RFC3339Nano), time.Now().Format(time.RFC3339Nano),
tx.Block, tx.GetTxHash(), tx.Maker, tx.Program, tx.Event, tx.Token1Amount, tx.CUPrice, tx.MevAgent, tx.MevAgentFee, tx.Platform, tx.PlatformFee, tx.EntryContract, tx.Mayhem) tx.Block, tx.GetTxHash(), tx.Maker, tx.Program, tx.Event, tx.Token1Amount, tx.CUPrice, tx.MevAgent, tx.MevAgentFee, tx.Platform, tx.PlatformFee, tx.EntryContract, tx.Mayhem)
break //break
} }
if !printed { if !printed {
continue continue
@@ -79,7 +83,7 @@ func main() {
// tx.BeforeSolBalance, tx.AfterSOLBalance, tx.AfterSignerToken0Balance, tx.TokenCreator, tx.Token0Program, tx.Mayhem) // tx.BeforeSolBalance, tx.AfterSOLBalance, tx.AfterSignerToken0Balance, tx.TokenCreator, tx.Token0Program, tx.Mayhem)
} }
currentBlock = ptx.Block // currentBlock = ptx.Block
// //
//if tx.Event == "create" { //if tx.Event == "create" {
// if err := pool.Submit(func() { // if err := pool.Submit(func() {

View File

@@ -5,6 +5,7 @@ import (
) )
var pumpProgram = solana.MustPublicKeyFromBase58("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P") var pumpProgram = solana.MustPublicKeyFromBase58("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")
var pumpFeesProgram = solana.MustPublicKeyFromBase58("pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ")
var pumpMigrationAccount = solana.MustPublicKeyFromBase58("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg") var pumpMigrationAccount = solana.MustPublicKeyFromBase58("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg")
var mayhemFeeAccounts = []solana.PublicKey{ var mayhemFeeAccounts = []solana.PublicKey{
solana.MustPublicKeyFromBase58("GesfTA3X2arioaHp8bbKdjG9vJtskViWACZoYvxp4twS"), solana.MustPublicKeyFromBase58("GesfTA3X2arioaHp8bbKdjG9vJtskViWACZoYvxp4twS"),
@@ -17,6 +18,7 @@ var mayhemFeeAccounts = []solana.PublicKey{
solana.MustPublicKeyFromBase58("6AUH3WEHucYZyC61hqpqYUWVto5qA5hjHuNQ32GNnNxA"), solana.MustPublicKeyFromBase58("6AUH3WEHucYZyC61hqpqYUWVto5qA5hjHuNQ32GNnNxA"),
} }
var pumpGetFeesDiscriminator = calculateDiscriminator("global:get_fees")
var pumpBuyDiscriminator = calculateDiscriminator("global:buy") var pumpBuyDiscriminator = calculateDiscriminator("global:buy")
var pumpBuyV2Discriminator = calculateDiscriminator("global:buy_exact_sol_in") var pumpBuyV2Discriminator = calculateDiscriminator("global:buy_exact_sol_in")
var pumpSellDiscriminator = calculateDiscriminator("global:sell") var pumpSellDiscriminator = calculateDiscriminator("global:sell")

34
pump.go
View File

@@ -174,6 +174,15 @@ type PumpTradeEvent struct {
Fee uint64 Fee uint64
Creator solana.PublicKey Creator solana.PublicKey
CreatorFeeBasisPoints uint64
CreatorFee uint64
}
type PumpTradeFeeArg struct {
IsPump bool
MarketCap [16]byte
TradeSize uint64
} }
type CompleteEvent struct { type CompleteEvent struct {
@@ -189,8 +198,16 @@ func BuyOrSellParser(tx *Tx, instruction Instruction, innerInstructions InnerIns
var err error var err error
var programIndex = instruction.ProgramIDIndex var programIndex = instruction.ProgramIDIndex
feeEventProgramIndex := 0
for i, b := range result.accountList {
if b.Equals(pumpFeesProgram) {
feeEventProgramIndex = i
break
}
}
var ( var (
tradeEvent PumpTradeEvent tradeEvent PumpTradeEvent
tradeFeeArg PumpTradeFeeArg
completeEvent CompleteEvent completeEvent CompleteEvent
completed bool completed bool
newoffset [2]uint newoffset [2]uint
@@ -203,6 +220,13 @@ func BuyOrSellParser(tx *Tx, instruction Instruction, innerInstructions InnerIns
} }
for innerIndex, innerInstr := range inners { for innerIndex, innerInstr := range inners {
if innerInstr.ProgramIDIndex == feeEventProgramIndex && bytes.Equal(innerInstr.Data[:8], pumpGetFeesDiscriminator[:]) {
err = agbinary.NewBorshDecoder(innerInstr.Data[8:]).Decode(&tradeFeeArg)
if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("pump get fees event decode error: %v, offset, %d, %d", err, offset[0], offset[1])
}
continue
}
if innerInstr.ProgramIDIndex == programIndex && bytes.Equal(innerInstr.Data[:8], pumpEventDiscriminator[:]) { if innerInstr.ProgramIDIndex == programIndex && bytes.Equal(innerInstr.Data[:8], pumpEventDiscriminator[:]) {
if bytes.Equal(innerInstr.Data[8:16], pumpTradeEventDiscriminator[8:16]) { if bytes.Equal(innerInstr.Data[8:16], pumpTradeEventDiscriminator[8:16]) {
err = agbinary.NewBorshDecoder(innerInstr.Data[16:]).Decode(&tradeEvent) err = agbinary.NewBorshDecoder(innerInstr.Data[16:]).Decode(&tradeEvent)
@@ -260,6 +284,14 @@ func BuyOrSellParser(tx *Tx, instruction Instruction, innerInstructions InnerIns
Decimals: 6, Decimals: 6,
} }
} }
solAmount := tradeEvent.SolAmount
if tradeEvent.IsBuy && bytes.Equal(instruction.Data[:8], pumpBuyV2Discriminator[:]) {
fee := tradeEvent.Fee + tradeEvent.CreatorFee
solAmount = tradeFeeArg.TradeSize
if solAmount > fee {
solAmount = solAmount - fee
}
}
swaps := []Swap{ swaps := []Swap{
{ {
Program: SolProgramPump, Program: SolProgramPump,
@@ -274,7 +306,7 @@ func BuyOrSellParser(tx *Tx, instruction Instruction, innerInstructions InnerIns
QuoteMintDecimals: 9, QuoteMintDecimals: 9,
User: tradeEvent.User, User: tradeEvent.User,
BaseAmount: decimal.NewFromUint64(tradeEvent.TokenAmount), BaseAmount: decimal.NewFromUint64(tradeEvent.TokenAmount),
QuoteAmount: decimal.NewFromUint64(tradeEvent.SolAmount), QuoteAmount: decimal.NewFromUint64(solAmount),
BaseReserve: decimal.NewFromUint64(tradeEvent.RealTokenReserves), BaseReserve: decimal.NewFromUint64(tradeEvent.RealTokenReserves),
QuoteReserve: decimal.NewFromUint64(tradeEvent.RealSolReserves), QuoteReserve: decimal.NewFromUint64(tradeEvent.RealSolReserves),
Mayhem: isMayhemPump(result.accountList[instruction.Accounts[1]]), Mayhem: isMayhemPump(result.accountList[instruction.Accounts[1]]),

26
pump_test.go Normal file
View File

@@ -0,0 +1,26 @@
package pump_parser
import (
"encoding/hex"
"testing"
agbinary "github.com/gagliardetto/binary"
)
func TestTradeEvent(t *testing.T) {
hexData := "e445a52e51cb9a1dbddb7fd34ee661ee051d1834b36cc6f04cc5bd998d53ab2a566a0ca2415bcfad5f9ed6941a851d3f84ecb200000000006c267d17170000000190d2c525ef0ea205f4b4abfdb6eaaf37fcb5a1b1dec2e2689448eecab6ba93b6c922246900000000c314f11a0d000000be71bf9e22080200c368cd1e06000000bed9ac52910901004ac2f8d0dd5cbc97e3289c197cb5062a54f3d956b9ce6e5115f96567aa5cb3e65f000000000000002c6a010000000000c9e17c171227a50a5b62e3a4a3f8ff4fafe0bca9c332bdf7f32eedbc4229604d1e000000000000005f72000000000000010000000000000000000000000000000000000000000000000000000000000000100000006275795f65786163745f736f6c5f696e"
d, err := hex.DecodeString(hexData)
if err != nil {
t.Errorf("Failed to decode base64 data: %v", err)
}
var tradeEvent PumpTradeEvent
err = agbinary.NewBorshDecoder(d[16:]).Decode(&tradeEvent)
if err != nil {
t.Errorf("Failed to deserialize trade event: %v", err)
}
t.Logf("Trade Event: %+v", tradeEvent)
}

View File

@@ -38,4 +38,5 @@ func TestDecodePoolData(t *testing.T) {
func TestAmmBuyEvent(t *testing.T) { func TestAmmBuyEvent(t *testing.T) {
fmt.Println(pumpAmmBuyEventDiscriminator) fmt.Println(pumpAmmBuyEventDiscriminator)
fmt.Println(pumpGetFeesDiscriminator)
} }

3
tx.go
View File

@@ -1,8 +1,6 @@
package pump_parser package pump_parser
import ( import (
"fmt"
"github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go"
"github.com/mr-tron/base58" "github.com/mr-tron/base58"
"github.com/shopspring/decimal" "github.com/shopspring/decimal"
@@ -137,7 +135,6 @@ func (tx *Tx) CheckPlatform(swap Swap) (string, decimal.Decimal) {
platform != PlatformFake { platform != PlatformFake {
if (swap.QuoteMint.Equals(wSolMint) || swap.QuoteMint.IsZero()) && if (swap.QuoteMint.Equals(wSolMint) || swap.QuoteMint.IsZero()) &&
platformFee.LessThan(swap.QuoteAmount.Div(decimal.New(1, int32(swap.QuoteMintDecimals))).Div(decimal.NewFromInt(10000)).Mul(decimal.NewFromInt(9))) { platformFee.LessThan(swap.QuoteAmount.Div(decimal.New(1, int32(swap.QuoteMintDecimals))).Div(decimal.NewFromInt(10000)).Mul(decimal.NewFromInt(9))) {
fmt.Printf("\n amount: %s, platform: %s, fee: %s \n", swap.QuoteAmount.Div(decimal.New(1, int32(swap.QuoteMintDecimals))), platform, platformFee.String())
platform = PlatformFake platform = PlatformFake
} else if swap.BaseMint.Equals(wSolMint) && } else if swap.BaseMint.Equals(wSolMint) &&
platformFee.LessThan(swap.QuoteAmount.Div(decimal.New(1, int32(swap.QuoteMintDecimals))).Div(decimal.NewFromInt(10000)).Mul(decimal.NewFromInt(9))) { platformFee.LessThan(swap.QuoteAmount.Div(decimal.New(1, int32(swap.QuoteMintDecimals))).Div(decimal.NewFromInt(10000)).Mul(decimal.NewFromInt(9))) {