Update metora dlmm program parse
This commit is contained in:
170
cmd/dlmmparse/main.go
Normal file
170
cmd/dlmmparse/main.go
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gagliardetto/solana-go"
|
||||||
|
"github.com/gagliardetto/solana-go/programs/address-lookup-table"
|
||||||
|
"github.com/gagliardetto/solana-go/rpc"
|
||||||
|
|
||||||
|
"github.com/samlior/libsam/pkg/shreder"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OKX tx
|
||||||
|
// const dlmmSignature = "4W8gD2iEYyvzpPiW9BhdH5hUrfXhqH46ziLzPkaaxmaA8XXK53erUvrPdZ5cY2XrgWwix1hmRajUnGAiNp4cSGpN"
|
||||||
|
|
||||||
|
const dlmmSignature = "3Kcm9rqG9mJ6PCM5DuUoZ6jk3kzbH7J5GP488E5MKMwodf2NXgddygEcWBmzRBrV2YZFmXtG22gvcJixqdsCjRPn"
|
||||||
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const rpcURL = "https://staked.helius-rpc.com?api-key=5adcf1f9-5719-43d1-bf3f-c2d4e1e5f94d"
|
||||||
|
if rpcURL == "" {
|
||||||
|
log.Fatal("SOL_RPC_URL is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := rpc.New(rpcURL)
|
||||||
|
sig, err := solana.SignatureFromBase58(dlmmSignature)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("invalid dlmmSignature: %v", err)
|
||||||
|
}
|
||||||
|
version := uint64(0)
|
||||||
|
tx, err := client.GetTransaction(
|
||||||
|
context.Background(),
|
||||||
|
sig,
|
||||||
|
&rpc.GetTransactionOpts{
|
||||||
|
Commitment: rpc.CommitmentFinalized,
|
||||||
|
MaxSupportedTransactionVersion: &version,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("getTransaction failed: %v", err)
|
||||||
|
}
|
||||||
|
if tx == nil || tx.Transaction == nil {
|
||||||
|
log.Fatal("transaction is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
rawTx, err := tx.Transaction.GetTransaction()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("decode transaction failed: %v", err)
|
||||||
|
}
|
||||||
|
if rawTx == nil {
|
||||||
|
log.Fatal("decoded transaction is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rawTx.Message.AddressTableLookups) > 0 {
|
||||||
|
tables := make(map[solana.PublicKey]solana.PublicKeySlice, len(rawTx.Message.AddressTableLookups))
|
||||||
|
for _, lookup := range rawTx.Message.AddressTableLookups {
|
||||||
|
state, err := addresslookuptable.GetAddressLookupTable(context.Background(), client, lookup.AccountKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("load address table %s failed: %v", lookup.AccountKey, err)
|
||||||
|
}
|
||||||
|
tables[lookup.AccountKey] = state.Addresses
|
||||||
|
}
|
||||||
|
if err := rawTx.Message.SetAddressTables(tables); err != nil {
|
||||||
|
log.Fatalf("set address tables failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := rawTx.Message.ResolveLookups(); err != nil {
|
||||||
|
log.Fatalf("resolve address lookups failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update := toSubscribeUpdate(tx.Slot, rawTx)
|
||||||
|
signals := shreder.ParseTransaction(update, nil, true)
|
||||||
|
if len(signals) == 0 {
|
||||||
|
fmt.Println("no signals parsed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
printed := false
|
||||||
|
for _, signal := range signals {
|
||||||
|
if signal == nil || signal.Label != "dlmm" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
printed = true
|
||||||
|
output, err := json.MarshalIndent(signal, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("marshal signal failed: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(string(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
if printed {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("no dlmm signal parsed, dump all signals:")
|
||||||
|
for _, signal := range signals {
|
||||||
|
if signal == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
output, err := json.MarshalIndent(signal, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("marshal signal failed: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(string(output))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toSubscribeUpdate(slot uint64, tx *solana.Transaction) *shreder.SubscribeUpdateTransaction {
|
||||||
|
signatures := make([][]byte, len(tx.Signatures))
|
||||||
|
for i, sig := range tx.Signatures {
|
||||||
|
signatures[i] = sig[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
accountKeys := make([][]byte, len(tx.Message.AccountKeys))
|
||||||
|
for i, key := range tx.Message.AccountKeys {
|
||||||
|
accountKeys[i] = key[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
instructions := make([]*shreder.CompiledInstruction, len(tx.Message.Instructions))
|
||||||
|
for i, instr := range tx.Message.Instructions {
|
||||||
|
accounts := make([]byte, len(instr.Accounts))
|
||||||
|
for j, acc := range instr.Accounts {
|
||||||
|
accounts[j] = byte(acc)
|
||||||
|
}
|
||||||
|
instructions[i] = &shreder.CompiledInstruction{
|
||||||
|
ProgramIdIndex: uint32(instr.ProgramIDIndex),
|
||||||
|
Accounts: accounts,
|
||||||
|
Data: instr.Data[:],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addressTableLookups := make([]*shreder.MessageAddressTableLookup, len(tx.Message.AddressTableLookups))
|
||||||
|
for i, lookup := range tx.Message.AddressTableLookups {
|
||||||
|
writable := make([]byte, len(lookup.WritableIndexes))
|
||||||
|
for j, idx := range lookup.WritableIndexes {
|
||||||
|
writable[j] = byte(idx)
|
||||||
|
}
|
||||||
|
readonly := make([]byte, len(lookup.ReadonlyIndexes))
|
||||||
|
for j, idx := range lookup.ReadonlyIndexes {
|
||||||
|
readonly[j] = byte(idx)
|
||||||
|
}
|
||||||
|
addressTableLookups[i] = &shreder.MessageAddressTableLookup{
|
||||||
|
AccountKey: lookup.AccountKey[:],
|
||||||
|
WritableIndexes: writable,
|
||||||
|
ReadonlyIndexes: readonly,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &shreder.SubscribeUpdateTransaction{
|
||||||
|
Transaction: &shreder.Transaction{
|
||||||
|
Signatures: signatures,
|
||||||
|
Message: &shreder.Message{
|
||||||
|
Header: &shreder.MessageHeader{
|
||||||
|
NumRequiredSignatures: uint32(tx.Message.Header.NumRequiredSignatures),
|
||||||
|
NumReadonlySignedAccounts: uint32(tx.Message.Header.NumReadonlySignedAccounts),
|
||||||
|
NumReadonlyUnsignedAccounts: uint32(tx.Message.Header.NumReadonlyUnsignedAccounts),
|
||||||
|
},
|
||||||
|
AccountKeys: accountKeys,
|
||||||
|
RecentBlockhash: nil,
|
||||||
|
Instructions: instructions,
|
||||||
|
Versioned: false,
|
||||||
|
AddressTableLookups: addressTableLookups,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Slot: slot,
|
||||||
|
}
|
||||||
|
}
|
||||||
8471
pkg/shreder/dlmm_idl.json
Normal file
8471
pkg/shreder/dlmm_idl.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,13 @@ type TxSignal struct {
|
|||||||
|
|
||||||
ExactSOL bool `json:"exact_in"`
|
ExactSOL bool `json:"exact_in"`
|
||||||
|
|
||||||
|
|
||||||
|
//Just for metaora DLMM
|
||||||
|
// ActiveBin is the active bin id provided by swap_with_price_impact(2).
|
||||||
|
ActiveBin int32 `json:"active_bin"`
|
||||||
|
// MaxPriceImpactBps is the price impact guard for swap_with_price_impact(2).
|
||||||
|
MaxPriceImpactBps uint16 `json:"max_price_impact_bps"`
|
||||||
|
|
||||||
// parsed values
|
// parsed values
|
||||||
Token0AmountUint64 uint64 `json:"-"`
|
Token0AmountUint64 uint64 `json:"-"`
|
||||||
Token1AmountUint64 uint64 `json:"-"`
|
Token1AmountUint64 uint64 `json:"-"`
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ var (
|
|||||||
gmgnProgramID = solana.MustPublicKeyFromBase58("GMgnVFR8Jb39LoXsEVzb3DvBy3ywCmdmJquHUy1Lrkqb")
|
gmgnProgramID = solana.MustPublicKeyFromBase58("GMgnVFR8Jb39LoXsEVzb3DvBy3ywCmdmJquHUy1Lrkqb")
|
||||||
|
|
||||||
bonkProgramID = solana.MustPublicKeyFromBase58("BBRouter1cVunVXvkcqeKkZQcBK7ruan37PPm3xzWaXD")
|
bonkProgramID = solana.MustPublicKeyFromBase58("BBRouter1cVunVXvkcqeKkZQcBK7ruan37PPm3xzWaXD")
|
||||||
|
|
||||||
|
|
||||||
|
// For Metaora dlmm
|
||||||
|
dlmmProgramID = solana.MustPublicKeyFromBase58("LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo")
|
||||||
)
|
)
|
||||||
|
|
||||||
type AccountNotFoundError struct {
|
type AccountNotFoundError struct {
|
||||||
@@ -102,6 +106,13 @@ var (
|
|||||||
gmgnBuyTokensIX = []byte{0x66, 0x06, 0x3d, 0x12, 0x01, 0xda, 0xeb, 0xea}
|
gmgnBuyTokensIX = []byte{0x66, 0x06, 0x3d, 0x12, 0x01, 0xda, 0xeb, 0xea}
|
||||||
|
|
||||||
bonkBuyAndSellTokensIX = []byte{0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}
|
bonkBuyAndSellTokensIX = []byte{0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}
|
||||||
|
|
||||||
|
dlmmSwapIX = []byte{248, 198, 158, 145, 225, 117, 135, 200}
|
||||||
|
dlmmSwap2IX = []byte{65, 75, 63, 76, 235, 91, 91, 136}
|
||||||
|
dlmmSwapExactOutIX = []byte{250, 73, 101, 33, 38, 207, 75, 184}
|
||||||
|
dlmmSwapExactOut2IX = []byte{43, 215, 247, 132, 137, 60, 243, 81}
|
||||||
|
dlmmSwapPriceImpactIX = []byte{56, 173, 230, 208, 173, 228, 156, 205}
|
||||||
|
dlmmSwapPriceImpact2IX = []byte{74, 98, 192, 214, 177, 51, 75, 51}
|
||||||
)
|
)
|
||||||
|
|
||||||
type compiledInstruction struct {
|
type compiledInstruction struct {
|
||||||
@@ -349,6 +360,9 @@ func ParseTransaction(update *SubscribeUpdateTransaction, loader *AddressTables,
|
|||||||
case bonkProgramID:
|
case bonkProgramID:
|
||||||
txRes, err := parseBonkInstruction(versioned, i)
|
txRes, err := parseBonkInstruction(versioned, i)
|
||||||
parsed = appendParsed(now, parsed, txRes, err, txHash, "bonk")
|
parsed = appendParsed(now, parsed, txRes, err, txHash, "bonk")
|
||||||
|
case dlmmProgramID:
|
||||||
|
txRes, err := parseDlmmInstruction(versioned, i)
|
||||||
|
parsed = appendParsed(now, parsed, txRes, err, txHash, "dlmm")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1344,6 +1358,222 @@ func parseTermSell(tx *versionedTransaction, instruction *compiledInstruction) (
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dlmmTokenOrder(tokenX, tokenY solana.PublicKey) (solana.PublicKey, solana.PublicKey) {
|
||||||
|
switch {
|
||||||
|
case tokenX.Equals(solana.WrappedSol):
|
||||||
|
return tokenY, tokenX
|
||||||
|
case tokenY.Equals(solana.WrappedSol):
|
||||||
|
return tokenX, tokenY
|
||||||
|
default:
|
||||||
|
return tokenX, tokenY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findAssociatedTokenAddressWithTokenProgram(wallet, mint, tokenProgram solana.PublicKey) (solana.PublicKey, uint8, error) {
|
||||||
|
return solana.FindProgramAddress([][]byte{
|
||||||
|
wallet[:],
|
||||||
|
tokenProgram[:],
|
||||||
|
mint[:],
|
||||||
|
}, solana.SPLAssociatedTokenAccountProgramID)
|
||||||
|
}
|
||||||
|
|
||||||
|
type dlmmParsedArgs struct {
|
||||||
|
AmountIn uint64
|
||||||
|
AmountOut uint64
|
||||||
|
ExactIn bool
|
||||||
|
ExactOut bool
|
||||||
|
ActiveBin int32
|
||||||
|
MaxPriceImpactBps uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDlmmSwapArgs(disc []byte, payload []byte) (*dlmmParsedArgs, error) {
|
||||||
|
switch {
|
||||||
|
case bytes.Equal(disc, dlmmSwapIX), bytes.Equal(disc, dlmmSwap2IX):
|
||||||
|
if len(payload) < 16 {
|
||||||
|
return nil, fmt.Errorf("data too short for dlmm swap args, len=%d", len(payload))
|
||||||
|
}
|
||||||
|
return &dlmmParsedArgs{
|
||||||
|
AmountIn: binary.LittleEndian.Uint64(payload[0:8]),
|
||||||
|
AmountOut: binary.LittleEndian.Uint64(payload[8:16]),
|
||||||
|
ExactIn: true,
|
||||||
|
}, nil
|
||||||
|
case bytes.Equal(disc, dlmmSwapExactOutIX), bytes.Equal(disc, dlmmSwapExactOut2IX):
|
||||||
|
if len(payload) < 16 {
|
||||||
|
return nil, fmt.Errorf("data too short for dlmm swap exact out args, len=%d", len(payload))
|
||||||
|
}
|
||||||
|
return &dlmmParsedArgs{
|
||||||
|
AmountIn: binary.LittleEndian.Uint64(payload[0:8]),
|
||||||
|
AmountOut: binary.LittleEndian.Uint64(payload[8:16]),
|
||||||
|
ExactOut: true,
|
||||||
|
}, nil
|
||||||
|
case bytes.Equal(disc, dlmmSwapPriceImpactIX), bytes.Equal(disc, dlmmSwapPriceImpact2IX):
|
||||||
|
if len(payload) < 11 {
|
||||||
|
return nil, fmt.Errorf("data too short for dlmm swap with price impact args, len=%d", len(payload))
|
||||||
|
}
|
||||||
|
amountIn := binary.LittleEndian.Uint64(payload[0:8])
|
||||||
|
idx := 8
|
||||||
|
if len(payload) < idx+1 {
|
||||||
|
return nil, fmt.Errorf("data too short for dlmm swap with price impact args, len=%d", len(payload))
|
||||||
|
}
|
||||||
|
activeBinTag := payload[idx]
|
||||||
|
idx++
|
||||||
|
var activeBin int32
|
||||||
|
if activeBinTag == 1 {
|
||||||
|
if len(payload) < idx+4 {
|
||||||
|
return nil, fmt.Errorf("data too short for dlmm swap with price impact args, len=%d", len(payload))
|
||||||
|
}
|
||||||
|
activeBin = int32(binary.LittleEndian.Uint32(payload[idx : idx+4]))
|
||||||
|
idx += 4
|
||||||
|
} else if activeBinTag != 0 {
|
||||||
|
return nil, fmt.Errorf("invalid active_id tag %d", activeBinTag)
|
||||||
|
}
|
||||||
|
if len(payload) < idx+2 {
|
||||||
|
return nil, fmt.Errorf("data too short for dlmm swap with price impact args, len=%d", len(payload))
|
||||||
|
}
|
||||||
|
return &dlmmParsedArgs{
|
||||||
|
AmountIn: amountIn,
|
||||||
|
ExactIn: true,
|
||||||
|
ActiveBin: activeBin,
|
||||||
|
MaxPriceImpactBps: binary.LittleEndian.Uint16(payload[idx : idx+2]),
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDlmmInstruction(tx *versionedTransaction, instructionIndex int) (*TxSignal, error) {
|
||||||
|
msg := tx.Message
|
||||||
|
if instructionIndex >= len(msg.Instructions) {
|
||||||
|
return nil, fmt.Errorf("instruction index out of bounds")
|
||||||
|
}
|
||||||
|
instruction := msg.Instructions[instructionIndex]
|
||||||
|
if len(instruction.Data) < 8 {
|
||||||
|
return nil, fmt.Errorf("data is empty")
|
||||||
|
}
|
||||||
|
if len(instruction.Accounts) < 13 {
|
||||||
|
return nil, fmt.Errorf("accounts too short")
|
||||||
|
}
|
||||||
|
|
||||||
|
disc := instruction.Data[:8]
|
||||||
|
payload := instruction.Data[8:]
|
||||||
|
|
||||||
|
args, err := parseDlmmSwapArgs(disc, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if args == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
staticKeys := tx.Message.StaticAccountKeys
|
||||||
|
userTokenIn, err := getStaticKey(staticKeys, int(instruction.Accounts[4]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
userTokenOut, err := getStaticKey(staticKeys, int(instruction.Accounts[5]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tokenX, err := getStaticKey(staticKeys, int(instruction.Accounts[6]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tokenY, err := getStaticKey(staticKeys, int(instruction.Accounts[7]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
user, err := getStaticKey(staticKeys, int(instruction.Accounts[10]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tokenXProgram, err := getStaticKey(staticKeys, int(instruction.Accounts[11]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tokenYProgram, err := getStaticKey(staticKeys, int(instruction.Accounts[12]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
token0Mint, token1Mint := dlmmTokenOrder(tokenX, tokenY)
|
||||||
|
var (
|
||||||
|
token0AmountUint64 uint64
|
||||||
|
token1AmountUint64 uint64
|
||||||
|
)
|
||||||
|
if !tokenX.Equals(solana.WrappedSol) && !tokenY.Equals(solana.WrappedSol) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
wsolProgram := tokenXProgram
|
||||||
|
if tokenY.Equals(solana.WrappedSol) {
|
||||||
|
wsolProgram = tokenYProgram
|
||||||
|
}
|
||||||
|
wsolAta, _, err := findAssociatedTokenAddressWithTokenProgram(user, solana.WrappedSol, wsolProgram)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
wsolIn := userTokenIn.Equals(wsolAta)
|
||||||
|
wsolOut := userTokenOut.Equals(wsolAta)
|
||||||
|
if !wsolIn && !wsolOut {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
event := "sell"
|
||||||
|
if wsolIn {
|
||||||
|
event = "buy"
|
||||||
|
}
|
||||||
|
exactSol := (args.ExactIn && wsolIn) || (args.ExactOut && wsolOut)
|
||||||
|
|
||||||
|
if wsolIn {
|
||||||
|
if args.ExactIn {
|
||||||
|
token1AmountUint64 = args.AmountIn
|
||||||
|
}
|
||||||
|
if args.ExactOut {
|
||||||
|
token0AmountUint64 = args.AmountOut
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if args.ExactOut {
|
||||||
|
token1AmountUint64 = args.AmountOut
|
||||||
|
}
|
||||||
|
if args.ExactIn {
|
||||||
|
token0AmountUint64 = args.AmountIn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token0Amount := formatTokenAmount(token0AmountUint64)
|
||||||
|
if token0Mint.Equals(solana.WrappedSol) {
|
||||||
|
token0Amount = formatSolAmount(token0AmountUint64)
|
||||||
|
}
|
||||||
|
token1Amount := decimal.Zero
|
||||||
|
if token1AmountUint64 > 0 {
|
||||||
|
if token1Mint.Equals(solana.WrappedSol) {
|
||||||
|
token1Amount = formatSolAmount(token1AmountUint64)
|
||||||
|
} else {
|
||||||
|
token1Amount = formatTokenAmount(token1AmountUint64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &TxSignal{
|
||||||
|
TxHash: tx.Signatures[0].String(),
|
||||||
|
Label: "dlmm",
|
||||||
|
Maker: user.String(),
|
||||||
|
Token0Address: token0Mint.String(),
|
||||||
|
Token1Address: token1Mint.String(),
|
||||||
|
Token0Amount: token0Amount,
|
||||||
|
Token1Amount: token1Amount,
|
||||||
|
Program: "MeteoraDLMM",
|
||||||
|
Event: event,
|
||||||
|
IsToken2022: false,
|
||||||
|
IsMayhemMode: false,
|
||||||
|
ExactSOL: exactSol,
|
||||||
|
ActiveBin: args.ActiveBin,
|
||||||
|
MaxPriceImpactBps: args.MaxPriceImpactBps,
|
||||||
|
Block: tx.Block,
|
||||||
|
Token0AmountUint64: token0AmountUint64,
|
||||||
|
Token1AmountUint64: token1AmountUint64,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func decodePumpAmmBuyArgs(data []byte) (uint64, uint64, error) {
|
func decodePumpAmmBuyArgs(data []byte) (uint64, uint64, error) {
|
||||||
if len(data) < 9 {
|
if len(data) < 9 {
|
||||||
return 0, 0, fmt.Errorf("data too short for pump amm buy args, len=%d", len(data))
|
return 0, 0, fmt.Errorf("data too short for pump amm buy args, len=%d", len(data))
|
||||||
|
|||||||
Reference in New Issue
Block a user