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;
|
// 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.
|
// if stream sends a mismatched vault (wrong token / stale), fall back to derived.
|
||||||
let creator = bonding_curve.creator;
|
let creator = bonding_curve.creator;
|
||||||
let creator_vault_pda = resolve_creator_vault_for_ix(&creator, protocol_params.creator_vault)
|
let creator_vault_pda = resolve_creator_vault_for_ix(
|
||||||
.ok_or_else(|| {
|
&creator,
|
||||||
anyhow!(
|
protocol_params.creator_vault,
|
||||||
"creator_vault PDA derivation failed (creator={})",
|
¶ms.output_mint,
|
||||||
creator
|
)
|
||||||
)
|
.ok_or_else(|| {
|
||||||
})?;
|
anyhow!(
|
||||||
|
"creator_vault PDA derivation failed (creator={})",
|
||||||
|
creator
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
// Trade calculation and account address preparation
|
// Trade calculation and account address preparation
|
||||||
@@ -206,13 +210,17 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
|
|||||||
|
|
||||||
let bonding_curve = &protocol_params.bonding_curve;
|
let bonding_curve = &protocol_params.bonding_curve;
|
||||||
let creator = bonding_curve.creator;
|
let creator = bonding_curve.creator;
|
||||||
let creator_vault_pda = resolve_creator_vault_for_ix(&creator, protocol_params.creator_vault)
|
let creator_vault_pda = resolve_creator_vault_for_ix(
|
||||||
.ok_or_else(|| {
|
&creator,
|
||||||
anyhow!(
|
protocol_params.creator_vault,
|
||||||
"creator_vault PDA derivation failed (creator={})",
|
¶ms.input_mint,
|
||||||
creator
|
)
|
||||||
)
|
.ok_or_else(|| {
|
||||||
})?;
|
anyhow!(
|
||||||
|
"creator_vault PDA derivation failed (creator={})",
|
||||||
|
creator
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
// Trade calculation and account address preparation
|
// 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 GLOBAL_VOLUME_ACCUMULATOR_SEED: &[u8] = b"global_volume_accumulator";
|
||||||
|
|
||||||
pub const FEE_CONFIG_SEED: &[u8] = b"fee_config";
|
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 {
|
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).
|
/// `feeSharingConfig` PDA per mint (`pump-sdk` `feeSharingConfigPda` → `pump-fees` program).
|
||||||
/// Use gRPC `from_event` only when it equals that PDA; if it differs (wrong mint / stale parse), use derived.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn resolve_creator_vault_for_ix(creator: &Pubkey, from_event: Pubkey) -> Option<Pubkey> {
|
pub fn get_fee_sharing_config_pda(mint: &Pubkey) -> Option<Pubkey> {
|
||||||
let derived = get_creator_vault_pda(creator)?;
|
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() {
|
if from_event == Pubkey::default() {
|
||||||
Some(derived)
|
return Some(v_creator);
|
||||||
} else if from_event == derived {
|
|
||||||
Some(from_event)
|
|
||||||
} else {
|
|
||||||
Some(derived)
|
|
||||||
}
|
}
|
||||||
|
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]
|
#[inline]
|
||||||
@@ -436,4 +460,12 @@ mod tests {
|
|||||||
let b = get_creator_vault_pda(&creator).unwrap();
|
let b = get_creator_vault_pda(&creator).unwrap();
|
||||||
assert_eq!(a, b);
|
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(
|
let creator_vault_resolved = crate::instruction::utils::pumpfun::resolve_creator_vault_for_ix(
|
||||||
&bonding_curve_account.creator,
|
&bonding_curve_account.creator,
|
||||||
creator_vault,
|
creator_vault,
|
||||||
|
&mint,
|
||||||
)
|
)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
Self {
|
Self {
|
||||||
@@ -232,6 +233,7 @@ impl PumpFunParams {
|
|||||||
let creator_vault_resolved = crate::instruction::utils::pumpfun::resolve_creator_vault_for_ix(
|
let creator_vault_resolved = crate::instruction::utils::pumpfun::resolve_creator_vault_for_ix(
|
||||||
&bonding_curve.creator,
|
&bonding_curve.creator,
|
||||||
creator_vault,
|
creator_vault,
|
||||||
|
&mint,
|
||||||
)
|
)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
Reference in New Issue
Block a user