Compare commits

..

5 Commits

Author SHA1 Message Date
bijianing97
7a82990770 Update meteoradlmm remove and add enum 2026-03-16 10:14:50 +08:00
bijianing97
e82bcb3c07 Merge remote-tracking branch 'origin' 2026-03-12 16:22:09 +08:00
bijianing97
a74f769064 Add raydiumv4 swapv2 2026-03-12 16:21:38 +08:00
thloyi
1e276e8bd2 [tx] swap inner idx 2026-03-12 13:49:34 +08:00
thloyi
eb2bde98ac update parsed tx: add swap at instr idx 2026-03-12 13:49:34 +08:00
5 changed files with 113 additions and 4 deletions

View File

@@ -202,6 +202,8 @@ const (
raydiumV4SwapBaseInDiscriminator = uint8(9) raydiumV4SwapBaseInDiscriminator = uint8(9)
raydiumV4SwapBaseOutDiscriminator = uint8(11) raydiumV4SwapBaseOutDiscriminator = uint8(11)
raydiumV4SwapBaseInV2Discriminator = uint8(16)
raydiumV4SwapBaseOutV2Discriminator = uint8(17)
raydiumV4AddLiquidityDiscriminator = uint8(3) raydiumV4AddLiquidityDiscriminator = uint8(3)
raydiumV4RemoveLiquidityDiscriminator = uint8(4) raydiumV4RemoveLiquidityDiscriminator = uint8(4)

View File

@@ -634,7 +634,7 @@ func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstruc
swap := Swap{ swap := Swap{
Program: SolProgramMeteoraDLMM, Program: SolProgramMeteoraDLMM,
Event: "add_liquidity", Event: "add",
Pool: pool, Pool: pool,
BaseMint: baseMint, BaseMint: baseMint,
QuoteMint: quoteMint, QuoteMint: quoteMint,
@@ -802,7 +802,7 @@ func metaoradlmmRemoveLiquidityParser(tx *Tx, instruction Instruction, innerInst
swap := Swap{ swap := Swap{
Program: SolProgramMeteoraDLMM, Program: SolProgramMeteoraDLMM,
Event: "remove_liquidity", Event: "remove",
Pool: pool, Pool: pool,
BaseMint: baseMint, BaseMint: baseMint,
QuoteMint: quoteMint, QuoteMint: quoteMint,

View File

@@ -127,6 +127,9 @@ func (tx *Tx) Parser() error {
//fmt.Printf("parser failed tx error: %s, block: %d tx: %s\n", err, tx.Block, tx.GetTxHash()) //fmt.Printf("parser failed tx error: %s, block: %d tx: %s\n", err, tx.Block, tx.GetTxHash())
} }
if len(swaps) > 0 { if len(swaps) > 0 {
for i := range swaps {
swaps[i].InstrIdx = tx.Err.Index
}
tx.Swaps = swaps tx.Swaps = swaps
} }
for i, instr := range tx.rawTx.Transaction.Message.Instructions { for i, instr := range tx.rawTx.Transaction.Message.Instructions {
@@ -172,6 +175,7 @@ func (tx *Tx) Parser() error {
swap.AfterSOLBalance = decimal.NewFromUint64(tx.rawTx.Meta.PostBalances[userIdx]).Div(decimal.NewFromInt(1e9)) swap.AfterSOLBalance = decimal.NewFromUint64(tx.rawTx.Meta.PostBalances[userIdx]).Div(decimal.NewFromInt(1e9))
} }
} }
swap.InstrIdx = uint8(i)
tx.Swaps = append(tx.Swaps, swap) tx.Swaps = append(tx.Swaps, swap)
} }
@@ -219,6 +223,8 @@ func (tx *Tx) Parser() error {
swap.AfterSOLBalance = decimal.NewFromUint64(tx.rawTx.Meta.PostBalances[userIdx]).Div(decimal.NewFromInt(1e9)) swap.AfterSOLBalance = decimal.NewFromUint64(tx.rawTx.Meta.PostBalances[userIdx]).Div(decimal.NewFromInt(1e9))
} }
} }
swap.InstrIdx = uint8(i)
swap.InnerIdx = uint8(j)
tx.Swaps = append(tx.Swaps, swap) tx.Swaps = append(tx.Swaps, swap)
} }
// tx.Swaps = append(tx.Swaps, swaps...) // tx.Swaps = append(tx.Swaps, swaps...)

View File

