Compare commits
7 Commits
v0.2.25
...
fb8d93f426
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb8d93f426 | ||
|
|
0cc843b370 | ||
|
|
d9a214b4b4 | ||
|
|
047b549d0f | ||
|
|
9327eab010 | ||
|
|
0ef57cf79a | ||
|
|
03030d817d |
121
cmd/rpc_parse/main.go
Normal file
121
cmd/rpc_parse/main.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/gagliardetto/solana-go"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
pump_parser "github.com/thloyi/pump-parser"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const rpcURL = "https://staked.helius-rpc.com?api-key=5adcf1f9-5719-43d1-bf3f-c2d4e1e5f94d"
|
||||
txHash := os.Getenv("TX_HASH")
|
||||
if txHash == "" {
|
||||
txHash = "2AhpL5KhVmG3D38CwMzrHuRyTucEQ43GzBXL2mo5WiugdZMVmK1dtX8brGe3sxvvFDY6iSSviJTvqCtr4UL3Pc7J"
|
||||
}
|
||||
|
||||
if txHash == "" {
|
||||
fmt.Fprintln(os.Stderr, "txHash is empty; set it in cmd/rpc_parse/main.go")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
sig, err := solana.SignatureFromBase58(txHash)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "invalid txHash: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
client := rpc.New(rpcURL)
|
||||
maxSupportedVersion := uint64(0)
|
||||
out, err := client.GetTransaction(context.Background(), sig, &rpc.GetTransactionOpts{
|
||||
Encoding: solana.EncodingBase64,
|
||||
Commitment: rpc.CommitmentConfirmed,
|
||||
MaxSupportedTransactionVersion: &maxSupportedVersion,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "rpc getTransaction error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if out == nil || out.Transaction == nil || out.Meta == nil {
|
||||
fmt.Fprintln(os.Stderr, "rpc getTransaction returned empty response")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
rawBinary := out.Transaction.GetBinary()
|
||||
if len(rawBinary) == 0 {
|
||||
fmt.Fprintln(os.Stderr, "rpc getTransaction returned empty transaction data")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
txWithMeta := rpc.TransactionWithMeta{
|
||||
Slot: out.Slot,
|
||||
BlockTime: out.BlockTime,
|
||||
Transaction: rpc.DataBytesOrJSONFromBytes(rawBinary),
|
||||
Meta: out.Meta,
|
||||
Version: out.Version,
|
||||
}
|
||||
|
||||
var blockTime *uint64
|
||||
if out.BlockTime != nil {
|
||||
bt := uint64(*out.BlockTime)
|
||||
blockTime = &bt
|
||||
}
|
||||
|
||||
rawTx, err := pump_parser.FromRpcTransactionWithMeta(txWithMeta, blockTime, out.Slot, 0)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "convert rpc transaction error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
pump_parser.EnableAllParsers()
|
||||
|
||||
parsed, err := pump_parser.ParseRawTx(rawTx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "parse raw tx error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if len(parsed.Swaps) == 0 {
|
||||
fmt.Println("no swaps parsed from tx")
|
||||
return
|
||||
}
|
||||
|
||||
for i, swap := range parsed.Swaps {
|
||||
fmt.Printf("swap[%d]\n", i)
|
||||
fmt.Printf(" program: %s\n", swap.Program)
|
||||
fmt.Printf(" event: %s\n", swap.Event)
|
||||
fmt.Printf(" pool: %s\n", swap.Pool)
|
||||
fmt.Printf(" user: %s\n", swap.User)
|
||||
fmt.Printf(" base_mint: %s (decimals=%d)\n", swap.BaseMint, swap.BaseMintDecimals)
|
||||
fmt.Printf(" quote_mint: %s (decimals=%d)\n", swap.QuoteMint, swap.QuoteMintDecimals)
|
||||
fmt.Printf(" base_amount: %s\n", swap.BaseAmount.String())
|
||||
fmt.Printf(" quote_amount: %s\n", swap.QuoteAmount.String())
|
||||
if !swap.FeeAmount.IsZero() || swap.FeeSide != "" {
|
||||
fmt.Printf(" fee_amount: %s\n", swap.FeeAmount.String())
|
||||
fmt.Printf(" lp_fee_amount: %s\n", swap.LpFeeAmount.String())
|
||||
fmt.Printf(" fee_side: %s\n", swap.FeeSide)
|
||||
fmt.Printf(" fee_mint: %s (decimals=%d)\n", swap.FeeMint, swap.FeeMintDecimals)
|
||||
fmt.Printf(" fee_token_program: %s\n", swap.FeeTokenProgram)
|
||||
}
|
||||
fmt.Printf(" base_reserve: %s\n", swap.BaseReserve.String())
|
||||
fmt.Printf(" quote_reserve: %s\n", swap.QuoteReserve.String())
|
||||
fmt.Printf(" base_token_program: %s\n", swap.BaseTokenProgram)
|
||||
fmt.Printf(" quote_token_program: %s\n", swap.QuoteTokenProgram)
|
||||
fmt.Printf(" entry_contract: %s\n", swap.EntryContract)
|
||||
fmt.Printf(" user_base_balance: %s\n", swap.UserBaseBalance.String())
|
||||
fmt.Printf(" user_quote_balance: %s\n", swap.UserQuoteBalance.String())
|
||||
fmt.Printf(" active_bin_id: %d\n", swap.ActiveBinId)
|
||||
fmt.Printf(" start_bin_id: %d\n", swap.StartBinId)
|
||||
fmt.Printf(" end_bin_id: %d\n", swap.EndBinId)
|
||||
fmt.Printf(" remove_bp: %d\n", swap.RemoveBp)
|
||||
fmt.Printf(" position_account: %s\n", swap.PositionAccount)
|
||||
if swap.Mayhem {
|
||||
fmt.Printf(" mayhem: true\n")
|
||||
} else {
|
||||
fmt.Printf(" mayhem: false\n")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
54
consts.go
54
consts.go
@@ -185,6 +185,7 @@ var mevAgentFeeAddresses = map[solana.PublicKey]string{
|
||||
solana.MustPublicKeyFromBase58("soyascXFW5wEEYiwfEmHy2pNwomqzvggJosGVD6TJdY"): MevAgentSoyas,
|
||||
solana.MustPublicKeyFromBase58("soyasDBdKjADwPz3xk82U3TNPRDKEWJj7wWLajNHZ1L"): MevAgentSoyas,
|
||||
solana.MustPublicKeyFromBase58("soyasE2abjBAynmHbGWgEwk4ctBy7JMTUCNrMbjcnyH"): MevAgentSoyas,
|
||||
solana.MustPublicKeyFromBase58("soyasF3QPWPAKKmgA3GjfWax1kmTT1aoqSGxPzVLNUQ"): MevAgentSoyas,
|
||||
solana.MustPublicKeyFromBase58("ste11JV3MLMM7x7EJUM2sXcJC1H7F4jBLnP9a9PG8PH"): MevAgentStellium,
|
||||
solana.MustPublicKeyFromBase58("ste11MWPjXCRfQryCshzi86SGhuXjF4Lv6xMXD2AoSt"): MevAgentStellium,
|
||||
solana.MustPublicKeyFromBase58("ste11p5x8tJ53H1NbNQsRBg1YNRd4GcVpxtDw8PBpmb"): MevAgentStellium,
|
||||
@@ -209,6 +210,14 @@ var mevAgentFeeAddresses = map[solana.PublicKey]string{
|
||||
solana.MustPublicKeyFromBase58("B1ooMauwuJPhHsXqt3uj7B92CAFG8kaD1Q2iGEmGYnx"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("B1ooMdjcY7zemxDWiH8jVZPxEMdHnE5AraWPHdHQoPj"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("B1ooMKzu6siJzQutP6a6oLiY3fpzgQnBZsAjxuAm9qo"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("AstrA1ejL4UeXC2SBP4cpeEmtcFPZVLxx3XGKXyCW6to"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("AsTra79FET4aCKWspPqeSFvjJNyp96SvAnrmyAxqg5b7"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("AsTRADtvb6tTmrsqULQ9Wji9PigDMjhfEMza6zkynEvV"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("AsTRAEoyMofR3vUPpf9k68Gsfb6ymTZttEtsAbv8Bk4d"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("AStrAJv2RN2hKCHxwUMtqmSxgdcNZbihCwc1mCSnG83W"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("Astran35aiQUF57XZsmkWMtNCtXGLzs8upfiqXxth2bz"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("AStRAnpi6kFrKypragExgeRoJ1QnKH7pbSjLAKQVWUum"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("ASTRaoF93eYt73TYvwtsv6fMWHWbGmMUZfVZPo3CRU9C"): MevAgentAstralane,
|
||||
solana.MustPublicKeyFromBase58("Gu2UGEfze3Gg5cHuEC4jGbyCufgpev75RkVvBdKKtf12"): MevAgentNozomi,
|
||||
solana.MustPublicKeyFromBase58("E8wD3SMD1trozPrvSN9F6SyuUXD7rrFDuR3WexGziKG5"): MevAgent0slot,
|
||||
solana.MustPublicKeyFromBase58("18hCV7f9CPmZRAH3QCNZaGHhHeNSfisQKeKuFkQsPLY"): MevAgent0slot,
|
||||
@@ -327,6 +336,51 @@ var mevAgentFeeAddresses = map[solana.PublicKey]string{
|
||||
solana.MustPublicKeyFromBase58("bgH7YhymSykyvMa3nAZpzvrn73owJHU5iB75S1aiLT9"): MevAgentNozomi,
|
||||
solana.MustPublicKeyFromBase58("pfngGVVQLiVRFbLWw3Ektiv17ef9NiRZbcgdAhh4ZEW"): MevAgentNozomi,
|
||||
solana.MustPublicKeyFromBase58("nEFs3jph8HJt7honu3k7XtGUufMnwAvSXmXcKSPxryP"): MevAgentNozomi,
|
||||
solana.MustPublicKeyFromBase58("Fa1con11xLjPddfzRwRUB16sbFZggp2JeJkCeWREyR8X"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Fa1con11TM1RuAQzbQzYjTy4Ekfap9Lnc9fnEbQYEd6Q"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Fa1con113Bvi76nS5AzUiRDC2fqjfzkNMUNRLgQybMYt"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Fa1con1QGHJK232s8yZpzZZwqPexnAKcoyKj626LNsMv"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Fa1con1zUzb6qJVFz5tNkPq1Ahm8H1qKW7Q48252QbkQ"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Fa1con16d3MSwd3SAiwvr2LwgkpE7ot8zntbpuec8HAx"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Fa1con1i7mpa7Qc6epYJ6r4P9AbU77DFFz173r59Df1x"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Fa1con18nWn8TdAGL7JX8PertfMUGVSc899NawokJ4Bq"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Fa1con1GKusK2EqsfzrDzGPaYZSxQtFGzJiRMMU9Zm2g"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Fa1con1RDwVwM9VrJ53CwVefD3VU9c58EMpDawV7fLMi"): MevagentFa1con,
|
||||
solana.MustPublicKeyFromBase58("Sp1x2AqpQckPLaWnWCJUNg8k6qQexfaEWcSRKf5JcDV"): MevagentBlocksprint,
|
||||
solana.MustPublicKeyFromBase58("Sp4JHSh9cksfzXbgK7Pq2ovtn8LirLQydaJKTsiNT77"): MevagentBlocksprint,
|
||||
solana.MustPublicKeyFromBase58("Sp1xMS2cbw83SZDNr4AGqkBYYLjb3LvVnmDSrTMaHkr"): MevagentBlocksprint,
|
||||
solana.MustPublicKeyFromBase58("SpagSJmnh8E9cGT5Y431xPPaS2c1xLREGGCWN9yDeUf"): MevagentBlocksprint,
|
||||
solana.MustPublicKeyFromBase58("SpWrza9E63MQuHeGnnfzmtLVCs3pBdjyKPXUABPo9nq"): MevagentBlocksprint,
|
||||
solana.MustPublicKeyFromBase58("moon17L6BgxXRX5uHKudAmqVF96xia9h8ygcmG2sL3F"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("moon26Sek222Md7ZydcAGxoKG832DK36CkLrS3PQY4c"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("moon7fwyajcVstMoBnVy7UBcTx87SBtNoGGAaH2Cb8V"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("moonBtH9HvLHjLqi9ivyrMVKgFUsSfrz9BwQ9khhn1u"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("moonCJg8476LNFLptX1qrK8PdRsA1HD1R6XWyu9MB93"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("moonF2sz7qwAtdETnrgxNbjonnhGGjd6r4W4UC9284s"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("moonKfftMiGSak3cezvhEqvkPSzwrmQxQHXuspC96yj"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("moonQBUKBpkifLcTd78bfxxt4PYLwmJ5admLW6cBBs8"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("moonXwpKwoVkMegt5Bc776cSW793X1irL5hHV1vJ3JA"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("moonZ6u9E2fgk6eWd82621eLPHt9zuJuYECXAYjMY1C"): MevAgentMoon,
|
||||
solana.MustPublicKeyFromBase58("SpEEdz8S1KorkMZqjMUxfxrmWwofmp6ReNP2Nx6CUmq"): MevAgentSpeedlanding,
|
||||
solana.MustPublicKeyFromBase58("SpeeDy3GJM4wcrQmk1itRFWgidvxX4rwjTLMv78wwjE"): MevAgentSpeedlanding,
|
||||
solana.MustPublicKeyFromBase58("SPeEdva37vW8vRtqgYjprQs1g3965icfVN5Rt7SMAyh"): MevAgentSpeedlanding,
|
||||
solana.MustPublicKeyFromBase58("speEdrSEpox5GUfHWcBc7tQjRuSfUin2yvB7qoYvvJh"): MevAgentSpeedlanding,
|
||||
solana.MustPublicKeyFromBase58("SPeEDmkHkN3A2roSZf6aZyEMsmrGqTHKqwP51y2Y4rV"): MevAgentSpeedlanding,
|
||||
solana.MustPublicKeyFromBase58("SpeedLdTJXh2RKpXEaP8JCxkWoUVXhtdPQ1EnxBJMxc"): MevAgentSpeedlanding,
|
||||
solana.MustPublicKeyFromBase58("SpEediGKLbbXndSYTzwmz6Z3NDgHQLDcTDEvGFkSMH9"): MevAgentSpeedlanding,
|
||||
solana.MustPublicKeyFromBase58("speede8xCcUq2Tiv1efXeTuE3k9TDNq8TnGKaKSc6J4"): MevAgentSpeedlanding,
|
||||
solana.MustPublicKeyFromBase58("harkEpXoJv5qVzHaN7HSuUAd6PHjyMcFMcDYBMDJCEQ"): MevAgentAllenhark,
|
||||
solana.MustPublicKeyFromBase58("harkm2BTWxZuszoNpZnfe84jRbQTg6KGHaQBmWzDGQQ"): MevAgentAllenhark,
|
||||
solana.MustPublicKeyFromBase58("harkR2YJ4Dpt4UDJTcBirjnSPBhNpQFcoFkNpCkVqNk"): MevAgentAllenhark,
|
||||
solana.MustPublicKeyFromBase58("t3QLYyXH4vZYbEifLqjD581t5dPVhq9LABxWceySzL2"): MevAgentRaiden,
|
||||
solana.MustPublicKeyFromBase58("t46SqGmwStEffUMp1fr2xmv5uyR85TB9annJuLKLf83"): MevAgentRaiden,
|
||||
solana.MustPublicKeyFromBase58("t1TcSg9biJsz4NjKjhopK8QZzPS4KzBgFSszu5QTGgF"): MevAgentRaiden,
|
||||
solana.MustPublicKeyFromBase58("t2XFAFBaUkCzxJwEbLWFX9PKFjfBCp2tSyFtx5z4RZM"): MevAgentRaiden,
|
||||
solana.MustPublicKeyFromBase58("t55hdzzftxWkYy3J8t32C9RRcZDuMZ4LDuBmbTzJFkU"): MevAgentRaiden,
|
||||
solana.MustPublicKeyFromBase58("t6UtTQLUGHJJrzxAb8PBBZdZKra8SWUqvTv9zPnxKNz"): MevAgentRaiden,
|
||||
solana.MustPublicKeyFromBase58("t7qUQU35sLpPydh42BcPmtEfTWW8gBe4Ry3gjwVnokJ"): MevAgentRaiden,
|
||||
solana.MustPublicKeyFromBase58("t8pPgarSK3TnuLbbHmoE1RCQdLxfxuPqNTyFjBKahok"): MevAgentRaiden,
|
||||
solana.MustPublicKeyFromBase58("t96GGdw3MiaGR993XN8PSsRpKGXx56t5Wf6zcF1hBpY"): MevAgentRaiden,
|
||||
}
|
||||
|
||||
var entryContractAddresses = map[solana.PublicKey]string{
|
||||
|
||||
34
enum.go
34
enum.go
@@ -1,20 +1,26 @@
|
||||
package pump_parser
|
||||
|
||||
const (
|
||||
MevAgentJito = "jito"
|
||||
MevAgent0slot = "0slot"
|
||||
MevAgentBlocxRoute = "blocxroute"
|
||||
MevAgentNozomi = "nozomi"
|
||||
MevAgentNextBlock = "nextblock"
|
||||
MevAgentHelius = "helius"
|
||||
MevAgentNode1 = "node1"
|
||||
MevAgentFlashBlock = "flashBlock"
|
||||
MevAgentUnknown = "unknown"
|
||||
MevAgentBlockRazor = "blockrazor"
|
||||
MevAgentFast = "fast"
|
||||
MevAgentSoyas = "soyas"
|
||||
MevAgentStellium = "stellium"
|
||||
MevAgentAstralane = "astralane"
|
||||
MevAgentJito = "jito"
|
||||
MevAgent0slot = "0slot"
|
||||
MevAgentBlocxRoute = "blocxroute"
|
||||
MevAgentNozomi = "nozomi"
|
||||
MevAgentNextBlock = "nextblock"
|
||||
MevAgentHelius = "helius"
|
||||
MevAgentNode1 = "node1"
|
||||
MevAgentFlashBlock = "flashBlock"
|
||||
MevAgentUnknown = "unknown"
|
||||
MevAgentBlockRazor = "blockrazor"
|
||||
MevAgentFast = "fast"
|
||||
MevAgentSoyas = "soyas"
|
||||
MevAgentStellium = "stellium"
|
||||
MevAgentAstralane = "astralane"
|
||||
MevagentFa1con = "fa1con"
|
||||
MevagentBlocksprint = "blocksprint"
|
||||
MevAgentMoon = "moon"
|
||||
MevAgentSpeedlanding = "speedlanding"
|
||||
MevAgentAllenhark = "allenhark"
|
||||
MevAgentRaiden = "raiden"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
78
meta.go
78
meta.go
@@ -68,40 +68,50 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
meteoraInitializeLbPairDiscriminator = calculateDiscriminator("global:initialize_lb_pair2")
|
||||
meteoraInitializeLbPairEventDiscriminator = calculateDiscriminator("event:LbPairCreate")
|
||||
meteoraDlmmSwapDiscriminator = calculateDiscriminator("global:swap")
|
||||
meteoraDlmmSwap2Discriminator = calculateDiscriminator("global:swap2")
|
||||
meteoraDlmmSwapExactOutDiscriminator = calculateDiscriminator("global:swap_exact_out")
|
||||
meteoraDlmmSwapExactOut2Discriminator = calculateDiscriminator("global:swap_exact_out2")
|
||||
meteoraDlmmSwapWithPriceImpactDiscriminator = calculateDiscriminator("global:swap_with_price_impact")
|
||||
meteoraDlmmSwapWithPriceImpact2Discriminator = calculateDiscriminator("global:swap_with_price_impact2")
|
||||
meteoraDlmmInitializePositionDiscriminator = calculateDiscriminator("global:initialize_position")
|
||||
meteoraDlmmInitializePosition2Discriminator = calculateDiscriminator("global:initialize_position2")
|
||||
meteoraDlmmInitializePositionByOperatorDiscriminator = calculateDiscriminator("global:initialize_position_by_operator")
|
||||
meteoraDlmmInitializePositionPdaDiscriminator = calculateDiscriminator("global:initialize_position_pda")
|
||||
meteoraDlmmClosePositionDiscriminator = calculateDiscriminator("global:close_position")
|
||||
meteoraDlmmClosePosition2Discriminator = calculateDiscriminator("global:close_position2")
|
||||
meteoraDlmmClosePositionIfEmptyDiscriminator = calculateDiscriminator("global:close_position_if_empty")
|
||||
meteoraDlmmSwapEventDiscriminator = calculateDiscriminator("event:Swap")
|
||||
meteoraDlmmAddLiquidityDiscriminator = calculateDiscriminator("global:add_liquidity")
|
||||
meteoraDlmmAddLiquidity2Discriminator = calculateDiscriminator("global:add_liquidity2")
|
||||
meteoraDlmmAddLiquidityByStrategyDiscriminator = calculateDiscriminator("global:add_liquidity_by_strategy")
|
||||
meteoraDlmmAddLiquidityByStrategy2Discriminator = calculateDiscriminator("global:add_liquidity_by_strategy2")
|
||||
meteoraDlmmClaimFeeDiscriminator = calculateDiscriminator("global:claim_fee")
|
||||
meteoraDlmmClaimFee2Discriminator = calculateDiscriminator("global:claim_fee2")
|
||||
meteoraDlmmRebalanceLiquidityDiscriminator = calculateDiscriminator("global:rebalance_liquidity")
|
||||
meteoraDlmmRemoveLiquidityDiscriminator = calculateDiscriminator("global:remove_liquidity")
|
||||
meteoraDlmmRemoveLiquidity2Discriminator = calculateDiscriminator("global:remove_liquidity2")
|
||||
meteoraDlmmRemoveLiquidityByRangeDiscriminator = calculateDiscriminator("global:remove_liquidity_by_range")
|
||||
meteoraDlmmRemoveLiquidityByRange2Discriminator = calculateDiscriminator("global:remove_liquidity_by_range2")
|
||||
meteoraDlmmAddLiquidityEventDiscriminator = calculateDiscriminator("event:AddLiquidity")
|
||||
meteoraDlmmClaimFeeEventDiscriminator = calculateDiscriminator("event:ClaimFee")
|
||||
meteoraDlmmClaimFee2EventDiscriminator = calculateDiscriminator("event:ClaimFee2")
|
||||
meteoraDlmmPositionCloseEventDiscriminator = calculateDiscriminator("event:PositionClose")
|
||||
meteoraDlmmPositionCreateEventDiscriminator = calculateDiscriminator("event:PositionCreate")
|
||||
meteoraDlmmRebalancingEventDiscriminator = calculateDiscriminator("event:Rebalancing")
|
||||
meteoraDlmmRemoveLiquidityEventDiscriminator = calculateDiscriminator("event:RemoveLiquidity")
|
||||
meteoraInitializeCustomizablePermissionlessLbPairDiscriminator = calculateDiscriminator("global:initialize_customizable_permissionless_lb_pair")
|
||||
meteoraInitializeCustomizablePermissionlessLbPair2Discriminator = calculateDiscriminator("global:initialize_customizable_permissionless_lb_pair2")
|
||||
meteoraInitializeLbPairDiscriminator = calculateDiscriminator("global:initialize_lb_pair")
|
||||
meteoraInitializeLbPair2Discriminator = calculateDiscriminator("global:initialize_lb_pair2")
|
||||
meteoraInitializePermissionLbPairDiscriminator = calculateDiscriminator("global:initialize_permission_lb_pair")
|
||||
meteoraInitializeLbPairEventDiscriminator = calculateDiscriminator("event:LbPairCreate")
|
||||
meteoraDlmmSwapDiscriminator = calculateDiscriminator("global:swap")
|
||||
meteoraDlmmSwap2Discriminator = calculateDiscriminator("global:swap2")
|
||||
meteoraDlmmSwapExactOutDiscriminator = calculateDiscriminator("global:swap_exact_out")
|
||||
meteoraDlmmSwapExactOut2Discriminator = calculateDiscriminator("global:swap_exact_out2")
|
||||
meteoraDlmmSwapWithPriceImpactDiscriminator = calculateDiscriminator("global:swap_with_price_impact")
|
||||
meteoraDlmmSwapWithPriceImpact2Discriminator = calculateDiscriminator("global:swap_with_price_impact2")
|
||||
meteoraDlmmInitializePositionDiscriminator = calculateDiscriminator("global:initialize_position")
|
||||
meteoraDlmmInitializePosition2Discriminator = calculateDiscriminator("global:initialize_position2")
|
||||
meteoraDlmmInitializePositionByOperatorDiscriminator = calculateDiscriminator("global:initialize_position_by_operator")
|
||||
meteoraDlmmInitializePositionPdaDiscriminator = calculateDiscriminator("global:initialize_position_pda")
|
||||
meteoraDlmmClosePositionDiscriminator = calculateDiscriminator("global:close_position")
|
||||
meteoraDlmmClosePosition2Discriminator = calculateDiscriminator("global:close_position2")
|
||||
meteoraDlmmClosePositionIfEmptyDiscriminator = calculateDiscriminator("global:close_position_if_empty")
|
||||
meteoraDlmmSwapEventDiscriminator = calculateDiscriminator("event:Swap")
|
||||
meteoraDlmmAddLiquidityDiscriminator = calculateDiscriminator("global:add_liquidity")
|
||||
meteoraDlmmAddLiquidity2Discriminator = calculateDiscriminator("global:add_liquidity2")
|
||||
meteoraDlmmAddLiquidityByStrategyDiscriminator = calculateDiscriminator("global:add_liquidity_by_strategy")
|
||||
meteoraDlmmAddLiquidityByStrategy2Discriminator = calculateDiscriminator("global:add_liquidity_by_strategy2")
|
||||
meteoraDlmmAddLiquidityByWeightDiscriminator = calculateDiscriminator("global:add_liquidity_by_weight")
|
||||
meteoraDlmmAddLiquidityOneSideDiscriminator = calculateDiscriminator("global:add_liquidity_one_side")
|
||||
meteoraDlmmAddLiquidityOneSidePreciseDiscriminator = calculateDiscriminator("global:add_liquidity_one_side_precise")
|
||||
meteoraDlmmAddLiquidityOneSidePrecise2Discriminator = calculateDiscriminator("global:add_liquidity_one_side_precise2")
|
||||
meteoraDlmmAddLiquidityByStrategyOneSideDiscriminator = calculateDiscriminator("global:add_liquidity_by_strategy_one_side")
|
||||
meteoraDlmmClaimFeeDiscriminator = calculateDiscriminator("global:claim_fee")
|
||||
meteoraDlmmClaimFee2Discriminator = calculateDiscriminator("global:claim_fee2")
|
||||
meteoraDlmmRebalanceLiquidityDiscriminator = calculateDiscriminator("global:rebalance_liquidity")
|
||||
meteoraDlmmRemoveAllLiquidityDiscriminator = calculateDiscriminator("global:remove_all_liquidity")
|
||||
meteoraDlmmRemoveLiquidityDiscriminator = calculateDiscriminator("global:remove_liquidity")
|
||||
meteoraDlmmRemoveLiquidity2Discriminator = calculateDiscriminator("global:remove_liquidity2")
|
||||
meteoraDlmmRemoveLiquidityByRangeDiscriminator = calculateDiscriminator("global:remove_liquidity_by_range")
|
||||
meteoraDlmmRemoveLiquidityByRange2Discriminator = calculateDiscriminator("global:remove_liquidity_by_range2")
|
||||
meteoraDlmmAddLiquidityEventDiscriminator = calculateDiscriminator("event:AddLiquidity")
|
||||
meteoraDlmmClaimFeeEventDiscriminator = calculateDiscriminator("event:ClaimFee")
|
||||
meteoraDlmmClaimFee2EventDiscriminator = calculateDiscriminator("event:ClaimFee2")
|
||||
meteoraDlmmPositionCloseEventDiscriminator = calculateDiscriminator("event:PositionClose")
|
||||
meteoraDlmmPositionCreateEventDiscriminator = calculateDiscriminator("event:PositionCreate")
|
||||
meteoraDlmmRebalancingEventDiscriminator = calculateDiscriminator("event:Rebalancing")
|
||||
meteoraDlmmRemoveLiquidityEventDiscriminator = calculateDiscriminator("event:RemoveLiquidity")
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
680
metaoradlmm.go
680
metaoradlmm.go
@@ -66,6 +66,13 @@ type dlmmPositionCloseEvent struct {
|
||||
Owner solana.PublicKey
|
||||
}
|
||||
|
||||
type dlmmLbPairCreateEvent struct {
|
||||
LbPair solana.PublicKey
|
||||
BinStep uint16
|
||||
TokenX solana.PublicKey
|
||||
TokenY solana.PublicKey
|
||||
}
|
||||
|
||||
type dlmmClaimFeeInnerEvent struct {
|
||||
LbPair solana.PublicKey
|
||||
Position solana.PublicKey
|
||||
@@ -117,6 +124,11 @@ type dlmmBinLiquidityDistribution struct {
|
||||
DistributionY uint16
|
||||
}
|
||||
|
||||
type dlmmBinLiquidityDistributionByWeight struct {
|
||||
BinId int32
|
||||
Weight uint16
|
||||
}
|
||||
|
||||
type dlmmBinLiquidityReduction struct {
|
||||
BinId int32
|
||||
BpsToRemove uint16
|
||||
@@ -143,6 +155,14 @@ type dlmmLiquidityParameterByStrategy struct {
|
||||
StrategyParameters dlmmStrategyParameters
|
||||
}
|
||||
|
||||
type dlmmLiquidityParameterByWeight struct {
|
||||
AmountX uint64
|
||||
AmountY uint64
|
||||
ActiveID int32
|
||||
MaxActiveBinSlippage int32
|
||||
BinLiquidityDist []dlmmBinLiquidityDistributionByWeight
|
||||
}
|
||||
|
||||
type dlmmAddLiquidityArgs struct {
|
||||
LiquidityParameter dlmmLiquidityParameter
|
||||
}
|
||||
@@ -161,6 +181,57 @@ type dlmmAddLiquidityByStrategy2Args struct {
|
||||
RemainingAccountsInfo dlmmRemainingAccountsInfo
|
||||
}
|
||||
|
||||
type dlmmAddLiquidityByWeightArgs struct {
|
||||
LiquidityParameter dlmmLiquidityParameterByWeight
|
||||
}
|
||||
|
||||
type dlmmLiquidityOneSideParameter struct {
|
||||
Amount uint64
|
||||
ActiveID int32
|
||||
MaxActiveBinSlippage int32
|
||||
BinLiquidityDist []dlmmBinLiquidityDistributionByWeight
|
||||
}
|
||||
|
||||
type dlmmLiquidityParameterByStrategyOneSide struct {
|
||||
Amount uint64
|
||||
ActiveID int32
|
||||
MaxActiveBinSlippage int32
|
||||
StrategyParameters dlmmStrategyParameters
|
||||
}
|
||||
|
||||
type dlmmAddLiquidityOneSideArgs struct {
|
||||
LiquidityParameter dlmmLiquidityOneSideParameter
|
||||
}
|
||||
|
||||
type dlmmAddLiquidityByStrategyOneSideArgs struct {
|
||||
LiquidityParameter dlmmLiquidityParameterByStrategyOneSide
|
||||
}
|
||||
|
||||
type dlmmCompressedBinDepositAmount struct {
|
||||
BinID int32
|
||||
Amount uint32
|
||||
}
|
||||
|
||||
type dlmmAddLiquiditySingleSidePreciseParameter struct {
|
||||
Bins []dlmmCompressedBinDepositAmount
|
||||
DecompressMultiplier uint64
|
||||
}
|
||||
|
||||
type dlmmAddLiquiditySingleSidePreciseParameter2 struct {
|
||||
Bins []dlmmCompressedBinDepositAmount
|
||||
DecompressMultiplier uint64
|
||||
MaxAmount uint64
|
||||
}
|
||||
|
||||
type dlmmAddLiquidityOneSidePreciseArgs struct {
|
||||
Parameter dlmmAddLiquiditySingleSidePreciseParameter
|
||||
}
|
||||
|
||||
type dlmmAddLiquidityOneSidePrecise2Args struct {
|
||||
LiquidityParameter dlmmAddLiquiditySingleSidePreciseParameter2
|
||||
RemainingAccountsInfo dlmmRemainingAccountsInfo
|
||||
}
|
||||
|
||||
type dlmmRemoveLiquidityArgs struct {
|
||||
BinLiquidityRemoval []dlmmBinLiquidityReduction
|
||||
}
|
||||
@@ -247,6 +318,16 @@ type dlmmLiquidityAccounts struct {
|
||||
tokenYProgramIdx int
|
||||
}
|
||||
|
||||
type dlmmOneSideLiquidityAccounts struct {
|
||||
positionIdx int
|
||||
poolIdx int
|
||||
userTokenIdx int
|
||||
reserveIdx int
|
||||
tokenMintIdx int
|
||||
userIdx int
|
||||
tokenProgramIdx int
|
||||
}
|
||||
|
||||
var meteoraDlmmEventAuthority = func() solana.PublicKey {
|
||||
key, _, err := solana.FindProgramAddress([][]byte{[]byte("__event_authority")}, meteoraDlmmProgram)
|
||||
if err != nil {
|
||||
@@ -266,7 +347,11 @@ func metaoradlmmParser(tx *Tx, instruction Instruction, innerInstructions InnerI
|
||||
|
||||
discriminator := *(*[8]byte)(decode[:8])
|
||||
switch discriminator {
|
||||
case meteoraInitializeLbPairDiscriminator:
|
||||
case meteoraInitializeCustomizablePermissionlessLbPairDiscriminator,
|
||||
meteoraInitializeCustomizablePermissionlessLbPair2Discriminator,
|
||||
meteoraInitializeLbPairDiscriminator,
|
||||
meteoraInitializeLbPair2Discriminator,
|
||||
meteoraInitializePermissionLbPairDiscriminator:
|
||||
return metaoradlmmInitializeParser(tx, instruction, innerInstructions, offset)
|
||||
case meteoraDlmmInitializePositionDiscriminator, meteoraDlmmInitializePosition2Discriminator,
|
||||
meteoraDlmmInitializePositionByOperatorDiscriminator, meteoraDlmmInitializePositionPdaDiscriminator:
|
||||
@@ -276,13 +361,16 @@ func metaoradlmmParser(tx *Tx, instruction Instruction, innerInstructions InnerI
|
||||
case meteoraDlmmSwap2Discriminator, meteoraDlmmSwapExactOut2Discriminator, meteoraDlmmSwapWithPriceImpact2Discriminator:
|
||||
return metaoradlmmSwap2Parser(tx, instruction, innerInstructions, offset)
|
||||
case meteoraDlmmAddLiquidityDiscriminator, meteoraDlmmAddLiquidity2Discriminator,
|
||||
meteoraDlmmAddLiquidityByStrategyDiscriminator, meteoraDlmmAddLiquidityByStrategy2Discriminator:
|
||||
meteoraDlmmAddLiquidityByStrategyDiscriminator, meteoraDlmmAddLiquidityByStrategy2Discriminator,
|
||||
meteoraDlmmAddLiquidityByWeightDiscriminator, meteoraDlmmAddLiquidityOneSideDiscriminator,
|
||||
meteoraDlmmAddLiquidityOneSidePreciseDiscriminator, meteoraDlmmAddLiquidityOneSidePrecise2Discriminator,
|
||||
meteoraDlmmAddLiquidityByStrategyOneSideDiscriminator:
|
||||
return metaoradlmmAddLiquidityParser(tx, instruction, innerInstructions, offset)
|
||||
case meteoraDlmmClaimFeeDiscriminator, meteoraDlmmClaimFee2Discriminator:
|
||||
return metaoradlmmClaimFeeParser(tx, instruction, innerInstructions, offset)
|
||||
case meteoraDlmmRebalanceLiquidityDiscriminator:
|
||||
return metaoradlmmRebalanceLiquidityParser(tx, instruction, innerInstructions, offset)
|
||||
case meteoraDlmmRemoveLiquidityDiscriminator, meteoraDlmmRemoveLiquidity2Discriminator,
|
||||
case meteoraDlmmRemoveAllLiquidityDiscriminator, meteoraDlmmRemoveLiquidityDiscriminator, meteoraDlmmRemoveLiquidity2Discriminator,
|
||||
meteoraDlmmRemoveLiquidityByRangeDiscriminator, meteoraDlmmRemoveLiquidityByRange2Discriminator:
|
||||
return metaoradlmmRemoveLiquidityParser(tx, instruction, innerInstructions, offset)
|
||||
case meteoraDlmmClosePositionDiscriminator, meteoraDlmmClosePosition2Discriminator, meteoraDlmmClosePositionIfEmptyDiscriminator:
|
||||
@@ -292,53 +380,131 @@ func metaoradlmmParser(tx *Tx, instruction Instruction, innerInstructions InnerI
|
||||
}
|
||||
}
|
||||
|
||||
type dlmmInitializeAccounts struct {
|
||||
pool solana.PublicKey
|
||||
token0 solana.PublicKey
|
||||
token1 solana.PublicKey
|
||||
baseTokenProgram solana.PublicKey
|
||||
quoteTokenProgram solana.PublicKey
|
||||
user solana.PublicKey
|
||||
}
|
||||
|
||||
func resolveDlmmInitializeAccounts(result *RawTx, data []byte, accounts []int) (dlmmInitializeAccounts, error) {
|
||||
if len(data) < 8 {
|
||||
return dlmmInitializeAccounts{}, fmt.Errorf("instruction data too short")
|
||||
}
|
||||
|
||||
accountList := result.getAccountList()
|
||||
resolveAt := func(position int) (solana.PublicKey, error) {
|
||||
if position < 0 || position >= len(accounts) {
|
||||
return solana.PublicKey{}, fmt.Errorf("accounts too short, missing position %d", position)
|
||||
}
|
||||
accountIndex := accounts[position]
|
||||
if accountIndex < 0 || accountIndex >= len(accountList) {
|
||||
return solana.PublicKey{}, fmt.Errorf("account index out of range at position %d", position)
|
||||
}
|
||||
return accountList[accountIndex], nil
|
||||
}
|
||||
|
||||
resolveCommon := func(poolPos, token0Pos, token1Pos, userPos, baseTokenProgramPos, quoteTokenProgramPos int) (dlmmInitializeAccounts, error) {
|
||||
pool, err := resolveAt(poolPos)
|
||||
if err != nil {
|
||||
return dlmmInitializeAccounts{}, err
|
||||
}
|
||||
token0, err := resolveAt(token0Pos)
|
||||
if err != nil {
|
||||
return dlmmInitializeAccounts{}, err
|
||||
}
|
||||
token1, err := resolveAt(token1Pos)
|
||||
if err != nil {
|
||||
return dlmmInitializeAccounts{}, err
|
||||
}
|
||||
baseTokenProgram, err := resolveAt(baseTokenProgramPos)
|
||||
if err != nil {
|
||||
return dlmmInitializeAccounts{}, err
|
||||
}
|
||||
quoteTokenProgram, err := resolveAt(quoteTokenProgramPos)
|
||||
if err != nil {
|
||||
return dlmmInitializeAccounts{}, err
|
||||
}
|
||||
user, err := resolveAt(userPos)
|
||||
if err != nil {
|
||||
return dlmmInitializeAccounts{}, err
|
||||
}
|
||||
|
||||
return dlmmInitializeAccounts{
|
||||
pool: pool,
|
||||
token0: token0,
|
||||
token1: token1,
|
||||
baseTokenProgram: baseTokenProgram,
|
||||
quoteTokenProgram: quoteTokenProgram,
|
||||
user: user,
|
||||
}, nil
|
||||
}
|
||||
|
||||
discriminator := *(*[8]byte)(data[:8])
|
||||
switch discriminator {
|
||||
case meteoraInitializeLbPairDiscriminator,
|
||||
meteoraInitializeCustomizablePermissionlessLbPairDiscriminator:
|
||||
return resolveCommon(0, 2, 3, 8, 9, 9)
|
||||
case meteoraInitializeLbPair2Discriminator,
|
||||
meteoraInitializeCustomizablePermissionlessLbPair2Discriminator:
|
||||
return resolveCommon(0, 2, 3, 8, 11, 12)
|
||||
case meteoraInitializePermissionLbPairDiscriminator:
|
||||
return resolveCommon(1, 3, 4, 8, 11, 12)
|
||||
default:
|
||||
return dlmmInitializeAccounts{}, fmt.Errorf("unsupported initialize discriminator")
|
||||
}
|
||||
}
|
||||
|
||||
func metaoradlmmInitializeParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
market := tx.rawTx.accountList[instruction.Accounts[0]]
|
||||
token0 := tx.rawTx.accountList[instruction.Accounts[2]]
|
||||
token1 := tx.rawTx.accountList[instruction.Accounts[3]]
|
||||
accounts, err := resolveDlmmInitializeAccounts(tx.rawTx, instruction.Data, instruction.Accounts)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm initialize accounts parse error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
|
||||
entryContract := tx.rawTx.accountList[tx.rawTx.Transaction.Message.Instructions[offset[0]].ProgramIDIndex]
|
||||
|
||||
var baseDecimals uint8
|
||||
var quoteDecimals uint8
|
||||
for _, acc := range tx.rawTx.Meta.PostTokenBalances {
|
||||
if acc.MintAccount.Equals(token0) {
|
||||
baseDecimals = uint8(acc.UITokenAmount.Decimals)
|
||||
}
|
||||
if acc.MintAccount.Equals(token1) {
|
||||
quoteDecimals = uint8(acc.UITokenAmount.Decimals)
|
||||
findMintDecimals := func(mint solana.PublicKey) uint8 {
|
||||
for _, acc := range tx.rawTx.Meta.PostTokenBalances {
|
||||
if acc.MintAccount.Equals(mint) {
|
||||
return uint8(acc.UITokenAmount.Decimals)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
swap := Swap{
|
||||
Program: SolProgramMeteoraDLMM,
|
||||
Event: "create",
|
||||
Pool: market,
|
||||
BaseMint: token0,
|
||||
QuoteMint: token1,
|
||||
BaseTokenProgram: tx.rawTx.accountList[instruction.Accounts[11]],
|
||||
QuoteTokenProgram: tx.rawTx.accountList[instruction.Accounts[12]],
|
||||
Pool: accounts.pool,
|
||||
BaseMint: accounts.token0,
|
||||
QuoteMint: accounts.token1,
|
||||
BaseTokenProgram: accounts.baseTokenProgram,
|
||||
QuoteTokenProgram: accounts.quoteTokenProgram,
|
||||
Creator: tx.rawTx.accountList[0],
|
||||
BaseMintDecimals: baseDecimals,
|
||||
QuoteMintDecimals: quoteDecimals,
|
||||
User: tx.rawTx.accountList[instruction.Accounts[8]],
|
||||
BaseMintDecimals: findMintDecimals(accounts.token0),
|
||||
QuoteMintDecimals: findMintDecimals(accounts.token1),
|
||||
User: accounts.user,
|
||||
EntryContract: entryContract,
|
||||
}
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
createEvent, nextOffset, found, err := dlmmLbPairCreateEventFromInnerInstructions(innerInstructions, instruction, offset)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("pump create get inner instructions error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
return nil, nextOffset, err
|
||||
}
|
||||
var programIndex = instruction.ProgramIDIndex
|
||||
|
||||
for innerIndex, innerInstr := range inners {
|
||||
if innerInstr.ProgramIDIndex == programIndex && len(innerInstr.Data) >= 16 && bytes.Equal(innerInstr.Data[:8], pumpEventDiscriminator[:]) && bytes.Equal(innerInstr.Data[8:16], meteoraInitializeLbPairEventDiscriminator[:]) {
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
break
|
||||
if found {
|
||||
offset = nextOffset
|
||||
if !createEvent.LbPair.IsZero() {
|
||||
swap.Pool = createEvent.LbPair
|
||||
}
|
||||
if !createEvent.TokenX.IsZero() {
|
||||
swap.BaseMint = createEvent.TokenX
|
||||
}
|
||||
if !createEvent.TokenY.IsZero() {
|
||||
swap.QuoteMint = createEvent.TokenY
|
||||
}
|
||||
swap.BaseMintDecimals = findMintDecimals(swap.BaseMint)
|
||||
swap.QuoteMintDecimals = findMintDecimals(swap.QuoteMint)
|
||||
}
|
||||
return []Swap{swap}, offset, nil
|
||||
}
|
||||
@@ -392,10 +558,13 @@ func metaoradlmmPositionCreateParser(tx *Tx, instruction Instruction, innerInstr
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm create position accounts parse error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
|
||||
createEvent, nextOffset, err := dlmmPositionCreateEventFromInnerInstructions(innerInstructions, instruction, offset)
|
||||
createEvent, nextOffset, found, err := dlmmPositionCreateEventFromInnerInstructions(innerInstructions, instruction, offset)
|
||||
if err != nil {
|
||||
return nil, nextOffset, err
|
||||
}
|
||||
if !found {
|
||||
return nil, nextOffset, InstructionIgnoredError
|
||||
}
|
||||
offset = nextOffset
|
||||
|
||||
if !createEvent.LbPair.IsZero() {
|
||||
@@ -649,6 +818,18 @@ func metaoradlmmSwapParser(tx *Tx, instruction Instruction, innerInstructions In
|
||||
userQuote = userQuote.Add(decimal.NewFromUint64(solAmount))
|
||||
}
|
||||
}
|
||||
feeAmount, feeSide, feeMint, feeTokenProgram, feeDecimals := dlmmSwapFeeInfo(
|
||||
baseIsX,
|
||||
swapForY,
|
||||
swapEvent.Fee,
|
||||
baseMint,
|
||||
quoteMint,
|
||||
baseTokenProgram,
|
||||
quoteTokenProgram,
|
||||
baseDecimals,
|
||||
quoteDecimals,
|
||||
)
|
||||
lpFeeAmount := dlmmSwapLpFeeAmount(swapEvent.Fee, swapEvent.ProtocolFee, swapEvent.HostFee)
|
||||
|
||||
swap := Swap{
|
||||
Program: SolProgramMeteoraDLMM,
|
||||
@@ -664,6 +845,13 @@ func metaoradlmmSwapParser(tx *Tx, instruction Instruction, innerInstructions In
|
||||
User: eventUser,
|
||||
BaseAmount: baseAmount,
|
||||
QuoteAmount: quoteAmount,
|
||||
FeeAmount: feeAmount,
|
||||
FeeBps: dlmmSwapFeeBpsString(swapEvent.FeeBps),
|
||||
LpFeeAmount: lpFeeAmount,
|
||||
FeeSide: feeSide,
|
||||
FeeMint: feeMint,
|
||||
FeeTokenProgram: feeTokenProgram,
|
||||
FeeMintDecimals: feeDecimals,
|
||||
BaseReserve: baseReserve,
|
||||
QuoteReserve: quoteReserve,
|
||||
UserBaseBalance: userBase,
|
||||
@@ -681,6 +869,39 @@ func metaoradlmmSwap2Parser(tx *Tx, instruction Instruction, innerInstructions I
|
||||
return metaoradlmmSwapParser(tx, instruction, innerInstructions, offset)
|
||||
}
|
||||
|
||||
func dlmmSwapFeeInfo(
|
||||
baseIsX bool,
|
||||
swapForY bool,
|
||||
fee uint64,
|
||||
baseMint solana.PublicKey,
|
||||
quoteMint solana.PublicKey,
|
||||
baseTokenProgram solana.PublicKey,
|
||||
quoteTokenProgram solana.PublicKey,
|
||||
baseDecimals uint8,
|
||||
quoteDecimals uint8,
|
||||
) (decimal.Decimal, string, solana.PublicKey, solana.PublicKey, uint8) {
|
||||
feeAmount := decimal.NewFromUint64(fee)
|
||||
if baseIsX == swapForY {
|
||||
return feeAmount, "base", baseMint, baseTokenProgram, baseDecimals
|
||||
}
|
||||
return feeAmount, "quote", quoteMint, quoteTokenProgram, quoteDecimals
|
||||
}
|
||||
|
||||
func dlmmSwapLpFeeAmount(fee, protocolFee, hostFee uint64) decimal.Decimal {
|
||||
total := decimal.NewFromUint64(fee)
|
||||
protocol := decimal.NewFromUint64(protocolFee)
|
||||
host := decimal.NewFromUint64(hostFee)
|
||||
lpFee := total.Sub(protocol).Sub(host)
|
||||
if lpFee.IsNegative() {
|
||||
return decimal.Zero
|
||||
}
|
||||
return lpFee
|
||||
}
|
||||
|
||||
func dlmmSwapFeeBpsString(feeBps agbinary.Uint128) string {
|
||||
return feeBps.DecimalString()
|
||||
}
|
||||
|
||||
func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstructions InnerInstructions, offset [2]uint) ([]Swap, [2]uint, error) {
|
||||
result := tx.rawTx
|
||||
|
||||
@@ -705,9 +926,10 @@ func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstruc
|
||||
amountX uint64
|
||||
amountY uint64
|
||||
binDist []dlmmBinLiquidityDistribution
|
||||
weightDist []dlmmBinLiquidityDistributionByWeight
|
||||
startBinId int32
|
||||
endBinId int32
|
||||
hasRange bool
|
||||
oneSide bool
|
||||
)
|
||||
|
||||
switch discriminator {
|
||||
@@ -720,7 +942,6 @@ func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstruc
|
||||
amountY = args.LiquidityParameter.AmountY
|
||||
binDist = args.LiquidityParameter.BinLiquidityDist
|
||||
startBinId, endBinId = dlmmMinMaxBinIdFromDistribution(binDist)
|
||||
hasRange = len(binDist) > 0
|
||||
case meteoraDlmmAddLiquidity2Discriminator:
|
||||
var args dlmmAddLiquidity2Args
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
@@ -730,7 +951,6 @@ func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstruc
|
||||
amountY = args.LiquidityParameter.AmountY
|
||||
binDist = args.LiquidityParameter.BinLiquidityDist
|
||||
startBinId, endBinId = dlmmMinMaxBinIdFromDistribution(binDist)
|
||||
hasRange = len(binDist) > 0
|
||||
case meteoraDlmmAddLiquidityByStrategyDiscriminator:
|
||||
var args dlmmAddLiquidityByStrategyArgs
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
@@ -740,7 +960,6 @@ func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstruc
|
||||
amountY = args.LiquidityParameter.AmountY
|
||||
startBinId = args.LiquidityParameter.StrategyParameters.MinBinId
|
||||
endBinId = args.LiquidityParameter.StrategyParameters.MaxBinId
|
||||
hasRange = true
|
||||
case meteoraDlmmAddLiquidityByStrategy2Discriminator:
|
||||
var args dlmmAddLiquidityByStrategy2Args
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
@@ -750,16 +969,49 @@ func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstruc
|
||||
amountY = args.LiquidityParameter.AmountY
|
||||
startBinId = args.LiquidityParameter.StrategyParameters.MinBinId
|
||||
endBinId = args.LiquidityParameter.StrategyParameters.MaxBinId
|
||||
hasRange = true
|
||||
case meteoraDlmmAddLiquidityByWeightDiscriminator:
|
||||
var args dlmmAddLiquidityByWeightArgs
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm add liquidity by weight decode error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
amountX = args.LiquidityParameter.AmountX
|
||||
amountY = args.LiquidityParameter.AmountY
|
||||
weightDist = args.LiquidityParameter.BinLiquidityDist
|
||||
startBinId, endBinId = dlmmMinMaxBinIdFromWeightDistribution(weightDist)
|
||||
case meteoraDlmmAddLiquidityOneSideDiscriminator:
|
||||
var args dlmmAddLiquidityOneSideArgs
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm add liquidity one side decode error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
weightDist = args.LiquidityParameter.BinLiquidityDist
|
||||
startBinId, endBinId = dlmmMinMaxBinIdFromWeightDistribution(weightDist)
|
||||
oneSide = true
|
||||
case meteoraDlmmAddLiquidityOneSidePreciseDiscriminator:
|
||||
var args dlmmAddLiquidityOneSidePreciseArgs
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm add liquidity one side precise decode error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
startBinId, endBinId = dlmmMinMaxBinIDFromCompressedDeposits(args.Parameter.Bins)
|
||||
oneSide = true
|
||||
case meteoraDlmmAddLiquidityOneSidePrecise2Discriminator:
|
||||
var args dlmmAddLiquidityOneSidePrecise2Args
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm add liquidity one side precise2 decode error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
startBinId, endBinId = dlmmMinMaxBinIDFromCompressedDeposits(args.LiquidityParameter.Bins)
|
||||
oneSide = true
|
||||
case meteoraDlmmAddLiquidityByStrategyOneSideDiscriminator:
|
||||
var args dlmmAddLiquidityByStrategyOneSideArgs
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm add liquidity by strategy one side decode error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
startBinId = args.LiquidityParameter.StrategyParameters.MinBinId
|
||||
endBinId = args.LiquidityParameter.StrategyParameters.MaxBinId
|
||||
oneSide = true
|
||||
default:
|
||||
return nil, increaseOffset(offset), InstructionIgnoredError
|
||||
}
|
||||
|
||||
accounts, err := resolveDlmmLiquidityAccounts(result, instruction.Accounts)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm add liquidity accounts parse error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
|
||||
addEvent, nextOffset, err := dlmmAddLiquidityEventFromInnerInstructions(innerInstructions, instruction, offset)
|
||||
if err != nil {
|
||||
return nil, nextOffset, err
|
||||
@@ -768,11 +1020,17 @@ func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstruc
|
||||
amountX = addEvent.Amounts[0]
|
||||
amountY = addEvent.Amounts[1]
|
||||
|
||||
binChanges := []DlmmBinLiquidityChange(nil)
|
||||
if len(binDist) > 0 {
|
||||
binChanges = dlmmBinChangesFromDistribution(amountX, amountY, binDist)
|
||||
} else if hasRange {
|
||||
binChanges = dlmmBinChangesFromRange(startBinId, endBinId, 0)
|
||||
if oneSide {
|
||||
swaps, err := dlmmBuildOneSideAddSwap(tx, instruction, addEvent, startBinId, endBinId, entryContract)
|
||||
if err != nil {
|
||||
return nil, offset, err
|
||||
}
|
||||
return swaps, offset, nil
|
||||
}
|
||||
|
||||
accounts, err := resolveDlmmLiquidityAccounts(result, instruction.Accounts)
|
||||
if err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm add liquidity accounts parse error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
|
||||
pool := result.accountList[accounts.poolIdx]
|
||||
@@ -805,7 +1063,6 @@ func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstruc
|
||||
baseAmount = amountYDec
|
||||
quoteAmount = amountXDec
|
||||
}
|
||||
|
||||
eventUser := result.accountList[accounts.userIdx]
|
||||
if !addEvent.From.IsZero() {
|
||||
eventUser = addEvent.From
|
||||
@@ -866,7 +1123,6 @@ func metaoradlmmAddLiquidityParser(tx *Tx, instruction Instruction, innerInstruc
|
||||
ActiveBinId: addEvent.ActiveBinId,
|
||||
StartBinId: startBinId,
|
||||
EndBinId: endBinId,
|
||||
BinChanges: binChanges,
|
||||
PositionAccount: result.accountList[accounts.positionIdx],
|
||||
}
|
||||
|
||||
@@ -894,19 +1150,19 @@ func metaoradlmmRemoveLiquidityParser(tx *Tx, instruction Instruction, innerInst
|
||||
|
||||
discriminator := *(*[8]byte)(decode[:8])
|
||||
var (
|
||||
binChanges []DlmmBinLiquidityChange
|
||||
startBinId int32
|
||||
endBinId int32
|
||||
removeBp int32
|
||||
)
|
||||
|
||||
switch discriminator {
|
||||
case meteoraDlmmRemoveAllLiquidityDiscriminator:
|
||||
removeBp = 10000
|
||||
case meteoraDlmmRemoveLiquidityDiscriminator:
|
||||
var args dlmmRemoveLiquidityArgs
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm remove liquidity decode error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
binChanges = dlmmBinChangesFromReduction(args.BinLiquidityRemoval)
|
||||
startBinId, endBinId = dlmmMinMaxBinIdFromReduction(args.BinLiquidityRemoval)
|
||||
removeBp = dlmmCommonRemoveBp(args.BinLiquidityRemoval)
|
||||
case meteoraDlmmRemoveLiquidity2Discriminator:
|
||||
@@ -914,7 +1170,6 @@ func metaoradlmmRemoveLiquidityParser(tx *Tx, instruction Instruction, innerInst
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
return nil, increaseOffset(offset), fmt.Errorf("meteora dlmm remove liquidity2 decode error: %v, offset, %d, %d", err, offset[0], offset[1])
|
||||
}
|
||||
binChanges = dlmmBinChangesFromReduction(args.BinLiquidityRemoval)
|
||||
startBinId, endBinId = dlmmMinMaxBinIdFromReduction(args.BinLiquidityRemoval)
|
||||
removeBp = dlmmCommonRemoveBp(args.BinLiquidityRemoval)
|
||||
case meteoraDlmmRemoveLiquidityByRangeDiscriminator:
|
||||
@@ -925,7 +1180,6 @@ func metaoradlmmRemoveLiquidityParser(tx *Tx, instruction Instruction, innerInst
|
||||
startBinId = args.FromBinId
|
||||
endBinId = args.ToBinId
|
||||
removeBp = int32(args.BpsToRemove)
|
||||
binChanges = dlmmBinChangesFromRange(startBinId, endBinId, args.BpsToRemove)
|
||||
case meteoraDlmmRemoveLiquidityByRange2Discriminator:
|
||||
var args dlmmRemoveLiquidityByRange2Args
|
||||
if err := agbinary.NewBorshDecoder(decode[8:]).Decode(&args); err != nil {
|
||||
@@ -934,7 +1188,6 @@ func metaoradlmmRemoveLiquidityParser(tx *Tx, instruction Instruction, innerInst
|
||||
startBinId = args.FromBinId
|
||||
endBinId = args.ToBinId
|
||||
removeBp = int32(args.BpsToRemove)
|
||||
binChanges = dlmmBinChangesFromRange(startBinId, endBinId, args.BpsToRemove)
|
||||
default:
|
||||
return nil, increaseOffset(offset), InstructionIgnoredError
|
||||
}
|
||||
@@ -980,7 +1233,6 @@ func metaoradlmmRemoveLiquidityParser(tx *Tx, instruction Instruction, innerInst
|
||||
baseAmount = amountYDec
|
||||
quoteAmount = amountXDec
|
||||
}
|
||||
|
||||
eventUser := result.accountList[accounts.userIdx]
|
||||
if !removeEvent.From.IsZero() {
|
||||
eventUser = removeEvent.From
|
||||
@@ -1042,7 +1294,6 @@ func metaoradlmmRemoveLiquidityParser(tx *Tx, instruction Instruction, innerInst
|
||||
StartBinId: startBinId,
|
||||
EndBinId: endBinId,
|
||||
RemoveBp: removeBp,
|
||||
BinChanges: binChanges,
|
||||
PositionAccount: result.accountList[accounts.positionIdx],
|
||||
}
|
||||
|
||||
@@ -1286,7 +1537,6 @@ func metaoradlmmRebalanceLiquidityParser(tx *Tx, instruction Instruction, innerI
|
||||
ActiveBinId: event.ActiveBinId,
|
||||
StartBinId: event.OldMinBinId,
|
||||
EndBinId: event.OldMaxBinId,
|
||||
BinChanges: dlmmBinChangesFromRange(event.OldMinBinId, event.OldMaxBinId, 0),
|
||||
PositionAccount: result.accountList[accounts.positionIdx],
|
||||
})
|
||||
}
|
||||
@@ -1312,7 +1562,6 @@ func metaoradlmmRebalanceLiquidityParser(tx *Tx, instruction Instruction, innerI
|
||||
ActiveBinId: event.ActiveBinId,
|
||||
StartBinId: event.NewMinBinId,
|
||||
EndBinId: event.NewMaxBinId,
|
||||
BinChanges: dlmmBinChangesFromRange(event.NewMinBinId, event.NewMaxBinId, 0),
|
||||
PositionAccount: result.accountList[accounts.positionIdx],
|
||||
})
|
||||
}
|
||||
@@ -1446,11 +1695,11 @@ func dlmmRebalancingEventFromInnerInstructions(innerInstructions InnerInstructio
|
||||
return dlmmRebalancingEvent{}, increaseOffset(offset), fmt.Errorf("meteora dlmm rebalance liquidity event not found, offset, %d, %d", offset[0], prefixLen)
|
||||
}
|
||||
|
||||
func dlmmPositionCreateEventFromInnerInstructions(innerInstructions InnerInstructions, instruction Instruction, offset [2]uint) (dlmmPositionCreateEvent, [2]uint, error) {
|
||||
func dlmmPositionCreateEventFromInnerInstructions(innerInstructions InnerInstructions, instruction Instruction, offset [2]uint) (dlmmPositionCreateEvent, [2]uint, bool, error) {
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
if err != nil {
|
||||
return dlmmPositionCreateEvent{}, increaseOffset(offset), fmt.Errorf("meteora dlmm create position get inner instructions error: %v, offset, %d, %d", err, offset[0], prefixLen)
|
||||
return dlmmPositionCreateEvent{}, increaseOffset(offset), false, fmt.Errorf("meteora dlmm create position get inner instructions error: %v, offset, %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
for innerIndex, innerInstr := range inners {
|
||||
if innerInstr.ProgramIDIndex != instruction.ProgramIDIndex {
|
||||
@@ -1465,9 +1714,9 @@ func dlmmPositionCreateEventFromInnerInstructions(innerInstructions InnerInstruc
|
||||
} else {
|
||||
offset[1] = uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
return event, offset, nil
|
||||
return event, offset, true, nil
|
||||
}
|
||||
return dlmmPositionCreateEvent{}, increaseOffset(offset), fmt.Errorf("meteora dlmm create position event not found, offset, %d, %d", offset[0], prefixLen)
|
||||
return dlmmPositionCreateEvent{}, increaseOffset(offset), false, nil
|
||||
}
|
||||
|
||||
func dlmmPositionCloseEventFromInnerInstructions(innerInstructions InnerInstructions, instruction Instruction, offset [2]uint) (dlmmPositionCloseEvent, [2]uint, bool, error) {
|
||||
@@ -1494,6 +1743,51 @@ func dlmmPositionCloseEventFromInnerInstructions(innerInstructions InnerInstruct
|
||||
return dlmmPositionCloseEvent{}, increaseOffset(offset), false, nil
|
||||
}
|
||||
|
||||
func dlmmLbPairCreateEventFromInnerInstructions(innerInstructions InnerInstructions, instruction Instruction, offset [2]uint) (dlmmLbPairCreateEvent, [2]uint, bool, error) {
|
||||
var prefixLen = offset[1]
|
||||
inners, err := getInnerInstructions(innerInstructions, prefixLen)
|
||||
if err != nil {
|
||||
return dlmmLbPairCreateEvent{}, increaseOffset(offset), false, fmt.Errorf("meteora dlmm create get inner instructions error: %v, offset, %d, %d", err, offset[0], prefixLen)
|
||||
}
|
||||
for innerIndex, innerInstr := range inners {
|
||||
if innerInstr.ProgramIDIndex != instruction.ProgramIDIndex {
|
||||
continue
|
||||
}
|
||||
event, ok := dlmmDecodeLbPairCreateEvent(innerInstr.Data)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if offset[1] == 0 {
|
||||
offset[0] += 1
|
||||
} else {
|
||||
offset[1] = uint(innerIndex) + 1 + prefixLen
|
||||
}
|
||||
return event, offset, true, nil
|
||||
}
|
||||
return dlmmLbPairCreateEvent{}, increaseOffset(offset), false, nil
|
||||
}
|
||||
|
||||
func dlmmDecodeLbPairCreateEvent(data []byte) (dlmmLbPairCreateEvent, bool) {
|
||||
switch {
|
||||
case len(data) >= 8 && bytes.Equal(data[:8], meteoraInitializeLbPairEventDiscriminator[:]):
|
||||
var event dlmmLbPairCreateEvent
|
||||
if err := agbinary.NewBorshDecoder(data[8:]).Decode(&event); err != nil {
|
||||
return dlmmLbPairCreateEvent{}, false
|
||||
}
|
||||
return event, true
|
||||
case len(data) >= 16 &&
|
||||
bytes.Equal(data[:8], eventDiscriminator[:]) &&
|
||||
bytes.Equal(data[8:16], meteoraInitializeLbPairEventDiscriminator[:]):
|
||||
var event dlmmLbPairCreateEvent
|
||||
if err := agbinary.NewBorshDecoder(data[16:]).Decode(&event); err != nil {
|
||||
return dlmmLbPairCreateEvent{}, false
|
||||
}
|
||||
return event, true
|
||||
default:
|
||||
return dlmmLbPairCreateEvent{}, false
|
||||
}
|
||||
}
|
||||
|
||||
func dlmmDecodeAddLiquidityEvent(data []byte) (dlmmAddLiquidityEvent, bool) {
|
||||
switch {
|
||||
case len(data) >= 8 && bytes.Equal(data[:8], meteoraDlmmAddLiquidityEventDiscriminator[:]):
|
||||
@@ -1787,6 +2081,154 @@ func resolveDlmmLiquidityAccounts(result *RawTx, accounts []int) (dlmmLiquidityA
|
||||
}, nil
|
||||
}
|
||||
|
||||
func resolveDlmmOneSideLiquidityAccounts(result *RawTx, accounts []int) (dlmmOneSideLiquidityAccounts, error) {
|
||||
if len(accounts) < 10 {
|
||||
return dlmmOneSideLiquidityAccounts{}, fmt.Errorf("accounts too short, expected at least 10")
|
||||
}
|
||||
accountList := result.accountList
|
||||
|
||||
eventAuthorityPos := -1
|
||||
for i, idx := range accounts {
|
||||
if idx < 0 || idx >= len(accountList) {
|
||||
continue
|
||||
}
|
||||
if accountList[idx].Equals(meteoraDlmmEventAuthority) {
|
||||
eventAuthorityPos = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if eventAuthorityPos == -1 {
|
||||
return dlmmOneSideLiquidityAccounts{}, fmt.Errorf("event authority not found")
|
||||
}
|
||||
if eventAuthorityPos+1 >= len(accounts) || !accountList[accounts[eventAuthorityPos+1]].Equals(meteoraDlmmProgram) {
|
||||
return dlmmOneSideLiquidityAccounts{}, fmt.Errorf("program id not found after event authority")
|
||||
}
|
||||
|
||||
tokenProgramPos := eventAuthorityPos - 1
|
||||
userPos := eventAuthorityPos - 2
|
||||
if tokenProgramPos < 0 || userPos < 0 {
|
||||
return dlmmOneSideLiquidityAccounts{}, fmt.Errorf("one side liquidity account positions invalid")
|
||||
}
|
||||
if len(accounts) < 6 {
|
||||
return dlmmOneSideLiquidityAccounts{}, fmt.Errorf("accounts too short for one side liquidity parsing")
|
||||
}
|
||||
|
||||
return dlmmOneSideLiquidityAccounts{
|
||||
positionIdx: accounts[0],
|
||||
poolIdx: accounts[1],
|
||||
userTokenIdx: accounts[3],
|
||||
reserveIdx: accounts[4],
|
||||
tokenMintIdx: accounts[5],
|
||||
userIdx: accounts[userPos],
|
||||
tokenProgramIdx: accounts[tokenProgramPos],
|
||||
}, nil
|
||||
}
|
||||
|
||||
func dlmmBuildOneSideAddSwap(
|
||||
tx *Tx,
|
||||
instruction Instruction,
|
||||
addEvent dlmmAddLiquidityEvent,
|
||||
startBinId int32,
|
||||
endBinId int32,
|
||||
entryContract solana.PublicKey,
|
||||
) ([]Swap, error) {
|
||||
result := tx.rawTx
|
||||
accounts, err := resolveDlmmOneSideLiquidityAccounts(result, instruction.Accounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
knownMint := result.accountList[accounts.tokenMintIdx]
|
||||
knownTokenProgram := result.accountList[accounts.tokenProgramIdx]
|
||||
knownDecimals, ok := dlmmTokenDecimals(result, accounts.reserveIdx)
|
||||
if !ok {
|
||||
knownDecimals, _ = dlmmTokenDecimals(result, accounts.userTokenIdx)
|
||||
}
|
||||
knownReserveBalance := getAccountBalanceAfterTx(result, accounts.reserveIdx)
|
||||
knownUserBalance := getAccountBalanceAfterTx(result, accounts.userTokenIdx)
|
||||
if knownMint.Equals(wSolMint) {
|
||||
if solAmount, err := GetSolAfterTx(result, accounts.userIdx); err == nil {
|
||||
knownUserBalance = knownUserBalance.Add(decimal.NewFromUint64(solAmount))
|
||||
}
|
||||
}
|
||||
|
||||
eventUser := result.accountList[accounts.userIdx]
|
||||
if !addEvent.From.IsZero() {
|
||||
eventUser = addEvent.From
|
||||
}
|
||||
positionAccount := result.accountList[accounts.positionIdx]
|
||||
if !addEvent.Position.IsZero() {
|
||||
positionAccount = addEvent.Position
|
||||
}
|
||||
|
||||
swap := Swap{
|
||||
Program: SolProgramMeteoraDLMM,
|
||||
Event: "add",
|
||||
Pool: result.accountList[accounts.poolIdx],
|
||||
User: eventUser,
|
||||
EntryContract: entryContract,
|
||||
ActiveBinId: addEvent.ActiveBinId,
|
||||
StartBinId: startBinId,
|
||||
EndBinId: endBinId,
|
||||
PositionAccount: positionAccount,
|
||||
}
|
||||
|
||||
knownIsX := dlmmInferOneSideLiquidityAxis(result, accounts, addEvent)
|
||||
if knownIsX {
|
||||
swap.BaseMint = knownMint
|
||||
swap.BaseTokenProgram = knownTokenProgram
|
||||
swap.BaseMintDecimals = knownDecimals
|
||||
swap.BaseAmount = decimal.NewFromUint64(addEvent.Amounts[0])
|
||||
swap.BaseReserve = knownReserveBalance
|
||||
swap.UserBaseBalance = knownUserBalance
|
||||
if _, exists := tx.Token[knownMint]; !exists && !knownMint.Equals(wSolMint) {
|
||||
tx.Token[knownMint] = TokenMeta{
|
||||
Mint: knownMint,
|
||||
Decimals: knownDecimals,
|
||||
TokenProgram: knownTokenProgram,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
swap.QuoteMint = knownMint
|
||||
swap.QuoteTokenProgram = knownTokenProgram
|
||||
swap.QuoteMintDecimals = knownDecimals
|
||||
swap.QuoteAmount = decimal.NewFromUint64(addEvent.Amounts[1])
|
||||
swap.QuoteReserve = knownReserveBalance
|
||||
swap.UserQuoteBalance = knownUserBalance
|
||||
if _, exists := tx.Token[knownMint]; !exists && !knownMint.Equals(wSolMint) {
|
||||
tx.Token[knownMint] = TokenMeta{
|
||||
Mint: knownMint,
|
||||
Decimals: knownDecimals,
|
||||
TokenProgram: knownTokenProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return []Swap{swap}, nil
|
||||
}
|
||||
|
||||
func dlmmInferOneSideLiquidityAxis(result *RawTx, accounts dlmmOneSideLiquidityAccounts, addEvent dlmmAddLiquidityEvent) bool {
|
||||
knownAmount, ok := dlmmTokenDelta(result, accounts.reserveIdx)
|
||||
if !ok || knownAmount.IsZero() {
|
||||
knownAmount, _ = dlmmTokenDelta(result, accounts.userTokenIdx)
|
||||
}
|
||||
|
||||
amountX := decimal.NewFromUint64(addEvent.Amounts[0])
|
||||
amountY := decimal.NewFromUint64(addEvent.Amounts[1])
|
||||
switch {
|
||||
case !knownAmount.IsZero() && knownAmount.Equal(amountX) && !knownAmount.Equal(amountY):
|
||||
return true
|
||||
case !knownAmount.IsZero() && knownAmount.Equal(amountY) && !knownAmount.Equal(amountX):
|
||||
return false
|
||||
case addEvent.Amounts[0] > 0 && addEvent.Amounts[1] == 0:
|
||||
return true
|
||||
case addEvent.Amounts[1] > 0 && addEvent.Amounts[0] == 0:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func resolveDlmmClaimFeeAccounts(result *RawTx, data []byte, accounts []int) (dlmmLiquidityAccounts, error) {
|
||||
if len(data) < 8 {
|
||||
return dlmmLiquidityAccounts{}, fmt.Errorf("instruction data too short")
|
||||
@@ -1958,56 +2400,67 @@ func dlmmTokenBalanceMeta(result *RawTx, accountIndex int) (TokenBalance, bool)
|
||||
return TokenBalance{}, false
|
||||
}
|
||||
|
||||
func dlmmBinChangesFromDistribution(amountX, amountY uint64, dist []dlmmBinLiquidityDistribution) []DlmmBinLiquidityChange {
|
||||
if len(dist) == 0 {
|
||||
func dlmmAllocateByWeights(total uint64, weights []uint64) []decimal.Decimal {
|
||||
if len(weights) == 0 {
|
||||
return nil
|
||||
}
|
||||
totalX := decimal.NewFromUint64(amountX)
|
||||
totalY := decimal.NewFromUint64(amountY)
|
||||
denom := decimal.NewFromInt(10000)
|
||||
changes := make([]DlmmBinLiquidityChange, 0, len(dist))
|
||||
for _, item := range dist {
|
||||
x := totalX.Mul(decimal.NewFromInt(int64(item.DistributionX))).Div(denom).Truncate(0)
|
||||
y := totalY.Mul(decimal.NewFromInt(int64(item.DistributionY))).Div(denom).Truncate(0)
|
||||
changes = append(changes, DlmmBinLiquidityChange{
|
||||
BinId: item.BinId,
|
||||
AmountX: x,
|
||||
AmountY: y,
|
||||
})
|
||||
|
||||
sumWeights := uint64(0)
|
||||
for _, weight := range weights {
|
||||
sumWeights += weight
|
||||
}
|
||||
return changes
|
||||
if sumWeights == 0 {
|
||||
sumWeights = uint64(len(weights))
|
||||
weights = append([]uint64(nil), weights...)
|
||||
for i := range weights {
|
||||
weights[i] = 1
|
||||
}
|
||||
}
|
||||
|
||||
allocations := make([]decimal.Decimal, len(weights))
|
||||
remaining := total
|
||||
for i, weight := range weights {
|
||||
amount := uint64(0)
|
||||
if i == len(weights)-1 {
|
||||
amount = remaining
|
||||
} else if sumWeights > 0 {
|
||||
amount = total * weight / sumWeights
|
||||
if amount > remaining {
|
||||
amount = remaining
|
||||
}
|
||||
remaining -= amount
|
||||
}
|
||||
allocations[i] = decimal.NewFromUint64(amount)
|
||||
}
|
||||
return allocations
|
||||
}
|
||||
|
||||
func dlmmBinChangesFromReduction(reduction []dlmmBinLiquidityReduction) []DlmmBinLiquidityChange {
|
||||
if len(reduction) == 0 {
|
||||
return nil
|
||||
func dlmmApplySignedAllocation(values []decimal.Decimal, negative bool) []decimal.Decimal {
|
||||
if !negative {
|
||||
return values
|
||||
}
|
||||
changes := make([]DlmmBinLiquidityChange, 0, len(reduction))
|
||||
for _, item := range reduction {
|
||||
changes = append(changes, DlmmBinLiquidityChange{
|
||||
BinId: item.BinId,
|
||||
BpsToRemove: item.BpsToRemove,
|
||||
})
|
||||
out := make([]decimal.Decimal, len(values))
|
||||
for i, value := range values {
|
||||
out[i] = value.Neg()
|
||||
}
|
||||
return changes
|
||||
return out
|
||||
}
|
||||
|
||||
func dlmmBinChangesFromRange(startBinId, endBinId int32, bpsToRemove uint16) []DlmmBinLiquidityChange {
|
||||
if startBinId > endBinId {
|
||||
startBinId, endBinId = endBinId, startBinId
|
||||
func dlmmMinMaxBinIDFromCompressedDeposits(bins []dlmmCompressedBinDepositAmount) (startBinID, endBinID int32) {
|
||||
if len(bins) == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
count := int(endBinId-startBinId) + 1
|
||||
if count <= 0 {
|
||||
return nil
|
||||
startBinID = bins[0].BinID
|
||||
endBinID = bins[0].BinID
|
||||
for _, bin := range bins[1:] {
|
||||
if bin.BinID < startBinID {
|
||||
startBinID = bin.BinID
|
||||
}
|
||||
if bin.BinID > endBinID {
|
||||
endBinID = bin.BinID
|
||||
}
|
||||
}
|
||||
changes := make([]DlmmBinLiquidityChange, 0, count)
|
||||
for binId := startBinId; binId <= endBinId; binId++ {
|
||||
changes = append(changes, DlmmBinLiquidityChange{
|
||||
BinId: binId,
|
||||
BpsToRemove: bpsToRemove,
|
||||
})
|
||||
}
|
||||
return changes
|
||||
return startBinID, endBinID
|
||||
}
|
||||
|
||||
func dlmmCommonRemoveBp(reduction []dlmmBinLiquidityReduction) int32 {
|
||||
@@ -2047,6 +2500,23 @@ func dlmmMinMaxBinIdFromDistribution(dist []dlmmBinLiquidityDistribution) (int32
|
||||
return min, max
|
||||
}
|
||||
|
||||
func dlmmMinMaxBinIdFromWeightDistribution(dist []dlmmBinLiquidityDistributionByWeight) (int32, int32) {
|
||||
if len(dist) == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
min := dist[0].BinId
|
||||
max := dist[0].BinId
|
||||
for _, item := range dist[1:] {
|
||||
if item.BinId < min {
|
||||
min = item.BinId
|
||||
}
|
||||
if item.BinId > max {
|
||||
max = item.BinId
|
||||
}
|
||||
}
|
||||
return min, max
|
||||
}
|
||||
|
||||
func dlmmMinMaxBinIdFromReduction(reduction []dlmmBinLiquidityReduction) (int32, int32) {
|
||||
if len(reduction) == 0 {
|
||||
return 0, 0
|
||||
|
||||
424
metaoradlmm_test.go
Normal file
424
metaoradlmm_test.go
Normal file
@@ -0,0 +1,424 @@
|
||||
package pump_parser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
agbinary "github.com/gagliardetto/binary"
|
||||
"github.com/gagliardetto/solana-go"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
func testPublicKey(seed byte) solana.PublicKey {
|
||||
buf := make([]byte, solana.PublicKeyLength)
|
||||
for i := range buf {
|
||||
buf[i] = seed
|
||||
}
|
||||
return solana.PublicKeyFromBytes(buf)
|
||||
}
|
||||
|
||||
func seqInts(n int) []int {
|
||||
out := make([]int, n)
|
||||
for i := range out {
|
||||
out[i] = i
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func mustBorshEncode(t *testing.T, value any) []byte {
|
||||
t.Helper()
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := agbinary.NewBorshEncoder(&buf).Encode(value); err != nil {
|
||||
t.Fatalf("borsh encode failed: %v", err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func TestMeteoraDlmmInitializeParserCompatibility(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
discriminator [8]byte
|
||||
accountCount int
|
||||
wantPoolPos int
|
||||
wantBaseMintPos int
|
||||
wantQuoteMintPos int
|
||||
wantUserPos int
|
||||
wantBaseProgramPos int
|
||||
wantQuoteProgramPos int
|
||||
}{
|
||||
{
|
||||
name: "initialize_lb_pair",
|
||||
discriminator: meteoraInitializeLbPairDiscriminator,
|
||||
accountCount: 14,
|
||||
wantPoolPos: 0,
|
||||
wantBaseMintPos: 2,
|
||||
wantQuoteMintPos: 3,
|
||||
wantUserPos: 8,
|
||||
wantBaseProgramPos: 9,
|
||||
wantQuoteProgramPos: 9,
|
||||
},
|
||||
{
|
||||
name: "initialize_lb_pair2",
|
||||
discriminator: meteoraInitializeLbPair2Discriminator,
|
||||
accountCount: 16,
|
||||
wantPoolPos: 0,
|
||||
wantBaseMintPos: 2,
|
||||
wantQuoteMintPos: 3,
|
||||
wantUserPos: 8,
|
||||
wantBaseProgramPos: 11,
|
||||
wantQuoteProgramPos: 12,
|
||||
},
|
||||
{
|
||||
name: "initialize_customizable_permissionless_lb_pair",
|
||||
discriminator: meteoraInitializeCustomizablePermissionlessLbPairDiscriminator,
|
||||
accountCount: 14,
|
||||
wantPoolPos: 0,
|
||||
wantBaseMintPos: 2,
|
||||
wantQuoteMintPos: 3,
|
||||
wantUserPos: 8,
|
||||
wantBaseProgramPos: 9,
|
||||
wantQuoteProgramPos: 9,
|
||||
},
|
||||
{
|
||||
name: "initialize_customizable_permissionless_lb_pair2",
|
||||
discriminator: meteoraInitializeCustomizablePermissionlessLbPair2Discriminator,
|
||||
accountCount: 17,
|
||||
wantPoolPos: 0,
|
||||
wantBaseMintPos: 2,
|
||||
wantQuoteMintPos: 3,
|
||||
wantUserPos: 8,
|
||||
wantBaseProgramPos: 11,
|
||||
wantQuoteProgramPos: 12,
|
||||
},
|
||||
{
|
||||
name: "initialize_permission_lb_pair",
|
||||
discriminator: meteoraInitializePermissionLbPairDiscriminator,
|
||||
accountCount: 17,
|
||||
wantPoolPos: 1,
|
||||
wantBaseMintPos: 3,
|
||||
wantQuoteMintPos: 4,
|
||||
wantUserPos: 8,
|
||||
wantBaseProgramPos: 11,
|
||||
wantQuoteProgramPos: 12,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
accountList := make([]solana.PublicKey, 32)
|
||||
for i := range accountList {
|
||||
accountList[i] = testPublicKey(byte(i + 1))
|
||||
}
|
||||
programIndex := 30
|
||||
accountList[programIndex] = meteoraDlmmProgram
|
||||
|
||||
instruction := Instruction{
|
||||
Accounts: seqInts(tc.accountCount),
|
||||
Data: solana.Base58(tc.discriminator[:]),
|
||||
ProgramIDIndex: programIndex,
|
||||
}
|
||||
|
||||
rawTx := &RawTx{
|
||||
accountList: accountList,
|
||||
Meta: Meta{
|
||||
PostTokenBalances: []TokenBalance{
|
||||
{
|
||||
MintAccount: accountList[tc.wantBaseMintPos],
|
||||
UITokenAmount: UITokenAmount{
|
||||
Decimals: 6,
|
||||
},
|
||||
},
|
||||
{
|
||||
MintAccount: accountList[tc.wantQuoteMintPos],
|
||||
UITokenAmount: UITokenAmount{
|
||||
Decimals: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Transaction: Transaction{
|
||||
Message: Message{
|
||||
Instructions: []Instruction{instruction},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tx := &Tx{rawTx: rawTx}
|
||||
|
||||
swaps, _, err := metaoradlmmParser(tx, instruction, InnerInstructions{}, [2]uint{0, 0})
|
||||
if err != nil {
|
||||
t.Fatalf("metaoradlmmParser() error = %v", err)
|
||||
}
|
||||
if len(swaps) != 1 {
|
||||
t.Fatalf("metaoradlmmParser() swaps len = %d, want 1", len(swaps))
|
||||
}
|
||||
|
||||
swap := swaps[0]
|
||||
if !swap.Pool.Equals(accountList[tc.wantPoolPos]) {
|
||||
t.Fatalf("swap.Pool = %s, want %s", swap.Pool, accountList[tc.wantPoolPos])
|
||||
}
|
||||
if !swap.BaseMint.Equals(accountList[tc.wantBaseMintPos]) {
|
||||
t.Fatalf("swap.BaseMint = %s, want %s", swap.BaseMint, accountList[tc.wantBaseMintPos])
|
||||
}
|
||||
if !swap.QuoteMint.Equals(accountList[tc.wantQuoteMintPos]) {
|
||||
t.Fatalf("swap.QuoteMint = %s, want %s", swap.QuoteMint, accountList[tc.wantQuoteMintPos])
|
||||
}
|
||||
if !swap.User.Equals(accountList[tc.wantUserPos]) {
|
||||
t.Fatalf("swap.User = %s, want %s", swap.User, accountList[tc.wantUserPos])
|
||||
}
|
||||
if !swap.BaseTokenProgram.Equals(accountList[tc.wantBaseProgramPos]) {
|
||||
t.Fatalf("swap.BaseTokenProgram = %s, want %s", swap.BaseTokenProgram, accountList[tc.wantBaseProgramPos])
|
||||
}
|
||||
if !swap.QuoteTokenProgram.Equals(accountList[tc.wantQuoteProgramPos]) {
|
||||
t.Fatalf("swap.QuoteTokenProgram = %s, want %s", swap.QuoteTokenProgram, accountList[tc.wantQuoteProgramPos])
|
||||
}
|
||||
if swap.BaseMintDecimals != 6 {
|
||||
t.Fatalf("swap.BaseMintDecimals = %d, want 6", swap.BaseMintDecimals)
|
||||
}
|
||||
if swap.QuoteMintDecimals != 9 {
|
||||
t.Fatalf("swap.QuoteMintDecimals = %d, want 9", swap.QuoteMintDecimals)
|
||||
}
|
||||
if !swap.EntryContract.Equals(meteoraDlmmProgram) {
|
||||
t.Fatalf("swap.EntryContract = %s, want %s", swap.EntryContract, meteoraDlmmProgram)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDlmmDecodeLbPairCreateEvent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
event := dlmmLbPairCreateEvent{
|
||||
LbPair: testPublicKey(90),
|
||||
BinStep: 42,
|
||||
TokenX: testPublicKey(91),
|
||||
TokenY: testPublicKey(92),
|
||||
}
|
||||
|
||||
body := mustBorshEncode(t, event)
|
||||
|
||||
barePayload := append(append([]byte{}, meteoraInitializeLbPairEventDiscriminator[:]...), body...)
|
||||
decodedBare, ok := dlmmDecodeLbPairCreateEvent(barePayload)
|
||||
if !ok {
|
||||
t.Fatalf("dlmmDecodeLbPairCreateEvent() failed for bare payload")
|
||||
}
|
||||
if decodedBare != event {
|
||||
t.Fatalf("decoded bare event = %+v, want %+v", decodedBare, event)
|
||||
}
|
||||
|
||||
anchorPayload := append(append(append([]byte{}, eventDiscriminator[:]...), meteoraInitializeLbPairEventDiscriminator[:]...), body...)
|
||||
decodedAnchor, ok := dlmmDecodeLbPairCreateEvent(anchorPayload)
|
||||
if !ok {
|
||||
t.Fatalf("dlmmDecodeLbPairCreateEvent() failed for anchor payload")
|
||||
}
|
||||
if decodedAnchor != event {
|
||||
t.Fatalf("decoded anchor event = %+v, want %+v", decodedAnchor, event)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeteoraDlmmInitializeParserUsesLbPairCreateEvent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
accountList := make([]solana.PublicKey, 32)
|
||||
for i := range accountList {
|
||||
accountList[i] = testPublicKey(byte(i + 1))
|
||||
}
|
||||
programIndex := 30
|
||||
accountList[programIndex] = meteoraDlmmProgram
|
||||
|
||||
instruction := Instruction{
|
||||
Accounts: seqInts(16),
|
||||
Data: solana.Base58(meteoraInitializeLbPair2Discriminator[:]),
|
||||
ProgramIDIndex: programIndex,
|
||||
}
|
||||
|
||||
event := dlmmLbPairCreateEvent{
|
||||
LbPair: testPublicKey(111),
|
||||
BinStep: 25,
|
||||
TokenX: testPublicKey(112),
|
||||
TokenY: testPublicKey(113),
|
||||
}
|
||||
innerEventData := append(
|
||||
append(append([]byte{}, eventDiscriminator[:]...), meteoraInitializeLbPairEventDiscriminator[:]...),
|
||||
mustBorshEncode(t, event)...,
|
||||
)
|
||||
|
||||
rawTx := &RawTx{
|
||||
accountList: accountList,
|
||||
Meta: Meta{
|
||||
PostTokenBalances: []TokenBalance{
|
||||
{
|
||||
MintAccount: accountList[2],
|
||||
UITokenAmount: UITokenAmount{
|
||||
Decimals: 6,
|
||||
},
|
||||
},
|
||||
{
|
||||
MintAccount: accountList[3],
|
||||
UITokenAmount: UITokenAmount{
|
||||
Decimals: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
InnerInstructions: []InnerInstructions{
|
||||
{
|
||||
Index: 0,
|
||||
Instructions: []Instruction{
|
||||
{
|
||||
ProgramIDIndex: programIndex,
|
||||
Data: solana.Base58(innerEventData),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Transaction: Transaction{
|
||||
Message: Message{
|
||||
Instructions: []Instruction{instruction},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tx := &Tx{rawTx: rawTx}
|
||||
|
||||
swaps, nextOffset, err := metaoradlmmParser(tx, instruction, rawTx.Meta.InnerInstructions[0], [2]uint{0, 0})
|
||||
if err != nil {
|
||||
t.Fatalf("metaoradlmmParser() error = %v", err)
|
||||
}
|
||||
if len(swaps) != 1 {
|
||||
t.Fatalf("metaoradlmmParser() swaps len = %d, want 1", len(swaps))
|
||||
}
|
||||
|
||||
swap := swaps[0]
|
||||
if !swap.Pool.Equals(event.LbPair) {
|
||||
t.Fatalf("swap.Pool = %s, want event %s", swap.Pool, event.LbPair)
|
||||
}
|
||||
if !swap.BaseMint.Equals(event.TokenX) {
|
||||
t.Fatalf("swap.BaseMint = %s, want event %s", swap.BaseMint, event.TokenX)
|
||||
}
|
||||
if !swap.QuoteMint.Equals(event.TokenY) {
|
||||
t.Fatalf("swap.QuoteMint = %s, want event %s", swap.QuoteMint, event.TokenY)
|
||||
}
|
||||
if nextOffset != ([2]uint{1, 0}) {
|
||||
t.Fatalf("nextOffset = %#v, want [2]uint{1, 0}", nextOffset)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDlmmSwapFeeInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
baseMint := testPublicKey(1)
|
||||
quoteMint := testPublicKey(2)
|
||||
baseProgram := testPublicKey(3)
|
||||
quoteProgram := testPublicKey(4)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
baseIsX bool
|
||||
swapForY bool
|
||||
wantFeeSide string
|
||||
wantFeeMint solana.PublicKey
|
||||
wantFeeProg solana.PublicKey
|
||||
wantDecimals uint8
|
||||
}{
|
||||
{
|
||||
name: "x is base and input is x",
|
||||
baseIsX: true,
|
||||
swapForY: true,
|
||||
wantFeeSide: "base",
|
||||
wantFeeMint: baseMint,
|
||||
wantFeeProg: baseProgram,
|
||||
wantDecimals: 6,
|
||||
},
|
||||
{
|
||||
name: "x is base and input is y",
|
||||
baseIsX: true,
|
||||
swapForY: false,
|
||||
wantFeeSide: "quote",
|
||||
wantFeeMint: quoteMint,
|
||||
wantFeeProg: quoteProgram,
|
||||
wantDecimals: 9,
|
||||
},
|
||||
{
|
||||
name: "y is base and input is x",
|
||||
baseIsX: false,
|
||||
swapForY: true,
|
||||
wantFeeSide: "quote",
|
||||
wantFeeMint: quoteMint,
|
||||
wantFeeProg: quoteProgram,
|
||||
wantDecimals: 9,
|
||||
},
|
||||
{
|
||||
name: "y is base and input is y",
|
||||
baseIsX: false,
|
||||
swapForY: false,
|
||||
wantFeeSide: "base",
|
||||
wantFeeMint: baseMint,
|
||||
wantFeeProg: baseProgram,
|
||||
wantDecimals: 6,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
feeAmount, feeSide, feeMint, feeProgram, feeDecimals := dlmmSwapFeeInfo(
|
||||
tc.baseIsX,
|
||||
tc.swapForY,
|
||||
123,
|
||||
baseMint,
|
||||
quoteMint,
|
||||
baseProgram,
|
||||
quoteProgram,
|
||||
6,
|
||||
9,
|
||||
)
|
||||
if !feeAmount.Equal(decimal.NewFromInt(123)) {
|
||||
t.Fatalf("feeAmount = %s, want 123", feeAmount)
|
||||
}
|
||||
if feeSide != tc.wantFeeSide {
|
||||
t.Fatalf("feeSide = %s, want %s", feeSide, tc.wantFeeSide)
|
||||
}
|
||||
if !feeMint.Equals(tc.wantFeeMint) {
|
||||
t.Fatalf("feeMint = %s, want %s", feeMint, tc.wantFeeMint)
|
||||
}
|
||||
if !feeProgram.Equals(tc.wantFeeProg) {
|
||||
t.Fatalf("feeProgram = %s, want %s", feeProgram, tc.wantFeeProg)
|
||||
}
|
||||
if feeDecimals != tc.wantDecimals {
|
||||
t.Fatalf("feeDecimals = %d, want %d", feeDecimals, tc.wantDecimals)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDlmmSwapLpFeeAmount(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
lpFee := dlmmSwapLpFeeAmount(100, 15, 5)
|
||||
if !lpFee.Equal(decimal.NewFromInt(80)) {
|
||||
t.Fatalf("lpFee = %s, want 80", lpFee)
|
||||
}
|
||||
|
||||
lpFee = dlmmSwapLpFeeAmount(10, 8, 5)
|
||||
if !lpFee.IsZero() {
|
||||
t.Fatalf("lpFee should floor at zero, got %s", lpFee)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDlmmSwapFeeBpsString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
feeBps := agbinary.Uint128{Lo: 12345}
|
||||
if got := dlmmSwapFeeBpsString(feeBps); got != "12345" {
|
||||
t.Fatalf("dlmmSwapFeeBpsString() = %s, want 12345", got)
|
||||
}
|
||||
}
|
||||
4
rawtx.go
4
rawtx.go
@@ -872,7 +872,9 @@ func ConvertYellowstoneGrpcTransactionToSolanaTransaction(y *pb.SubscribeUpdateT
|
||||
}
|
||||
sTx.Meta.Fee = meta.Fee
|
||||
//sTx.Meta.InnerInstructions = meta.InnerInstructions
|
||||
sTx.Meta.ComputeUnitsConsumed = *meta.ComputeUnitsConsumed
|
||||
if meta.ComputeUnitsConsumed != nil {
|
||||
sTx.Meta.ComputeUnitsConsumed = *meta.ComputeUnitsConsumed
|
||||
}
|
||||
for _, innerInstr := range meta.InnerInstructions {
|
||||
var instrs []Instruction
|
||||
for _, instr := range innerInstr.Instructions {
|
||||
|
||||
23
tx.go
23
tx.go
@@ -48,23 +48,22 @@ type Swap struct {
|
||||
AfterSOLBalance decimal.Decimal
|
||||
|
||||
//For meteora dlmm
|
||||
ActiveBinId int32
|
||||
StartBinId int32
|
||||
EndBinId int32
|
||||
RemoveBp int32
|
||||
BinChanges []DlmmBinLiquidityChange
|
||||
ActiveBinId int32
|
||||
StartBinId int32
|
||||
EndBinId int32
|
||||
RemoveBp int32
|
||||
PositionAccount solana.PublicKey
|
||||
FeeAmount decimal.Decimal
|
||||
FeeBps string
|
||||
LpFeeAmount decimal.Decimal
|
||||
FeeSide string
|
||||
FeeMint solana.PublicKey
|
||||
FeeTokenProgram solana.PublicKey
|
||||
FeeMintDecimals uint8
|
||||
|
||||
ConsumeUnit uint64
|
||||
}
|
||||
|
||||
type DlmmBinLiquidityChange struct {
|
||||
BinId int32
|
||||
AmountX decimal.Decimal
|
||||
AmountY decimal.Decimal
|
||||
BpsToRemove uint16
|
||||
}
|
||||
|
||||
type platformInfo struct {
|
||||
Platform string
|
||||
PlatformFee decimal.Decimal
|
||||
|
||||
Reference in New Issue
Block a user