docs: creator_vault/coin_creator from events; CODE_REVIEW three-repo check

Made-with: Cursor
This commit is contained in:
Wood
2026-03-07 11:45:33 +08:00
parent 30c91a74af
commit e32e7ee6ab
4 changed files with 86 additions and 2 deletions
+18
View File
@@ -321,6 +321,24 @@ PumpFun and PumpSwap support **cashback** for eligible tokens: part of the tradi
- The **pumpfun_copy_trading** and **pumpfun_sniper_trading** examples use sol-parser-sdk for gRPC subscription and pass `e.is_cashback_coin` when building params.
- **Claim**: Use `client.claim_cashback_pumpfun()` and `client.claim_cashback_pumpswap(...)` to claim accumulated cashback.
#### PumpFun: Creator Rewards Sharing (creator_vault)
Some PumpFun coins use **Creator Rewards Sharing**, so the on-chain `creator_vault` can differ from the default derivation. If you reuse cached params from a **buy** when **selling**, you may see program error **2006 (seeds constraint violated)**. To avoid this:
- **From gRPC/events (no RPC needed)**: You can get both `creator` and `creator_vault` from parsed transaction events:
- **sol-parser-sdk**: Before pushing events, the pipeline calls `fill_trade_accounts`, which fills `creator_vault` from the buy/sell instruction accounts (buy index 9, sell index 8). `creator` comes from the TradeEvent log. Use `PumpFunParams::from_trade(..., e.creator, e.creator_vault, ...)` or `from_dev_trade(..., e.creator, e.creator_vault, ...)` with the event `e`.
- **solana-streamer**: Instruction parsers set `creator_vault` from accounts[9] (buy) or accounts[8] (sell); `creator` comes from the merged CPI TradeEvent log. Use the same `from_trade` / `from_dev_trade` with `e.creator` and `e.creator_vault`.
- **Override after RPC**: If you get params via `PumpFunParams::from_mint_by_rpc` but later receive a newer `creator_vault` from gRPC, call `.with_creator_vault(latest_creator_vault)` on the params before selling.
The SDK does not fetch creator_vault from RPC on every sell (to avoid latency); pass the up-to-date vault from gRPC/events when available.
#### PumpSwap: coin_creator_vault from events (no RPC)
For **PumpSwap** (Pump AMM), `coin_creator_vault_ata` and `coin_creator_vault_authority` are required in buy/sell instructions. Both are available from parsed events without RPC:
- **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 events `coin_creator_vault_ata` and `coin_creator_vault_authority`.
## 🛡️ MEV Protection Services
You can apply for a key through the official website: [Community Website](https://fnzero.dev/swqos)
+18
View File
@@ -320,6 +320,24 @@ PumpFun 与 PumpSwap 支持**返现(Cashback**:部分手续费可返还
- **pumpfun_copy_trading**、**pumpfun_sniper_trading** 示例使用 sol-parser-sdk 订阅 gRPC 事件,并在构造参数时传入 `e.is_cashback_coin`
- **领取返现**:使用 `client.claim_cashback_pumpfun()``client.claim_cashback_pumpswap(...)` 领取累计的返现。
#### PumpFunCreator Rewards Sharingcreator_vault
部分 PumpFun 代币启用了 **Creator Rewards Sharing**,链上 `creator_vault` 可能与默认推导结果不同。若在**卖出**时复用**买入**时缓存的 params,可能触发程序错误 **2006seeds constraint violated**。建议:
- **来自 gRPC/事件(无需 RPC**`creator``creator_vault` 均可从解析后的事件中直接拿到:
- **sol-parser-sdk**:推送前会调用 `fill_trade_accounts`,从 buy/sell 指令账户补全 `creator_vault`buy 索引 9sell 索引 8);`creator` 来自 TradeEvent 日志。用 `PumpFunParams::from_trade(..., e.creator, e.creator_vault, ...)``from_dev_trade(..., e.creator, e.creator_vault, ...)` 即可。
- **solana-streamer**:指令解析时从 accounts[9]buy/ accounts[8]sell)写入 `creator_vault``creator` 来自合并后的 CPI TradeEvent 日志。同样用事件的 `e.creator``e.creator_vault` 调用 `from_trade` / `from_dev_trade`
- **RPC 后覆盖**:若通过 `PumpFunParams::from_mint_by_rpc` 得到 params,之后又从 gRPC 拿到更新的 `creator_vault`,在卖出前对 params 调用 `.with_creator_vault(latest_creator_vault)`
SDK 不会在每次卖出时通过 RPC 拉取 creator_vault(以避免延迟);请从 gRPC/事件中传入最新 vault。
#### PumpSwap:从事件拿 coin_creator_vault(无需 RPC
**PumpSwap**Pump AMM)的 buy/sell 指令需要 `coin_creator_vault_ata``coin_creator_vault_authority`,二者均可从解析事件中拿到,无需 RPC:
- **sol-parser-sdk**:指令解析从账户 17、18 写入;若事件来自日志,账户填充器也会从指令补全。用 `PumpSwapParams::from_trade(..., e.coin_creator_vault_ata, e.coin_creator_vault_authority, ...)` 即可。
- **solana-streamer**:指令解析从 `accounts.get(17)``accounts.get(18)` 写入。同样用事件的 `coin_creator_vault_ata``coin_creator_vault_authority` 调用 `from_trade`
## 🛡️ MEV 保护服务
可以通过官网申请密钥:[社区官网](https://fnzero.dev/swqos)
+34 -1
View File
@@ -111,7 +111,40 @@
---
## 7. 汇总:必须改 vs 建议改
## 7. 三库联动与超低延迟检查(sol-trade-sdk / sol-parser-sdk / solana-streamer
### 7.1 逻辑一致性(已确认)
| 检查项 | sol-parser-sdk | solana-streamer | 说明 |
|--------|----------------|-----------------|------|
| Pump buy 账户数 | 16fill 用 get(9) 填 creator_vault | 16accounts[9]=creator_vault | 与 idl/pumpfun.json 一致 |
| Pump sell 账户数 | 14get(8)=creator_vault | 14accounts[8]=creator_vault | 一致 |
| PumpSwap buy 17/18 | 指令解析 + fill_buy_accounts get(17)/get(18) | 指令解析 accounts.get(17)/get(18) | coin_creator_vault_ata/authority 正确 |
| PumpSwap sell 17/18 | fill_sell_accounts 同左 | 同左 | 一致 |
| 填充顺序 | 先 parselog 或 instruction)→ fill_accounts → push | 指令解析直接写 17/18;无单独 fill 步骤 | 两者均保证事件带齐 creator_vault / coin_creator_vault |
| find_instruction_invoke | 选「账户数最多」的 invoke,保证取到 outer buy/sell | N/A(按当前 instruction 解析) | 正确 |
### 7.2 版本化交易账户解析
- **sol-parser-sdk**`get_instruction_account_getter` 正确支持 versioned tx:先 `account_keys`,再 `loaded_writable_addresses`,再 `loaded_readonly_addresses`,与 Solana 约定一致。
- **solana-streamer**:指令的 `accounts` 为索引,通过 `accounts.get(idx as usize).copied()` 从完整 `accounts: &[Pubkey]` 解析;调用方需传入已包含 loaded 的完整账户列表,否则高索引会得到 `default()`
### 7.3 超低延迟相关
| 项目 | 状态 / 建议 |
|------|-------------|
| solana-streamer 热路径 | 已改为**顺序执行** inner 解析与 swap_data 提取,去掉 `thread::scope` + 双 spawn/join,减少 μs 级开销。 |
| sol-parser-sdk | log 与 instruction 并行(rayon::join);fill 仅在有 invoke 时做;`find_instruction_invoke` 为 O(invokes),单程序单 tx 下可接受。 |
| sol-trade-sdk | 见上文第 4 节;PumpSwap instruction 构建避免 `accounts.clone()` 已列为必须改。 |
### 7.4 建议
- **solana-streamer**:若 gRPC 上游已提供完整 `accounts`(含 loaded),可避免对每笔 tx 做 `accounts.to_vec()`,仅在需要 resize 时克隆,进一步降低分配。
- **三库**:保持 IDL 与账户索引注释同步(pumpfun.json / pump_amm.json),避免后续扩展时索引错位。
---
## 8. 汇总:必须改 vs 建议改
### 必须改(优先处理)
+16 -1
View File
@@ -89,11 +89,18 @@ impl std::fmt::Debug for SwapParams {
}
/// PumpFun protocol specific parameters
/// Configuration parameters specific to PumpFun trading protocol
/// Configuration parameters specific to PumpFun trading protocol.
///
/// **Creator Rewards Sharing**: Some coins use a dynamic `creator_vault` (fee-sharing config).
/// Always use the latest on-chain creator/vault when building params for **sell**; do not reuse
/// cached params from buy. Either fetch fresh data via RPC, or pass `creator_vault` from gRPC
/// using [`from_trade`](PumpFunParams::from_trade) / [`from_dev_trade`](PumpFunParams::from_dev_trade),
/// or override with [`with_creator_vault`](PumpFunParams::with_creator_vault).
#[derive(Clone)]
pub struct PumpFunParams {
pub bonding_curve: Arc<BondingCurveAccount>,
pub associated_bonding_curve: Pubkey,
/// Creator vault PDA. For Creator Rewards Sharing coins this can change; pass latest from gRPC when selling.
pub creator_vault: Pubkey,
pub token_program: Pubkey,
/// Whether to close token account when selling, only effective during sell operations
@@ -222,6 +229,14 @@ impl PumpFunParams {
token_program: mint_account.owner,
})
}
/// Override `creator_vault` with a value from gRPC/event (e.g. for Creator Rewards Sharing).
/// Use when selling so the instruction uses the latest on-chain vault and avoids "seeds constraint violated" (2006).
#[inline]
pub fn with_creator_vault(mut self, creator_vault: Pubkey) -> Self {
self.creator_vault = creator_vault;
self
}
}
/// PumpSwap Protocol Specific Parameters