Files
pump-parser/example/tx.go
2025-12-02 15:51:53 +08:00

237 lines
8.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package parser
import (
"time"
"github.com/gagliardetto/solana-go"
"github.com/jackc/pgtype"
"github.com/mr-tron/base58"
"github.com/shopspring/decimal"
parser "github.com/thloyi/pump-parser"
)
type Tx struct {
Err interface{} `json:"err,omitempty" gorm:"-"`
BondingCurve string `json:"bonding_curve" gorm:"-"`
PairAddress string `json:"pair_address"`
Maker string `json:"maker"`
Token0Address string `json:"token0_address"`
Token0Program string `json:"token0_program" gorm:"-"`
Token0Decimals uint8 `json:"token0_decimals" gorm:"-"`
Token1Address string `json:"token1_address"`
Token0Amount decimal.Decimal `json:"token0Amount" gorm:"column:token0_amount;type:numeric"`
Token1Amount decimal.Decimal `json:"token1Amount" gorm:"column:token1_amount;type:numeric"`
PriceUsd decimal.Decimal `json:"price_usd" gorm:"column:price_usd;type:numeric"`
AmountUsd decimal.Decimal `json:"amount_usd" gorm:"column:amount_usd;type:numeric"`
Block uint64 `json:"block"`
BlockIndex uint64 `json:"index"`
Event string `json:"event"`
CachedTxHash string `json:"tx_hash" gorm:"column:tx_hash"`
txHash *[64]byte `gorm:"-"`
TxIndex uint64 `json:"topic_index"`
Program string `json:"program"`
BlockAt pgtype.Timestamptz `gorm:"column:block_at;default:NULL" json:"block_at"`
CreatedAt *pgtype.Timestamptz `gorm:"autoCreateTime" json:"-"`
TotalSupply string `gorm:"total_supply"`
AfterReserve0 string `gorm:"after_reserve0"`
AfterReserve1 string `gorm:"after_reserve1"`
PositionChange int64 `gorm:"position_change"`
QuoteIsToken0 bool `gorm:"-"`
CurrentPrice decimal.Decimal `gorm:"-"`
TokenCreator string `gorm:"-"`
Platform string `gorm:"column:tx_platform;type:platform;default:'none'" json:"platform"`
MevAgent string `gorm:"column:tx_mev_agent;type:mev_agent;default:'none'" json:"tx_mev_agent"`
MevAgentFee decimal.Decimal `gorm:"column:tx_mev_agent_fee;type:numeric" json:"tx_mev_agent_fee"`
CUPrice decimal.Decimal `gorm:"column:tx_cu_price;type:numeric" json:"tx_cu_price"`
PlatformFee decimal.Decimal `gorm:"-"`
AfterSignerToken0Balance decimal.Decimal `gorm:"-" json:"-"`
BeforeSolBalance decimal.Decimal `gorm:"-" json:"-"`
AfterSOLBalance decimal.Decimal `gorm:"column:after_sol_balance;type:numeric" json:"after_sol_balance"`
EntryContract string `gorm:"column:tx_entry_contract;type:entry_contract;default:'none'" json:"tx_entry_contract"`
Mayhem bool
}
func (tx *Tx) GetTxHash() string {
if tx.CachedTxHash != "" {
return tx.CachedTxHash
}
if tx.txHash == nil {
return ""
}
tx.CachedTxHash = base58.Encode(tx.txHash[:])
return tx.CachedTxHash
}
func FromTx(tx *parser.Tx) []*Tx {
var txs = make([]*Tx, 0, len(tx.Swaps))
mev, mevFee := tx.CheckMevAgent()
for i, s := range tx.Swaps {
var newTx *Tx
platform, platformFee := tx.CheckPlatform(s)
token0Program := s.BaseTokenProgram
token0Address := s.BaseMint
token0Decimals := s.BaseMintDecimals
if s.Program == "Pump" {
quoteMint := s.QuoteMint
// 有些数据里 quote 会给 SystemProgram统一转成 WSOL
if quoteMint.Equals(solana.WrappedSol) || quoteMint.Equals(solana.SystemProgramID) {
quoteMint = solana.WrappedSol
}
newTx = &Tx{
Err: nil,
BondingCurve: s.Pool.String(),
//PairAddress: s.Pool.String(),
Maker: s.User.String(),
Token0Address: s.BaseMint.String(),
Token0Program: s.BaseTokenProgram.String(),
Token0Decimals: s.BaseMintDecimals,
Token1Address: quoteMint.String(),
Token0Amount: s.BaseAmount.Div(decimal.NewFromInt(1e6)),
Token1Amount: s.QuoteAmount.Div(decimal.NewFromInt(1e9)),
Block: tx.Block,
BlockIndex: tx.BlockIndex,
Event: s.Event,
CachedTxHash: "",
txHash: tx.TxHash,
TxIndex: uint64(i),
Program: s.Program,
BlockAt: pgtype.Timestamptz{
Time: time.Unix(tx.BlockAt, 0),
},
//CreatedAt: nil,
TotalSupply: "1000000000",
AfterReserve0: s.BaseReserve.Div(decimal.New(1, int32(s.BaseMintDecimals))).String(),
AfterReserve1: s.QuoteReserve.Div(decimal.New(1, int32(s.QuoteMintDecimals))).String(),
QuoteIsToken0: false,
// CurrentPrice: decimal.Decimal{},
TokenCreator: s.Creator.String(),
Platform: platform,
PlatformFee: platformFee,
MevAgent: mev,
MevAgentFee: mevFee,
CUPrice: tx.CUPrice,
AfterSignerToken0Balance: s.UserBaseBalance.Div(decimal.New(1, int32(s.BaseMintDecimals))),
BeforeSolBalance: tx.BeforeSolBalance,
AfterSOLBalance: tx.AfterSOLBalance,
EntryContract: s.CheckEntryContract(),
Mayhem: s.Mayhem,
}
} else if s.Program == "PumpAMM" {
if s.BaseMint.Equals(solana.WrappedSol) {
eventName := s.Event
if s.Event == "buy" {
eventName = "sell"
} else if s.Event == "sell" {
eventName = "buy"
}
token0Program = s.QuoteTokenProgram
token0Address = s.QuoteMint
token0Decimals = s.QuoteMintDecimals
newTx = &Tx{
Err: nil,
//BondingCurve: s.Pool.String(),
PairAddress: s.Pool.String(),
Maker: s.User.String(),
Token1Address: s.BaseMint.String(),
Token0Program: s.QuoteTokenProgram.String(),
Token0Decimals: s.QuoteMintDecimals,
Token0Address: s.QuoteMint.String(),
Token1Amount: s.BaseAmount.Div(decimal.New(1, int32(s.BaseMintDecimals))),
Token0Amount: s.QuoteAmount.Div(decimal.New(1, int32(s.QuoteMintDecimals))),
Block: tx.Block,
BlockIndex: tx.BlockIndex,
Event: eventName,
CachedTxHash: "",
txHash: tx.TxHash,
TxIndex: uint64(i),
Program: s.Program,
BlockAt: pgtype.Timestamptz{
Time: time.Unix(tx.BlockAt, 0),
},
//CreatedAt: nil,
TotalSupply: "1000000000",
AfterReserve1: s.BaseReserve.Div(decimal.New(1, int32(s.BaseMintDecimals))).String(),
AfterReserve0: s.QuoteReserve.Div(decimal.New(1, int32(s.QuoteMintDecimals))).String(),
QuoteIsToken0: true,
// CurrentPrice: decimal.Decimal{},
TokenCreator: s.Creator.String(),
Platform: platform,
PlatformFee: platformFee,
MevAgent: mev,
MevAgentFee: mevFee,
CUPrice: tx.CUPrice,
AfterSignerToken0Balance: s.UserQuoteBalance.Div(decimal.New(1, int32(s.QuoteMintDecimals))),
BeforeSolBalance: tx.BeforeSolBalance,
AfterSOLBalance: tx.AfterSOLBalance,
EntryContract: s.CheckEntryContract(),
Mayhem: s.Mayhem,
}
} else {
newTx = &Tx{
Err: nil,
//BondingCurve: s.Pool.String(),
PairAddress: s.Pool.String(),
Maker: s.User.String(),
Token0Address: s.BaseMint.String(),
Token0Program: s.BaseTokenProgram.String(),
Token0Decimals: s.BaseMintDecimals,
Token1Address: s.QuoteMint.String(),
Token0Amount: s.BaseAmount.Div(decimal.New(1, int32(s.BaseMintDecimals))),
Token1Amount: s.QuoteAmount.Div(decimal.New(1, int32(s.QuoteMintDecimals))),
Block: tx.Block,
BlockIndex: tx.BlockIndex,
Event: s.Event,
CachedTxHash: "",
txHash: tx.TxHash,
TxIndex: uint64(i),
Program: s.Program,
BlockAt: pgtype.Timestamptz{
Time: time.Unix(tx.BlockAt, 0),
},
//CreatedAt: nil,
TotalSupply: "1000000000",
AfterReserve0: s.BaseReserve.Div(decimal.New(1, int32(s.BaseMintDecimals))).String(),
AfterReserve1: s.QuoteReserve.Div(decimal.New(1, int32(s.QuoteMintDecimals))).String(),
QuoteIsToken0: false,
// CurrentPrice: decimal.Decimal{},
TokenCreator: s.Creator.String(),
Platform: platform,
PlatformFee: platformFee,
MevAgent: mev,
MevAgentFee: mevFee,
CUPrice: tx.CUPrice,
AfterSignerToken0Balance: s.UserBaseBalance.Div(decimal.New(1, int32(s.BaseMintDecimals))),
BeforeSolBalance: tx.BeforeSolBalance,
AfterSOLBalance: tx.AfterSOLBalance,
EntryContract: s.CheckEntryContract(),
Mayhem: s.Mayhem,
}
}
}
if newTx == nil {
continue
}
if newTx.Maker == "HV1KXxWFaSeriyFvXyx48FqG9BoFbfinB8njCJonqP7K" && newTx.EntryContract == "oKXAggregatorV2" {
newTx.Maker = tx.Signer.String()
newTx.AfterSignerToken0Balance = tx.GetSignerTokenBalanceAfterTx(token0Program, token0Address).Div(decimal.New(1, int32(token0Decimals)))
}
txs = append(txs, newTx)
}
return txs
}