balancer_maths_rust/hooks/akron/
mod.rs1use crate::common::maths::{div_down_fixed, div_up_fixed, mul_div_up_fixed, pow_up_fixed};
2use crate::common::types::{HookStateBase, SwapKind};
3use crate::hooks::types::{DynamicSwapFeeResult, HookState};
4use crate::hooks::{DefaultHook, HookBase, HookConfig};
5use num_bigint::BigInt;
6use num_traits::Zero;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11pub struct AkronHookState {
12 pub hook_type: String,
14 pub weights: Vec<BigInt>,
16 pub minimum_swap_fee_percentage: BigInt,
18}
19
20impl HookStateBase for AkronHookState {
21 fn hook_type(&self) -> &str {
22 &self.hook_type
23 }
24}
25
26impl Default for AkronHookState {
27 fn default() -> Self {
28 Self {
29 hook_type: "Akron".to_string(),
30 weights: vec![],
31 minimum_swap_fee_percentage: BigInt::zero(),
32 }
33 }
34}
35
36pub struct AkronHook {
39 config: HookConfig,
40}
41
42impl AkronHook {
43 pub fn new() -> Self {
44 let config = HookConfig {
45 should_call_compute_dynamic_swap_fee: true,
46 ..Default::default()
47 };
48
49 Self { config }
50 }
51
52 fn compute_swap_fee_percentage_given_exact_in(
54 balance_in: &BigInt,
55 exponent: &BigInt,
56 amount_in: &BigInt,
57 ) -> Result<BigInt, crate::common::errors::PoolError> {
58 let balance_plus_amount = balance_in + amount_in;
60 let balance_plus_amount_times_2 = balance_in + amount_in * BigInt::from(2);
61
62 let power_with_fees = pow_up_fixed(
63 &div_up_fixed(&balance_plus_amount, &balance_plus_amount_times_2)?,
64 exponent,
65 )?;
66 let power_without_fees =
67 pow_up_fixed(&div_up_fixed(balance_in, &balance_plus_amount)?, exponent)?;
68
69 let numerator = mul_div_up_fixed(
70 &balance_plus_amount,
71 &(power_with_fees.clone() - power_without_fees),
72 &power_with_fees,
73 )?;
74
75 mul_div_up_fixed(exponent, &numerator, amount_in)
76 }
77
78 fn compute_swap_fee_percentage_given_exact_out(
80 balance_out: &BigInt,
81 exponent: &BigInt,
82 amount_out: &BigInt,
83 ) -> Result<BigInt, crate::common::errors::PoolError> {
84 let balance_minus_amount = balance_out - amount_out;
86 let balance_minus_amount_times_2 = balance_out - amount_out * BigInt::from(2);
87
88 let power_with_fees = pow_up_fixed(
89 &div_up_fixed(&balance_minus_amount, &balance_minus_amount_times_2)?,
90 exponent,
91 )?;
92 let power_without_fees =
93 pow_up_fixed(&div_up_fixed(balance_out, &balance_minus_amount)?, exponent)?;
94
95 let numerator = power_with_fees.clone() - power_without_fees;
96 let denominator = power_with_fees.clone() - crate::common::constants::WAD.clone();
97
98 div_up_fixed(&numerator, &denominator)
99 }
100}
101
102impl HookBase for AkronHook {
103 fn hook_type(&self) -> &str {
104 "Akron"
105 }
106
107 fn config(&self) -> &HookConfig {
108 &self.config
109 }
110
111 fn on_compute_dynamic_swap_fee(
112 &self,
113 swap_params: &crate::common::types::SwapParams,
114 _static_swap_fee_percentage: &BigInt,
115 hook_state: &HookState,
116 ) -> DynamicSwapFeeResult {
117 match hook_state {
118 HookState::Akron(state) => {
119 let calculated_swap_fee_percentage = if swap_params.swap_kind == SwapKind::GivenIn {
120 let exponent = div_down_fixed(
121 &state.weights[swap_params.token_in_index],
122 &state.weights[swap_params.token_out_index],
123 )
124 .unwrap_or_else(|_| BigInt::zero());
125
126 Self::compute_swap_fee_percentage_given_exact_in(
127 &swap_params.balances_live_scaled_18[swap_params.token_in_index],
128 &exponent,
129 &swap_params.amount_scaled_18,
130 )
131 .unwrap_or_else(|_| BigInt::zero())
132 } else {
133 let exponent = div_up_fixed(
134 &state.weights[swap_params.token_out_index],
135 &state.weights[swap_params.token_in_index],
136 )
137 .unwrap_or_else(|_| BigInt::zero());
138
139 Self::compute_swap_fee_percentage_given_exact_out(
140 &swap_params.balances_live_scaled_18[swap_params.token_out_index],
141 &exponent,
142 &swap_params.amount_scaled_18,
143 )
144 .unwrap_or_else(|_| BigInt::zero())
145 };
146
147 let dynamic_swap_fee =
149 if state.minimum_swap_fee_percentage > calculated_swap_fee_percentage {
150 state.minimum_swap_fee_percentage.clone()
151 } else {
152 calculated_swap_fee_percentage
153 };
154
155 DynamicSwapFeeResult {
156 success: true,
157 dynamic_swap_fee,
158 }
159 }
160 _ => DynamicSwapFeeResult {
161 success: false,
162 dynamic_swap_fee: BigInt::zero(),
163 },
164 }
165 }
166
167 fn on_before_add_liquidity(
169 &self,
170 kind: crate::common::types::AddLiquidityKind,
171 max_amounts_in_scaled_18: &[BigInt],
172 min_bpt_amount_out: &BigInt,
173 balances_scaled_18: &[BigInt],
174 hook_state: &HookState,
175 ) -> crate::hooks::types::BeforeAddLiquidityResult {
176 DefaultHook::new().on_before_add_liquidity(
177 kind,
178 max_amounts_in_scaled_18,
179 min_bpt_amount_out,
180 balances_scaled_18,
181 hook_state,
182 )
183 }
184
185 fn on_after_add_liquidity(
186 &self,
187 kind: crate::common::types::AddLiquidityKind,
188 amounts_in_scaled_18: &[BigInt],
189 amounts_in_raw: &[BigInt],
190 bpt_amount_out: &BigInt,
191 balances_scaled_18: &[BigInt],
192 hook_state: &HookState,
193 ) -> crate::hooks::types::AfterAddLiquidityResult {
194 DefaultHook::new().on_after_add_liquidity(
195 kind,
196 amounts_in_scaled_18,
197 amounts_in_raw,
198 bpt_amount_out,
199 balances_scaled_18,
200 hook_state,
201 )
202 }
203
204 fn on_before_remove_liquidity(
205 &self,
206 kind: crate::common::types::RemoveLiquidityKind,
207 max_bpt_amount_in: &BigInt,
208 min_amounts_out_scaled_18: &[BigInt],
209 balances_scaled_18: &[BigInt],
210 hook_state: &HookState,
211 ) -> crate::hooks::types::BeforeRemoveLiquidityResult {
212 DefaultHook::new().on_before_remove_liquidity(
213 kind,
214 max_bpt_amount_in,
215 min_amounts_out_scaled_18,
216 balances_scaled_18,
217 hook_state,
218 )
219 }
220
221 fn on_after_remove_liquidity(
222 &self,
223 kind: crate::common::types::RemoveLiquidityKind,
224 bpt_amount_in: &BigInt,
225 amounts_out_scaled_18: &[BigInt],
226 amounts_out_raw: &[BigInt],
227 balances_scaled_18: &[BigInt],
228 hook_state: &HookState,
229 ) -> crate::hooks::types::AfterRemoveLiquidityResult {
230 DefaultHook::new().on_after_remove_liquidity(
231 kind,
232 bpt_amount_in,
233 amounts_out_scaled_18,
234 amounts_out_raw,
235 balances_scaled_18,
236 hook_state,
237 )
238 }
239
240 fn on_before_swap(
241 &self,
242 swap_params: &crate::common::types::SwapParams,
243 hook_state: &HookState,
244 ) -> crate::hooks::types::BeforeSwapResult {
245 DefaultHook::new().on_before_swap(swap_params, hook_state)
246 }
247
248 fn on_after_swap(
249 &self,
250 after_swap_params: &crate::hooks::types::AfterSwapParams,
251 hook_state: &HookState,
252 ) -> crate::hooks::types::AfterSwapResult {
253 DefaultHook::new().on_after_swap(after_swap_params, hook_state)
254 }
255}
256
257impl Default for AkronHook {
258 fn default() -> Self {
259 AkronHook::new()
260 }
261}