pump_rust_client/math/
fees.rs1use solana_program::pubkey::Pubkey;
8
9use crate::pda;
10use crate::pump::types::{FeeTier as PumpFeeTier, Fees as PumpFees};
11use crate::pump_amm::types::{FeeTier as AmmFeeTier, Fees as AmmFees};
12use crate::state::pump_amm::{FeeConfig as AmmFeeConfig, GlobalConfig};
13use crate::state::{FeeConfig as PumpFeeConfig, Global};
14
15#[inline]
17pub fn ceil_div(a: u128, b: u128) -> u128 {
18 a.div_ceil(b)
19}
20
21#[inline]
23pub fn fee_amount(amount: u128, basis_points: u64) -> u128 {
24 ceil_div(amount * basis_points as u128, 10_000)
25}
26
27#[inline]
30pub fn bonding_curve_market_cap(
31 mint_supply: u64,
32 virtual_quote_reserves: u64,
33 virtual_token_reserves: u64,
34) -> u128 {
35 debug_assert!(virtual_token_reserves != 0);
36 (virtual_quote_reserves as u128) * (mint_supply as u128) / (virtual_token_reserves as u128)
37}
38
39#[inline]
42pub fn pool_market_cap(base_mint_supply: u64, base_reserve: u64, quote_reserve: u64) -> u128 {
43 debug_assert!(base_reserve != 0);
44 (quote_reserve as u128) * (base_mint_supply as u128) / (base_reserve as u128)
45}
46
47pub fn is_pump_pool(base_mint: &Pubkey, pool_creator: &Pubkey) -> bool {
51 &pda::pump::pool_authority(base_mint).0 == pool_creator
52}
53
54#[derive(Clone, Copy, Debug)]
57pub struct BondingCurveFeeBps {
58 pub protocol_fee_bps: u64,
59 pub creator_fee_bps: u64,
60}
61
62#[derive(Clone, Copy, Debug)]
64pub struct AmmFeeBps {
65 pub lp_fee_bps: u64,
66 pub protocol_fee_bps: u64,
67 pub creator_fee_bps: u64,
68}
69
70fn calculate_pump_fee_tier(tiers: &[PumpFeeTier], market_cap: u128) -> &PumpFees {
74 let first = &tiers[0].fees;
75 if market_cap < tiers[0].market_cap_lamports_threshold {
76 return first;
77 }
78 for tier in tiers.iter().rev() {
79 if market_cap >= tier.market_cap_lamports_threshold {
80 return &tier.fees;
81 }
82 }
83 first
84}
85
86fn calculate_amm_fee_tier(tiers: &[AmmFeeTier], market_cap: u128) -> &AmmFees {
87 let first = &tiers[0].fees;
88 if market_cap < tiers[0].market_cap_lamports_threshold {
89 return first;
90 }
91 for tier in tiers.iter().rev() {
92 if market_cap >= tier.market_cap_lamports_threshold {
93 return &tier.fees;
94 }
95 }
96 first
97}
98
99pub fn compute_bonding_curve_fee_bps(
103 global: &Global,
104 fee_config: Option<&PumpFeeConfig>,
105 mint_supply: u64,
106 virtual_quote_reserves: u64,
107 virtual_token_reserves: u64,
108) -> BondingCurveFeeBps {
109 if let Some(cfg) = fee_config {
110 let market_cap =
111 bonding_curve_market_cap(mint_supply, virtual_quote_reserves, virtual_token_reserves);
112 let fees = calculate_pump_fee_tier(&cfg.fee_tiers, market_cap);
113 BondingCurveFeeBps {
114 protocol_fee_bps: fees.protocol_fee_bps,
115 creator_fee_bps: fees.creator_fee_bps,
116 }
117 } else {
118 BondingCurveFeeBps {
119 protocol_fee_bps: global.fee_basis_points,
120 creator_fee_bps: global.creator_fee_basis_points,
121 }
122 }
123}
124
125pub fn compute_amm_fee_bps(
130 global_config: &GlobalConfig,
131 fee_config: Option<&AmmFeeConfig>,
132 base_mint: &Pubkey,
133 pool_creator: &Pubkey,
134 base_mint_supply: u64,
135 base_reserve: u64,
136 quote_reserve: u64,
137) -> AmmFeeBps {
138 if let Some(cfg) = fee_config {
139 let market_cap = pool_market_cap(base_mint_supply, base_reserve, quote_reserve);
140 let fees = if is_pump_pool(base_mint, pool_creator) {
141 calculate_amm_fee_tier(&cfg.fee_tiers, market_cap)
142 } else {
143 &cfg.flat_fees
144 };
145 AmmFeeBps {
146 lp_fee_bps: fees.lp_fee_bps,
147 protocol_fee_bps: fees.protocol_fee_bps,
148 creator_fee_bps: fees.creator_fee_bps,
149 }
150 } else {
151 AmmFeeBps {
152 lp_fee_bps: global_config.lp_fee_basis_points,
153 protocol_fee_bps: global_config.protocol_fee_basis_points,
154 creator_fee_bps: global_config.coin_creator_fee_basis_points,
155 }
156 }
157}