fix(sell): trust observed creator_vault directly to prevent Anchor 2006
In build_sell_v1/v2, the creator_vault was previously derived via
effective_creator_for_trade() passed to resolve_creator_vault_for_ix_with_fee_sharing.
When observed_trade_creator differs from bonding_curve.creator (e.g. creator
updated post-deployment), the derived vault PDA mismatches the on-chain
seeds constraint, causing Anchor error 2006 (ConstraintSeeds) on sell.
The pump.fun sell instruction validates creator_vault seeds as
PDA("creator-vault", bonding_curve.creator), but buy does not check seeds,
so buy succeeds while sell fails with 2006.
Fix: when protocol_params.creator_vault is a valid non-default/non-phantom
value (observed from gRPC / update_fee_shares), use it directly without
re-derivation. Only fall back to resolve via bonding_curve.creator when
creator_vault is missing. This ensures the authoritative observed vault
is never overridden by a stale or mismatched creator.
This commit is contained in:
+46
-24
@@ -226,6 +226,7 @@ fn build_sell_v1(params: &SwapParams) -> Result<Vec<Instruction>> {
|
||||
use crate::instruction::pumpfun_ix_data::encode_pumpfun_sell_ix_data;
|
||||
use crate::instruction::utils::pumpfun::{
|
||||
get_bonding_curve_v2_pda, get_protocol_extra_fee_recipient_random,
|
||||
is_phantom_default_creator_vault,
|
||||
};
|
||||
|
||||
let protocol_params = params
|
||||
@@ -246,19 +247,29 @@ fn build_sell_v1(params: &SwapParams) -> Result<Vec<Instruction>> {
|
||||
let slippage_bp = params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE);
|
||||
|
||||
let bonding_curve = &protocol_params.bonding_curve;
|
||||
let creator = protocol_params.effective_creator_for_trade();
|
||||
let creator_vault_account = resolve_creator_vault_for_ix_with_fee_sharing(
|
||||
&creator,
|
||||
protocol_params.creator_vault,
|
||||
¶ms.input_mint,
|
||||
protocol_params.fee_sharing_creator_vault_if_active,
|
||||
)
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"creator_vault PDA derivation failed (creator={})",
|
||||
creator
|
||||
|
||||
// 卖出时:优先信任观测到的 creator_vault(来自 gRPC / pump fee 事件)。
|
||||
// 不要通过 effective_creator 推导覆盖,避免 creator 被修改后推导出错 → Anchor 2006。
|
||||
let creator_vault_account = if protocol_params.creator_vault != Pubkey::default()
|
||||
&& !is_phantom_default_creator_vault(&protocol_params.creator_vault)
|
||||
{
|
||||
protocol_params.creator_vault
|
||||
} else {
|
||||
resolve_creator_vault_for_ix_with_fee_sharing(
|
||||
&bonding_curve.creator,
|
||||
protocol_params.creator_vault,
|
||||
¶ms.input_mint,
|
||||
protocol_params.fee_sharing_creator_vault_if_active,
|
||||
)
|
||||
})?;
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"creator_vault PDA derivation failed (curve_creator={})",
|
||||
bonding_curve.creator
|
||||
)
|
||||
})?
|
||||
};
|
||||
|
||||
let creator = protocol_params.effective_creator_for_trade();
|
||||
|
||||
let sol_amount = get_sell_sol_amount_from_token_amount(
|
||||
bonding_curve.virtual_token_reserves as u128,
|
||||
@@ -569,6 +580,7 @@ fn build_sell_v2(params: &SwapParams) -> Result<Vec<Instruction>> {
|
||||
use crate::instruction::pumpfun_ix_data::encode_pumpfun_sell_v2_ix_data;
|
||||
use crate::instruction::utils::pumpfun::{
|
||||
get_buyback_fee_recipient_random, get_fee_sharing_config_pda,
|
||||
is_phantom_default_creator_vault,
|
||||
};
|
||||
|
||||
let protocol_params = params
|
||||
@@ -589,19 +601,29 @@ fn build_sell_v2(params: &SwapParams) -> Result<Vec<Instruction>> {
|
||||
let slippage_bp = params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE);
|
||||
|
||||
let bonding_curve = &protocol_params.bonding_curve;
|
||||
let creator = protocol_params.effective_creator_for_trade();
|
||||
let creator_vault_account = resolve_creator_vault_for_ix_with_fee_sharing(
|
||||
&creator,
|
||||
protocol_params.creator_vault,
|
||||
¶ms.input_mint,
|
||||
protocol_params.fee_sharing_creator_vault_if_active,
|
||||
)
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"creator_vault PDA derivation failed (creator={})",
|
||||
creator
|
||||
|
||||
// 卖出时:优先信任观测到的 creator_vault(来自 gRPC / pump fee 事件)。
|
||||
// 不要通过 effective_creator 推导覆盖,避免 creator 被修改后推导出错 → Anchor 2006。
|
||||
let creator_vault_account = if protocol_params.creator_vault != Pubkey::default()
|
||||
&& !is_phantom_default_creator_vault(&protocol_params.creator_vault)
|
||||
{
|
||||
protocol_params.creator_vault
|
||||
} else {
|
||||
resolve_creator_vault_for_ix_with_fee_sharing(
|
||||
&bonding_curve.creator,
|
||||
protocol_params.creator_vault,
|
||||
¶ms.input_mint,
|
||||
protocol_params.fee_sharing_creator_vault_if_active,
|
||||
)
|
||||
})?;
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"creator_vault PDA derivation failed (curve_creator={})",
|
||||
bonding_curve.creator
|
||||
)
|
||||
})?
|
||||
};
|
||||
|
||||
let creator = protocol_params.effective_creator_for_trade();
|
||||
|
||||
let sol_amount = get_sell_sol_amount_from_token_amount(
|
||||
bonding_curve.virtual_token_reserves as u128,
|
||||
|
||||
Reference in New Issue
Block a user