punm parser
This commit is contained in:
513
pumpamm.go
Normal file
513
pumpamm.go
Normal file
@@ -0,0 +1,513 @@
|
||||
package pump_parser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
agbinary "github.com/gagliardetto/binary"
|
||||
"github.com/gagliardetto/solana-go"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
type ammBuyEvent struct {
|
||||
TimeStamp int64
|
||||
BaseAmountOut uint64
|
||||
MaxQuoteAmountIn uint64
|
||||
UserBaseTokenReserve uint64
|
||||
UserQuoteTokenReserve uint64
|
||||
PoolBaseTokenReserve uint64
|
||||
PoolQuoteTokenReserve uint64
|
||||
QuoteAmountIn uint64
|
||||
LpFeeBasisPoints uint64
|
||||
LpFee uint64
|
||||
ProtocolFee uint64
|
||||
QuoteAmountInWithLpFee uint64
|
||||
UserQuoteAmountIn uint64
|
||||
|
||||
Pool solana.PublicKey
|
||||
User solana.PublicKey
|
||||
UserBaseTokenAccount solana.PublicKey
|
||||
UserQuoteTokenAccount solana.PublicKey
|
||||
ProtocolFeeRecipient solana.PublicKey
|
||||
ProtocolFeeRecipientTokenAccount solana.PublicKey
|
||||
CoinCreator solana.PublicKey
|
||||
}
|
||||
|
||||
type ammCreatePoolEvent struct {
|
||||
TimeStamp int64
|
||||
Index uint16
|
||||
Creator solana.PublicKey
|
||||
BaseMint solana.PublicKey
|
||||
QuoteMint solana.PublicKey
|
||||
BaseMintDecimals uint8
|
||||
QuoteMintDecimals uint8
|
||||
BaseAmountIn uint64
|
||||
QuoteAmountIn uint64
|
||||
PoolBaseAmount uint64
|
||||
PoolQuoteAmount uint64
|
||||
MinimumLiquidity uint64
|
||||
InitialLiquidity uint64
|
||||
LpTokenAmountOut uint64
|
||||
PoolBump uint8
|
||||
|
||||
Pool solana.PublicKey
|
||||
LpMint solana.PublicKey
|
||||
UserBaseTokenAccount solana.PublicKey
|
||||
UserQuoteTokenAccount solana.PublicKey
|
||||
CoinCreator solana.PublicKey
|
||||
IsMayhemMode bool
|
||||
}
|
||||
|
||||
type ammDepositEvent struct {
|
||||
TimeStamp int64
|
||||
LpTokenAmountOut uint64
|
||||
MaxBaseAmountIn uint64
|
||||
MaxQuoteAmountIn uint64
|
||||
UserBaseTokenReserves uint64
|
||||
UserQuoteTokenReserves uint64
|
||||
PoolBaseTokenReserves uint64
|
||||
PoolQuoteTokenReserves uint64
|
||||
BaseAmountIn uint64
|
||||
QuoteAmountIn uint64
|
||||
LpMintSupply uint64
|
||||
|
||||
Pool solana.PublicKey
|
||||
User solana.PublicKey
|
||||
UserBaseTokenAccount solana.PublicKey
|
||||
UserQuoteTokenAccount solana.PublicKey
|
||||
UserPoolTokenAccount solana.PublicKey
|
||||
}
|
||||
|
||||
type ammSellEvent struct {
|
||||
Timestamp int64
|
||||
BaseAmountIn uint64
|
||||
MinQuoteAmountOut uint64
|
||||
UserBaseTokenReserves uint64
|
||||
UserQuoteTokenReserves uint64
|
||||
PoolBaseTokenReserves uint64
|
||||
PoolQuoteTokenReserves uint64
|
||||
QuoteAmountOut uint64
|
||||
LpFeeBasisPoints uint64
|
||||
LpFee uint64
|
||||
ProtocolFeeBasisPoints uint64
|
||||
ProtocolFee uint64
|
||||
QuoteAmountOutWithoutLpFee uint64
|
||||
UserQuoteAmountOut uint64
|
||||
|
||||
Pool solana.PublicKey
|
||||
User solana.PublicKey
|
||||
UserBaseTokenAccount solana.PublicKey
|
||||
UserQuoteTokenAccount solana.PublicKey
|
||||
ProtocolFeeRecipient solana.PublicKey
|
||||
ProtocolFeeRecipientTokenAccount solana.PublicKey
|
||||
CoinCreator solana.PublicKey
|
||||
}
|
||||
|
||||
type ammWithdrawEvent struct {
|
||||
Timestamp int64
|
||||
LpTokenAmountIn uint64
|
||||
MinBaseAmountOut uint64
|
||||
MinQuoteAmountOut uint64
|
||||
UserBaseTokenReserves uint64
|
||||
UserQuoteTokenReserves uint64
|
||||
PoolBaseTokenReserves uint64
|
||||
PoolQuoteTokenReserves uint64
|
||||
BaseAmountOut uint64
|
||||
QuoteAmountOut uint64
|
||||
LpMintSupply uint64
|
||||
|
||||
Pool solana.PublicKey
|
||||
User solana.PublicKey
|
||||
UserBaseTokenAccount solana.PublicKey
|
||||
UserQuoteTokenAccount solana.PublicKey
|
||||
UserPoolTokenAccount solana.PublicKey
|
||||
}
|
||||
|
||||
func pumpAmmParser(result *RawTx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
|
||||
if !result.accountList[instruction.ProgramIDIndex].Equals(pumpAmmProgram) {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pump amm program instruction not found, offset: %d, %d", offset[0], offset[1])
|
||||
}
|
||||
decode := instruction.Data
|
||||
if len(decode) < 8 {
|
||||
offset[1] += 1
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pumpamm program instruction data too short, offset: %d, %d", offset[0], offset[1])
|
||||
}
|
||||
|
||||
discriminator := *(*[8]byte)(decode[:8])
|
||||
switch discriminator {
|
||||
case pumpAmmCreateDiscriminator:
|
||||
return ammCreatePoolParser(result, instruction, innerInstructions, offset)
|
||||
case pumpAmmBuyDiscriminator:
|
||||
return ammBuyParser(result, instruction, innerInstructions, offset)
|
||||
case pumpAmmSellDiscriminator:
|
||||
return ammSellParser(result, instruction, innerInstructions, offset)
|
||||
case pumpAmmDepositDiscriminator:
|
||||
return depositParse(result, instruction, innerInstructions, offset)
|
||||
case pumpAmmWithdrawDiscriminator:
|
||||
return withdrawParse(result, instruction, innerInstructions, offset)
|
||||
default:
|
||||
return nil, increaseOffset(offset), InstructionIgnoredError
|
||||
}
|
||||
}
|
||||
|
||||
func ammCreatePoolParser(result *RawTx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
var entryContract = result.accountList[result.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
var err error
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pumpamm create get inner instructions error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
var createEvent ammCreatePoolEvent
|
||||
for innerIndex, innerInstr := range inners {
|
||||
if innerInstr.ProgramIDIndex == instruction.ProgramIDIndex &&
|
||||
bytes.Equal(innerInstr.Data[:8], pumpAmmEventDiscriminator[:]) &&
|
||||
bytes.Equal(innerInstr.Data[8:16], pumpAmmCreateEventDiscriminator[:]) {
|
||||
err = agbinary.NewBorshDecoder(innerInstr.Data[16:]).Decode(&createEvent)
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] += uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
if err != nil {
|
||||
return nil, offset, fmt.Errorf("pump amm create pool event decode error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if createEvent == (ammCreatePoolEvent{}) {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pump amm create pool event not found, offset: %d, %d", offset[0], prefixLen)
|
||||
}
|
||||
|
||||
baseTokenProgram := result.accountList[instruction.Accounts[13]]
|
||||
quoteTokenProgram := result.accountList[instruction.Accounts[14]]
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramPumpAMM,
|
||||
Event: "create",
|
||||
Pool: createEvent.Pool,
|
||||
BaseMint: createEvent.BaseMint,
|
||||
QuoteMint: createEvent.QuoteMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
Creator: createEvent.CoinCreator,
|
||||
BaseMintDecimals: createEvent.BaseMintDecimals,
|
||||
QuoteMintDecimals: createEvent.QuoteMintDecimals,
|
||||
User: createEvent.Creator,
|
||||
BaseAmount: decimal.NewFromUint64(createEvent.BaseAmountIn),
|
||||
QuoteAmount: decimal.NewFromUint64(createEvent.QuoteAmountIn),
|
||||
BaseReserve: decimal.NewFromUint64(createEvent.PoolBaseAmount),
|
||||
QuoteReserve: decimal.NewFromUint64(createEvent.PoolQuoteAmount),
|
||||
UserBaseBalance: decimal.Decimal{},
|
||||
UserQuoteBalance: decimal.Decimal{},
|
||||
EntryContract: entryContract,
|
||||
Mayhem: createEvent.IsMayhemMode,
|
||||
},
|
||||
}, offset, nil
|
||||
|
||||
}
|
||||
|
||||
func ammBuyParser(result *RawTx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
var entryContract = result.accountList[result.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
var err error
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pumpamm create get inner instructions error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
var event ammBuyEvent
|
||||
for innerIndex, innerInstr := range inners {
|
||||
if innerInstr.ProgramIDIndex == instruction.ProgramIDIndex &&
|
||||
bytes.Equal(innerInstr.Data[:8], pumpAmmEventDiscriminator[:]) &&
|
||||
bytes.Equal(innerInstr.Data[8:16], pumpAmmBuyEventDiscriminator[:]) {
|
||||
err = agbinary.NewBorshDecoder(innerInstr.Data[16:]).Decode(&event)
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] += uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
if err != nil {
|
||||
return nil, offset, fmt.Errorf("pump amm buy pool event decode error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if event == (ammBuyEvent{}) {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pump amm buy event not found, offset: %d, %d", offset[0], prefixLen)
|
||||
}
|
||||
baseMint := result.accountList[instruction.Accounts[3]]
|
||||
quoteMint := result.accountList[instruction.Accounts[4]]
|
||||
baseTokenProgram := result.accountList[instruction.Accounts[11]]
|
||||
quoteTokenProgram := result.accountList[instruction.Accounts[12]]
|
||||
|
||||
poolBaseAccountIdx := instruction.Accounts[7]
|
||||
poolQuoteAccountIdx := instruction.Accounts[8]
|
||||
var (
|
||||
baseMintDecimals uint8
|
||||
quoteMintDecimals uint8
|
||||
)
|
||||
for _, meta := range result.Meta.PostTokenBalances {
|
||||
if meta.AccountIndex == poolBaseAccountIdx {
|
||||
baseMintDecimals = uint8(meta.UITokenAmount.Decimals)
|
||||
} else if meta.AccountIndex == poolQuoteAccountIdx {
|
||||
quoteMintDecimals = uint8(meta.UITokenAmount.Decimals)
|
||||
}
|
||||
}
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramPumpAMM,
|
||||
Event: "buy",
|
||||
Pool: event.Pool,
|
||||
BaseMint: baseMint,
|
||||
QuoteMint: quoteMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
Creator: event.CoinCreator,
|
||||
BaseMintDecimals: baseMintDecimals,
|
||||
QuoteMintDecimals: quoteMintDecimals,
|
||||
User: event.User,
|
||||
BaseAmount: decimal.NewFromUint64(event.BaseAmountOut),
|
||||
QuoteAmount: decimal.NewFromUint64(event.UserQuoteAmountIn),
|
||||
BaseReserve: decimal.NewFromUint64(event.PoolBaseTokenReserve - event.BaseAmountOut),
|
||||
QuoteReserve: decimal.NewFromUint64(event.PoolQuoteTokenReserve + event.QuoteAmountIn),
|
||||
Mayhem: isMayhemPump(result.accountList[instruction.Accounts[9]]),
|
||||
UserBaseBalance: decimal.NewFromUint64(event.UserBaseTokenReserve + event.BaseAmountOut),
|
||||
UserQuoteBalance: decimal.NewFromUint64(event.UserQuoteTokenReserve - event.UserQuoteAmountIn),
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
|
||||
func ammSellParser(result *RawTx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
var entryContract = result.accountList[result.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
var err error
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pumpamm sell get inner instructions error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
var event ammSellEvent
|
||||
for innerIndex, innerInstr := range inners {
|
||||
if innerInstr.ProgramIDIndex == instruction.ProgramIDIndex &&
|
||||
bytes.Equal(innerInstr.Data[:8], pumpAmmEventDiscriminator[:]) &&
|
||||
bytes.Equal(innerInstr.Data[8:16], pumpAmmSellEventDiscriminator[:]) {
|
||||
err = agbinary.NewBorshDecoder(innerInstr.Data[16:]).Decode(&event)
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] += uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
if err != nil {
|
||||
return nil, offset, fmt.Errorf("pump amm sell pool event decode error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if event == (ammSellEvent{}) {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pump amm sell event not found, offset: %d, %d", offset[0], prefixLen)
|
||||
}
|
||||
baseMint := result.accountList[instruction.Accounts[3]]
|
||||
quoteMint := result.accountList[instruction.Accounts[4]]
|
||||
baseTokenProgram := result.accountList[instruction.Accounts[11]]
|
||||
quoteTokenProgram := result.accountList[instruction.Accounts[12]]
|
||||
|
||||
poolBaseAccountIdx := instruction.Accounts[7]
|
||||
poolQuoteAccountIdx := instruction.Accounts[8]
|
||||
var (
|
||||
baseMintDecimals uint8
|
||||
quoteMintDecimals uint8
|
||||
)
|
||||
for _, meta := range result.Meta.PostTokenBalances {
|
||||
if meta.AccountIndex == poolBaseAccountIdx {
|
||||
baseMintDecimals = uint8(meta.UITokenAmount.Decimals)
|
||||
} else if meta.AccountIndex == poolQuoteAccountIdx {
|
||||
quoteMintDecimals = uint8(meta.UITokenAmount.Decimals)
|
||||
}
|
||||
}
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramPumpAMM,
|
||||
Event: "sell",
|
||||
Pool: event.Pool,
|
||||
BaseMint: baseMint,
|
||||
QuoteMint: quoteMint,
|
||||
BaseTokenProgram: baseTokenProgram,
|
||||
QuoteTokenProgram: quoteTokenProgram,
|
||||
Creator: event.CoinCreator,
|
||||
BaseMintDecimals: baseMintDecimals,
|
||||
QuoteMintDecimals: quoteMintDecimals,
|
||||
User: event.User,
|
||||
BaseAmount: decimal.NewFromUint64(event.BaseAmountIn),
|
||||
QuoteAmount: decimal.NewFromUint64(event.UserQuoteAmountOut),
|
||||
BaseReserve: decimal.NewFromUint64(event.PoolBaseTokenReserves + event.BaseAmountIn),
|
||||
QuoteReserve: decimal.NewFromUint64(event.PoolQuoteTokenReserves - event.QuoteAmountOut),
|
||||
Mayhem: isMayhemPump(result.accountList[instruction.Accounts[9]]),
|
||||
UserBaseBalance: decimal.NewFromUint64(event.UserBaseTokenReserves - event.BaseAmountIn),
|
||||
UserQuoteBalance: decimal.NewFromUint64(event.UserQuoteTokenReserves + event.UserQuoteAmountOut),
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
|
||||
func depositParse(result *RawTx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
var entryContract = result.accountList[result.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
var err error
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pumpamm deposit get inner instructions error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
|
||||
var event ammDepositEvent
|
||||
|
||||
for innerIndex, innerInstr := range inners {
|
||||
if innerInstr.ProgramIDIndex == instruction.ProgramIDIndex &&
|
||||
bytes.Equal(innerInstr.Data[:8], pumpAmmEventDiscriminator[:]) &&
|
||||
bytes.Equal(innerInstr.Data[8:16], pumpAmmDepositEventDiscriminator[:]) {
|
||||
err = agbinary.NewBorshDecoder(innerInstr.Data[16:]).Decode(&event)
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] += uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
if err != nil {
|
||||
return nil, offset, fmt.Errorf("pump amm deposit pool event decode error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if event == (ammDepositEvent{}) {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pump amm deposit event not found, offset: %d, %d", offset[0], prefixLen)
|
||||
}
|
||||
|
||||
var (
|
||||
poolBaseAccountIdx = instruction.Accounts[9]
|
||||
poolQuoteAccountIdx = instruction.Accounts[10]
|
||||
baseMintDecimals uint8
|
||||
quoteMintDecimals uint8
|
||||
baseMintProgram solana.PublicKey
|
||||
quoteMintProgram solana.PublicKey
|
||||
)
|
||||
for _, meta := range result.Meta.PostTokenBalances {
|
||||
if meta.AccountIndex == poolBaseAccountIdx {
|
||||
baseMintDecimals = uint8(meta.UITokenAmount.Decimals)
|
||||
baseMintProgram = meta.ProgramIDAccount
|
||||
if baseMintProgram.IsZero() && meta.ProgramID != "" {
|
||||
baseMintProgram = solana.MustPublicKeyFromBase58(meta.ProgramID)
|
||||
}
|
||||
}
|
||||
if meta.AccountIndex == poolQuoteAccountIdx {
|
||||
quoteMintDecimals = uint8(meta.UITokenAmount.Decimals)
|
||||
quoteMintProgram = meta.ProgramIDAccount
|
||||
if quoteMintProgram.IsZero() && meta.ProgramID != "" {
|
||||
quoteMintProgram = solana.MustPublicKeyFromBase58(meta.ProgramID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramPumpAMM,
|
||||
Event: "deposit",
|
||||
Pool: event.Pool,
|
||||
BaseMint: result.accountList[instruction.Accounts[3]],
|
||||
QuoteMint: result.accountList[instruction.Accounts[4]],
|
||||
BaseTokenProgram: baseMintProgram,
|
||||
QuoteTokenProgram: quoteMintProgram,
|
||||
//Creator: solana.PublicKey{},
|
||||
BaseMintDecimals: baseMintDecimals,
|
||||
QuoteMintDecimals: quoteMintDecimals,
|
||||
User: event.User,
|
||||
BaseAmount: decimal.NewFromUint64(event.BaseAmountIn),
|
||||
QuoteAmount: decimal.NewFromUint64(event.QuoteAmountIn),
|
||||
BaseReserve: decimal.NewFromUint64(event.PoolBaseTokenReserves + event.BaseAmountIn),
|
||||
QuoteReserve: decimal.NewFromUint64(event.PoolQuoteTokenReserves + event.QuoteAmountIn),
|
||||
//Mayhem: false,
|
||||
UserBaseBalance: decimal.NewFromUint64(event.UserBaseTokenReserves - event.BaseAmountIn),
|
||||
UserQuoteBalance: decimal.NewFromUint64(event.UserQuoteTokenReserves - event.QuoteAmountIn),
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
|
||||
func withdrawParse(result *RawTx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
var entryContract = result.accountList[result.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
var err error
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pumpamm withdraw get inner instructions error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
|
||||
var event ammWithdrawEvent
|
||||
|
||||
for innerIndex, innerInstr := range inners {
|
||||
if innerInstr.ProgramIDIndex == instruction.ProgramIDIndex &&
|
||||
bytes.Equal(innerInstr.Data[:8], pumpAmmEventDiscriminator[:]) &&
|
||||
bytes.Equal(innerInstr.Data[8:16], pumpAmmWithdrawEventDiscriminator[:]) {
|
||||
err = agbinary.NewBorshDecoder(innerInstr.Data[16:]).Decode(&event)
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] += uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
if err != nil {
|
||||
return nil, offset, fmt.Errorf("pump amm withdraw pool event decode error: %v, offset: %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if event == (ammWithdrawEvent{}) {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pump amm withdraw event not found, offset: %d, %d", offset[0], prefixLen)
|
||||
}
|
||||
|
||||
var (
|
||||
poolBaseAccountIdx = instruction.Accounts[9]
|
||||
poolQuoteAccountIdx = instruction.Accounts[10]
|
||||
baseMintDecimals uint8
|
||||
quoteMintDecimals uint8
|
||||
baseMintProgram solana.PublicKey
|
||||
quoteMintProgram solana.PublicKey
|
||||
)
|
||||
for _, meta := range result.Meta.PostTokenBalances {
|
||||
if meta.AccountIndex == poolBaseAccountIdx {
|
||||
baseMintDecimals = uint8(meta.UITokenAmount.Decimals)
|
||||
baseMintProgram = meta.ProgramIDAccount
|
||||
if baseMintProgram.IsZero() && meta.ProgramID != "" {
|
||||
baseMintProgram = solana.MustPublicKeyFromBase58(meta.ProgramID)
|
||||
}
|
||||
}
|
||||
if meta.AccountIndex == poolQuoteAccountIdx {
|
||||
quoteMintDecimals = uint8(meta.UITokenAmount.Decimals)
|
||||
quoteMintProgram = meta.ProgramIDAccount
|
||||
if quoteMintProgram.IsZero() && meta.ProgramID != "" {
|
||||
quoteMintProgram = solana.MustPublicKeyFromBase58(meta.ProgramID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return []Swap{
|
||||
{
|
||||
Program: SolProgramPumpAMM,
|
||||
Event: "withdraw",
|
||||
Pool: event.Pool,
|
||||
BaseMint: result.accountList[instruction.Accounts[3]],
|
||||
QuoteMint: result.accountList[instruction.Accounts[4]],
|
||||
BaseTokenProgram: baseMintProgram,
|
||||
QuoteTokenProgram: quoteMintProgram,
|
||||
//Creator: solana.PublicKey{},
|
||||
BaseMintDecimals: baseMintDecimals,
|
||||
QuoteMintDecimals: quoteMintDecimals,
|
||||
User: event.User,
|
||||
BaseAmount: decimal.NewFromUint64(event.BaseAmountOut),
|
||||
QuoteAmount: decimal.NewFromUint64(event.QuoteAmountOut),
|
||||
BaseReserve: decimal.NewFromUint64(event.PoolBaseTokenReserves - event.BaseAmountOut),
|
||||
QuoteReserve: decimal.NewFromUint64(event.PoolQuoteTokenReserves - event.QuoteAmountOut),
|
||||
//Mayhem: false,
|
||||
UserBaseBalance: decimal.NewFromUint64(event.UserBaseTokenReserves + event.BaseAmountOut),
|
||||
UserQuoteBalance: decimal.NewFromUint64(event.UserQuoteTokenReserves + event.QuoteAmountOut),
|
||||
EntryContract: entryContract,
|
||||
},
|
||||
}, offset, nil
|
||||
}
|
||||
Reference in New Issue
Block a user