From 1f63a3a18fd7c2ca4312dd8d18b52255f60a1ccc Mon Sep 17 00:00:00 2001 From: thloyi Date: Mon, 24 Nov 2025 17:47:56 +0800 Subject: [PATCH] pump buy_exact_sol_in parsered --- example/geyser/cmd/main.go | 16 ++++++++++------ meta.go | 2 ++ pump.go | 34 +++++++++++++++++++++++++++++++++- pump_test.go | 26 ++++++++++++++++++++++++++ pumpamm_test.go | 1 + tx.go | 3 --- 6 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 pump_test.go diff --git a/example/geyser/cmd/main.go b/example/geyser/cmd/main.go index 1d115fb..d1a36fa 100644 --- a/example/geyser/cmd/main.go +++ b/example/geyser/cmd/main.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/shopspring/decimal" parser "github.com/thloyi/pump-parser" example "github.com/thloyi/pump-parser/example" "github.com/thloyi/pump-parser/example/geyser" @@ -21,7 +22,7 @@ func main() { ch := make(chan geyser.SubscriptionMessage, 1) go geyser.RunLoopWithReConnect(context.Background(), "127.0.0.1:10001", parser.SolProgramPump, ch) // var tokenTxs = make(map[string]*types.Tx) - currentBlock := uint64(0) + // currentBlock := uint64(0) for msg := range ch { if msg.Tx == nil { block := msg.Block @@ -42,9 +43,9 @@ func main() { //if tx.Program != parser.SolProgramPump { // continue //} - if currentBlock == ptx.Block { - continue - } + //if currentBlock == ptx.Block { + // continue + //} // 处理交易 txErr, ok := ptx.Err.(*geyser.TransactionError) @@ -64,11 +65,14 @@ func main() { if tx.Program != parser.SolProgramPump { continue } + if tx.Token1Amount.GreaterThanOrEqual(decimal.NewFromFloat(0.1)) || tx.Event != "buy" { + continue + } 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", 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) - break + //break } if !printed { continue @@ -79,7 +83,7 @@ func main() { // tx.BeforeSolBalance, tx.AfterSOLBalance, tx.AfterSignerToken0Balance, tx.TokenCreator, tx.Token0Program, tx.Mayhem) } - currentBlock = ptx.Block + // currentBlock = ptx.Block // //if tx.Event == "create" { // if err := pool.Submit(func() { diff --git a/meta.go b/meta.go index fc9e8dd..6090c8b 100644 --- a/meta.go +++ b/meta.go @@ -5,6 +5,7 @@ import ( ) var pumpProgram = solana.MustPublicKeyFromBase58("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P") +var pumpFeesProgram = solana.MustPublicKeyFromBase58("pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ") var pumpMigrationAccount = solana.MustPublicKeyFromBase58("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg") var mayhemFeeAccounts = []solana.PublicKey{ solana.MustPublicKeyFromBase58("GesfTA3X2arioaHp8bbKdjG9vJtskViWACZoYvxp4twS"), @@ -17,6 +18,7 @@ var mayhemFeeAccounts = []solana.PublicKey{ solana.MustPublicKeyFromBase58("6AUH3WEHucYZyC61hqpqYUWVto5qA5hjHuNQ32GNnNxA"), } +var pumpGetFeesDiscriminator = calculateDiscriminator("global:get_fees") var pumpBuyDiscriminator = calculateDiscriminator("global:buy") var pumpBuyV2Discriminator = calculateDiscriminator("global:buy_exact_sol_in") var pumpSellDiscriminator = calculateDiscriminator("global:sell") diff --git a/pump.go b/pump.go index b5847c8..1a600a0 100644 --- a/pump.go +++ b/pump.go @@ -174,6 +174,15 @@ type PumpTradeEvent struct { Fee uint64 Creator solana.PublicKey + + CreatorFeeBasisPoints uint64 + CreatorFee uint64 +} + +type PumpTradeFeeArg struct { + IsPump bool + MarketCap [16]byte + TradeSize uint64 } type CompleteEvent struct { @@ -189,8 +198,16 @@ func BuyOrSellParser(tx *Tx, instruction Instruction, innerInstructions InnerIns var err error var programIndex = instruction.ProgramIDIndex + feeEventProgramIndex := 0 + for i, b := range result.accountList { + if b.Equals(pumpFeesProgram) { + feeEventProgramIndex = i + break + } + } var ( tradeEvent PumpTradeEvent + tradeFeeArg PumpTradeFeeArg completeEvent CompleteEvent completed bool newoffset [2]uint @@ -203,6 +220,13 @@ func BuyOrSellParser(tx *Tx, instruction Instruction, innerInstructions InnerIns } 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 bytes.Equal(innerInstr.Data[8:16], pumpTradeEventDiscriminator[8:16]) { err = agbinary.NewBorshDecoder(innerInstr.Data[16:]).Decode(&tradeEvent) @@ -260,6 +284,14 @@ func BuyOrSellParser(tx *Tx, instruction Instruction, innerInstructions InnerIns 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{ { Program: SolProgramPump, @@ -274,7 +306,7 @@ func BuyOrSellParser(tx *Tx, instruction Instruction, innerInstructions InnerIns QuoteMintDecimals: 9, User: tradeEvent.User, BaseAmount: decimal.NewFromUint64(tradeEvent.TokenAmount), - QuoteAmount: decimal.NewFromUint64(tradeEvent.SolAmount), + QuoteAmount: decimal.NewFromUint64(solAmount), BaseReserve: decimal.NewFromUint64(tradeEvent.RealTokenReserves), QuoteReserve: decimal.NewFromUint64(tradeEvent.RealSolReserves), Mayhem: isMayhemPump(result.accountList[instruction.Accounts[1]]), diff --git a/pump_test.go b/pump_test.go new file mode 100644 index 0000000..92c8186 --- /dev/null +++ b/pump_test.go @@ -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) + +} diff --git a/pumpamm_test.go b/pumpamm_test.go index 4025428..6195662 100644 --- a/pumpamm_test.go +++ b/pumpamm_test.go @@ -38,4 +38,5 @@ func TestDecodePoolData(t *testing.T) { func TestAmmBuyEvent(t *testing.T) { fmt.Println(pumpAmmBuyEventDiscriminator) + fmt.Println(pumpGetFeesDiscriminator) } diff --git a/tx.go b/tx.go index e09c77f..9fd5cc6 100644 --- a/tx.go +++ b/tx.go @@ -1,8 +1,6 @@ package pump_parser import ( - "fmt" - "github.com/gagliardetto/solana-go" "github.com/mr-tron/base58" "github.com/shopspring/decimal" @@ -137,7 +135,6 @@ func (tx *Tx) CheckPlatform(swap Swap) (string, decimal.Decimal) { platform != PlatformFake { 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))) { - fmt.Printf("\n amount: %s, platform: %s, fee: %s \n", swap.QuoteAmount.Div(decimal.New(1, int32(swap.QuoteMintDecimals))), platform, platformFee.String()) platform = PlatformFake } 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))) {