all parser
This commit is contained in:
399
raydiumv4.go
Normal file
399
raydiumv4.go
Normal file
@@ -0,0 +1,399 @@
|
||||
package pump_parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
func raydiumV4Parser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
if !tx.rawTx.accountList[instruction.ProgramIDIndex].Equals(raydiumV4Program) {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("raydiumv4 instruction not found, offset, %d, %d", offset[0], offset[1])
|
||||
}
|
||||
|
||||
decode := instruction.Data
|
||||
if len(decode) < 1 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("raydiumv4 program instruction data too short, offset, %d, %d", offset[0], offset[1])
|
||||
}
|
||||
|
||||
discriminator := decode[0]
|
||||
|
||||
switch discriminator {
|
||||
case raydiumV4InitializePoolDiscriminator:
|
||||
return raydiumv4InitializeParser(tx, instruction, innerInstructions, offset)
|
||||
case raydiumV4AddLiquidityDiscriminator:
|
||||
return raydiumv4AddLiquidityParser(tx, instruction, innerInstructions, offset)
|
||||
case raydiumV4RemoveLiquidityDiscriminator:
|
||||
return raydiumv4RemoveLiquidityParser(tx, instruction, innerInstructions, offset)
|
||||
case raydiumV4WithdrawPNLDiscriminator:
|
||||
return raydiumv4WithdrawPNLParser(tx, instruction, innerInstructions, offset)
|
||||
case raydiumV4SwapBaseInDiscriminator, raydiumV4SwapBaseOutDiscriminator:
|
||||
return raydiumv4SwapParser(tx, instruction, innerInstructions, offset)
|
||||
|
||||
default:
|
||||
return nil, increaseOffset(offset), InstructionIgnoredError
|
||||
}
|
||||
}
|
||||
|
||||
func raydiumv4InitializeParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
accountsLen := len(instruction.Accounts)
|
||||
if accountsLen != 21 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("invalid number of accounts for raydiumv4 initialize instruction, offset %d, %d", offset[0], offset[1])
|
||||
}
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
//who := tx.rawTx.accountList[instruction.Accounts[accountsLen-1]]
|
||||
user := tx.rawTx.accountList[instruction.Accounts[accountsLen-4]]
|
||||
baseVaultIdx := instruction.Accounts[10]
|
||||
quoteVaultIdx := instruction.Accounts[11]
|
||||
|
||||
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)
|
||||
}
|
||||
baseReserve, _ := decimal.NewFromString(baseTokenbalance.UITokenAmount.Amount)
|
||||
quoteReserve, _ := decimal.NewFromString(quoteTokenbalance.UITokenAmount.Amount)
|
||||
offset[1] += 30
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramRaydiumV4,
|
||||
Event: "create",
|
||||
Pool: tx.rawTx.accountList[instruction.Accounts[4]],
|
||||
BaseMint: baseTokenbalance.MintAccount,
|
||||
QuoteMint: quoteTokenbalance.MintAccount,
|
||||
BaseTokenProgram: baseTokenbalance.ProgramIDAccount,
|
||||
QuoteTokenProgram: quoteTokenbalance.ProgramIDAccount,
|
||||
Creator: user,
|
||||
BaseMintDecimals: uint8(baseTokenbalance.UITokenAmount.Decimals),
|
||||
QuoteMintDecimals: uint8(quoteTokenbalance.UITokenAmount.Decimals),
|
||||
User: user,
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
|
||||
func raydiumv4AddLiquidityParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
accountsLen := len(instruction.Accounts)
|
||||
if accountsLen != 14 && accountsLen != 15 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("invalid number of accounts for raydiumv4 add liquidity instruction, offset %d, %d", offset[0], offset[1])
|
||||
}
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
|
||||
baseVaultAccountIndex := instruction.Accounts[6]
|
||||
quoteVaultAccountIndex := instruction.Accounts[7]
|
||||
|
||||
userBaseVaultAccountIndex := instruction.Accounts[9]
|
||||
userQuoteVaultAccountIndex := instruction.Accounts[10]
|
||||
|
||||
baseTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get base vault balance after tx: %v", err)
|
||||
}
|
||||
quoteTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, quoteVaultAccountIndex)
|
||||
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 baseFound, quoteFound bool
|
||||
var baseAmount, quoteAmount decimal.Decimal
|
||||
for i, inner := range inners {
|
||||
from, to, amount, err := parseTokenTransfer(tx.rawTx, inner)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if from.Equals(tx.rawTx.accountList[userBaseVaultAccountIndex]) && to.Equals(tx.rawTx.accountList[baseVaultAccountIndex]) && !baseFound {
|
||||
baseAmount = decimal.NewFromUint64(amount)
|
||||
baseFound = true
|
||||
} else if from.Equals(tx.rawTx.accountList[userQuoteVaultAccountIndex]) && to.Equals(tx.rawTx.accountList[quoteVaultAccountIndex]) && !quoteFound {
|
||||
quoteAmount = decimal.NewFromUint64(amount)
|
||||
quoteFound = true
|
||||
}
|
||||
if baseFound && quoteFound {
|
||||
nextIndex = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if !baseFound || !quoteFound {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to find token transfer inner instruction for add liquidity, offset %d, %d", offset[0], offset[1])
|
||||
}
|
||||
offset[1] += uint(nextIndex + 1)
|
||||
baseReserve, _ := decimal.NewFromString(baseTokenbalance.UITokenAmount.Amount)
|
||||
quoteReserve, _ := decimal.NewFromString(quoteTokenbalance.UITokenAmount.Amount)
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramRaydiumV4,
|
||||
Event: "remove_liquidity",
|
||||
Pool: tx.rawTx.accountList[instruction.Accounts[1]],
|
||||
BaseMint: baseTokenbalance.MintAccount,
|
||||
QuoteMint: quoteTokenbalance.MintAccount,
|
||||
BaseTokenProgram: baseTokenbalance.ProgramIDAccount,
|
||||
QuoteTokenProgram: quoteTokenbalance.ProgramIDAccount,
|
||||
User: tx.rawTx.accountList[instruction.Accounts[12]],
|
||||
BaseMintDecimals: uint8(baseTokenbalance.UITokenAmount.Decimals),
|
||||
QuoteMintDecimals: uint8(quoteTokenbalance.UITokenAmount.Decimals),
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
BaseAmount: baseAmount,
|
||||
QuoteAmount: quoteAmount,
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
|
||||
func raydiumv4RemoveLiquidityParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
accountsLen := len(instruction.Accounts)
|
||||
const AccountLen = 20
|
||||
if accountsLen != AccountLen && accountsLen != AccountLen+1 && accountsLen != AccountLen+2 && accountsLen != AccountLen+3 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("invalid number of accounts for raydiumv4 add liquidity instruction, offset %d, %d", offset[0], offset[1])
|
||||
}
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
baseVaultAccountIndex := instruction.Accounts[6]
|
||||
quoteVaultAccountIndex := instruction.Accounts[7]
|
||||
userBaseVaultAccountIndex := instruction.Accounts[14]
|
||||
userQuoteVaultAccountIndex := instruction.Accounts[16]
|
||||
|
||||
if accountsLen == AccountLen+2 || accountsLen == AccountLen+3 {
|
||||
userBaseVaultAccountIndex = instruction.Accounts[16]
|
||||
userQuoteVaultAccountIndex = instruction.Accounts[17]
|
||||
}
|
||||
|
||||
baseTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get base vault balance after tx: %v", err)
|
||||
}
|
||||
quoteTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, quoteVaultAccountIndex)
|
||||
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 baseFound, quoteFound bool
|
||||
var baseAmount, quoteAmount decimal.Decimal
|
||||
for i, inner := range inners {
|
||||
from, to, amount, err := parseTokenTransfer(tx.rawTx, inner)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if to.Equals(tx.rawTx.accountList[userBaseVaultAccountIndex]) && from.Equals(tx.rawTx.accountList[baseVaultAccountIndex]) && !baseFound {
|
||||
baseAmount = decimal.NewFromUint64(amount)
|
||||
baseFound = true
|
||||
} else if to.Equals(tx.rawTx.accountList[userQuoteVaultAccountIndex]) && from.Equals(tx.rawTx.accountList[quoteVaultAccountIndex]) && !quoteFound {
|
||||
quoteAmount = decimal.NewFromUint64(amount)
|
||||
quoteFound = true
|
||||
}
|
||||
if baseFound && quoteFound {
|
||||
nextIndex = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if !baseFound || !quoteFound {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to find token transfer inner instruction for add liquidity, offset %d, %d", offset[0], offset[1])
|
||||
}
|
||||
offset[1] += uint(nextIndex + 1)
|
||||
baseReserve, _ := decimal.NewFromString(baseTokenbalance.UITokenAmount.Amount)
|
||||
quoteReserve, _ := decimal.NewFromString(quoteTokenbalance.UITokenAmount.Amount)
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramRaydiumV4,
|
||||
Event: "remove_liquidity",
|
||||
Pool: tx.rawTx.accountList[instruction.Accounts[1]],
|
||||
BaseMint: baseTokenbalance.MintAccount,
|
||||
QuoteMint: quoteTokenbalance.MintAccount,
|
||||
BaseTokenProgram: baseTokenbalance.ProgramIDAccount,
|
||||
QuoteTokenProgram: quoteTokenbalance.ProgramIDAccount,
|
||||
User: tx.rawTx.accountList[0],
|
||||
BaseMintDecimals: uint8(baseTokenbalance.UITokenAmount.Decimals),
|
||||
QuoteMintDecimals: uint8(quoteTokenbalance.UITokenAmount.Decimals),
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
BaseAmount: baseAmount,
|
||||
QuoteAmount: quoteAmount,
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
|
||||
func raydiumv4WithdrawPNLParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
accountsLen := len(instruction.Accounts)
|
||||
if accountsLen != 17 && accountsLen != 18 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("invalid number of accounts for raydiumv4 WithdrawPNL instruction, offset %d, %d", offset[0], offset[1])
|
||||
}
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
|
||||
baseVaultAccountIndex := instruction.Accounts[5]
|
||||
quoteVaultAccountIndex := instruction.Accounts[6]
|
||||
userBaseVaultAccountIndex := instruction.Accounts[7]
|
||||
userQuoteVaultAccountIndex := instruction.Accounts[8]
|
||||
|
||||
baseTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get base vault balance after tx: %v", err)
|
||||
}
|
||||
quoteTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, quoteVaultAccountIndex)
|
||||
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 baseFound, quoteFound bool
|
||||
var baseAmount, quoteAmount decimal.Decimal
|
||||
for i, inner := range inners {
|
||||
from, to, amount, err := parseTokenTransfer(tx.rawTx, inner)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if to.Equals(tx.rawTx.accountList[userBaseVaultAccountIndex]) && from.Equals(tx.rawTx.accountList[baseVaultAccountIndex]) && !baseFound {
|
||||
baseAmount = decimal.NewFromUint64(amount)
|
||||
baseFound = true
|
||||
} else if to.Equals(tx.rawTx.accountList[userQuoteVaultAccountIndex]) && from.Equals(tx.rawTx.accountList[quoteVaultAccountIndex]) && !quoteFound {
|
||||
quoteAmount = decimal.NewFromUint64(amount)
|
||||
quoteFound = true
|
||||
}
|
||||
if baseFound && quoteFound {
|
||||
nextIndex = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if !baseFound || !quoteFound {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to find token transfer inner instruction for with pnl, offset %d, %d", offset[0], offset[1])
|
||||
}
|
||||
offset[1] += uint(nextIndex + 1)
|
||||
|
||||
baseReserve, _ := decimal.NewFromString(baseTokenbalance.UITokenAmount.Amount)
|
||||
quoteReserve, _ := decimal.NewFromString(quoteTokenbalance.UITokenAmount.Amount)
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramRaydiumV4,
|
||||
Event: "remove_liquidity",
|
||||
Pool: tx.rawTx.accountList[instruction.Accounts[1]],
|
||||
BaseMint: baseTokenbalance.MintAccount,
|
||||
QuoteMint: quoteTokenbalance.MintAccount,
|
||||
BaseTokenProgram: baseTokenbalance.ProgramIDAccount,
|
||||
QuoteTokenProgram: quoteTokenbalance.ProgramIDAccount,
|
||||
User: tx.rawTx.accountList[instruction.Accounts[9]],
|
||||
BaseMintDecimals: uint8(baseTokenbalance.UITokenAmount.Decimals),
|
||||
QuoteMintDecimals: uint8(quoteTokenbalance.UITokenAmount.Decimals),
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
BaseAmount: baseAmount,
|
||||
QuoteAmount: quoteAmount,
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
|
||||
func raydiumv4SwapParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
accountsLen := len(instruction.Accounts)
|
||||
if accountsLen != 17 && accountsLen != 18 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("invalid number of accounts for raydiumv4 swap instruction, offset %d, %d", offset[0], offset[1])
|
||||
}
|
||||
user := tx.rawTx.accountList[instruction.Accounts[accountsLen-1]]
|
||||
userSrcIdx := instruction.Accounts[accountsLen-3]
|
||||
userDestIdx := instruction.Accounts[accountsLen-2]
|
||||
vaultBaseIdx := instruction.Accounts[4]
|
||||
vaultQuoteIdx := instruction.Accounts[5]
|
||||
if accountsLen == 18 {
|
||||
vaultBaseIdx = instruction.Accounts[5]
|
||||
vaultQuoteIdx = instruction.Accounts[6]
|
||||
}
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
|
||||
ammAccount := tx.rawTx.accountList[instruction.Accounts[1]]
|
||||
|
||||
userSourceTokenAccount := tx.rawTx.accountList[userSrcIdx]
|
||||
userDestinationTokenAccount := tx.rawTx.accountList[userDestIdx]
|
||||
baseTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, vaultBaseIdx)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get base vault balance after tx: %v", err)
|
||||
}
|
||||
quoteTokenbalance, err := getTokenBalanceAfterTx(tx.rawTx, vaultQuoteIdx)
|
||||
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[vaultBaseIdx]) {
|
||||
event = "sell"
|
||||
baseAmount = decimal.NewFromUint64(amount)
|
||||
srcFound = true
|
||||
} else if to.Equals(tx.rawTx.accountList[vaultQuoteIdx]) {
|
||||
event = "buy"
|
||||
quoteAmount = decimal.NewFromUint64(amount)
|
||||
srcFound = true
|
||||
}
|
||||
} else if to.Equals(userDestinationTokenAccount) && !destFound {
|
||||
if from.Equals(tx.rawTx.accountList[vaultQuoteIdx]) {
|
||||
event = "sell"
|
||||
quoteAmount = decimal.NewFromUint64(amount)
|
||||
destFound = true
|
||||
} else if from.Equals(tx.rawTx.accountList[vaultBaseIdx]) {
|
||||
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 swap, offset %d, %d", offset[0], offset[1])
|
||||
}
|
||||
offset[1] += uint(nextIndex + 1)
|
||||
userBase := getAccountBalanceAfterTx(tx.rawTx, userSrcIdx)
|
||||
userQuote := getAccountBalanceAfterTx(tx.rawTx, userDestIdx)
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user