feat(pumpswap): support virtual quote reserves
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "sol-trade-sdk"
|
name = "sol-trade-sdk"
|
||||||
version = "4.0.22"
|
version = "4.0.23"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = [
|
authors = [
|
||||||
"William <byteblock6@gmail.com>",
|
"William <byteblock6@gmail.com>",
|
||||||
|
|||||||
@@ -92,9 +92,9 @@ This SDK is available in multiple languages:
|
|||||||
|
|
||||||
## 🔖 Current Release
|
## 🔖 Current Release
|
||||||
|
|
||||||
**Rust crate:** `sol-trade-sdk = "4.0.21"`
|
**Rust crate:** `sol-trade-sdk = "4.0.23"`
|
||||||
|
|
||||||
This release refreshes PumpFun native-SOL quote handling so SOL/WSOL sentinels prefer the smaller V1 hot path, keeps the default RPC submit lane active alongside SWQoS lanes, restores the fast-submit result window to 5 seconds, and aligns Raydium CPMM fixed-output swaps with the on-chain `swap_base_out` instruction. Trade execution requires a caller-supplied `recent_blockhash` or durable nonce; hot-path execution does not query RPC for blockhash, account, or balance data.
|
This release updates PumpSwap for the July 2026 virtual quote reserve rollout. Pool and event schemas include `virtual_quote_reserves`, and all PumpSwap buy, sell, pricing, and dynamic-fee calculations use `quote_vault_balance + virtual_quote_reserves`.
|
||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
|
||||||
@@ -126,14 +126,14 @@ Add the dependency to your `Cargo.toml`:
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
# Add to your Cargo.toml
|
# Add to your Cargo.toml
|
||||||
sol-trade-sdk = { path = "./sol-trade-sdk", version = "4.0.21" }
|
sol-trade-sdk = { path = "./sol-trade-sdk", version = "4.0.23" }
|
||||||
```
|
```
|
||||||
|
|
||||||
### Use crates.io
|
### Use crates.io
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# Add to your Cargo.toml
|
# Add to your Cargo.toml
|
||||||
sol-trade-sdk = "4.0.21"
|
sol-trade-sdk = "4.0.23"
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🛠️ Usage Examples
|
## 🛠️ Usage Examples
|
||||||
@@ -506,6 +506,14 @@ For **PumpSwap** (Pump AMM), `coin_creator_vault_ata` and `coin_creator_vault_au
|
|||||||
- **sol-parser-sdk**: Instruction parser sets them from accounts 17 and 18; the account filler also fills them when the event comes from logs. Use `PumpSwapParams::from_trade(..., e.coin_creator_vault_ata, e.coin_creator_vault_authority, ...)` with the buy/sell event `e`.
|
- **sol-parser-sdk**: Instruction parser sets them from accounts 17 and 18; the account filler also fills them when the event comes from logs. Use `PumpSwapParams::from_trade(..., e.coin_creator_vault_ata, e.coin_creator_vault_authority, ...)` with the buy/sell event `e`.
|
||||||
- **solana-streamer**: Instruction parser sets them from `accounts.get(17)` and `accounts.get(18)`. Use the same `from_trade` with the event's `coin_creator_vault_ata` and `coin_creator_vault_authority`.
|
- **solana-streamer**: Instruction parser sets them from `accounts.get(17)` and `accounts.get(18)`. Use the same `from_trade` with the event's `coin_creator_vault_ata` and `coin_creator_vault_authority`.
|
||||||
|
|
||||||
|
#### PumpSwap: virtual quote reserves
|
||||||
|
|
||||||
|
PumpSwap quotes must use `effective_quote_reserves = pool_quote_token_account.amount + virtual_quote_reserves`. The Pool account and BuyEvent/SellEvent encode `virtual_quote_reserves` as `i128`.
|
||||||
|
|
||||||
|
- RPC constructors such as `PumpSwapParams::from_pool_address_by_rpc` read and apply the Pool field automatically.
|
||||||
|
- Event fast paths must pass the event's raw `pool_quote_token_reserves` and `virtual_quote_reserves` separately to `PumpSwapParams::from_trade(...)` or `from_trade_with_fee_basis_points(...)`. Do not add them before calling the constructor.
|
||||||
|
- The SDK uses effective reserves for buys, sells, prices, and dynamic fee-tier selection. Invalid signed sums return an error instead of wrapping.
|
||||||
|
|
||||||
## 🛡️ MEV Protection Services
|
## 🛡️ MEV Protection Services
|
||||||
|
|
||||||
You can apply for a key through the official website: [Community Website](https://fnzero.dev/swqos)
|
You can apply for a key through the official website: [Community Website](https://fnzero.dev/swqos)
|
||||||
|
|||||||
+12
-4
@@ -92,9 +92,9 @@
|
|||||||
|
|
||||||
## 🔖 当前版本
|
## 🔖 当前版本
|
||||||
|
|
||||||
**Rust crate:** `sol-trade-sdk = "4.0.21"`
|
**Rust crate:** `sol-trade-sdk = "4.0.23"`
|
||||||
|
|
||||||
本版本刷新 PumpFun native SOL quote 处理逻辑,SOL/WSOL sentinel 默认优先走更小的 V1 热路径,确保默认 RPC 提交通道会和 SWQoS 通道一起发出,快速提交结果等待窗口恢复为 5 秒,并将 Raydium CPMM fixed-output 交易对齐到链上 `swap_base_out` 指令。交易执行必须由调用方传入 `recent_blockhash` 或 durable nonce;热路径不会查询 RPC 获取 blockhash、账户或余额数据。
|
本版本适配 PumpSwap 2026 年 7 月的虚拟 quote 储备升级。Pool 与事件 schema 新增 `virtual_quote_reserves`,PumpSwap 买入、卖出、报价和动态费率计算统一使用 `quote_vault_balance + virtual_quote_reserves`。
|
||||||
|
|
||||||
## ✨ 项目特性
|
## ✨ 项目特性
|
||||||
|
|
||||||
@@ -126,14 +126,14 @@ git clone https://github.com/0xfnzero/sol-trade-sdk
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
# 添加到您的 Cargo.toml
|
# 添加到您的 Cargo.toml
|
||||||
sol-trade-sdk = { path = "./sol-trade-sdk", version = "4.0.21" }
|
sol-trade-sdk = { path = "./sol-trade-sdk", version = "4.0.23" }
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用 crates.io
|
### 使用 crates.io
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# 添加到您的 Cargo.toml
|
# 添加到您的 Cargo.toml
|
||||||
sol-trade-sdk = "4.0.21"
|
sol-trade-sdk = "4.0.23"
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🛠️ 使用示例
|
## 🛠️ 使用示例
|
||||||
@@ -503,6 +503,14 @@ legacy SOL 事件里如果 `quote_mint` 是默认值或 Solscan SOL,并且 quo
|
|||||||
| 未设置(默认)/ `SOL_TOKEN_ACCOUNT` (`So111...11111`) / `WSOL_TOKEN_ACCOUNT` (`So111...11112`) | 优先旧版 `buy`/`sell`/`buy_exact_sol_in` | native SOL 配对;普通 SOL 结算走 V1,显式 WSOL 结算才走 V2 |
|
| 未设置(默认)/ `SOL_TOKEN_ACCOUNT` (`So111...11111`) / `WSOL_TOKEN_ACCOUNT` (`So111...11112`) | 优先旧版 `buy`/`sell`/`buy_exact_sol_in` | native SOL 配对;普通 SOL 结算走 V1,显式 WSOL 结算才走 V2 |
|
||||||
| `USDC_TOKEN_ACCOUNT` | `buy_v2`/`sell_v2`/`buy_exact_quote_in_v2` | USDC 配对(必须使用 v2) |
|
| `USDC_TOKEN_ACCOUNT` | `buy_v2`/`sell_v2`/`buy_exact_quote_in_v2` | USDC 配对(必须使用 v2) |
|
||||||
|
|
||||||
|
#### PumpSwap:虚拟 quote 储备
|
||||||
|
|
||||||
|
PumpSwap 报价必须使用 `effective_quote_reserves = pool_quote_token_account.amount + virtual_quote_reserves`。Pool 账户以及 BuyEvent/SellEvent 中的 `virtual_quote_reserves` 类型均为 `i128`。
|
||||||
|
|
||||||
|
- `PumpSwapParams::from_pool_address_by_rpc` 等 RPC 构造器会自动读取并应用 Pool 字段。
|
||||||
|
- 事件热路径必须把事件中的原始 `pool_quote_token_reserves` 和 `virtual_quote_reserves` 分别传给 `PumpSwapParams::from_trade(...)` 或 `from_trade_with_fee_basis_points(...)`,不要在调用前自行相加。
|
||||||
|
- SDK 在买入、卖出、报价和动态费率分层中统一使用有效储备;无效的有符号结果会返回错误,不会发生整数回绕。
|
||||||
|
|
||||||
## 🛡️ MEV 保护服务
|
## 🛡️ MEV 保护服务
|
||||||
|
|
||||||
可以通过官网申请密钥:[社区官网](https://fnzero.dev/swqos)
|
可以通过官网申请密钥:[社区官网](https://fnzero.dev/swqos)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ cargo run --release --package pumpswap_trading
|
|||||||
|
|
||||||
- The buy uses `BuyAmount::WithMaxInput`, which applies slippage to maximum quote cost and is appropriate when fill priority matters.
|
- The buy uses `BuyAmount::WithMaxInput`, which applies slippage to maximum quote cost and is appropriate when fill priority matters.
|
||||||
- Buy parameters use post-trade reserves and LP/protocol/creator fee bps from the event.
|
- Buy parameters use post-trade reserves and LP/protocol/creator fee bps from the event.
|
||||||
|
- `solana-streamer-sdk 0.5.0` predates the appended `virtual_quote_reserves` event field, so this compatibility example reads that Pool field once before quoting. When the parser exposes the field, pass it directly to `PumpSwapParams::from_trade_with_fee_basis_points` or keep it in a Pool account cache to remove this RPC from the hot path.
|
||||||
- The example records the pre-buy balance and sells only the confirmed balance increase. It refreshes pool state and blockhash before selling.
|
- The example records the pre-buy balance and sells only the confirmed balance increase. It refreshes pool state and blockhash before selling.
|
||||||
- Use `BuyAmount::ExactInput` when the quote spend must be exact. That mode protects minimum output and can fail more often in an active pool.
|
- Use `BuyAmount::ExactInput` when the quote spend must be exact. That mode protects minimum output and can fail more often in an active pool.
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ cargo run --release --package pumpswap_trading
|
|||||||
|
|
||||||
- 买入使用 `BuyAmount::WithMaxInput`,适合优先成交的跟单/狙击场景,滑点限制最大 quote 成本。
|
- 买入使用 `BuyAmount::WithMaxInput`,适合优先成交的跟单/狙击场景,滑点限制最大 quote 成本。
|
||||||
- 买入参数使用事件中的成交后储备和 LP/protocol/creator fee bps。
|
- 买入参数使用事件中的成交后储备和 LP/protocol/creator fee bps。
|
||||||
|
- `solana-streamer-sdk 0.5.0` 尚未暴露追加的 `virtual_quote_reserves` 事件字段,因此该兼容示例会在报价前读取一次 Pool 字段。解析器暴露该字段后,应直接传给 `PumpSwapParams::from_trade_with_fee_basis_points`,或维护 Pool 账户缓存,以移除热路径中的这次 RPC。
|
||||||
- 示例记录买前余额,只卖出确认后的余额增量;卖出前重新获取池状态和 blockhash。
|
- 示例记录买前余额,只卖出确认后的余额增量;卖出前重新获取池状态和 blockhash。
|
||||||
- 若业务必须精确花费 quote,应改用 `BuyAmount::ExactInput`。这会启用最小输出保护,在活跃池中更容易因状态变化而失败。
|
- 若业务必须精确花费 quote,应改用 `BuyAmount::ExactInput`。这会启用最小输出保护,在活跃池中更容易因状态变化而失败。
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use sol_trade_sdk::common::{clock::now_micros, SolanaRpcClient, TradeConfig};
|
use sol_trade_sdk::common::{clock::now_micros, SolanaRpcClient, TradeConfig};
|
||||||
|
use sol_trade_sdk::instruction::utils::pumpswap::fetch_pool;
|
||||||
use sol_trade_sdk::TradeTokenType;
|
use sol_trade_sdk::TradeTokenType;
|
||||||
use sol_trade_sdk::{
|
use sol_trade_sdk::{
|
||||||
common::AnyResult,
|
common::AnyResult,
|
||||||
@@ -279,6 +280,10 @@ async fn pumpswap_trade_with_grpc_buy_event(
|
|||||||
blockhash_cache: BlockhashCache,
|
blockhash_cache: BlockhashCache,
|
||||||
trade_info: PumpSwapBuyEvent,
|
trade_info: PumpSwapBuyEvent,
|
||||||
) -> AnyResult<()> {
|
) -> AnyResult<()> {
|
||||||
|
// solana-streamer-sdk 0.5.0 predates the appended event field. Read the
|
||||||
|
// Pool value so this compatibility example still prices effective reserves.
|
||||||
|
let virtual_quote_reserves =
|
||||||
|
fetch_pool(&client.infrastructure.rpc, &trade_info.pool).await?.virtual_quote_reserves;
|
||||||
let params = PumpSwapParams::from_trade_with_fee_basis_points(
|
let params = PumpSwapParams::from_trade_with_fee_basis_points(
|
||||||
trade_info.pool,
|
trade_info.pool,
|
||||||
trade_info.base_mint,
|
trade_info.base_mint,
|
||||||
@@ -287,6 +292,7 @@ async fn pumpswap_trade_with_grpc_buy_event(
|
|||||||
trade_info.pool_quote_token_account,
|
trade_info.pool_quote_token_account,
|
||||||
trade_info.pool_base_token_reserves,
|
trade_info.pool_base_token_reserves,
|
||||||
trade_info.pool_quote_token_reserves,
|
trade_info.pool_quote_token_reserves,
|
||||||
|
virtual_quote_reserves,
|
||||||
trade_info.coin_creator_vault_ata,
|
trade_info.coin_creator_vault_ata,
|
||||||
trade_info.coin_creator_vault_authority,
|
trade_info.coin_creator_vault_authority,
|
||||||
trade_info.base_token_program,
|
trade_info.base_token_program,
|
||||||
@@ -317,6 +323,8 @@ async fn pumpswap_trade_with_grpc_sell_event(
|
|||||||
blockhash_cache: BlockhashCache,
|
blockhash_cache: BlockhashCache,
|
||||||
trade_info: PumpSwapSellEvent,
|
trade_info: PumpSwapSellEvent,
|
||||||
) -> AnyResult<()> {
|
) -> AnyResult<()> {
|
||||||
|
let virtual_quote_reserves =
|
||||||
|
fetch_pool(&client.infrastructure.rpc, &trade_info.pool).await?.virtual_quote_reserves;
|
||||||
let params = PumpSwapParams::from_trade_with_fee_basis_points(
|
let params = PumpSwapParams::from_trade_with_fee_basis_points(
|
||||||
trade_info.pool,
|
trade_info.pool,
|
||||||
trade_info.base_mint,
|
trade_info.base_mint,
|
||||||
@@ -325,6 +333,7 @@ async fn pumpswap_trade_with_grpc_sell_event(
|
|||||||
trade_info.pool_quote_token_account,
|
trade_info.pool_quote_token_account,
|
||||||
trade_info.pool_base_token_reserves,
|
trade_info.pool_base_token_reserves,
|
||||||
trade_info.pool_quote_token_reserves,
|
trade_info.pool_quote_token_reserves,
|
||||||
|
virtual_quote_reserves,
|
||||||
trade_info.coin_creator_vault_ata,
|
trade_info.coin_creator_vault_ata,
|
||||||
trade_info.coin_creator_vault_authority,
|
trade_info.coin_creator_vault_authority,
|
||||||
trade_info.base_token_program,
|
trade_info.base_token_program,
|
||||||
|
|||||||
@@ -288,6 +288,213 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "boost_buy_and_burn",
|
||||||
|
"discriminator": [
|
||||||
|
105,
|
||||||
|
68,
|
||||||
|
6,
|
||||||
|
175,
|
||||||
|
0,
|
||||||
|
7,
|
||||||
|
35,
|
||||||
|
162
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "pool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "authority",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "global_config",
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
103,
|
||||||
|
108,
|
||||||
|
111,
|
||||||
|
98,
|
||||||
|
97,
|
||||||
|
108,
|
||||||
|
95,
|
||||||
|
99,
|
||||||
|
111,
|
||||||
|
110,
|
||||||
|
102,
|
||||||
|
105,
|
||||||
|
103
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base_mint",
|
||||||
|
"writable": true,
|
||||||
|
"relations": [
|
||||||
|
"pool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quote_mint",
|
||||||
|
"relations": [
|
||||||
|
"pool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pool_base_token_account",
|
||||||
|
"writable": true,
|
||||||
|
"relations": [
|
||||||
|
"pool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pool_quote_token_account",
|
||||||
|
"writable": true,
|
||||||
|
"relations": [
|
||||||
|
"pool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "boost_vault_authority",
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
98,
|
||||||
|
111,
|
||||||
|
111,
|
||||||
|
115,
|
||||||
|
116,
|
||||||
|
95,
|
||||||
|
118,
|
||||||
|
97,
|
||||||
|
117,
|
||||||
|
108,
|
||||||
|
116
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "pool"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "boost_vault",
|
||||||
|
"writable": true,
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "boost_vault_authority"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "quote_token_program"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "quote_mint"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"program": {
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
140,
|
||||||
|
151,
|
||||||
|
37,
|
||||||
|
143,
|
||||||
|
78,
|
||||||
|
36,
|
||||||
|
137,
|
||||||
|
241,
|
||||||
|
187,
|
||||||
|
61,
|
||||||
|
16,
|
||||||
|
41,
|
||||||
|
20,
|
||||||
|
142,
|
||||||
|
13,
|
||||||
|
131,
|
||||||
|
11,
|
||||||
|
90,
|
||||||
|
19,
|
||||||
|
153,
|
||||||
|
218,
|
||||||
|
255,
|
||||||
|
16,
|
||||||
|
132,
|
||||||
|
4,
|
||||||
|
142,
|
||||||
|
123,
|
||||||
|
216,
|
||||||
|
219,
|
||||||
|
233,
|
||||||
|
248,
|
||||||
|
89
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base_token_program"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quote_token_program"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "event_authority",
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
95,
|
||||||
|
95,
|
||||||
|
101,
|
||||||
|
118,
|
||||||
|
101,
|
||||||
|
110,
|
||||||
|
116,
|
||||||
|
95,
|
||||||
|
97,
|
||||||
|
117,
|
||||||
|
116,
|
||||||
|
104,
|
||||||
|
111,
|
||||||
|
114,
|
||||||
|
105,
|
||||||
|
116,
|
||||||
|
121
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "program"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "quote_amount_in",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "min_base_amount_burned",
|
||||||
|
"type": "u64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "buy",
|
"name": "buy",
|
||||||
"docs": [
|
"docs": [
|
||||||
@@ -2587,6 +2794,208 @@
|
|||||||
],
|
],
|
||||||
"args": []
|
"args": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "init_boost",
|
||||||
|
"discriminator": [
|
||||||
|
140,
|
||||||
|
233,
|
||||||
|
33,
|
||||||
|
94,
|
||||||
|
132,
|
||||||
|
90,
|
||||||
|
194,
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "pool",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "global_config",
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
103,
|
||||||
|
108,
|
||||||
|
111,
|
||||||
|
98,
|
||||||
|
97,
|
||||||
|
108,
|
||||||
|
95,
|
||||||
|
99,
|
||||||
|
111,
|
||||||
|
110,
|
||||||
|
102,
|
||||||
|
105,
|
||||||
|
103
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "creator",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base_mint",
|
||||||
|
"relations": [
|
||||||
|
"pool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quote_mint",
|
||||||
|
"relations": [
|
||||||
|
"pool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pool_base_token_account",
|
||||||
|
"relations": [
|
||||||
|
"pool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pool_quote_token_account",
|
||||||
|
"writable": true,
|
||||||
|
"relations": [
|
||||||
|
"pool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "boost_vault_authority",
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
98,
|
||||||
|
111,
|
||||||
|
111,
|
||||||
|
115,
|
||||||
|
116,
|
||||||
|
95,
|
||||||
|
118,
|
||||||
|
97,
|
||||||
|
117,
|
||||||
|
108,
|
||||||
|
116
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "pool"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "boost_vault",
|
||||||
|
"writable": true,
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "boost_vault_authority"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "quote_token_program"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "quote_mint"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"program": {
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
140,
|
||||||
|
151,
|
||||||
|
37,
|
||||||
|
143,
|
||||||
|
78,
|
||||||
|
36,
|
||||||
|
137,
|
||||||
|
241,
|
||||||
|
187,
|
||||||
|
61,
|
||||||
|
16,
|
||||||
|
41,
|
||||||
|
20,
|
||||||
|
142,
|
||||||
|
13,
|
||||||
|
131,
|
||||||
|
11,
|
||||||
|
90,
|
||||||
|
19,
|
||||||
|
153,
|
||||||
|
218,
|
||||||
|
255,
|
||||||
|
16,
|
||||||
|
132,
|
||||||
|
4,
|
||||||
|
142,
|
||||||
|
123,
|
||||||
|
216,
|
||||||
|
219,
|
||||||
|
233,
|
||||||
|
248,
|
||||||
|
89
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quote_token_program"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "system_program",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "associated_token_program",
|
||||||
|
"address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "event_authority",
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
95,
|
||||||
|
95,
|
||||||
|
101,
|
||||||
|
118,
|
||||||
|
101,
|
||||||
|
110,
|
||||||
|
116,
|
||||||
|
95,
|
||||||
|
97,
|
||||||
|
117,
|
||||||
|
116,
|
||||||
|
104,
|
||||||
|
111,
|
||||||
|
114,
|
||||||
|
105,
|
||||||
|
116,
|
||||||
|
121
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "program"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "init_user_volume_accumulator",
|
"name": "init_user_volume_accumulator",
|
||||||
"discriminator": [
|
"discriminator": [
|
||||||
@@ -3175,6 +3584,72 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "set_boost_authority",
|
||||||
|
"discriminator": [
|
||||||
|
227,
|
||||||
|
149,
|
||||||
|
76,
|
||||||
|
42,
|
||||||
|
130,
|
||||||
|
39,
|
||||||
|
234,
|
||||||
|
205
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"signer": true,
|
||||||
|
"relations": [
|
||||||
|
"global_config"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "global_config",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "boost_authority"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "system_program",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "event_authority",
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
95,
|
||||||
|
95,
|
||||||
|
101,
|
||||||
|
118,
|
||||||
|
101,
|
||||||
|
110,
|
||||||
|
116,
|
||||||
|
95,
|
||||||
|
97,
|
||||||
|
117,
|
||||||
|
116,
|
||||||
|
104,
|
||||||
|
111,
|
||||||
|
114,
|
||||||
|
105,
|
||||||
|
116,
|
||||||
|
121
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "program"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "set_coin_creator",
|
"name": "set_coin_creator",
|
||||||
"docs": [
|
"docs": [
|
||||||
@@ -3610,6 +4085,38 @@
|
|||||||
],
|
],
|
||||||
"args": []
|
"args": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "toggle_boost",
|
||||||
|
"discriminator": [
|
||||||
|
117,
|
||||||
|
161,
|
||||||
|
160,
|
||||||
|
74,
|
||||||
|
223,
|
||||||
|
137,
|
||||||
|
118,
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"signer": true,
|
||||||
|
"relations": [
|
||||||
|
"global_config"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "global_config",
|
||||||
|
"writable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "toggle_cashback_enabled",
|
"name": "toggle_cashback_enabled",
|
||||||
"discriminator": [
|
"discriminator": [
|
||||||
@@ -4672,6 +5179,19 @@
|
|||||||
222
|
222
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "BoostBuyAndBurnEvent",
|
||||||
|
"discriminator": [
|
||||||
|
63,
|
||||||
|
69,
|
||||||
|
28,
|
||||||
|
22,
|
||||||
|
48,
|
||||||
|
92,
|
||||||
|
194,
|
||||||
|
185
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "BuyEvent",
|
"name": "BuyEvent",
|
||||||
"discriminator": [
|
"discriminator": [
|
||||||
@@ -4802,6 +5322,19 @@
|
|||||||
124
|
124
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "InitBoostEvent",
|
||||||
|
"discriminator": [
|
||||||
|
174,
|
||||||
|
124,
|
||||||
|
74,
|
||||||
|
249,
|
||||||
|
4,
|
||||||
|
81,
|
||||||
|
246,
|
||||||
|
17
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "InitUserVolumeAccumulatorEvent",
|
"name": "InitUserVolumeAccumulatorEvent",
|
||||||
"discriminator": [
|
"discriminator": [
|
||||||
@@ -4867,6 +5400,19 @@
|
|||||||
211
|
211
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "SetBoostAuthorityEvent",
|
||||||
|
"discriminator": [
|
||||||
|
89,
|
||||||
|
128,
|
||||||
|
240,
|
||||||
|
141,
|
||||||
|
91,
|
||||||
|
202,
|
||||||
|
71,
|
||||||
|
105
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "SetMetaplexCoinCreatorEvent",
|
"name": "SetMetaplexCoinCreatorEvent",
|
||||||
"discriminator": [
|
"discriminator": [
|
||||||
@@ -5177,6 +5723,51 @@
|
|||||||
{
|
{
|
||||||
"code": 6058,
|
"code": 6058,
|
||||||
"name": "BuybackFeeRecipientMissing"
|
"name": "BuybackFeeRecipientMissing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6059,
|
||||||
|
"name": "MissingCashbackAccounts",
|
||||||
|
"msg": "Cashback trade is missing the required remaining accounts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6060,
|
||||||
|
"name": "InvalidCashbackAccumulator",
|
||||||
|
"msg": "Cashback user_volume_accumulator account is invalid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6061,
|
||||||
|
"name": "InvalidCashbackAccumulatorAta",
|
||||||
|
"msg": "Cashback user_volume_accumulator ATA is missing or invalid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6062,
|
||||||
|
"name": "InvalidPoolV2",
|
||||||
|
"msg": "pool_v2 remaining account is missing or invalid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6063,
|
||||||
|
"name": "InsufficientRealQuoteReserves",
|
||||||
|
"msg": "BOOST: sell output exceeds the real quote vault. effective = real + virtual is pricing-only; payout is capped at real_vault, so quote min(out, real_vault)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6064,
|
||||||
|
"name": "BoostPoolLiquidityUnsupported",
|
||||||
|
"msg": "BOOST: deposit/withdraw don't apply to boost pools"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6065,
|
||||||
|
"name": "PoolCannotBoost",
|
||||||
|
"msg": "BOOST: pool cannot be boosted (no virtual reserves)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6066,
|
||||||
|
"name": "BoostDisabled",
|
||||||
|
"msg": "BOOST: boost is disabled"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6067,
|
||||||
|
"name": "SeedLockViolation",
|
||||||
|
"msg": "BOOST: lp_supply must never drop below the circulating LP mint supply"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"types": [
|
"types": [
|
||||||
@@ -5292,6 +5883,62 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "BoostBuyAndBurnEvent",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": "i64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mint",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bonding_curve",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pool",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "authority",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quote_amount_in_requested",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quote_amount_in_used",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base_amount_burned",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "virtual_quote_reserves",
|
||||||
|
"type": "i128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "real_quote_reserves_after",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base_reserves_after",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "boost_vault_remaining",
|
||||||
|
"type": "u64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "BuyEvent",
|
"name": "BuyEvent",
|
||||||
"docs": [
|
"docs": [
|
||||||
@@ -5435,6 +6082,18 @@
|
|||||||
{
|
{
|
||||||
"name": "buyback_fee",
|
"name": "buyback_fee",
|
||||||
"type": "u64"
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "virtual_quote_reserves",
|
||||||
|
"type": "i128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "can_boost",
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base_supply",
|
||||||
|
"type": "u64"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6018,6 +6677,14 @@
|
|||||||
{
|
{
|
||||||
"name": "buyback_basis_points",
|
"name": "buyback_basis_points",
|
||||||
"type": "u64"
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "boost_authority",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "boost_enabled",
|
||||||
|
"type": "bool"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6064,6 +6731,38 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "InitBoostEvent",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": "i64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mint",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bonding_curve",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pool",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "virtual_quote_reserves",
|
||||||
|
"type": "i128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "real_quote_reserves_after",
|
||||||
|
"type": "u64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "InitUserVolumeAccumulatorEvent",
|
"name": "InitUserVolumeAccumulatorEvent",
|
||||||
"type": {
|
"type": {
|
||||||
@@ -6180,6 +6879,13 @@
|
|||||||
{
|
{
|
||||||
"name": "is_cashback_coin",
|
"name": "is_cashback_coin",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "virtual_quote_reserves",
|
||||||
|
"docs": [
|
||||||
|
"For non-boost pools, value is 0, so the behavior is identical to legacy pools."
|
||||||
|
],
|
||||||
|
"type": "i128"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6321,6 +7027,18 @@
|
|||||||
{
|
{
|
||||||
"name": "buyback_fee",
|
"name": "buyback_fee",
|
||||||
"type": "u64"
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "virtual_quote_reserves",
|
||||||
|
"type": "i128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "can_boost",
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base_supply",
|
||||||
|
"type": "u64"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6353,6 +7071,30 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "SetBoostAuthorityEvent",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": "i64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "old_boost_authority",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "new_boost_authority",
|
||||||
|
"type": "pubkey"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "SetMetaplexCoinCreatorEvent",
|
"name": "SetMetaplexCoinCreatorEvent",
|
||||||
"type": {
|
"type": {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
|||||||
let base_mint = protocol_params.base_mint;
|
let base_mint = protocol_params.base_mint;
|
||||||
let quote_mint = protocol_params.quote_mint;
|
let quote_mint = protocol_params.quote_mint;
|
||||||
let pool_base_token_reserves = protocol_params.pool_base_token_reserves;
|
let pool_base_token_reserves = protocol_params.pool_base_token_reserves;
|
||||||
let pool_quote_token_reserves = protocol_params.pool_quote_token_reserves;
|
let pool_quote_token_reserves = protocol_params.effective_quote_reserves()?;
|
||||||
let params_coin_creator_vault_ata = protocol_params.coin_creator_vault_ata;
|
let params_coin_creator_vault_ata = protocol_params.coin_creator_vault_ata;
|
||||||
let params_coin_creator_vault_authority = protocol_params.coin_creator_vault_authority;
|
let params_coin_creator_vault_authority = protocol_params.coin_creator_vault_authority;
|
||||||
let create_input_ata = params.create_input_mint_ata;
|
let create_input_ata = params.create_input_mint_ata;
|
||||||
@@ -283,7 +283,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
|||||||
let base_mint = protocol_params.base_mint;
|
let base_mint = protocol_params.base_mint;
|
||||||
let quote_mint = protocol_params.quote_mint;
|
let quote_mint = protocol_params.quote_mint;
|
||||||
let pool_base_token_reserves = protocol_params.pool_base_token_reserves;
|
let pool_base_token_reserves = protocol_params.pool_base_token_reserves;
|
||||||
let pool_quote_token_reserves = protocol_params.pool_quote_token_reserves;
|
let pool_quote_token_reserves = protocol_params.effective_quote_reserves()?;
|
||||||
let pool_base_token_account = protocol_params.pool_base_token_account;
|
let pool_base_token_account = protocol_params.pool_base_token_account;
|
||||||
let pool_quote_token_account = protocol_params.pool_quote_token_account;
|
let pool_quote_token_account = protocol_params.pool_quote_token_account;
|
||||||
let params_coin_creator_vault_ata = protocol_params.coin_creator_vault_ata;
|
let params_coin_creator_vault_ata = protocol_params.coin_creator_vault_ata;
|
||||||
@@ -535,6 +535,7 @@ mod tests {
|
|||||||
pk(4),
|
pk(4),
|
||||||
1_000_000_000,
|
1_000_000_000,
|
||||||
2_000_000_000,
|
2_000_000_000,
|
||||||
|
0,
|
||||||
pk(5),
|
pk(5),
|
||||||
accounts::DEFAULT_COIN_CREATOR_VAULT_AUTHORITY,
|
accounts::DEFAULT_COIN_CREATOR_VAULT_AUTHORITY,
|
||||||
crate::constants::TOKEN_PROGRAM,
|
crate::constants::TOKEN_PROGRAM,
|
||||||
@@ -627,6 +628,7 @@ mod tests {
|
|||||||
pk(4),
|
pk(4),
|
||||||
1_000_000_000,
|
1_000_000_000,
|
||||||
2_000_000_000,
|
2_000_000_000,
|
||||||
|
0,
|
||||||
pk(5),
|
pk(5),
|
||||||
accounts::DEFAULT_COIN_CREATOR_VAULT_AUTHORITY,
|
accounts::DEFAULT_COIN_CREATOR_VAULT_AUTHORITY,
|
||||||
crate::constants::TOKEN_PROGRAM,
|
crate::constants::TOKEN_PROGRAM,
|
||||||
@@ -653,8 +655,9 @@ mod tests {
|
|||||||
let mut params = swap_params(TradeType::Buy, None);
|
let mut params = swap_params(TradeType::Buy, None);
|
||||||
params.input_amount = Some(1_000_000);
|
params.input_amount = Some(1_000_000);
|
||||||
params.use_exact_sol_amount = Some(false);
|
params.use_exact_sol_amount = Some(false);
|
||||||
params.protocol_params =
|
let mut protocol_params = pumpswap_params().with_fee_basis_points(20, 5, 75);
|
||||||
DexParamEnum::PumpSwap(pumpswap_params().with_fee_basis_points(20, 5, 75));
|
protocol_params.virtual_quote_reserves = 500_000_000;
|
||||||
|
params.protocol_params = DexParamEnum::PumpSwap(protocol_params);
|
||||||
|
|
||||||
let instructions =
|
let instructions =
|
||||||
PumpSwapInstructionBuilder.build_buy_instructions(¶ms).await.unwrap();
|
PumpSwapInstructionBuilder.build_buy_instructions(¶ms).await.unwrap();
|
||||||
@@ -667,10 +670,33 @@ mod tests {
|
|||||||
1_000_000,
|
1_000_000,
|
||||||
100,
|
100,
|
||||||
1_000_000_000,
|
1_000_000_000,
|
||||||
2_000_000_000,
|
2_500_000_000,
|
||||||
&crate::instruction::utils::pumpswap::PumpSwapFeeBasisPoints::new(20, 5, 0),
|
&crate::instruction::utils::pumpswap::PumpSwapFeeBasisPoints::new(20, 5, 0),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(base_amount_out, expected.base);
|
assert_eq!(base_amount_out, expected.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn pumpswap_sell_prices_with_effective_quote_reserves() {
|
||||||
|
let mut params = swap_params(TradeType::Sell, None);
|
||||||
|
let mut protocol_params = pumpswap_params().with_fee_basis_points(20, 5, 0);
|
||||||
|
protocol_params.virtual_quote_reserves = 500_000_000;
|
||||||
|
params.protocol_params = DexParamEnum::PumpSwap(protocol_params);
|
||||||
|
|
||||||
|
let instructions =
|
||||||
|
PumpSwapInstructionBuilder.build_sell_instructions(¶ms).await.unwrap();
|
||||||
|
let ix = instructions.last().unwrap();
|
||||||
|
let min_quote_amount_out = u64::from_le_bytes(ix.data[16..24].try_into().unwrap());
|
||||||
|
|
||||||
|
let expected = crate::utils::calc::pumpswap::sell_base_input_internal_with_fees(
|
||||||
|
100_000,
|
||||||
|
100,
|
||||||
|
1_000_000_000,
|
||||||
|
2_500_000_000,
|
||||||
|
&crate::instruction::utils::pumpswap::PumpSwapFeeBasisPoints::new(20, 5, 0),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(min_quote_amount_out, expected.min_quote);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use std::sync::{
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
// Pool account sizes moved to find_by_base_mint/find_by_quote_mint (POOL_DATA_LEN_SPL, POOL_DATA_LEN_T22)
|
// Pool account sizes are handled by find_by_base_mint/find_by_quote_mint.
|
||||||
|
|
||||||
/// Constants used as seeds for deriving PDAs (Program Derived Addresses)
|
/// Constants used as seeds for deriving PDAs (Program Derived Addresses)
|
||||||
pub mod seeds {
|
pub mod seeds {
|
||||||
@@ -740,12 +740,14 @@ pub async fn fetch_pool(
|
|||||||
Ok(pool)
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Known pool account sizes: 252 (SPL Token) and 643 (Token2022)
|
/// Known allocated Pool account sizes. The July 2026 layout carrying
|
||||||
const POOL_DATA_LEN_SPL: u64 = 8 + 244;
|
/// `virtual_quote_reserves` is allocated to 300 bytes on-chain.
|
||||||
const POOL_DATA_LEN_T22: u64 = 643;
|
const POOL_DATA_LEN_LEGACY: u64 = 8 + 244;
|
||||||
|
const POOL_DATA_LEN_CURRENT: u64 = 300;
|
||||||
|
const POOL_DATA_LEN_EXTENDED: u64 = 643;
|
||||||
|
|
||||||
/// Run getProgramAccounts with a Memcmp filter, querying both pool sizes in parallel.
|
/// Run getProgramAccounts with a Memcmp filter, querying known Pool sizes in parallel.
|
||||||
async fn get_program_accounts_both_sizes(
|
async fn get_program_accounts_known_sizes(
|
||||||
rpc: &SolanaRpcClient,
|
rpc: &SolanaRpcClient,
|
||||||
memcmp_offset: usize,
|
memcmp_offset: usize,
|
||||||
mint: &Pubkey,
|
mint: &Pubkey,
|
||||||
@@ -768,12 +770,14 @@ async fn get_program_accounts_both_sizes(
|
|||||||
};
|
};
|
||||||
let program_id = accounts::AMM_PROGRAM;
|
let program_id = accounts::AMM_PROGRAM;
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let (spl_result, t22_result) = tokio::join!(
|
let (legacy_result, current_result, extended_result) = tokio::join!(
|
||||||
rpc.get_program_accounts_with_config(&program_id, make_config(POOL_DATA_LEN_SPL)),
|
rpc.get_program_accounts_with_config(&program_id, make_config(POOL_DATA_LEN_LEGACY)),
|
||||||
rpc.get_program_accounts_with_config(&program_id, make_config(POOL_DATA_LEN_T22)),
|
rpc.get_program_accounts_with_config(&program_id, make_config(POOL_DATA_LEN_CURRENT)),
|
||||||
|
rpc.get_program_accounts_with_config(&program_id, make_config(POOL_DATA_LEN_EXTENDED)),
|
||||||
);
|
);
|
||||||
let mut all = spl_result.unwrap_or_default();
|
let mut all = legacy_result.unwrap_or_default();
|
||||||
all.extend(t22_result.unwrap_or_default());
|
all.extend(current_result.unwrap_or_default());
|
||||||
|
all.extend(extended_result.unwrap_or_default());
|
||||||
Ok(all)
|
Ok(all)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,7 +801,7 @@ pub async fn find_by_base_mint(
|
|||||||
base_mint: &Pubkey,
|
base_mint: &Pubkey,
|
||||||
) -> Result<(Pubkey, Pool), anyhow::Error> {
|
) -> Result<(Pubkey, Pool), anyhow::Error> {
|
||||||
// base_mint offset: 8(discriminator) + 1(bump) + 2(index) + 32(creator) = 43
|
// base_mint offset: 8(discriminator) + 1(bump) + 2(index) + 32(creator) = 43
|
||||||
let accounts = get_program_accounts_both_sizes(rpc, 43, base_mint).await?;
|
let accounts = get_program_accounts_known_sizes(rpc, 43, base_mint).await?;
|
||||||
if accounts.is_empty() {
|
if accounts.is_empty() {
|
||||||
return Err(anyhow!("No pool found for mint {}", base_mint));
|
return Err(anyhow!("No pool found for mint {}", base_mint));
|
||||||
}
|
}
|
||||||
@@ -814,7 +818,7 @@ pub async fn find_by_quote_mint(
|
|||||||
quote_mint: &Pubkey,
|
quote_mint: &Pubkey,
|
||||||
) -> Result<(Pubkey, Pool), anyhow::Error> {
|
) -> Result<(Pubkey, Pool), anyhow::Error> {
|
||||||
// quote_mint offset: 8 + 1 + 2 + 32 + 32 = 75
|
// quote_mint offset: 8 + 1 + 2 + 32 + 32 = 75
|
||||||
let accounts = get_program_accounts_both_sizes(rpc, 75, quote_mint).await?;
|
let accounts = get_program_accounts_known_sizes(rpc, 75, quote_mint).await?;
|
||||||
if accounts.is_empty() {
|
if accounts.is_empty() {
|
||||||
return Err(anyhow!("No pool found for mint {}", quote_mint));
|
return Err(anyhow!("No pool found for mint {}", quote_mint));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,121 @@ pub struct Pool {
|
|||||||
pub is_mayhem_mode: bool,
|
pub is_mayhem_mode: bool,
|
||||||
/// Whether this pool's coin has cashback enabled
|
/// Whether this pool's coin has cashback enabled
|
||||||
pub is_cashback_coin: bool,
|
pub is_cashback_coin: bool,
|
||||||
/// Reserved for future fields (pump-public-docs: pool structure = 244 bytes total)
|
/// Virtual quote reserves appended to the Pool account.
|
||||||
pub _reserved: [u8; 7],
|
///
|
||||||
|
/// Quotes must use `quote_vault_balance + virtual_quote_reserves`.
|
||||||
|
pub virtual_quote_reserves: i128,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borsh 解码用的 Pool 长度。链上池为 244 字节(pump-public-docs Breaking Change),与 POOL_SIZE 一致。
|
/// Minimum Borsh payload length for the current Pool layout, excluding the
|
||||||
pub const POOL_SIZE: usize = 244;
|
/// 8-byte Anchor account discriminator.
|
||||||
|
pub const POOL_SIZE: usize = 1 + 2 + 32 * 6 + 8 + 32 + 1 + 1 + 16;
|
||||||
|
const LEGACY_POOL_SIZE: usize = 1 + 2 + 32 * 6 + 8 + 32 + 1 + 1;
|
||||||
|
|
||||||
|
#[derive(BorshDeserialize)]
|
||||||
|
struct LegacyPool {
|
||||||
|
pool_bump: u8,
|
||||||
|
index: u16,
|
||||||
|
creator: Pubkey,
|
||||||
|
base_mint: Pubkey,
|
||||||
|
quote_mint: Pubkey,
|
||||||
|
lp_mint: Pubkey,
|
||||||
|
pool_base_token_account: Pubkey,
|
||||||
|
pool_quote_token_account: Pubkey,
|
||||||
|
lp_supply: u64,
|
||||||
|
coin_creator: Pubkey,
|
||||||
|
is_mayhem_mode: bool,
|
||||||
|
is_cashback_coin: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LegacyPool> for Pool {
|
||||||
|
fn from(pool: LegacyPool) -> Self {
|
||||||
|
Self {
|
||||||
|
pool_bump: pool.pool_bump,
|
||||||
|
index: pool.index,
|
||||||
|
creator: pool.creator,
|
||||||
|
base_mint: pool.base_mint,
|
||||||
|
quote_mint: pool.quote_mint,
|
||||||
|
lp_mint: pool.lp_mint,
|
||||||
|
pool_base_token_account: pool.pool_base_token_account,
|
||||||
|
pool_quote_token_account: pool.pool_quote_token_account,
|
||||||
|
lp_supply: pool.lp_supply,
|
||||||
|
coin_creator: pool.coin_creator,
|
||||||
|
is_mayhem_mode: pool.is_mayhem_mode,
|
||||||
|
is_cashback_coin: pool.is_cashback_coin,
|
||||||
|
virtual_quote_reserves: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pool_decode(data: &[u8]) -> Option<Pool> {
|
pub fn pool_decode(data: &[u8]) -> Option<Pool> {
|
||||||
if data.len() < POOL_SIZE {
|
if data.len() >= POOL_SIZE {
|
||||||
return None;
|
return borsh::from_slice::<Pool>(&data[..POOL_SIZE]).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.len() >= LEGACY_POOL_SIZE {
|
||||||
|
return borsh::from_slice::<LegacyPool>(&data[..LEGACY_POOL_SIZE]).ok().map(Into::into);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the quote reserves used by PumpSwap pricing.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the signed sum is negative or cannot fit in a `u64`.
|
||||||
|
#[inline]
|
||||||
|
pub fn effective_quote_reserves(
|
||||||
|
quote_vault_balance: u64,
|
||||||
|
virtual_quote_reserves: i128,
|
||||||
|
) -> Option<u64> {
|
||||||
|
i128::from(quote_vault_balance)
|
||||||
|
.checked_add(virtual_quote_reserves)
|
||||||
|
.and_then(|reserves| u64::try_from(reserves).ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn pool_payload(virtual_quote_reserves: i128) -> Vec<u8> {
|
||||||
|
let mut data = Vec::with_capacity(POOL_SIZE);
|
||||||
|
data.push(7);
|
||||||
|
data.extend_from_slice(&42u16.to_le_bytes());
|
||||||
|
for seed in 1..=6 {
|
||||||
|
data.extend_from_slice(Pubkey::new_from_array([seed; 32]).as_ref());
|
||||||
|
}
|
||||||
|
data.extend_from_slice(&123_456u64.to_le_bytes());
|
||||||
|
data.extend_from_slice(Pubkey::new_from_array([7; 32]).as_ref());
|
||||||
|
data.push(1);
|
||||||
|
data.push(0);
|
||||||
|
data.extend_from_slice(&virtual_quote_reserves.to_le_bytes());
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decodes_current_pool_virtual_quote_reserves() {
|
||||||
|
let pool = pool_decode(&pool_payload(987_654_321)).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(pool.virtual_quote_reserves, 987_654_321);
|
||||||
|
assert!(pool.is_mayhem_mode);
|
||||||
|
assert!(!pool.is_cashback_coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decodes_legacy_pool_with_zero_virtual_quote_reserves() {
|
||||||
|
let mut data = pool_payload(0);
|
||||||
|
data.truncate(LEGACY_POOL_SIZE);
|
||||||
|
data.extend_from_slice(&[0; 7]);
|
||||||
|
|
||||||
|
let pool = pool_decode(&data).unwrap();
|
||||||
|
assert_eq!(pool.virtual_quote_reserves, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn effective_reserves_support_signed_virtual_amounts_and_reject_invalid_sums() {
|
||||||
|
assert_eq!(effective_quote_reserves(1_000, 250), Some(1_250));
|
||||||
|
assert_eq!(effective_quote_reserves(1_000, -250), Some(750));
|
||||||
|
assert_eq!(effective_quote_reserves(100, -101), None);
|
||||||
|
assert_eq!(effective_quote_reserves(u64::MAX, 1), None);
|
||||||
}
|
}
|
||||||
borsh::from_slice::<Pool>(&data[..POOL_SIZE]).ok()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ pub struct PumpSwapParams {
|
|||||||
pub pool_quote_token_account: Pubkey,
|
pub pool_quote_token_account: Pubkey,
|
||||||
/// Base token reserves in the pool
|
/// Base token reserves in the pool
|
||||||
pub pool_base_token_reserves: u64,
|
pub pool_base_token_reserves: u64,
|
||||||
/// Quote token reserves in the pool
|
/// Raw quote-vault token balance. Pricing uses this plus [`Self::virtual_quote_reserves`].
|
||||||
pub pool_quote_token_reserves: u64,
|
pub pool_quote_token_reserves: u64,
|
||||||
|
/// Signed virtual quote reserves from the PumpSwap Pool account or trade event.
|
||||||
|
pub virtual_quote_reserves: i128,
|
||||||
/// Coin creator vault ATA
|
/// Coin creator vault ATA
|
||||||
pub coin_creator_vault_ata: Pubkey,
|
pub coin_creator_vault_ata: Pubkey,
|
||||||
/// Coin creator vault authority
|
/// Coin creator vault authority
|
||||||
@@ -75,6 +77,7 @@ impl PumpSwapParams {
|
|||||||
pool_quote_token_account: Pubkey,
|
pool_quote_token_account: Pubkey,
|
||||||
pool_base_token_reserves: u64,
|
pool_base_token_reserves: u64,
|
||||||
pool_quote_token_reserves: u64,
|
pool_quote_token_reserves: u64,
|
||||||
|
virtual_quote_reserves: i128,
|
||||||
coin_creator_vault_ata: Pubkey,
|
coin_creator_vault_ata: Pubkey,
|
||||||
coin_creator_vault_authority: Pubkey,
|
coin_creator_vault_authority: Pubkey,
|
||||||
base_token_program: Pubkey,
|
base_token_program: Pubkey,
|
||||||
@@ -99,6 +102,7 @@ impl PumpSwapParams {
|
|||||||
pool_quote_token_account,
|
pool_quote_token_account,
|
||||||
pool_base_token_reserves,
|
pool_base_token_reserves,
|
||||||
pool_quote_token_reserves,
|
pool_quote_token_reserves,
|
||||||
|
virtual_quote_reserves,
|
||||||
coin_creator_vault_ata,
|
coin_creator_vault_ata,
|
||||||
coin_creator_vault_authority,
|
coin_creator_vault_authority,
|
||||||
base_token_program,
|
base_token_program,
|
||||||
@@ -127,6 +131,21 @@ impl PumpSwapParams {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Quote reserves used by PumpSwap pricing and fee-tier selection.
|
||||||
|
pub fn effective_quote_reserves(&self) -> Result<u64, anyhow::Error> {
|
||||||
|
crate::instruction::utils::pumpswap_types::effective_quote_reserves(
|
||||||
|
self.pool_quote_token_reserves,
|
||||||
|
self.virtual_quote_reserves,
|
||||||
|
)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"Invalid PumpSwap effective quote reserves: vault={} virtual={}",
|
||||||
|
self.pool_quote_token_reserves,
|
||||||
|
self.virtual_quote_reserves
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_fee_basis_points(
|
pub fn with_fee_basis_points(
|
||||||
mut self,
|
mut self,
|
||||||
lp_fee_basis_points: u64,
|
lp_fee_basis_points: u64,
|
||||||
@@ -161,6 +180,7 @@ impl PumpSwapParams {
|
|||||||
pool_quote_token_account: Pubkey,
|
pool_quote_token_account: Pubkey,
|
||||||
pool_base_token_reserves: u64,
|
pool_base_token_reserves: u64,
|
||||||
pool_quote_token_reserves: u64,
|
pool_quote_token_reserves: u64,
|
||||||
|
virtual_quote_reserves: i128,
|
||||||
coin_creator_vault_ata: Pubkey,
|
coin_creator_vault_ata: Pubkey,
|
||||||
coin_creator_vault_authority: Pubkey,
|
coin_creator_vault_authority: Pubkey,
|
||||||
base_token_program: Pubkey,
|
base_token_program: Pubkey,
|
||||||
@@ -178,6 +198,7 @@ impl PumpSwapParams {
|
|||||||
pool_quote_token_account,
|
pool_quote_token_account,
|
||||||
pool_base_token_reserves,
|
pool_base_token_reserves,
|
||||||
pool_quote_token_reserves,
|
pool_quote_token_reserves,
|
||||||
|
virtual_quote_reserves,
|
||||||
coin_creator_vault_ata,
|
coin_creator_vault_ata,
|
||||||
coin_creator_vault_authority,
|
coin_creator_vault_authority,
|
||||||
base_token_program,
|
base_token_program,
|
||||||
@@ -202,6 +223,7 @@ impl PumpSwapParams {
|
|||||||
pool_quote_token_account: Pubkey,
|
pool_quote_token_account: Pubkey,
|
||||||
pool_base_token_reserves: u64,
|
pool_base_token_reserves: u64,
|
||||||
pool_quote_token_reserves: u64,
|
pool_quote_token_reserves: u64,
|
||||||
|
virtual_quote_reserves: i128,
|
||||||
coin_creator_vault_ata: Pubkey,
|
coin_creator_vault_ata: Pubkey,
|
||||||
coin_creator_vault_authority: Pubkey,
|
coin_creator_vault_authority: Pubkey,
|
||||||
base_token_program: Pubkey,
|
base_token_program: Pubkey,
|
||||||
@@ -223,6 +245,7 @@ impl PumpSwapParams {
|
|||||||
pool_quote_token_account,
|
pool_quote_token_account,
|
||||||
pool_base_token_reserves,
|
pool_base_token_reserves,
|
||||||
pool_quote_token_reserves,
|
pool_quote_token_reserves,
|
||||||
|
virtual_quote_reserves,
|
||||||
coin_creator_vault_ata,
|
coin_creator_vault_ata,
|
||||||
coin_creator_vault_authority,
|
coin_creator_vault_authority,
|
||||||
base_token_program,
|
base_token_program,
|
||||||
@@ -277,6 +300,18 @@ impl PumpSwapParams {
|
|||||||
) -> Result<Self, anyhow::Error> {
|
) -> Result<Self, anyhow::Error> {
|
||||||
let (pool_base_token_reserves, pool_quote_token_reserves) =
|
let (pool_base_token_reserves, pool_quote_token_reserves) =
|
||||||
crate::instruction::utils::pumpswap::get_token_balances(pool_data, rpc).await?;
|
crate::instruction::utils::pumpswap::get_token_balances(pool_data, rpc).await?;
|
||||||
|
let effective_quote_token_reserves =
|
||||||
|
crate::instruction::utils::pumpswap_types::effective_quote_reserves(
|
||||||
|
pool_quote_token_reserves,
|
||||||
|
pool_data.virtual_quote_reserves,
|
||||||
|
)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"Invalid PumpSwap effective quote reserves: vault={} virtual={}",
|
||||||
|
pool_quote_token_reserves,
|
||||||
|
pool_data.virtual_quote_reserves
|
||||||
|
)
|
||||||
|
})?;
|
||||||
let base_mint_supply = fetch_mint_supply(rpc, &pool_data.base_mint).await.ok();
|
let base_mint_supply = fetch_mint_supply(rpc, &pool_data.base_mint).await.ok();
|
||||||
let fee_config = crate::instruction::utils::pumpswap::fetch_fee_config(rpc).await;
|
let fee_config = crate::instruction::utils::pumpswap::fetch_fee_config(rpc).await;
|
||||||
let raw_fee_basis_points = crate::instruction::utils::pumpswap::compute_fee_basis_points(
|
let raw_fee_basis_points = crate::instruction::utils::pumpswap::compute_fee_basis_points(
|
||||||
@@ -285,7 +320,7 @@ impl PumpSwapParams {
|
|||||||
pool_data.base_mint,
|
pool_data.base_mint,
|
||||||
base_mint_supply,
|
base_mint_supply,
|
||||||
pool_base_token_reserves,
|
pool_base_token_reserves,
|
||||||
pool_quote_token_reserves,
|
effective_quote_token_reserves,
|
||||||
);
|
);
|
||||||
let creator_fee_basis_points = if pool_data.coin_creator == Pubkey::default() {
|
let creator_fee_basis_points = if pool_data.coin_creator == Pubkey::default() {
|
||||||
0
|
0
|
||||||
@@ -319,6 +354,7 @@ impl PumpSwapParams {
|
|||||||
pool_quote_token_account: pool_data.pool_quote_token_account,
|
pool_quote_token_account: pool_data.pool_quote_token_account,
|
||||||
pool_base_token_reserves,
|
pool_base_token_reserves,
|
||||||
pool_quote_token_reserves,
|
pool_quote_token_reserves,
|
||||||
|
virtual_quote_reserves: pool_data.virtual_quote_reserves,
|
||||||
coin_creator_vault_ata,
|
coin_creator_vault_ata,
|
||||||
coin_creator_vault_authority,
|
coin_creator_vault_authority,
|
||||||
base_token_program: if pool_data.pool_base_token_account == base_token_program_ata {
|
base_token_program: if pool_data.pool_base_token_account == base_token_program_ata {
|
||||||
|
|||||||
Reference in New Issue
Block a user