230 lines
8.5 KiB
Go
230 lines
8.5 KiB
Go
|
|
package example
|
||
|
|
|
||
|
|
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, raw *parser.RawTx) []*Tx {
|
||
|
|
var txs []*Tx = make([]*Tx, 0, len(tx.Swaps))
|
||
|
|
mev, mevFee := tx.CheckMevAgent()
|
||
|
|
for i, s := range tx.Swaps {
|
||
|
|
var newTx *Tx
|
||
|
|
platform, platformFee := tx.CheckPlatform(s, raw)
|
||
|
|
token0Program := s.BaseTokenProgram
|
||
|
|
token0Address := s.BaseMint
|
||
|
|
if s.Program == "Pump" {
|
||
|
|
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: "",
|
||
|
|
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
|
||
|
|
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 = parser.GetTokenBalanceAfterTx(raw, 0, token0Program, token0Address)
|
||
|
|
}
|
||
|
|
|
||
|
|
txs = append(txs, newTx)
|
||
|
|
}
|
||
|
|
return txs
|
||
|
|
}
|