fix(pumpfun): resolve creator_vault with fee-sharing PDA (mint-aware)

- Add get_fee_sharing_config_pda per @pump-fun/pump-sdk (sharing-config + mint under pump-fees)
- resolve_creator_vault_for_ix now takes mint: accept gRPC creator_vault when it matches either
  PDA(creator) or PDA(fee_sharing_config(mint)) for migrated / fee-sharing bonding curves
- Mayhem uses the same Pump buy/sell account layout (IDL); Token-2022 + fee pool differ, not creator_vault seeds

Made-with: Cursor
This commit is contained in:
0xfnzero
2026-04-11 19:44:54 +08:00
parent 4dec087ea6
commit b13b4fda0a
3 changed files with 65 additions and 23 deletions
+22 -14
View File
@@ -46,13 +46,17 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
// creator_vault must be PDA(creator) per bonding curve. Event vault: use only if == derived;
// if stream sends a mismatched vault (wrong token / stale), fall back to derived.
let creator = bonding_curve.creator;
let creator_vault_pda = resolve_creator_vault_for_ix(&creator, protocol_params.creator_vault)
.ok_or_else(|| {
anyhow!(
"creator_vault PDA derivation failed (creator={})",
creator
)
})?;
let creator_vault_pda = resolve_creator_vault_for_ix(
&creator,
protocol_params.creator_vault,
&params.output_mint,
)
.ok_or_else(|| {
anyhow!(
"creator_vault PDA derivation failed (creator={})",
creator
)
})?;
// ========================================
// Trade calculation and account address preparation
@@ -206,13 +210,17 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
let bonding_curve = &protocol_params.bonding_curve;
let creator = bonding_curve.creator;
let creator_vault_pda = resolve_creator_vault_for_ix(&creator, protocol_params.creator_vault)
.ok_or_else(|| {
anyhow!(
"creator_vault PDA derivation failed (creator={})",
creator
)
})?;
let creator_vault_pda = resolve_creator_vault_for_ix(
&creator,
protocol_params.creator_vault,
&params.input_mint,
)
.ok_or_else(|| {
anyhow!(
"creator_vault PDA derivation failed (creator={})",
creator
)
})?;
// ========================================
// Trade calculation and account address preparation
+41 -9
View File
@@ -55,6 +55,9 @@ pub mod seeds {
pub const GLOBAL_VOLUME_ACCUMULATOR_SEED: &[u8] = b"global_volume_accumulator";
pub const FEE_CONFIG_SEED: &[u8] = b"fee_config";
/// `feeSharingConfig` PDA under pump-fees (`@pump-fun/pump-sdk` `feeSharingConfigPda`)
pub const SHARING_CONFIG_SEED: &[u8] = b"sharing-config";
}
pub mod global_constants {
@@ -342,18 +345,39 @@ pub fn get_creator_vault_pda(creator: &Pubkey) -> Option<Pubkey> {
)
}
/// Creator vault for buy/sell must be `PDA(["creator-vault", bonding_curve.creator])` (same as on-chain).
/// Use gRPC `from_event` only when it equals that PDA; if it differs (wrong mint / stale parse), use derived.
/// `feeSharingConfig` PDA per mint (`pump-sdk` `feeSharingConfigPda` → `pump-fees` program).
#[inline]
pub fn resolve_creator_vault_for_ix(creator: &Pubkey, from_event: Pubkey) -> Option<Pubkey> {
let derived = get_creator_vault_pda(creator)?;
pub fn get_fee_sharing_config_pda(mint: &Pubkey) -> Option<Pubkey> {
Pubkey::try_find_program_address(
&[seeds::SHARING_CONFIG_SEED, mint.as_ref()],
&accounts::FEE_PROGRAM,
)
.map(|(p, _)| p)
}
/// Creator vault for buy/sell must be `PDA(["creator-vault", bonding_curve.creator])` (IDL `bonding_curve.creator`).
/// After fee-sharing migration, on-chain `creator` may be [`get_fee_sharing_config_pda`]`(mint)` while gRPC
/// still sends the wallet — accept `from_event` when it matches either `PDA(wallet)` or `PDA(sharing_cfg)`.
#[inline]
pub fn resolve_creator_vault_for_ix(
creator: &Pubkey,
from_event: Pubkey,
mint: &Pubkey,
) -> Option<Pubkey> {
let v_creator = get_creator_vault_pda(creator)?;
let sharing = get_fee_sharing_config_pda(mint)?;
let v_sharing = get_creator_vault_pda(&sharing)?;
if from_event == Pubkey::default() {
Some(derived)
} else if from_event == derived {
Some(from_event)
} else {
Some(derived)
return Some(v_creator);
}
if from_event == v_creator || from_event == v_sharing {
return Some(from_event);
}
if v_creator == v_sharing {
return Some(v_creator);
}
Some(v_creator)
}
#[inline]
@@ -436,4 +460,12 @@ mod tests {
let b = get_creator_vault_pda(&creator).unwrap();
assert_eq!(a, b);
}
#[test]
fn fee_sharing_config_pda_deterministic() {
let mint = Pubkey::new_unique();
let a = get_fee_sharing_config_pda(&mint).unwrap();
let b = get_fee_sharing_config_pda(&mint).unwrap();
assert_eq!(a, b);
}
}
+2
View File
@@ -185,6 +185,7 @@ impl PumpFunParams {
let creator_vault_resolved = crate::instruction::utils::pumpfun::resolve_creator_vault_for_ix(
&bonding_curve_account.creator,
creator_vault,
&mint,
)
.unwrap_or_default();
Self {
@@ -232,6 +233,7 @@ impl PumpFunParams {
let creator_vault_resolved = crate::instruction::utils::pumpfun::resolve_creator_vault_for_ix(
&bonding_curve.creator,
creator_vault,
&mint,
)
.unwrap_or_default();
Self {