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:
+22
-14
@@ -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,
|
||||
¶ms.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,
|
||||
¶ms.input_mint,
|
||||
)
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"creator_vault PDA derivation failed (creator={})",
|
||||
creator
|
||||
)
|
||||
})?;
|
||||
|
||||
// ========================================
|
||||
// Trade calculation and account address preparation
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user