Compare commits

...

4 Commits

Author SHA1 Message Date
cachalots
56dac04a2a fix culimit 2026-02-12 10:11:29 +08:00
cachalots
852ad4b382 cu limit 2026-02-11 17:49:43 +08:00
thloyi
3fdd4c4490 fix parse error 2026-02-11 14:58:12 +08:00
thloyi
40012b531c fix meteora pool entrycontract 2026-02-10 10:32:46 +08:00
12 changed files with 46 additions and 31 deletions

View File

@@ -27,10 +27,11 @@ func budgetParser(tx *Tx, instr Instruction, _ InnerInstructions, offset [2]uint
} }
} }
func computeUnitLimitParser(offset [2]uint, _ *Tx, decodedData []byte) ([2]uint, error) { func computeUnitLimitParser(offset [2]uint, tx *Tx, decodedData []byte) ([2]uint, error) {
if len(decodedData) < 8 { if len(decodedData) < 4 {
return increaseOffset(offset), nil return increaseOffset(offset), nil
} }
tx.CuLimit = binary.LittleEndian.Uint32(decodedData[:4])
return increaseOffset(offset), nil return increaseOffset(offset), nil
} }

View File

@@ -31,6 +31,7 @@ func main() {
continue continue
} }
ptx := msg.Tx ptx := msg.Tx
fmt.Println("consume", ptx.ComputeUnitsConsumed, "limit", ptx.CuLimit, "hash", ptx.GetTxHash())
//data, _ := json.Marshal(tx) //data, _ := json.Marshal(tx)
//fmt.Println(string(data)) //fmt.Println(string(data))
//continue //continue

View File

