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