Merge pull request #100 from 0xfnzero/feat/pump-fee-recipient-upgrade
feat(pump): add protocol fee recipient accounts for PumpFun and PumpSwap
This commit is contained in:
@@ -9,8 +9,8 @@ use crate::{
|
||||
use crate::{
|
||||
instruction::utils::pumpfun::{
|
||||
accounts, get_bonding_curve_pda, get_bonding_curve_v2_pda,
|
||||
get_user_volume_accumulator_pda, pump_fun_fee_recipient_meta,
|
||||
resolve_creator_vault_for_ix,
|
||||
get_protocol_extra_fee_recipient_random, get_user_volume_accumulator_pda,
|
||||
pump_fun_fee_recipient_meta, resolve_creator_vault_for_ix,
|
||||
global_constants::{self},
|
||||
BUY_DISCRIMINATOR, BUY_EXACT_SOL_IN_DISCRIMINATOR, SELL_DISCRIMINATOR,
|
||||
},
|
||||
@@ -177,6 +177,8 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
|
||||
accounts::FEE_PROGRAM_META,
|
||||
];
|
||||
accounts.push(AccountMeta::new_readonly(bonding_curve_v2, false)); // remainingAccounts: @pump-fun/pump-sdk 要求末尾传 bondingCurveV2Pda(mint),勿删
|
||||
// Apr 2026: extra protocol fee recipient after bonding-curve-v2 (writable)
|
||||
accounts.push(AccountMeta::new(get_protocol_extra_fee_recipient_random(), false));
|
||||
|
||||
instructions.push(Instruction::new_with_bytes(accounts::PUMPFUN, &buy_data, accounts));
|
||||
|
||||
@@ -304,6 +306,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
|
||||
anyhow!("bonding_curve_v2 PDA derivation failed for mint {}", params.input_mint)
|
||||
})?;
|
||||
accounts.push(AccountMeta::new_readonly(bonding_curve_v2, false));
|
||||
accounts.push(AccountMeta::new(get_protocol_extra_fee_recipient_random(), false));
|
||||
|
||||
instructions.push(Instruction::new_with_bytes(accounts::PUMPFUN, &sell_data, accounts));
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ use crate::{
|
||||
constants::trade::trade::DEFAULT_SLIPPAGE,
|
||||
instruction::utils::pumpswap::{
|
||||
accounts, fee_recipient_ata, get_mayhem_fee_recipient_random, get_pool_v2_pda,
|
||||
get_user_volume_accumulator_pda, get_user_volume_accumulator_quote_ata,
|
||||
get_user_volume_accumulator_wsol_ata, BUY_DISCRIMINATOR, BUY_EXACT_QUOTE_IN_DISCRIMINATOR,
|
||||
SELL_DISCRIMINATOR,
|
||||
get_protocol_extra_fee_recipient_random, get_user_volume_accumulator_pda,
|
||||
get_user_volume_accumulator_quote_ata, get_user_volume_accumulator_wsol_ata,
|
||||
BUY_DISCRIMINATOR, BUY_EXACT_QUOTE_IN_DISCRIMINATOR, SELL_DISCRIMINATOR,
|
||||
},
|
||||
trading::{
|
||||
common::wsol_manager,
|
||||
@@ -166,7 +166,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
||||
}
|
||||
|
||||
// Create buy instruction
|
||||
let mut accounts = Vec::with_capacity(23);
|
||||
let mut accounts = Vec::with_capacity(28);
|
||||
accounts.extend([
|
||||
AccountMeta::new(pool, false), // pool_id
|
||||
AccountMeta::new(params.payer.pubkey(), true), // user (signer)
|
||||
@@ -206,6 +206,13 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
||||
let pool_v2 = get_pool_v2_pda(&base_mint)
|
||||
.ok_or_else(|| anyhow!("pool_v2 PDA derivation failed for base_mint {}", base_mint))?;
|
||||
accounts.push(AccountMeta::new_readonly(pool_v2, false));
|
||||
// Apr 2026: protocol fee recipient + quote ATA (after pool-v2)
|
||||
let protocol_extra = get_protocol_extra_fee_recipient_random();
|
||||
accounts.push(AccountMeta::new_readonly(protocol_extra, false));
|
||||
accounts.push(AccountMeta::new(
|
||||
crate::instruction::utils::pumpswap::fee_recipient_ata(protocol_extra, quote_mint),
|
||||
false,
|
||||
));
|
||||
|
||||
// Create instruction data(buy/buy_exact_quote_in 第三参数 track_volume: OptionBool,仅代币支持返现时传 Some(true);sell 仅两参数)
|
||||
let track_volume = if protocol_params.is_cashback_coin { [1u8, 1u8] } else { [1u8, 0u8] }; // Some(true) / Some(false)
|
||||
@@ -359,7 +366,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
||||
}
|
||||
|
||||
// Create sell instruction
|
||||
let mut accounts = Vec::with_capacity(23);
|
||||
let mut accounts = Vec::with_capacity(28);
|
||||
accounts.extend([
|
||||
AccountMeta::new(pool, false), // pool_id
|
||||
AccountMeta::new(params.payer.pubkey(), true), // user (signer)
|
||||
@@ -407,6 +414,12 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
||||
let pool_v2 = get_pool_v2_pda(&base_mint)
|
||||
.ok_or_else(|| anyhow!("pool_v2 PDA derivation failed for base_mint {}", base_mint))?;
|
||||
accounts.push(AccountMeta::new_readonly(pool_v2, false));
|
||||
let protocol_extra = get_protocol_extra_fee_recipient_random();
|
||||
accounts.push(AccountMeta::new_readonly(protocol_extra, false));
|
||||
accounts.push(AccountMeta::new(
|
||||
crate::instruction::utils::pumpswap::fee_recipient_ata(protocol_extra, quote_mint),
|
||||
false,
|
||||
));
|
||||
|
||||
// Create instruction data
|
||||
let mut data = [0u8; 24];
|
||||
|
||||
@@ -136,6 +136,19 @@ pub mod global_constants {
|
||||
pub const PUMPFUN_AMM_FEE_6: Pubkey = pubkey!("FWsW1xNtWscwNmKv6wVsU1iTzRN6wmmk3MjxRP5tT7hz"); // Pump.fun AMM: Protocol Fee 6
|
||||
pub const PUMPFUN_AMM_FEE_7: Pubkey = pubkey!("G5UZAVbAf46s7cKWoyKu8kYTip9DGTpbLZ2qa9Aq69dP");
|
||||
// Pump.fun AMM: Protocol Fee 7
|
||||
|
||||
/// Protocol extra fee recipients (Apr 2026 breaking upgrade). One is appended after `bonding-curve-v2`, **writable**.
|
||||
/// See: <https://github.com/pump-fun/pump-public-docs/blob/main/docs/BREAKING_FEE_RECIPIENT.md>
|
||||
pub const PROTOCOL_EXTRA_FEE_RECIPIENTS: [Pubkey; 8] = [
|
||||
pubkey!("5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD"),
|
||||
pubkey!("9M4giFFMxmFGXtc3feFzRai56WbBqehoSeRE5GK7gf7"),
|
||||
pubkey!("GXPFM2caqTtQYC2cJ5yJRi9VDkpsYZXzYdwYpGnLmtDL"),
|
||||
pubkey!("3BpXnfJaUTiwXnJNe7Ej1rcbzqTTQUvLShZaWazebsVR"),
|
||||
pubkey!("5cjcW9wExnJJiqgLjq7DEG75Pm6JBgE1hNv4B2vHXUW6"),
|
||||
pubkey!("EHAAiTxcdDwQ3U4bU6YcMsQGaekdzLS3B5SmYo46kJtL"),
|
||||
pubkey!("5eHhjP8JaYkz83CWwvGU2uMUXefd3AazWGx4gpcuEEYD"),
|
||||
pubkey!("A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"),
|
||||
];
|
||||
}
|
||||
|
||||
/// Constants related to program accounts and authorities
|
||||
@@ -258,6 +271,14 @@ pub fn get_standard_fee_recipient_meta_random() -> AccountMeta {
|
||||
}
|
||||
}
|
||||
|
||||
/// Random entry from [`global_constants::PROTOCOL_EXTRA_FEE_RECIPIENTS`] (must be last account after bonding-curve-v2, writable).
|
||||
#[inline]
|
||||
pub fn get_protocol_extra_fee_recipient_random() -> Pubkey {
|
||||
*global_constants::PROTOCOL_EXTRA_FEE_RECIPIENTS
|
||||
.choose(&mut rand::rng())
|
||||
.unwrap_or(&global_constants::PROTOCOL_EXTRA_FEE_RECIPIENTS[0])
|
||||
}
|
||||
|
||||
/// 账户 #2 fee recipient:优先使用 gRPC/ShredStream 解析值(同笔 create_v2+buy 的 `observed_fee_recipient` 或 `tradeEvent.feeRecipient`);未提供时按 mayhem 从静态池随机。
|
||||
#[inline]
|
||||
pub fn pump_fun_fee_recipient_meta(from_stream: Pubkey, is_mayhem_mode: bool) -> AccountMeta {
|
||||
|
||||
@@ -91,6 +91,18 @@ pub mod accounts {
|
||||
/// Default Mayhem fee recipient (first of MAYHEM_FEE_RECIPIENTS)
|
||||
pub const MAYHEM_FEE_RECIPIENT: Pubkey = MAYHEM_FEE_RECIPIENTS[0];
|
||||
|
||||
/// Protocol extra fee recipients (Apr 2026 breaking upgrade). After `pool-v2`: recipient (readonly), then quote ATA (writable).
|
||||
pub const PROTOCOL_EXTRA_FEE_RECIPIENTS: [Pubkey; 8] = [
|
||||
pubkey!("5YxQFdt3Tr9zJLvkFccqXVUwhdTWJQc1fFg2YPbxvxeD"),
|
||||
pubkey!("9M4giFFMxmFGXtc3feFzRai56WbBqehoSeRE5GK7gf7"),
|
||||
pubkey!("GXPFM2caqTtQYC2cJ5yJRi9VDkpsYZXzYdwYpGnLmtDL"),
|
||||
pubkey!("3BpXnfJaUTiwXnJNe7Ej1rcbzqTTQUvLShZaWazebsVR"),
|
||||
pubkey!("5cjcW9wExnJJiqgLjq7DEG75Pm6JBgE1hNv4B2vHXUW6"),
|
||||
pubkey!("EHAAiTxcdDwQ3U4bU6YcMsQGaekdzLS3B5SmYo46kJtL"),
|
||||
pubkey!("5eHhjP8JaYkz83CWwvGU2uMUXefd3AazWGx4gpcuEEYD"),
|
||||
pubkey!("A7hAgCzFw14fejgCp387JUJRMNyz4j89JKnhtKU8piqW"),
|
||||
];
|
||||
|
||||
// META
|
||||
|
||||
pub const GLOBAL_ACCOUNT_META: solana_sdk::instruction::AccountMeta =
|
||||
@@ -171,6 +183,14 @@ pub fn get_mayhem_fee_recipient_random() -> (Pubkey, AccountMeta) {
|
||||
(recipient, meta)
|
||||
}
|
||||
|
||||
/// Random entry from [`accounts::PROTOCOL_EXTRA_FEE_RECIPIENTS`] (readonly; paired with [`fee_recipient_ata`] as last account).
|
||||
#[inline]
|
||||
pub fn get_protocol_extra_fee_recipient_random() -> Pubkey {
|
||||
*accounts::PROTOCOL_EXTRA_FEE_RECIPIENTS
|
||||
.choose(&mut rand::rng())
|
||||
.unwrap_or(&accounts::PROTOCOL_EXTRA_FEE_RECIPIENTS[0])
|
||||
}
|
||||
|
||||
/// Pool v2 PDA (seeds: ["pool-v2", base_mint]). Required at end of buy/sell/buy_exact_quote_in accounts.
|
||||
#[inline]
|
||||
pub fn get_pool_v2_pda(base_mint: &Pubkey) -> Option<Pubkey> {
|
||||
|
||||
Reference in New Issue
Block a user