mirror of
https://github.com/0xfnzero/solana-streamer.git
synced 2026-11-02 07:16:31 +00:00
feat(pump): support compact trades, coin quotes and synthetic migration
This commit is contained in:
@@ -652,3 +652,12 @@ MIT License
|
||||
|
||||
- [English](README.md)
|
||||
- [中文](README_CN.md)
|
||||
|
||||
|
||||
## Pump upgrade (October 2026)
|
||||
|
||||
Compact Pump v3 and PumpSwap v2 trades use their new 17-account layouts. New typed events cover `PumpFunPostCompleteBuy`, `PumpFunComplete`, `PumpFunSweepBondingCurveFee` and `PumpSwapSweepPoolFee`, with program-scoped log and CPI parsing. Historical SOL CompleteEvent payloads remain supported. Curve/pool retained fees and synthetic counters are exposed; optional historical tails default to zero.
|
||||
|
||||
For a synthetic completing buy, retain TradeEvent **and** PostCompleteBuyEvent and aggregate execution amounts within the same invocation. CompleteEvent is the completion notification. For `multi_hop_swap`, retain each venue's trade events; different venues are not merged into one fill. The multi-hop intent decoder exposes the fixed user accounts, input/minimum limits and 5 roles per hop; these limits are not actual executed amounts. Streamer forwards the typed events and account fields through its parser bridge (its re-exported `parser_sdk` also provides the intent decoder).
|
||||
|
||||
Reference: [pump-public-docs](https://github.com/pump-fun/pump-public-docs/tree/8cda1fa30ea658b20909d8aedf002047119388d2). Validation uses offline official IDL fixtures; no live trade is sent by the tests.
|
||||
|
||||
@@ -251,6 +251,10 @@ fn push_streamer_event_sdk_grpc_types(
|
||||
St::PumpFeesUpdateFeeConfig => out.push(Sdk::PumpFeesUpdateFeeConfig),
|
||||
St::PumpFeesUpdateFeeShares => out.push(Sdk::PumpFeesUpdateFeeShares),
|
||||
St::PumpFeesUpsertFeeTiers => out.push(Sdk::PumpFeesUpsertFeeTiers),
|
||||
St::PumpFunPostCompleteBuy => out.push(Sdk::PumpFunPostCompleteBuy),
|
||||
St::PumpFunSweepBondingCurveFee => out.push(Sdk::PumpFunSweepBondingCurveFee),
|
||||
St::PumpFunComplete => out.push(Sdk::PumpFunComplete),
|
||||
St::PumpSwapSweepPoolFee => out.push(Sdk::PumpSwapSweepPoolFee),
|
||||
St::PumpFunMigrateBondingCurveCreator => out.push(Sdk::PumpFunMigrateBondingCurveCreator),
|
||||
St::PumpSwapBuy => out.push(Sdk::PumpSwapBuy),
|
||||
St::PumpSwapSell => out.push(Sdk::PumpSwapSell),
|
||||
@@ -373,6 +377,9 @@ fn push_protocol_sdk_grpc_event_types(protocol: &Protocol, out: &mut Vec<SdkGrpc
|
||||
Sdk::PumpFunCreateV2,
|
||||
Sdk::PumpFunMigrate,
|
||||
Sdk::PumpFunMigrateBondingCurveCreator,
|
||||
Sdk::PumpFunPostCompleteBuy,
|
||||
Sdk::PumpFunSweepBondingCurveFee,
|
||||
Sdk::PumpFunComplete,
|
||||
// Historical compatibility: streamer PumpFun also included PumpFees.
|
||||
Sdk::PumpFeesCreateFeeSharingConfig,
|
||||
Sdk::PumpFeesInitializeFeeConfig,
|
||||
@@ -400,6 +407,7 @@ fn push_protocol_sdk_grpc_event_types(protocol: &Protocol, out: &mut Vec<SdkGrpc
|
||||
Sdk::PumpSwapBuy,
|
||||
Sdk::PumpSwapSell,
|
||||
Sdk::PumpSwapCreatePool,
|
||||
Sdk::PumpSwapSweepPoolFee,
|
||||
Sdk::PumpSwapLiquidityAdded,
|
||||
Sdk::PumpSwapLiquidityRemoved,
|
||||
]),
|
||||
|
||||
@@ -73,6 +73,11 @@ pub enum ProtocolType {
|
||||
BorshDeserialize,
|
||||
)]
|
||||
pub enum EventType {
|
||||
PumpFunComplete,
|
||||
PumpFunPostCompleteBuy,
|
||||
PumpFunSweepBondingCurveFee,
|
||||
PumpSwapSweepPoolFee,
|
||||
|
||||
// PumpSwap events
|
||||
#[default]
|
||||
PumpSwapBuy,
|
||||
|
||||
@@ -170,6 +170,10 @@ pub enum DexEvent {
|
||||
// Appended to preserve existing serialized enum variant indices.
|
||||
TransactionCostEvent(TransactionCostEvent),
|
||||
RaydiumCpmmCollectCreatorFeeEvent(RaydiumCpmmCollectCreatorFeeEvent),
|
||||
PumpFunPostCompleteBuyEvent(PumpFunPostCompleteBuyEvent),
|
||||
PumpFunSweepBondingCurveFeeEvent(PumpFunSweepBondingCurveFeeEvent),
|
||||
PumpFunCompleteEvent(PumpFunCompleteEvent),
|
||||
PumpSwapSweepPoolFeeEvent(PumpSwapSweepPoolFeeEvent),
|
||||
}
|
||||
|
||||
/// Macro to generate metadata accessors for all DexEvent variants
|
||||
@@ -192,6 +196,10 @@ macro_rules! impl_dex_event_metadata {
|
||||
}
|
||||
|
||||
impl_dex_event_metadata!(
|
||||
PumpFunPostCompleteBuyEvent,
|
||||
PumpFunSweepBondingCurveFeeEvent,
|
||||
PumpFunCompleteEvent,
|
||||
PumpSwapSweepPoolFeeEvent,
|
||||
// Bonk events
|
||||
BonkTradeEvent,
|
||||
BonkPoolCreateEvent,
|
||||
|
||||
@@ -7,6 +7,9 @@ use crate::streaming::event_parser::protocols::pumpfun::types::{BondingCurve, Gl
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct PumpFunCreateTokenEvent {
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub depth: u8,
|
||||
#[borsh(skip)]
|
||||
pub metadata: EventMetadata,
|
||||
pub name: String,
|
||||
@@ -144,6 +147,9 @@ pub struct PumpFunCreateV2TokenEvent {
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct PumpFunTradeEvent {
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub creator_fee_unclaimed: u64,
|
||||
#[borsh(skip)]
|
||||
pub metadata: EventMetadata,
|
||||
pub mint: Pubkey,
|
||||
@@ -522,6 +528,7 @@ pub struct PumpFunFeeConfigAccountEvent {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct PumpFunFeeConfig {
|
||||
pub exotic_flat_fees: PumpFeesFees,
|
||||
pub bump: u8,
|
||||
pub admin: Pubkey,
|
||||
pub flat_fees: PumpFeesFees,
|
||||
@@ -623,3 +630,46 @@ pub mod discriminators {
|
||||
pub const BONDING_CURVE_ACCOUNT: &[u8] = &[23, 183, 248, 55, 96, 216, 172, 96];
|
||||
pub const GLOBAL_ACCOUNT: &[u8] = &[167, 232, 232, 177, 200, 108, 114, 127];
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct PumpFunPostCompleteBuyEvent {
|
||||
pub metadata: EventMetadata,
|
||||
pub user: Pubkey,
|
||||
pub mint: Pubkey,
|
||||
pub bonding_curve: Pubkey,
|
||||
pub quote_mint: Pubkey,
|
||||
pub timestamp: i64,
|
||||
pub base_out: u64,
|
||||
pub quote_in: u64,
|
||||
pub fee_basis_points: u64,
|
||||
pub fee: u64,
|
||||
pub creator_fee_basis_points: u64,
|
||||
pub creator_fee: u64,
|
||||
pub buyback_fee: u64,
|
||||
pub pool_base_reserves_before: u64,
|
||||
pub pool_quote_reserves_before: u64,
|
||||
pub pool_base_reserves_after: u64,
|
||||
pub pool_quote_reserves_after: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct PumpFunSweepBondingCurveFeeEvent {
|
||||
pub metadata: EventMetadata,
|
||||
pub timestamp: i64,
|
||||
pub mint: Pubkey,
|
||||
pub bonding_curve: Pubkey,
|
||||
pub quote_mint: Pubkey,
|
||||
pub recipient: Pubkey,
|
||||
pub amount: u64,
|
||||
pub bucket: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct PumpFunCompleteEvent {
|
||||
pub metadata: EventMetadata,
|
||||
pub user: Pubkey,
|
||||
pub mint: Pubkey,
|
||||
pub bonding_curve: Pubkey,
|
||||
pub timestamp: i64,
|
||||
pub quote_mint: Pubkey,
|
||||
}
|
||||
|
||||
@@ -4,6 +4,25 @@ use solana_sdk::pubkey::Pubkey;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct BondingCurve {
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub creator_fee: u64,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub protocol_fees: u64,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub depth: u8,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub initial_virtual_quote_reserves: u64,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub post_complete_base_out: u64,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub post_complete_quote_in: u64,
|
||||
|
||||
pub virtual_token_reserves: u64,
|
||||
pub virtual_quote_reserves: u64,
|
||||
pub real_token_reserves: u64,
|
||||
@@ -28,6 +47,22 @@ pub const BONDING_CURVE_SIZE: usize = BONDING_CURVE_CREATOR_FEE_SIZE + 1;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct Global {
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub creator_fee_configurable: bool,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub max_configurable_creator_fee_bps: u64,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub holder_reward_claim_authority: Pubkey,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub is_holder_reward_enabled: bool,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub max_curve_depth: u8,
|
||||
|
||||
pub initialized: bool,
|
||||
pub authority: Pubkey,
|
||||
pub fee_recipient: Pubkey,
|
||||
|
||||
@@ -8,6 +8,9 @@ use crate::streaming::event_parser::protocols::pumpswap::types::{GlobalConfig, P
|
||||
/// 买入事件
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct PumpSwapBuyEvent {
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub creator_fee_unclaimed: u64,
|
||||
#[borsh(skip)]
|
||||
pub metadata: EventMetadata,
|
||||
pub timestamp: i64,
|
||||
@@ -92,6 +95,9 @@ pub const PUMP_SWAP_BUY_EVENT_LOG_SIZE: usize = PUMP_SWAP_BUY_EVENT_LOG_MIN;
|
||||
/// 卖出事件
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct PumpSwapSellEvent {
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub creator_fee_unclaimed: u64,
|
||||
#[borsh(skip)]
|
||||
pub metadata: EventMetadata,
|
||||
pub timestamp: i64,
|
||||
@@ -375,3 +381,16 @@ pub mod discriminators {
|
||||
pub const GLOBAL_CONFIG_ACCOUNT: &[u8] = &[149, 8, 156, 202, 160, 252, 176, 217];
|
||||
pub const POOL_ACCOUNT: &[u8] = &[241, 154, 109, 4, 17, 177, 109, 188];
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct PumpSwapSweepPoolFeeEvent {
|
||||
pub metadata: EventMetadata,
|
||||
pub timestamp: i64,
|
||||
pub pool: Pubkey,
|
||||
pub base_mint: Pubkey,
|
||||
pub quote_mint: Pubkey,
|
||||
pub recipient: Pubkey,
|
||||
pub payer: Pubkey,
|
||||
pub amount: u64,
|
||||
pub bucket: u8,
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ pub const GLOBAL_CONFIG_SIZE: usize = 32 + 8 + 8 + 1 + 32 * 8 + 8 + 32 + 32 + 32
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
|
||||
pub struct Pool {
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub protocol_fees: u64,
|
||||
#[borsh(skip)]
|
||||
#[serde(default)]
|
||||
pub creator_fees: u64,
|
||||
pub pool_bump: u8,
|
||||
pub index: u16,
|
||||
pub creator: Pubkey,
|
||||
|
||||
@@ -195,6 +195,8 @@ pub(crate) fn pumpswap_global_config_from_pb(
|
||||
|
||||
pub(crate) fn pumpswap_pool_from_pb(p: sol_parser_sdk::core::events::PumpSwapPool) -> Pool {
|
||||
Pool {
|
||||
creator_fees: p.creator_fees,
|
||||
protocol_fees: p.protocol_fees,
|
||||
pool_bump: p.pool_bump,
|
||||
index: p.index,
|
||||
creator: p.creator,
|
||||
|
||||
@@ -23,6 +23,60 @@ pub(crate) fn convert_parser_event(
|
||||
recv_wall_us: i64,
|
||||
) -> Option<DexEvent> {
|
||||
match ev {
|
||||
PbDexEvent::PumpFunPostCompleteBuy(e) => {
|
||||
let meta = adapt_pm(
|
||||
e.metadata.clone(),
|
||||
bt,
|
||||
recv_wall_us,
|
||||
ProtocolType::PumpFun,
|
||||
EventType::PumpFunPostCompleteBuy,
|
||||
pump_program(),
|
||||
);
|
||||
Some(DexEvent::PumpFunPostCompleteBuyEvent(crate::streaming::event_parser::protocols::pumpfun::events::PumpFunPostCompleteBuyEvent{metadata:meta,user:e.user,mint:e.mint,bonding_curve:e.bonding_curve,quote_mint:e.quote_mint,timestamp:e.timestamp,base_out:e.base_out,quote_in:e.quote_in,fee_basis_points:e.fee_basis_points,fee:e.fee,creator_fee_basis_points:e.creator_fee_basis_points,creator_fee:e.creator_fee,buyback_fee:e.buyback_fee,pool_base_reserves_before:e.pool_base_reserves_before,pool_quote_reserves_before:e.pool_quote_reserves_before,pool_base_reserves_after:e.pool_base_reserves_after,pool_quote_reserves_after:e.pool_quote_reserves_after,}))
|
||||
}
|
||||
PbDexEvent::PumpFunSweepBondingCurveFee(e) => {
|
||||
let meta = adapt_pm(
|
||||
e.metadata.clone(),
|
||||
bt,
|
||||
recv_wall_us,
|
||||
ProtocolType::PumpFun,
|
||||
EventType::PumpFunSweepBondingCurveFee,
|
||||
pump_program(),
|
||||
);
|
||||
Some(DexEvent::PumpFunSweepBondingCurveFeeEvent(crate::streaming::event_parser::protocols::pumpfun::events::PumpFunSweepBondingCurveFeeEvent{metadata:meta,timestamp:e.timestamp,mint:e.mint,bonding_curve:e.bonding_curve,quote_mint:e.quote_mint,recipient:e.recipient,amount:e.amount,bucket:e.bucket,}))
|
||||
}
|
||||
PbDexEvent::PumpFunComplete(e) => {
|
||||
let meta = adapt_pm(
|
||||
e.metadata.clone(),
|
||||
bt,
|
||||
recv_wall_us,
|
||||
ProtocolType::PumpFun,
|
||||
EventType::PumpFunComplete,
|
||||
pump_program(),
|
||||
);
|
||||
Some(DexEvent::PumpFunCompleteEvent(
|
||||
crate::streaming::event_parser::protocols::pumpfun::events::PumpFunCompleteEvent {
|
||||
metadata: meta,
|
||||
user: e.user,
|
||||
mint: e.mint,
|
||||
bonding_curve: e.bonding_curve,
|
||||
timestamp: e.timestamp,
|
||||
quote_mint: e.quote_mint,
|
||||
},
|
||||
))
|
||||
}
|
||||
PbDexEvent::PumpSwapSweepPoolFee(e) => {
|
||||
let meta = adapt_pm(
|
||||
e.metadata.clone(),
|
||||
bt,
|
||||
recv_wall_us,
|
||||
ProtocolType::PumpSwap,
|
||||
EventType::PumpSwapSweepPoolFee,
|
||||
pumpswap_program(),
|
||||
);
|
||||
Some(DexEvent::PumpSwapSweepPoolFeeEvent(crate::streaming::event_parser::protocols::pumpswap::events::PumpSwapSweepPoolFeeEvent{metadata:meta,timestamp:e.timestamp,pool:e.pool,base_mint:e.base_mint,quote_mint:e.quote_mint,recipient:e.recipient,payer:e.payer,amount:e.amount,bucket:e.bucket,}))
|
||||
}
|
||||
|
||||
PbDexEvent::PumpFunTrade(t) => Some(pumpfun_trade_from_parser_with_event_type(
|
||||
t,
|
||||
bt,
|
||||
|
||||
@@ -419,6 +419,8 @@ mod tests {
|
||||
owner: Pubkey::new_unique(),
|
||||
rent_epoch: 0,
|
||||
pool: PbPumpSwapPool {
|
||||
protocol_fees: 0,
|
||||
creator_fees: 0,
|
||||
pool_bump: 7,
|
||||
index: 42,
|
||||
creator: Pubkey::new_unique(),
|
||||
|
||||
@@ -58,6 +58,7 @@ pub(crate) fn pumpfun_create_token_from_parser(
|
||||
virtual_quote_reserves: c.virtual_quote_reserves,
|
||||
creator_fee_bps: c.creator_fee_bps,
|
||||
is_holder_reward: c.is_holder_reward,
|
||||
depth: c.depth,
|
||||
ix_name: "create".to_string(),
|
||||
..Default::default()
|
||||
}
|
||||
@@ -356,6 +357,11 @@ pub(crate) fn pumpfun_global_account_from_parser(
|
||||
buyback_basis_points: e.global.buyback_basis_points,
|
||||
initial_virtual_quote_reserves: e.global.initial_virtual_quote_reserves,
|
||||
whitelisted_quote_mints: e.global.whitelisted_quote_mints,
|
||||
creator_fee_configurable: e.global.creator_fee_configurable,
|
||||
max_configurable_creator_fee_bps: e.global.max_configurable_creator_fee_bps,
|
||||
holder_reward_claim_authority: e.global.holder_reward_claim_authority,
|
||||
is_holder_reward_enabled: e.global.is_holder_reward_enabled,
|
||||
max_curve_depth: e.global.max_curve_depth,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -372,6 +378,13 @@ pub(crate) fn pumpfun_bonding_curve_account_from_parser(
|
||||
owner: pump_program(),
|
||||
rent_epoch: 0,
|
||||
bonding_curve: BondingCurve {
|
||||
creator_fee: e.bonding_curve.creator_fee,
|
||||
protocol_fees: e.bonding_curve.protocol_fees,
|
||||
depth: e.bonding_curve.depth,
|
||||
initial_virtual_quote_reserves: e.bonding_curve.initial_virtual_quote_reserves,
|
||||
post_complete_base_out: e.bonding_curve.post_complete_base_out,
|
||||
post_complete_quote_in: e.bonding_curve.post_complete_quote_in,
|
||||
|
||||
virtual_token_reserves: e.bonding_curve.virtual_token_reserves,
|
||||
virtual_quote_reserves: e.bonding_curve.virtual_quote_reserves,
|
||||
real_token_reserves: e.bonding_curve.real_token_reserves,
|
||||
@@ -401,6 +414,7 @@ pub(crate) fn pumpfun_fee_config_account_from_parser(
|
||||
owner: pump_program(),
|
||||
rent_epoch: 0,
|
||||
fee_config: PumpFunFeeConfig {
|
||||
exotic_flat_fees: pump_fees_fees_from_parser(e.fee_config.exotic_flat_fees),
|
||||
bump: e.fee_config.bump,
|
||||
admin: e.fee_config.admin,
|
||||
flat_fees: pump_fees_fees_from_parser(e.fee_config.flat_fees),
|
||||
@@ -533,6 +547,7 @@ pub(crate) fn pumpswap_buy_full_from_parser(
|
||||
buyback_fee_basis_points: b.buyback_fee_basis_points,
|
||||
buyback_fee: b.buyback_fee,
|
||||
virtual_quote_reserves: b.virtual_quote_reserves,
|
||||
creator_fee_unclaimed: b.creator_fee_unclaimed,
|
||||
can_boost: b.can_boost,
|
||||
base_supply: b.base_supply,
|
||||
holder_rewards_bps: b.holder_rewards_bps,
|
||||
@@ -586,6 +601,7 @@ pub(crate) fn pumpswap_sell_full_from_parser(
|
||||
buyback_fee_basis_points: s.buyback_fee_basis_points,
|
||||
buyback_fee: s.buyback_fee,
|
||||
virtual_quote_reserves: s.virtual_quote_reserves,
|
||||
creator_fee_unclaimed: s.creator_fee_unclaimed,
|
||||
can_boost: s.can_boost,
|
||||
base_supply: s.base_supply,
|
||||
holder_rewards_bps: s.holder_rewards_bps,
|
||||
@@ -757,6 +773,7 @@ pub(crate) fn pumpfun_trade_from_parser_with_event_type(
|
||||
quote_mint: normalize_pumpfun_quote_mint(t.quote_mint),
|
||||
quote_amount: t.quote_amount,
|
||||
virtual_quote_reserves: t.virtual_quote_reserves,
|
||||
creator_fee_unclaimed: t.creator_fee_unclaimed,
|
||||
real_quote_reserves: t.real_quote_reserves,
|
||||
holder_rewards_bps: t.holder_rewards_bps,
|
||||
holder_rewards: t.holder_rewards,
|
||||
|
||||
Reference in New Issue
Block a user