@@ -23,7 +23,7 @@ var ()
func main() { func main() {
var slot uint64 = 399060766 var slot uint64 = 399477968
var data = NewBlockData(decimal.NewFromFloat(100.0)) var data = NewBlockData(decimal.NewFromFloat(100.0))
client := rpc.New("https://staked.helius-rpc.com?api-key=5adcf1f9-5719-43d1-bf3f-c2d4e1e5f94d") client := rpc.New("https://staked.helius-rpc.com?api-key=5adcf1f9-5719-43d1-bf3f-c2d4e1e5f94d")
var rewards = false var rewards = false

View File

@@ -234,5 +234,6 @@ var transferDiscriminator = uint32(2)
var createAccountWithSeedDiscriminator = uint32(3) var createAccountWithSeedDiscriminator = uint32(3)
var systemProgram = solana.MustPublicKeyFromBase58("11111111111111111111111111111111") var systemProgram = solana.MustPublicKeyFromBase58("11111111111111111111111111111111")
var momoProgram = solana.MustPublicKeyFromBase58("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr")
var eventDiscriminator = [8]byte{228, 69, 165, 46, 81, 203, 154, 29} var eventDiscriminator = [8]byte{228, 69, 165, 46, 81, 203, 154, 29}

View File

@@ -371,6 +371,7 @@ func metaoraPoolAddLiquidity(tx *Tx, instruction Instruction, innerInstructions
if len(instruction.Accounts) < 14 { if len(instruction.Accounts) < 14 {
return nil, increaseOffset(offset), fmt.Errorf("invalid instruction accounts length") return nil, increaseOffset(offset), fmt.Errorf("invalid instruction accounts length")
} }
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
pool := tx.rawTx.accountList[instruction.Accounts[0]] pool := tx.rawTx.accountList[instruction.Accounts[0]]
lpMint := tx.rawTx.accountList[instruction.Accounts[1]] lpMint := tx.rawTx.accountList[instruction.Accounts[1]]
@@ -494,8 +495,6 @@ func metaoraPoolAddLiquidity(tx *Tx, instruction Instruction, innerInstructions
return nil, increaseOffset(offset), fmt.Errorf("failed to find deposit instructions") return nil, increaseOffset(offset), fmt.Errorf("failed to find deposit instructions")
} }
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
var event = "add_liquidity_one_side" var event = "add_liquidity_one_side"
if baseFound && quoteFound { if baseFound && quoteFound {
// both sides // both sides
@@ -530,6 +529,7 @@ func metaoraPoolRemoveLiquidity(tx *Tx, instruction Instruction, innerInstructio
if len(instruction.Accounts) < 14 { if len(instruction.Accounts) < 14 {
return nil, increaseOffset(offset), fmt.Errorf("invalid instruction accounts length") return nil, increaseOffset(offset), fmt.Errorf("invalid instruction accounts length")
} }
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
pool := tx.rawTx.accountList[instruction.Accounts[0]] pool := tx.rawTx.accountList[instruction.Accounts[0]]
lpMint := tx.rawTx.accountList[instruction.Accounts[1]] lpMint := tx.rawTx.accountList[instruction.Accounts[1]]
@@ -700,8 +700,6 @@ func metaoraPoolRemoveLiquidity(tx *Tx, instruction Instruction, innerInstructio
return nil, increaseOffset(offset), fmt.Errorf("failed to find withdraw instructions, baseFound: %v, quoteFound: %v", baseFound, quoteFound) return nil, increaseOffset(offset), fmt.Errorf("failed to find withdraw instructions, baseFound: %v, quoteFound: %v", baseFound, quoteFound)
} }
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
var event = "remove_liquidity_one_side" var event = "remove_liquidity_one_side"
if baseFound && quoteFound { if baseFound && quoteFound {
event = "remove_liquidity" event = "remove_liquidity"

View File

@@ -90,7 +90,7 @@ func meteoraDammV2InitializePoolParser(tx *Tx, instruction Instruction, innerIns
var prefixLen = offset[1] var prefixLen = offset[1]
inners, err := getInnerInstructions(innerInstructions, prefixLen) inners, err := getInnerInstructions(innerInstructions, prefixLen)
if err != nil { if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("meta Bonding Curve initial get inner instructions error: %v, offset, %d, %d", err, offset[0], offset[1]) return nil, increaseOffset(offset), fmt.Errorf("meta damm initial get inner instructions error: %v, offset, %d, %d", err, offset[0], offset[1])
} }
var loadedEvent bool var loadedEvent bool
var initializePoolEvent MetaoraDammInitializePoolEvent var initializePoolEvent MetaoraDammInitializePoolEvent
@@ -119,6 +119,13 @@ func meteoraDammV2InitializePoolParser(tx *Tx, instruction Instruction, innerIns
} }
baseVaultAccountIndex := instruction.Accounts[10] baseVaultAccountIndex := instruction.Accounts[10]
quoteVaultAccountIndex := instruction.Accounts[11] quoteVaultAccountIndex := instruction.Accounts[11]
if bytes.Equal(instruction.Data[:8], meteoraDammV2InitializePoolWithDynamicConfig[:]) {
baseVaultAccountIndex = instruction.Accounts[11]
quoteVaultAccountIndex = instruction.Accounts[12]
} else if bytes.Equal(instruction.Data[:8], meteoraDammV2InitializeCustomizablePoolDiscriminator[:]) {
baseVaultAccountIndex = instruction.Accounts[9]
quoteVaultAccountIndex = instruction.Accounts[10]
}
baseVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultAccountIndex) baseVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultAccountIndex)
if err != nil { if err != nil {

View File

@@ -848,11 +848,11 @@ func orcaWhirPoolSwapV2Parser(tx *Tx, instruction Instruction, innerInstructions
var baseFound, quoteFound bool var baseFound, quoteFound bool
var skipOffset = 0 var skipOffset = 0
for i, inner := range inners { for i, inner := range inners {
from, to, amount, err := parseTokenTransfer(tx.rawTx, inner) if !tx.rawTx.accountList[inner.ProgramIDIndex].Equals(solana.Token2022ProgramID) && !tx.rawTx.accountList[inner.ProgramIDIndex].Equals(solana.TokenProgramID) {
if err != nil {
if i <= 1 { //maybe momo??
continue continue
} }
from, to, amount, err := parseTokenTransfer(tx.rawTx, inner)
if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("orca whirpool swapv2 parse token transfer error: %v, offset, %d, %d", err, offset[0], offset[1]) return nil, increaseOffset(offset), fmt.Errorf("orca whirpool swapv2 parse token transfer error: %v, offset, %d, %d", err, offset[0], offset[1])
} }
if !baseFound && (from.Equals(vault0Account) || to.Equals(vault0Account)) { if !baseFound && (from.Equals(vault0Account) || to.Equals(vault0Account)) {
@@ -1010,11 +1010,11 @@ func orcaWhirPoolTwoHopSwapParser(tx *Tx, instruction Instruction, innerInstruct
{ {
baseTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, pool2VaultBase) baseTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, pool2VaultBase)
if err != nil { if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("failed to get pool1 token0 vault balance after tx: %v", err) return nil, increaseOffset(offset), fmt.Errorf("failed to get pool2 token0 vault balance after tx: %v", err)
} }
quoteTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, pool2VaultQuote) quoteTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, pool2VaultQuote)
if err != nil { if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("failed to get pool1 token1 vault balance after tx: %v", err) return nil, increaseOffset(offset), fmt.Errorf("failed to get pool2 token1 vault balance after tx: %v", err)
} }
userBase := getAccountBalanceAfterTx(tx.rawTx, pool2UserBase) userBase := getAccountBalanceAfterTx(tx.rawTx, pool2UserBase)
@@ -1105,8 +1105,8 @@ func orcaWhirPoolTwoHopSwapV2Parser(tx *Tx, instruction Instruction, innerInstru
//pool2UserBase := instruction.Accounts[8] //pool2UserBase := instruction.Accounts[8]
pool2VaultBase := instruction.Accounts[11] pool2VaultBase := instruction.Accounts[11]
pool2UserQuote := instruction.Accounts[12] pool2VaultQuote := instruction.Accounts[12]
pool2VaultQuote := instruction.Accounts[13] pool2UserQuote := instruction.Accounts[13]
swaps := make([]Swap, 2) swaps := make([]Swap, 2)
{ {
@@ -1186,11 +1186,11 @@ func orcaWhirPoolTwoHopSwapV2Parser(tx *Tx, instruction Instruction, innerInstru
{ {
baseTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, pool2VaultBase) baseTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, pool2VaultBase)
if err != nil { if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("failed to get pool1 token0 vault balance after tx: %v", err) return nil, increaseOffset(offset), fmt.Errorf("failed to get pool2 token0 vault balance after tx: %v", err)
} }
quoteTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, pool2VaultQuote) quoteTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, pool2VaultQuote)
if err != nil { if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("failed to get pool1 token1 vault balance after tx: %v", err) return nil, increaseOffset(offset), fmt.Errorf("failed to get pool2 token1 vault balance after tx: %v", err)
} }
userBase := decimal.Zero userBase := decimal.Zero

View File

@@ -91,6 +91,7 @@ func (tx *Tx) Parser() error {
tx.BlockAt = tx.rawTx.BlockTime tx.BlockAt = tx.rawTx.BlockTime
tx.CuFee = decimal.NewFromUint64(tx.rawTx.Meta.Fee) tx.CuFee = decimal.NewFromUint64(tx.rawTx.Meta.Fee)
tx.ComputeUnitsConsumed = tx.rawTx.Meta.ComputeUnitsConsumed
tx.BeforeSolBalance = decimal.NewFromUint64(tx.rawTx.Meta.PreBalances[0]).Div(decimal.NewFromInt(1e9)) tx.BeforeSolBalance = decimal.NewFromUint64(tx.rawTx.Meta.PreBalances[0]).Div(decimal.NewFromInt(1e9))
tx.AfterSOLBalance = decimal.NewFromUint64(tx.rawTx.Meta.PostBalances[0]).Div(decimal.NewFromInt(1e9)) tx.AfterSOLBalance = decimal.NewFromUint64(tx.rawTx.Meta.PostBalances[0]).Div(decimal.NewFromInt(1e9))

View File

@@ -156,6 +156,7 @@ type Meta struct {
PreBalances []uint64 `json:"preBalances"` PreBalances []uint64 `json:"preBalances"`
PreTokenBalances []TokenBalance `json:"preTokenBalances"` PreTokenBalances []TokenBalance `json:"preTokenBalances"`
Rewards []interface{} `json:"rewards"` Rewards []interface{} `json:"rewards"`
ComputeUnitsConsumed uint64 `json:"computeUnitsConsumed"`
} }
type Header struct { type Header struct {
NumReadonlySignedAccounts int `json:"numReadonlySignedAccounts"` NumReadonlySignedAccounts int `json:"numReadonlySignedAccounts"`
@@ -805,7 +806,7 @@ func ConvertYellowstoneGrpcTransactionToSolanaTransaction(y *pb.SubscribeUpdateT
} }
sTx.Meta.Fee = meta.Fee sTx.Meta.Fee = meta.Fee
//sTx.Meta.InnerInstructions = meta.InnerInstructions //sTx.Meta.InnerInstructions = meta.InnerInstructions
sTx.Meta.ComputeUnitsConsumed = *meta.ComputeUnitsConsumed
for _, innerInstr := range meta.InnerInstructions { for _, innerInstr := range meta.InnerInstructions {
var instrs []Instruction var instrs []Instruction
for _, instr := range innerInstr.Instructions { for _, instr := range innerInstr.Instructions {

View File

@@ -54,12 +54,12 @@ func raydiumCPmmCreatePoolParser(tx *Tx, instruction Instruction, innerInstructi
vault1 = instruction.Accounts[12] vault1 = instruction.Accounts[12]
} }
baseTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, instruction.Accounts[vault0]) baseTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, vault0)
if err != nil { if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("failed to get token0 vault balance after tx: %v", err) return nil, increaseOffset(offset), fmt.Errorf("failed to get token0 vault balance after tx: %v", err)
} }
quoteTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, instruction.Accounts[vault1]) quoteTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, vault1)
if err != nil { if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("failed to get token1 vault balance after tx: %v", err) return nil, increaseOffset(offset), fmt.Errorf("failed to get token1 vault balance after tx: %v", err)
} }

View File

@@ -143,7 +143,7 @@ type RaydiumLaunchLabCreateEvent struct {
} }
func raydiumLaunchLabInitializeParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) { func raydiumLaunchLabInitializeParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
if len(instruction.Accounts) < 16 { if len(instruction.Accounts) < 15 {
return nil, increaseOffset(offset), fmt.Errorf("not enough accounts for initialize instruction") return nil, increaseOffset(offset), fmt.Errorf("not enough accounts for initialize instruction")
} }
user := tx.rawTx.accountList[instruction.Accounts[0]] user := tx.rawTx.accountList[instruction.Accounts[0]]

5
tx.go
View File

@@ -47,6 +47,8 @@ type Swap struct {
StartBinId int32 StartBinId int32
EndBinId int32 EndBinId int32
BinChanges []DlmmBinLiquidityChange BinChanges []DlmmBinLiquidityChange
ConsumeUnit uint64
} }
type DlmmBinLiquidityChange struct { type DlmmBinLiquidityChange struct {
@@ -98,6 +100,9 @@ type Tx struct {
// update tokenInfo // update tokenInfo
Token map[solana.PublicKey]TokenMeta `gorm:"-"` Token map[solana.PublicKey]TokenMeta `gorm:"-"`
ComputeUnitsConsumed uint64 `json:"compute_units_consumed"`
CuLimit uint32 `json:"cu_limit"`
// todo pool info ?? // todo pool info ??
} }