Files
pump-parser/tx.go
2026-03-19 14:10:14 +08:00

241 lines
5.2 KiB
Go

package pump_parser
import (
"github.com/gagliardetto/solana-go"
"github.com/mr-tron/base58"
"github.com/shopspring/decimal"
)
type Swap struct {
Program string
Event string
TxIndex int
InstrIdx uint8
InnerIdx uint8
Pool solana.PublicKey
BaseMint solana.PublicKey
QuoteMint solana.PublicKey
BaseTokenProgram solana.PublicKey
QuoteTokenProgram solana.PublicKey
Creator solana.PublicKey
BaseMintDecimals uint8
QuoteMintDecimals uint8
User solana.PublicKey
BaseAmount decimal.Decimal
QuoteAmount decimal.Decimal
BaseReserve decimal.Decimal
QuoteReserve decimal.Decimal
Mayhem bool
Cashback bool
UserBaseBalance decimal.Decimal
UserQuoteBalance decimal.Decimal
EntryContract solana.PublicKey
MigrateToPool solana.PublicKey
MigrateTopProgram solana.PublicKey
LpMint solana.PublicKey
AfterSOLBalance decimal.Decimal
//For meteora dlmm
ActiveBinId int32
StartBinId int32
EndBinId int32
RemoveBp int32
BinChanges []DlmmBinLiquidityChange
PositionAccount solana.PublicKey
ConsumeUnit uint64
}
type DlmmBinLiquidityChange struct {
BinId int32
AmountX decimal.Decimal
AmountY decimal.Decimal
BpsToRemove uint16
}
type platformInfo struct {
Platform string
PlatformFee decimal.Decimal
}
type mevInfo struct {
MevAgent string
MevAgentFee decimal.Decimal
}
type SolTransfer struct {
From solana.PublicKey
To solana.PublicKey
Amount decimal.Decimal
}
type ChainLink struct {
Timestamp int64
Price decimal.Decimal
}
type Tx struct {
rawTx *RawTx
Vote bool
Signer solana.PublicKey
Err *TransactionParsedError `json:"err,omitempty"`
Swaps []Swap `json:"swaps,omitempty"`
SolTransfer []SolTransfer `json:"sol_transfer,omitempty"`
Block uint64 `json:"block"`
ChainLink ChainLink `json:"chain_link"`
BlockIndex uint64 `json:"index"`
TxHash *[64]byte `json:"-"`
BlockAt int64 `json:"block_at"`
CuFee decimal.Decimal `json:"cu_fee"`
cachedTxHash string
Platform map[string]platformInfo `json:"platform"`
MevAgent map[string]mevInfo ` json:"tx_mev_agent"`
CUPrice decimal.Decimal ` json:"tx_cu_price"`
BeforeSolBalance decimal.Decimal `json:"-"`
AfterSOLBalance decimal.Decimal `json:"after_sol_balance"`
// update tokenInfo
Token map[solana.PublicKey]TokenMeta `gorm:"-"`
ComputeUnitsConsumed uint64 `json:"compute_units_consumed"`
CuLimit uint32 `json:"cu_limit"`
// todo pool info ??
}
func (tx *Tx) GetRawTx() *RawTx {
return tx.rawTx
}
func (tx *Tx) SetRawTx(t *RawTx) {
tx.rawTx = t
}
func (tx *Tx) GetSignerTokenBalanceAfterTx(tokenProgram, tokenMint solana.PublicKey) decimal.Decimal {
return GetTokenBalanceAfterTx(tx.rawTx, 0, tokenProgram, tokenMint)
}
type TokenMeta struct {
Mint solana.PublicKey `json:"address"`
TokenProgram solana.PublicKey `json:"token_program"`
Decimals uint8 `json:"decimals"`
Name string
Symbol string
Url string
TotalSupply *decimal.Decimal
}
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 (tx *Tx) CheckPlatform(swap Swap) (string, decimal.Decimal) {
// hasSolProgramRaydiumLaunchLabBonk
var platform string
var platformFee decimal.Decimal
if len(tx.Platform) == 0 {
return PlatformNone, decimal.Zero
}
for p, info := range tx.Platform {
platform = p
platformFee = info.PlatformFee
break
}
quoteAmount := swap.QuoteAmount
if swap.BaseMint.Equals(solana.WrappedSol) {
quoteAmount = swap.BaseAmount
}
if platform != "" &&
platform != PlatformFake &&
platformFee.LessThan(quoteAmount.Mul(decimal.NewFromInt(9)).Div(decimal.New(10000, 9))) {
platform = PlatformFake
}
if platform == "" {
platform = PlatformNone
}
return platform, platformFee
}
func (tx *Tx) CheckMevAgent() (string, decimal.Decimal) {
var mevAgent = MevAgentUnknown
var mevAgentFee = decimal.Zero
for m, info := range tx.MevAgent {
if len(tx.MevAgent) > 1 && info.MevAgent == MevAgentUnknown {
continue
}
mevAgent = m
mevAgentFee = info.MevAgentFee
break
}
if len(tx.MevAgent) == 0 && mevAgent == MevAgentUnknown {
// set the mev agent to none if the platform does not exist
return "", decimal.Zero
}
return mevAgent, mevAgentFee
}
func (s Swap) CheckEntryContract() string {
name, ok := entryContractAddresses[s.EntryContract]
if ok {
return name
}
return EntryContractUnknown
}
func (tx *Tx) LoadAfterSOLBalance(swap Swap) decimal.Decimal {
if swap.User.Equals(tx.Signer) {
return tx.AfterSOLBalance
}
found := false
makerIndex := 0
for i, account := range tx.rawTx.getAccountList() {
if account == swap.User {
found = true
makerIndex = i
break
}
}
if found && makerIndex < len(tx.rawTx.Meta.PostBalances) {
return decimal.NewFromInt(
int64(tx.rawTx.Meta.PostBalances[makerIndex]),
).Div(decimal.NewFromInt(1000000000)) // sol decimals
}
return decimal.Zero
}
func (s Swap) CheckEntryContractV2() string {
name, ok := entryContractAddresses[s.EntryContract]
if ok {
return name
}
return s.EntryContract.String()
}