@@ -29,6 +29,8 @@ func raydiumV4Parser(tx *Tx, instruction Instruction, innerInstructions InnerIns
return raydiumv4WithdrawPNLParser(tx, instruction, innerInstructions, offset) return raydiumv4WithdrawPNLParser(tx, instruction, innerInstructions, offset)
case raydiumV4SwapBaseInDiscriminator, raydiumV4SwapBaseOutDiscriminator: case raydiumV4SwapBaseInDiscriminator, raydiumV4SwapBaseOutDiscriminator:
return raydiumv4SwapParser(tx, instruction, innerInstructions, offset) return raydiumv4SwapParser(tx, instruction, innerInstructions, offset)
case raydiumV4SwapBaseInV2Discriminator, raydiumV4SwapBaseOutV2Discriminator:
return raydiumv4SwapV2Parser(tx, instruction, innerInstructions, offset)
default: default:
return nil, increaseOffset(offset), InstructionIgnoredError return nil, increaseOffset(offset), InstructionIgnoredError
@@ -397,3 +399,99 @@ func raydiumv4SwapParser(tx *Tx, instruction Instruction, innerInstructions Inne
}, },
}, offset, nil }, offset, nil
} }
func raydiumv4SwapV2Parser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
accountsLen := len(instruction.Accounts)
if accountsLen != 8 {
return nil, increaseOffset(offset), fmt.Errorf("invalid number of accounts for raydiumv4 swapv2 instruction, offset %d, %d", offset[0], offset[1])
}
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
ammAccount := tx.rawTx.accountList[instruction.Accounts[1]]
user := tx.rawTx.accountList[instruction.Accounts[7]]
userSourceTokenAccount := tx.rawTx.accountList[instruction.Accounts[5]]
userDestinationTokenAccount := tx.rawTx.accountList[instruction.Accounts[6]]
baseVaultIdx := instruction.Accounts[3]
quoteVaultIdx := instruction.Accounts[4]
baseTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultIdx)
if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("failed to get base vault balance after tx: %v", err)
}
quoteTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, quoteVaultIdx)
if err != nil {
return nil, increaseOffset(offset), fmt.Errorf("failed to get quote vault balance after tx: %v", err)
}
inners, err := getInnerInstructions(innerInstructions, offset[1])
if err != nil {
return nil, increaseOffset(offset), err
}
var nextIndex int
var srcFound, destFound bool
var baseAmount, quoteAmount decimal.Decimal
var event string
for i, inner := range inners {
from, to, amount, err := parseTokenTransfer(tx.rawTx, inner)
if err != nil {
continue
}
if from.Equals(userSourceTokenAccount) && !srcFound {
if to.Equals(tx.rawTx.accountList[baseVaultIdx]) {
event = "sell"
baseAmount = decimal.NewFromUint64(amount)
srcFound = true
} else if to.Equals(tx.rawTx.accountList[quoteVaultIdx]) {
event = "buy"
quoteAmount = decimal.NewFromUint64(amount)
srcFound = true
}
} else if to.Equals(userDestinationTokenAccount) && !destFound {
if from.Equals(tx.rawTx.accountList[quoteVaultIdx]) {
event = "sell"
quoteAmount = decimal.NewFromUint64(amount)
destFound = true
} else if from.Equals(tx.rawTx.accountList[baseVaultIdx]) {
event = "buy"
baseAmount = decimal.NewFromUint64(amount)
destFound = true
}
}
if srcFound && destFound {
nextIndex = i + 1
break
}
}
if !srcFound || !destFound {
return nil, increaseOffset(offset), fmt.Errorf("raydiumv4 failed to find token transfer inner instruction for swapv2, offset %d, %d", offset[0], offset[1])
}
offset[1] += uint(nextIndex + 1)
userBase := getAccountBalanceAfterTx(tx.rawTx, instruction.Accounts[5])
userQuote := getAccountBalanceAfterTx(tx.rawTx, instruction.Accounts[6])
baseReserve, _ := decimal.NewFromString(baseTokenbalance.UITokenAmount.Amount)
quoteReserve, _ := decimal.NewFromString(quoteTokenbalance.UITokenAmount.Amount)
return []Swap{
{
Program: SolProgramRaydiumV4,
Event: event,
Pool: ammAccount,
BaseMint: baseTokenbalance.MintAccount,
QuoteMint: quoteTokenbalance.MintAccount,
BaseTokenProgram: baseTokenbalance.ProgramIDAccount,
QuoteTokenProgram: quoteTokenbalance.ProgramIDAccount,
BaseMintDecimals: uint8(baseTokenbalance.UITokenAmount.Decimals),
QuoteMintDecimals: uint8(quoteTokenbalance.UITokenAmount.Decimals),
User: user,
BaseAmount: baseAmount,
QuoteAmount: quoteAmount,
BaseReserve: baseReserve,
QuoteReserve: quoteReserve,
Mayhem: false,
UserBaseBalance: userBase,
UserQuoteBalance: userQuote,
EntryContract: entryContract,
},
}, offset, nil
}

3
tx.go
View File

@@ -12,6 +12,9 @@ type Swap struct {
TxIndex int TxIndex int
InstrIdx uint8
InnerIdx uint8
Pool solana.PublicKey Pool solana.PublicKey
BaseMint solana.PublicKey BaseMint solana.PublicKey
QuoteMint solana.PublicKey QuoteMint solana.PublicKey