all parser
This commit is contained in:
479
meteoradamm.go
Normal file
479
meteoradamm.go
Normal file
@@ -0,0 +1,479 @@
|
||||
package pump_parser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
agbinary "github.com/gagliardetto/binary"
|
||||
"github.com/gagliardetto/solana-go"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
func metaoraDammParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
if !tx.rawTx.accountList[instruction.ProgramIDIndex].Equals(meteoraDammV2Program) {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm program instruction not found, offset, %d, %d", offset[0], offset[1])
|
||||
}
|
||||
|
||||
decode := instruction.Data
|
||||
if len(decode) < 8 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm program instruction data too short, offset, %d, %d", offset[0], offset[1])
|
||||
}
|
||||
|
||||
discriminator := *(*[8]byte)(decode[:8])
|
||||
|
||||
switch discriminator {
|
||||
case meteoraDammV2InitializeCustomizablePoolDiscriminator,
|
||||
meteoraDammV2InitializePoolWithDynamicConfig,
|
||||
meteoraDammV2InitializePoolDiscriminator:
|
||||
return meteoraDammV2InitializePoolParser(tx, instruction, innerInstructions, offset)
|
||||
case meteoraDammV2SwapDiscriminator, meteoraDammV2SwapV2Discriminator:
|
||||
return meteoraDammV2Swap(tx, instruction, innerInstructions, offset)
|
||||
case meteoraDammV2AddLiquidityDiscriminator:
|
||||
return meteoraDammV2AddLiquidityParser(tx, instruction, innerInstructions, offset)
|
||||
case meteoraDammV2RemoveLiquidityDiscriminator, meteoraDammV2RemoveAllLiquidityDiscriminator:
|
||||
return meteoraDammV2RemoveLiquidityParser(tx, instruction, innerInstructions, offset)
|
||||
default:
|
||||
return nil, increaseOffset(offset), InstructionIgnoredError
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
metaoraDammInitializePoolDiscriminator = []byte{228, 69, 165, 46, 81, 203, 154, 29, 228, 50, 246, 85, 203, 66, 134, 37}
|
||||
meteoraDammSwapDiscriminator = []byte{228, 69, 165, 46, 81, 203, 154, 29, 189, 66, 51, 168, 38, 80, 117, 153}
|
||||
// EvtLiquidityChange
|
||||
meteoraDammAddLiquidityDiscriminator = []byte{228, 69, 165, 46, 81, 203, 154, 29, 197, 171, 78, 127, 224, 211, 87, 13}
|
||||
meteoraDammRemoveLiquidityDiscriminator = []byte{228, 69, 165, 46, 81, 203, 154, 29, 197, 171, 78, 127, 224, 211, 87, 13}
|
||||
)
|
||||
|
||||
type MetaoraDammDynamicFeeParameters struct {
|
||||
BinStep uint16
|
||||
BinStepU128 [16]byte
|
||||
FilterPeriod uint16
|
||||
DecayPeriod uint16
|
||||
ReductionFactor uint16
|
||||
MaxVolatilityAccumulator uint32
|
||||
VariableFeeControl uint32
|
||||
}
|
||||
|
||||
type MetaoraDammInitializePoolEvent struct {
|
||||
Pool solana.PublicKey `json:"pool"`
|
||||
TokenAMint solana.PublicKey `json:"tokenAMint"`
|
||||
TokenBMint solana.PublicKey `json:"tokenBMint"`
|
||||
Creator solana.PublicKey `json:"creator"`
|
||||
Payer solana.PublicKey `json:"payer"`
|
||||
AlphaVault solana.PublicKey `json:"alphaVault"`
|
||||
//PoolFees *struct {
|
||||
// BaseFee [30]byte
|
||||
// DynamicFee *MetaoraDammDynamicFeeParameters `json:"dynamicFee"`
|
||||
//} `json:"poolFees"`
|
||||
//SqrtMinPrice [16]byte `json:"sqrtMinPrice"`
|
||||
//SqrtMaxPrice [16]byte `json:"sqrtMaxPrice"`
|
||||
//ActivationType uint8 `json:"activationType"`
|
||||
//CollectFeeMode uint8 `json:"collectFeeMode"`
|
||||
//Liquidity [16]byte `json:"liquidity"`
|
||||
//SqrtPrice [16]byte `json:"sqrtPrice"`
|
||||
//ActivationPoint uint64 `json:"activationPoint"`
|
||||
//TokenAFlag uint8 `json:"tokenAFlag"`
|
||||
//TokenBFlag uint8 `json:"tokenBFlag"`
|
||||
//TokenAAmount uint64 `json:"tokenAAmount"`
|
||||
//TokenBAmount uint64 `json:"tokenBAmount"`
|
||||
//TotalAmountA uint64 `json:"totalAmountA"`
|
||||
//TotalAmountB uint64 `json:"totalAmountB"`
|
||||
//PoolType uint8 `json:"poolType"`
|
||||
}
|
||||
|
||||
func meteoraDammV2InitializePoolParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
if len(instruction.Accounts) < 12 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("invalid instruction accounts length")
|
||||
}
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
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])
|
||||
}
|
||||
var loadedEvent bool
|
||||
var initializePoolEvent MetaoraDammInitializePoolEvent
|
||||
for i, innerInstruction := range inners {
|
||||
if innerInstruction.ProgramIDIndex == instruction.ProgramIDIndex && len(innerInstruction.Data) >= 16 && bytes.Equal(innerInstruction.Data[:16], metaoraDammInitializePoolDiscriminator) {
|
||||
err := agbinary.NewBorshDecoder(innerInstruction.Data[16:]).Decode(&initializePoolEvent)
|
||||
if err != nil {
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(i) + 1 + prefixLen
|
||||
}
|
||||
return nil, offset, fmt.Errorf("failed to deserialize initialize pool event: %w", err)
|
||||
}
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(i) + 1 + prefixLen
|
||||
}
|
||||
loadedEvent = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !loadedEvent {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get initialize pool event")
|
||||
}
|
||||
baseVaultAccountIndex := instruction.Accounts[10]
|
||||
quoteVaultAccountIndex := instruction.Accounts[11]
|
||||
|
||||
baseVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm get base vault token balance error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
quoteVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, quoteVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm get quote vault token balance error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
baseReserve, _ := decimal.NewFromString(baseVaultTokenBalance.UITokenAmount.Amount)
|
||||
quoteReserve, _ := decimal.NewFromString(quoteVaultTokenBalance.UITokenAmount.Amount)
|
||||
|
||||
swap := Swap{
|
||||
Program: SolProgramMeteoraAmmV2,
|
||||
Event: "create",
|
||||
Pool: initializePoolEvent.Pool,
|
||||
BaseMint: initializePoolEvent.TokenAMint,
|
||||
QuoteMint: initializePoolEvent.TokenBMint,
|
||||
BaseTokenProgram: baseVaultTokenBalance.ProgramIDAccount,
|
||||
QuoteTokenProgram: quoteVaultTokenBalance.ProgramIDAccount,
|
||||
Creator: initializePoolEvent.Creator,
|
||||
BaseMintDecimals: uint8(baseVaultTokenBalance.UITokenAmount.Decimals),
|
||||
QuoteMintDecimals: uint8(quoteVaultTokenBalance.UITokenAmount.Decimals),
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
User: tx.rawTx.accountList[instruction.Accounts[0]],
|
||||
LpMint: tx.rawTx.accountList[instruction.Accounts[1]],
|
||||
EntryContract: entryContract,
|
||||
}
|
||||
return []Swap{swap}, offset, nil
|
||||
}
|
||||
|
||||
type meteoraDammSwapEvent struct {
|
||||
Pool solana.PublicKey
|
||||
TradeDirection uint8
|
||||
CollectFeeMode uint8
|
||||
HasReferral bool
|
||||
|
||||
Params *struct {
|
||||
Amount0 uint64
|
||||
Amount1 uint64
|
||||
SwapMode uint8
|
||||
}
|
||||
SwapResult *struct {
|
||||
IncludedFeeInputAmount uint64
|
||||
ExcludedFeeInputAmount uint64
|
||||
AmountLeft uint64
|
||||
OutputAmount uint64
|
||||
NextSqrtPrice [16]byte
|
||||
TradingFee uint64
|
||||
ProtocolFee uint64
|
||||
PartnerFee uint64
|
||||
ReferralFee uint64
|
||||
}
|
||||
IncludedTransferFeeAmountIn uint64
|
||||
IncludedTransferFeeAmountOut uint64
|
||||
ExcludedTransferFeeAmountOut uint64
|
||||
CurrentTimestamp uint64
|
||||
ReserveAAmount uint64
|
||||
ReserveBAmount uint64
|
||||
}
|
||||
|
||||
func meteoraDammV2Swap(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
if len(instruction.Accounts) < 9 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("invalid instruction accounts length")
|
||||
}
|
||||
|
||||
sourceAccountIndex := instruction.Accounts[2]
|
||||
destinationAccountIndex := instruction.Accounts[3]
|
||||
baseVaultAccountIndex := instruction.Accounts[4]
|
||||
quoteVaultAccountIndex := instruction.Accounts[5]
|
||||
tokenAMint := tx.rawTx.accountList[instruction.Accounts[6]]
|
||||
tokenBMint := tx.rawTx.accountList[instruction.Accounts[7]]
|
||||
payer := tx.rawTx.accountList[instruction.Accounts[8]]
|
||||
|
||||
baseVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm get base vault token balance error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
quoteVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, quoteVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm get quote vault token balance error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
|
||||
baseReserve, _ := decimal.NewFromString(baseVaultTokenBalance.UITokenAmount.Amount)
|
||||
quoteReserve, _ := decimal.NewFromString(quoteVaultTokenBalance.UITokenAmount.Amount)
|
||||
|
||||
baseMint := tokenAMint
|
||||
quoteMint := tokenBMint
|
||||
baseTokenProgram := baseVaultTokenBalance.ProgramIDAccount
|
||||
quoteTokenProgram := quoteVaultTokenBalance.ProgramIDAccount
|
||||
baseMintDecimals := uint8(baseVaultTokenBalance.UITokenAmount.Decimals)
|
||||
quoteMintDecimals := uint8(quoteVaultTokenBalance.UITokenAmount.Decimals)
|
||||
|
||||
userInputTokenBalance := getAccountBalanceAfterTx(tx.rawTx, sourceAccountIndex)
|
||||
userOutputTokenBalance := getAccountBalanceAfterTx(tx.rawTx, destinationAccountIndex)
|
||||
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
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])
|
||||
}
|
||||
var loadedEvent bool
|
||||
var swapEvent meteoraDammSwapEvent
|
||||
for i, innerInstruction := range inners {
|
||||
if innerInstruction.ProgramIDIndex == instruction.ProgramIDIndex && len(innerInstruction.Data) >= 16 && bytes.Equal(innerInstruction.Data[:16], meteoraDammSwapDiscriminator) {
|
||||
err := agbinary.NewBorshDecoder(innerInstruction.Data[16:]).Decode(&swapEvent)
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(i) + 1 + prefixLen
|
||||
}
|
||||
if err != nil {
|
||||
return nil, offset, fmt.Errorf("failed to deserialize swap event: %w", err)
|
||||
}
|
||||
|
||||
loadedEvent = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
if !loadedEvent {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get swap event")
|
||||
}
|
||||
var baseAmount decimal.Decimal
|
||||
var quoteAmount decimal.Decimal
|
||||
var userBase decimal.Decimal
|
||||
var userQuote decimal.Decimal
|
||||
event := "buy"
|
||||
if swapEvent.TradeDirection == 0 {
|
||||
// A -> B
|
||||
// sell base/A; buy quote/B
|
||||
event = "sell"
|
||||
userBase = userInputTokenBalance
|
||||
userQuote = userOutputTokenBalance
|
||||
baseAmount = decimal.NewFromUint64(swapEvent.SwapResult.IncludedFeeInputAmount)
|
||||
quoteAmount = decimal.NewFromUint64(swapEvent.ExcludedTransferFeeAmountOut)
|
||||
|
||||
} else if swapEvent.TradeDirection == 1 {
|
||||
// B -> A
|
||||
// sell quote/B; buy base/A
|
||||
userBase = userOutputTokenBalance
|
||||
userQuote = userInputTokenBalance
|
||||
baseAmount = decimal.NewFromUint64(swapEvent.ExcludedTransferFeeAmountOut)
|
||||
quoteAmount = decimal.NewFromUint64(swapEvent.SwapResult.IncludedFeeInputAmount)
|
||||
} else {
|
||||
return nil, offset, fmt.Errorf("invalid trade direction")
|
||||
}
|
||||
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramMeteoraAmmV2,
|
||||
Event: event,
|
||||
Pool: swapEvent.Pool,
|
||||
BaseMint: baseMint,
|
||||
QuoteMint: quoteMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
Creator: solana.PublicKey{},
|
||||
BaseMintDecimals: baseMintDecimals,
|
||||
QuoteMintDecimals: quoteMintDecimals,
|
||||
User: payer,
|
||||
BaseAmount: baseAmount,
|
||||
QuoteAmount: quoteAmount,
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
UserBaseBalance: userBase,
|
||||
UserQuoteBalance: userQuote,
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
|
||||
}
|
||||
|
||||
type MeteoraDammV2LiquidityData struct {
|
||||
LiquidityDelta [16]byte `json:"liquidityDelta"`
|
||||
TokenAAmounthreshold uint64 `json:"tokenAAmounthreshold"`
|
||||
TokenBAmounthreshold uint64 `json:"tokenBAmounthreshold"`
|
||||
}
|
||||
type MeteoraDammV2AddLiquidityEvent struct {
|
||||
Pool solana.PublicKey `json:"pool"`
|
||||
Position solana.PublicKey `json:"position"`
|
||||
Owner solana.PublicKey `json:"owner"`
|
||||
Params *MeteoraDammV2LiquidityData `json:"params"`
|
||||
TokenAAmount uint64 `json:"tokenAAmount"`
|
||||
TokenBAmount uint64 `json:"tokenBAmount"`
|
||||
TotalAmountA uint64 `json:"totalAmountA"`
|
||||
TotalAmountB uint64 `json:"totalAmountB"`
|
||||
}
|
||||
|
||||
type MeteoraDammV2RemoveLiquidityEvent struct {
|
||||
Pool solana.PublicKey `json:"pool"`
|
||||
Position solana.PublicKey `json:"position"`
|
||||
Owner solana.PublicKey `json:"owner"`
|
||||
Params *MeteoraDammV2LiquidityData `json:"params"`
|
||||
TokenAAmount uint64 `json:"tokenAAmount"`
|
||||
TokenBAmount uint64 `json:"tokenBAmount"`
|
||||
}
|
||||
|
||||
func meteoraDammV2AddLiquidityParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
|
||||
if len(instruction.Accounts) < 8 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("invalid instruction accounts length")
|
||||
}
|
||||
tokenAMint := tx.rawTx.accountList[instruction.Accounts[6]]
|
||||
tokenBMint := tx.rawTx.accountList[instruction.Accounts[7]]
|
||||
|
||||
baseVaultAccountIndex := instruction.Accounts[4]
|
||||
quoteVaultAccountIndex := instruction.Accounts[5]
|
||||
|
||||
baseVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm get base vault token balance error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
quoteVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, quoteVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm get quote vault token balance error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
baseReserve, _ := decimal.NewFromString(baseVaultTokenBalance.UITokenAmount.Amount)
|
||||
quoteReserve, _ := decimal.NewFromString(quoteVaultTokenBalance.UITokenAmount.Amount)
|
||||
|
||||
baseTokenProgram := baseVaultTokenBalance.ProgramIDAccount
|
||||
quoteTokenProgram := quoteVaultTokenBalance.ProgramIDAccount
|
||||
baseMintDecimals := uint8(baseVaultTokenBalance.UITokenAmount.Decimals)
|
||||
quoteMintDecimals := uint8(quoteVaultTokenBalance.UITokenAmount.Decimals)
|
||||
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
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])
|
||||
}
|
||||
var loadedEvent bool
|
||||
var liquidityEvent MeteoraDammV2AddLiquidityEvent
|
||||
for i, innerInstruction := range inners {
|
||||
if innerInstruction.ProgramIDIndex == instruction.ProgramIDIndex && len(innerInstruction.Data) >= 16 && bytes.Equal(innerInstruction.Data[:16], meteoraDammAddLiquidityDiscriminator[:]) {
|
||||
err := agbinary.NewBorshDecoder(innerInstruction.Data[16:]).Decode(&liquidityEvent)
|
||||
if err != nil {
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(i) + 1 + prefixLen
|
||||
}
|
||||
return nil, offset, fmt.Errorf("failed to deserialize add liquidity event: %w", err)
|
||||
}
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(i) + 1 + prefixLen
|
||||
}
|
||||
loadedEvent = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !loadedEvent {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get add liquidity event")
|
||||
}
|
||||
swap := Swap{
|
||||
Program: SolProgramMeteoraDLMM,
|
||||
Event: "add_liquidity",
|
||||
Pool: liquidityEvent.Pool,
|
||||
BaseMint: tokenAMint,
|
||||
QuoteMint: tokenBMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
BaseMintDecimals: baseMintDecimals,
|
||||
QuoteMintDecimals: quoteMintDecimals,
|
||||
User: liquidityEvent.Owner,
|
||||
BaseAmount: decimal.NewFromUint64(liquidityEvent.TokenAAmount),
|
||||
QuoteAmount: decimal.NewFromUint64(liquidityEvent.TokenBAmount),
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
EntryContract: entryContract,
|
||||
}
|
||||
|
||||
return []Swap{swap}, offset, nil
|
||||
}
|
||||
|
||||
func meteoraDammV2RemoveLiquidityParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
if len(instruction.Accounts) < 8 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("invalid instruction accounts length")
|
||||
}
|
||||
tokenAMint := tx.rawTx.accountList[instruction.Accounts[7]]
|
||||
tokenBMint := tx.rawTx.accountList[instruction.Accounts[8]]
|
||||
|
||||
baseVaultAccountIndex := instruction.Accounts[5]
|
||||
quoteVaultAccountIndex := instruction.Accounts[6]
|
||||
|
||||
baseVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, baseVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm get base vault token balance error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
quoteVaultTokenBalance, err := getTokenBalanceAfterTx(tx.rawTx, quoteVaultAccountIndex)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("metaora damm get quote vault token balance error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
baseReserve, _ := decimal.NewFromString(baseVaultTokenBalance.UITokenAmount.Amount)
|
||||
quoteReserve, _ := decimal.NewFromString(quoteVaultTokenBalance.UITokenAmount.Amount)
|
||||
|
||||
baseTokenProgram := baseVaultTokenBalance.ProgramIDAccount
|
||||
quoteTokenProgram := quoteVaultTokenBalance.ProgramIDAccount
|
||||
baseMintDecimals := uint8(baseVaultTokenBalance.UITokenAmount.Decimals)
|
||||
quoteMintDecimals := uint8(quoteVaultTokenBalance.UITokenAmount.Decimals)
|
||||
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meta damm get inner instructions error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
var loadedEvent bool
|
||||
var liquidityEvent MeteoraDammV2RemoveLiquidityEvent
|
||||
for i, innerInstruction := range inners {
|
||||
if innerInstruction.ProgramIDIndex == instruction.ProgramIDIndex && len(innerInstruction.Data) >= 16 && bytes.Equal(innerInstruction.Data[:16], meteoraDammRemoveLiquidityDiscriminator[:]) {
|
||||
err := agbinary.NewBorshDecoder(innerInstruction.Data[16:]).Decode(&liquidityEvent)
|
||||
if err != nil {
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(i) + 1 + prefixLen
|
||||
}
|
||||
return nil, offset, fmt.Errorf("failed to deserialize remove liquidity event: %w", err)
|
||||
}
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(i) + 1 + prefixLen
|
||||
}
|
||||
loadedEvent = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !loadedEvent {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get remove liquidity event")
|
||||
}
|
||||
swap := Swap{
|
||||
Program: SolProgramMeteoraDLMM,
|
||||
Event: "remove_liquidity",
|
||||
Pool: liquidityEvent.Pool,
|
||||
BaseMint: tokenAMint,
|
||||
QuoteMint: tokenBMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
BaseMintDecimals: baseMintDecimals,
|
||||
QuoteMintDecimals: quoteMintDecimals,
|
||||
User: liquidityEvent.Owner,
|
||||
BaseAmount: decimal.NewFromUint64(liquidityEvent.TokenAAmount),
|
||||
QuoteAmount: decimal.NewFromUint64(liquidityEvent.TokenBAmount),
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
EntryContract: entryContract,
|
||||
}
|
||||
|
||||
return []Swap{swap}, offset, nil
|
||||
}
|
||||
Reference in New Issue
Block a user