all parser
This commit is contained in:
470
raydiumlaunchlab.go
Normal file
470
raydiumlaunchlab.go
Normal file
@@ -0,0 +1,470 @@
|
||||
package pump_parser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
agbinary "github.com/gagliardetto/binary"
|
||||
"github.com/gagliardetto/solana-go"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
func raydiumLaunchLabParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
if !tx.rawTx.accountList[instruction.ProgramIDIndex].Equals(raydiumLaunchLabProgramID) {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("raydiumLaunchLab instruction not found, offset, %d, %d", offset[0], offset[1])
|
||||
}
|
||||
|
||||
decode := instruction.Data
|
||||
if len(decode) < 8 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("raydiumLaunchLab program instruction data too short, offset, %d, %d", offset[0], offset[1])
|
||||
}
|
||||
discriminator := *(*[8]byte)(decode[:8])
|
||||
|
||||
switch discriminator {
|
||||
case raydiumLaunchLabInitializeWithToken2022PoolDiscriminator, raydiumLaunchLabInitializeV2PoolDiscriminator:
|
||||
return raydiumLaunchLabInitializeParser(tx, instruction, innerInstructions, offset)
|
||||
case raydiumLaunchLabMigrateToAmmDiscriminator:
|
||||
return raydiumLaunchLabMigrateToAmmParser(tx, instruction, innerInstructions, offset)
|
||||
case raydiumLaunchLabMigrateToCpmmDiscriminator:
|
||||
return raydiumLaunchLabMigrateToCpmmParser(tx, instruction, innerInstructions, offset)
|
||||
case raydiumLaunchLabSellExactInDiscriminator,
|
||||
raydiumLaunchLabSellExactOutDiscriminator,
|
||||
raydiumLaunchLabBuyExactInDiscriminator,
|
||||
raydiumLaunchLabBuyExactOutDiscriminator:
|
||||
return raydiumLaunchLabSwapParser(tx, instruction, innerInstructions, offset)
|
||||
default:
|
||||
return nil, increaseOffset(offset), InstructionIgnoredError
|
||||
}
|
||||
}
|
||||
|
||||
type VestingParam struct {
|
||||
TotalLockedAmount uint64
|
||||
CliffPeriod uint64
|
||||
UnlockPeriod uint64
|
||||
}
|
||||
|
||||
type CurveParamKind uint8
|
||||
|
||||
const (
|
||||
CurveParamConstant CurveParamKind = 0
|
||||
CurveParamFixed CurveParamKind = 1
|
||||
CurveParamLinear CurveParamKind = 2
|
||||
)
|
||||
|
||||
type CurveParam struct {
|
||||
// rust enum ConstantCurve/FixedCurve/LinearCurve
|
||||
Kind CurveParamKind
|
||||
Constant *ConstantCurve
|
||||
Fixed *FixedCurve
|
||||
Linear *LinearCurve
|
||||
}
|
||||
|
||||
func (c *CurveParam) TotalSupply() uint64 {
|
||||
switch c.Kind {
|
||||
case CurveParamConstant:
|
||||
return c.Constant.TotalSupply
|
||||
case CurveParamFixed:
|
||||
return c.Fixed.TotalSupply
|
||||
case CurveParamLinear:
|
||||
return c.Linear.TotalSupply
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalWithDecoder 让 agbinary/borsh 解码时走自定义逻辑
|
||||
func (c *CurveParam) UnmarshalWithDecoder(dec *agbinary.Decoder) error {
|
||||
var tag uint8
|
||||
if err := dec.Decode(&tag); err != nil {
|
||||
return fmt.Errorf("decode CurveParam tag: %w", err)
|
||||
}
|
||||
|
||||
c.Kind = CurveParamKind(tag)
|
||||
c.Constant, c.Fixed, c.Linear = nil, nil, nil
|
||||
|
||||
switch c.Kind {
|
||||
case CurveParamConstant:
|
||||
var v ConstantCurve
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return fmt.Errorf("decode ConstantCurve: %w", err)
|
||||
}
|
||||
c.Constant = &v
|
||||
case CurveParamFixed:
|
||||
var v FixedCurve
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return fmt.Errorf("decode FixedCurve: %w", err)
|
||||
}
|
||||
c.Fixed = &v
|
||||
case CurveParamLinear:
|
||||
var v LinearCurve
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return fmt.Errorf("decode LinearCurve: %w", err)
|
||||
}
|
||||
c.Linear = &v
|
||||
default:
|
||||
return fmt.Errorf("unknown CurveParam tag: %d", tag)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ConstantCurve struct {
|
||||
TotalSupply uint64
|
||||
TotalBaseSell uint64
|
||||
TotalQuoteFundRaising uint64
|
||||
MigrateType uint8
|
||||
}
|
||||
|
||||
type FixedCurve struct {
|
||||
TotalSupply uint64
|
||||
TotalQuoteFundRaising uint64
|
||||
MigrateType uint8
|
||||
}
|
||||
|
||||
type LinearCurve struct {
|
||||
TotalSupply uint64
|
||||
TotalQuoteFundRaising uint64
|
||||
MigrateType uint8
|
||||
}
|
||||
|
||||
type BaseMintParam struct {
|
||||
Decimals uint8
|
||||
Name string
|
||||
Symbol string
|
||||
Uri string
|
||||
}
|
||||
type RaydiumLaunchLabCreateEvent struct {
|
||||
Pool solana.PublicKey
|
||||
Creator solana.PublicKey
|
||||
Config solana.PublicKey
|
||||
BaseMintParam BaseMintParam
|
||||
CurveParam CurveParam
|
||||
VestingParam VestingParam
|
||||
ammFeeOn uint8 // 0 or 1, QuoteToken/BaseToken fee on amm swap
|
||||
}
|
||||
|
||||
func raydiumLaunchLabInitializeParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
if len(instruction.Accounts) < 16 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("not enough accounts for initialize instruction")
|
||||
}
|
||||
user := tx.rawTx.accountList[instruction.Accounts[0]]
|
||||
creator := tx.rawTx.accountList[instruction.Accounts[1]]
|
||||
pool := tx.rawTx.accountList[instruction.Accounts[5]]
|
||||
platformConfig := tx.rawTx.accountList[instruction.Accounts[3]]
|
||||
baseMint := tx.rawTx.accountList[instruction.Accounts[6]]
|
||||
quoteMint := tx.rawTx.accountList[instruction.Accounts[7]]
|
||||
baseVaultIdx := instruction.Accounts[8]
|
||||
quoteVaultIdx := instruction.Accounts[9]
|
||||
var (
|
||||
baseTokenProgram solana.PublicKey
|
||||
quoteTokenProgram solana.PublicKey
|
||||
)
|
||||
if bytes.Equal(instruction.Data[:8], raydiumLaunchLabInitializeWithToken2022PoolDiscriminator[:]) {
|
||||
baseTokenProgram = tx.rawTx.accountList[instruction.Accounts[10]]
|
||||
quoteTokenProgram = tx.rawTx.accountList[instruction.Accounts[11]]
|
||||
} else if bytes.Equal(instruction.Data[:8], raydiumLaunchLabInitializeV2PoolDiscriminator[:]) {
|
||||
baseTokenProgram = tx.rawTx.accountList[instruction.Accounts[11]]
|
||||
quoteTokenProgram = tx.rawTx.accountList[instruction.Accounts[12]]
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
var programName string
|
||||
if platformConfig.Equals(bonkPlatformConfig) {
|
||||
programName = SolProgramRaydiumLaunchLabBonk
|
||||
} else {
|
||||
programName = SolProgramRaydiumLaunchLab
|
||||
}
|
||||
|
||||
baseReserve, _ := decimal.NewFromString(baseTokenBalance.UITokenAmount.Amount)
|
||||
quoteReserve, _ := decimal.NewFromString(quoteTokenBalance.UITokenAmount.Amount)
|
||||
baseDecimals := uint8(baseTokenBalance.UITokenAmount.Decimals)
|
||||
var createEvent RaydiumLaunchLabCreateEvent
|
||||
inners, err := getInnerInstructions(innerInstructions, offset[1])
|
||||
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get inner instructions: %v", err)
|
||||
}
|
||||
var entryContract = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
loadedEvent := false
|
||||
var prefixLen uint = offset[1]
|
||||
for innerIndex, innerInstruction := range inners {
|
||||
if innerInstruction.ProgramIDIndex == instruction.ProgramIDIndex && len(innerInstruction.Data) >= 16 &&
|
||||
bytes.Equal(innerInstruction.Data[:8], pumpEventDiscriminator[:]) &&
|
||||
bytes.Equal(innerInstruction.Data[8:16], raydiumLaunchLabCreatePoolEvnet[:]) &&
|
||||
len(innerInstruction.Accounts) == 1 {
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
err := agbinary.NewBorshDecoder(innerInstruction.Data[16:]).Decode(&createEvent)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to deserialize create event: %w", err)
|
||||
}
|
||||
|
||||
loadedEvent = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !loadedEvent {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get create event")
|
||||
}
|
||||
totalSupply := decimal.NewFromUint64(createEvent.CurveParam.TotalSupply()).Div(decimal.New(1, int32(baseDecimals)))
|
||||
tx.Token[baseMint] = TokenMeta{
|
||||
Mint: baseMint,
|
||||
TokenProgram: baseTokenProgram,
|
||||
Decimals: baseDecimals,
|
||||
Name: createEvent.BaseMintParam.Name,
|
||||
Symbol: createEvent.BaseMintParam.Symbol,
|
||||
Url: createEvent.BaseMintParam.Uri,
|
||||
TotalSupply: &totalSupply,
|
||||
}
|
||||
return []Swap{{
|
||||
Program: programName,
|
||||
Event: "create",
|
||||
Pool: pool,
|
||||
BaseMint: baseMint,
|
||||
QuoteMint: quoteMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
Creator: creator,
|
||||
BaseMintDecimals: uint8(baseTokenBalance.UITokenAmount.Decimals),
|
||||
QuoteMintDecimals: uint8(quoteTokenBalance.UITokenAmount.Decimals),
|
||||
User: user,
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
EntryContract: entryContract,
|
||||
}}, offset, nil
|
||||
}
|
||||
|
||||
func raydiumLaunchLabMigrateToCpmmParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
if len(instruction.Accounts) < 27 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("not enough accounts for migrate instruction")
|
||||
}
|
||||
var entryContract solana.PublicKey = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
platformConfig := tx.rawTx.accountList[instruction.Accounts[3]]
|
||||
var programName string
|
||||
if platformConfig.Equals(bonkPlatformConfig) {
|
||||
programName = SolProgramRaydiumLaunchLabBonk
|
||||
} else {
|
||||
programName = SolProgramRaydiumLaunchLab
|
||||
}
|
||||
baseTokenProgram := tx.rawTx.accountList[instruction.Accounts[22]]
|
||||
quoteTokenProgram := tx.rawTx.accountList[instruction.Accounts[23]]
|
||||
|
||||
baseMint := tx.rawTx.accountList[instruction.Accounts[1]]
|
||||
quoteMint := tx.rawTx.accountList[instruction.Accounts[2]]
|
||||
pool := tx.rawTx.accountList[instruction.Accounts[17]]
|
||||
|
||||
baseVaultIdx := instruction.Accounts[19]
|
||||
quoteVaultIdx := instruction.Accounts[20]
|
||||
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)
|
||||
}
|
||||
offset[1] += 1
|
||||
return []Swap{
|
||||
{
|
||||
Program: programName,
|
||||
Event: "migrate",
|
||||
Pool: pool,
|
||||
BaseMint: baseMint,
|
||||
QuoteMint: quoteMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
BaseMintDecimals: uint8(baseTokenBalance.UITokenAmount.Decimals),
|
||||
QuoteMintDecimals: uint8(quoteTokenBalance.UITokenAmount.Decimals),
|
||||
User: tx.rawTx.accountList[instruction.Accounts[0]],
|
||||
//BaseAmount: decimal.Decimal{},
|
||||
//QuoteAmount: decimal.Decimal{},
|
||||
MigrateTopProgram: tx.rawTx.accountList[instruction.Accounts[4]],
|
||||
MigrateToPool: tx.rawTx.accountList[instruction.Accounts[5]],
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
|
||||
func raydiumLaunchLabMigrateToAmmParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
if len(instruction.Accounts) < 27 {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("not enough accounts for migrate instruction")
|
||||
}
|
||||
platformConfig := tx.rawTx.accountList[instruction.Accounts[3]]
|
||||
var programName string
|
||||
if platformConfig.Equals(bonkPlatformConfig) {
|
||||
programName = SolProgramRaydiumLaunchLabBonk
|
||||
} else {
|
||||
programName = SolProgramRaydiumLaunchLab
|
||||
}
|
||||
var entryContract solana.PublicKey = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
|
||||
baseMint := tx.rawTx.accountList[instruction.Accounts[1]]
|
||||
quoteMint := tx.rawTx.accountList[instruction.Accounts[2]]
|
||||
pool := tx.rawTx.accountList[instruction.Accounts[23]]
|
||||
|
||||
baseVaultIdx := instruction.Accounts[25]
|
||||
quoteVaultIdx := instruction.Accounts[26]
|
||||
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)
|
||||
}
|
||||
baseTokenProgram := baseTokenBalance.ProgramIDAccount
|
||||
quoteTokenProgram := quoteTokenBalance.ProgramIDAccount
|
||||
offset[1] += 1
|
||||
return []Swap{
|
||||
{
|
||||
Program: programName,
|
||||
Event: "migrate",
|
||||
Pool: pool,
|
||||
BaseMint: baseMint,
|
||||
QuoteMint: quoteMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
BaseMintDecimals: uint8(baseTokenBalance.UITokenAmount.Decimals),
|
||||
QuoteMintDecimals: uint8(quoteTokenBalance.UITokenAmount.Decimals),
|
||||
User: tx.rawTx.accountList[instruction.Accounts[0]],
|
||||
//BaseAmount: decimal.Decimal{},
|
||||
//QuoteAmount: decimal.Decimal{},
|
||||
MigrateTopProgram: tx.rawTx.accountList[instruction.Accounts[12]],
|
||||
MigrateToPool: tx.rawTx.accountList[instruction.Accounts[13]],
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
|
||||
type RaydiumLaunchLabSwapEvent struct {
|
||||
PoolState solana.PublicKey
|
||||
TotalBaseSell uint64
|
||||
VirtualBase uint64
|
||||
VirtualQuote uint64
|
||||
RealBaseBefore uint64
|
||||
RealQuoteBefore uint64
|
||||
RealBaseAfter uint64
|
||||
RealQuoteAfter uint64
|
||||
AmountIn uint64
|
||||
AmountOut uint64
|
||||
ProtocolFee uint64
|
||||
PlatformFee uint64
|
||||
CreatorFee uint64
|
||||
ShareFee uint64
|
||||
TradeDirection uint8 // 0: buy 1: sell
|
||||
PoolStatus uint8 // 0 Fund, 1 Migrate, 2 Trade
|
||||
|
||||
}
|
||||
|
||||
func raydiumLaunchLabSwapParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
platformConfig := tx.rawTx.accountList[instruction.Accounts[3]]
|
||||
var programName string
|
||||
if platformConfig.Equals(bonkPlatformConfig) {
|
||||
programName = SolProgramRaydiumLaunchLabBonk
|
||||
} else {
|
||||
programName = SolProgramRaydiumLaunchLab
|
||||
}
|
||||
var entryContract solana.PublicKey = tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
user := tx.rawTx.accountList[instruction.Accounts[0]]
|
||||
pool := tx.rawTx.accountList[instruction.Accounts[4]]
|
||||
userBaseIdx := instruction.Accounts[5]
|
||||
userQuoteIdx := instruction.Accounts[6]
|
||||
baseVaultIdx := instruction.Accounts[7]
|
||||
quoteVaultIdx := instruction.Accounts[8]
|
||||
baseMint := tx.rawTx.accountList[instruction.Accounts[9]]
|
||||
quoteMint := tx.rawTx.accountList[instruction.Accounts[10]]
|
||||
baseTokenProgram := tx.rawTx.accountList[instruction.Accounts[11]]
|
||||
quoteTokenProgram := tx.rawTx.accountList[instruction.Accounts[12]]
|
||||
|
||||
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)
|
||||
}
|
||||
baseMintDecimals := uint8(baseTokenBalance.UITokenAmount.Decimals)
|
||||
quoteMintDecimals := uint8(quoteTokenBalance.UITokenAmount.Decimals)
|
||||
inners, err := getInnerInstructions(innerInstructions, offset[1])
|
||||
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("failed to get inner instructions: %v", err)
|
||||
}
|
||||
|
||||
var swapEvent RaydiumLaunchLabSwapEvent
|
||||
loadedEvent := false
|
||||
var prefixLen uint = offset[1]
|
||||
for innerIndex, innerInstruction := range inners {
|
||||
if innerInstruction.ProgramIDIndex == instruction.ProgramIDIndex && len(innerInstruction.Data) >= 16 &&
|
||||
bytes.Equal(innerInstruction.Data[:8], pumpEventDiscriminator[:]) &&
|
||||
bytes.Equal(innerInstruction.Data[8:16], raydiumLaunchLabTradeEvnet[:]) &&
|
||||
len(innerInstruction.Accounts) == 1 {
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
err := agbinary.NewBorshDecoder(innerInstruction.Data[16:]).Decode(&swapEvent)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(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 event string
|
||||
var baseAmount, quoteAmount decimal.Decimal
|
||||
if swapEvent.TradeDirection == 0 {
|
||||
event = "buy"
|
||||
baseAmount = decimal.NewFromInt(int64(swapEvent.AmountOut))
|
||||
quoteAmount = decimal.NewFromInt(int64(swapEvent.AmountIn))
|
||||
} else {
|
||||
event = "sell"
|
||||
baseAmount = decimal.NewFromInt(int64(swapEvent.AmountIn))
|
||||
quoteAmount = decimal.NewFromInt(int64(swapEvent.AmountOut))
|
||||
}
|
||||
baseReserve := decimal.NewFromInt(int64(swapEvent.RealBaseAfter))
|
||||
quoteReserve := decimal.NewFromInt(int64(swapEvent.RealQuoteAfter))
|
||||
userBase := getAccountBalanceAfterTx(tx.rawTx, userBaseIdx)
|
||||
userQuote := getAccountBalanceAfterTx(tx.rawTx, userQuoteIdx)
|
||||
|
||||
return []Swap{{
|
||||
Program: programName,
|
||||
Event: event,
|
||||
Pool: pool,
|
||||
BaseMint: baseMint,
|
||||
QuoteMint: quoteMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
BaseMintDecimals: baseMintDecimals,
|
||||
QuoteMintDecimals: quoteMintDecimals,
|
||||
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