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