balancer_maths_rust/hooks/exit_fee/
mod.rs1use crate::common::maths::mul_down_fixed;
4use crate::common::types::{HookStateBase, RemoveLiquidityKind};
5use crate::hooks::types::{AfterRemoveLiquidityResult, HookState};
6use crate::hooks::{DefaultHook, HookBase, HookConfig};
7use num_bigint::BigInt;
8use num_traits::Zero;
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub struct ExitFeeHookState {
14 pub hook_type: String,
16 pub tokens: Vec<String>,
18 pub remove_liquidity_hook_fee_percentage: BigInt,
20}
21
22impl HookStateBase for ExitFeeHookState {
23 fn hook_type(&self) -> &str {
24 &self.hook_type
25 }
26}
27
28impl Default for ExitFeeHookState {
29 fn default() -> Self {
30 Self {
31 hook_type: "ExitFee".to_string(),
32 tokens: vec![],
33 remove_liquidity_hook_fee_percentage: BigInt::zero(),
34 }
35 }
36}
37
38pub struct ExitFeeHook {
41 config: HookConfig,
42}
43
44impl ExitFeeHook {
45 pub fn new() -> Self {
46 let config = HookConfig {
47 should_call_after_remove_liquidity: true,
48 enable_hook_adjusted_amounts: true,
49 ..Default::default()
50 };
51
52 Self { config }
53 }
54}
55
56impl HookBase for ExitFeeHook {
57 fn hook_type(&self) -> &str {
58 "ExitFee"
59 }
60
61 fn config(&self) -> &HookConfig {
62 &self.config
63 }
64
65 fn on_after_remove_liquidity(
66 &self,
67 kind: RemoveLiquidityKind,
68 _bpt_amount_in: &BigInt,
69 _amounts_out_scaled_18: &[BigInt],
70 amounts_out_raw: &[BigInt],
71 _balances_scaled_18: &[BigInt],
72 hook_state: &HookState,
73 ) -> AfterRemoveLiquidityResult {
74 match hook_state {
75 HookState::ExitFee(state) => {
76 if kind != RemoveLiquidityKind::Proportional {
80 return AfterRemoveLiquidityResult {
81 success: false,
82 hook_adjusted_amounts_out_raw: amounts_out_raw.to_vec(),
83 };
84 }
85
86 let mut accrued_fees = vec![BigInt::zero(); state.tokens.len()];
87 let mut hook_adjusted_amounts_out_raw = amounts_out_raw.to_vec();
88
89 if state.remove_liquidity_hook_fee_percentage > BigInt::zero() {
90 for i in 0..amounts_out_raw.len() {
92 let hook_fee = mul_down_fixed(
93 &amounts_out_raw[i],
94 &state.remove_liquidity_hook_fee_percentage,
95 )
96 .unwrap_or_else(|_| BigInt::zero());
97
98 accrued_fees[i] = hook_fee.clone();
99 hook_adjusted_amounts_out_raw[i] =
100 &hook_adjusted_amounts_out_raw[i] - &hook_fee;
101 }
103
104 }
116
117 AfterRemoveLiquidityResult {
118 success: true,
119 hook_adjusted_amounts_out_raw,
120 }
121 }
122 _ => AfterRemoveLiquidityResult {
123 success: false,
124 hook_adjusted_amounts_out_raw: amounts_out_raw.to_vec(),
125 },
126 }
127 }
128
129 fn on_before_add_liquidity(
131 &self,
132 kind: crate::common::types::AddLiquidityKind,
133 max_amounts_in_scaled_18: &[BigInt],
134 min_bpt_amount_out: &BigInt,
135 balances_scaled_18: &[BigInt],
136 hook_state: &HookState,
137 ) -> crate::hooks::types::BeforeAddLiquidityResult {
138 DefaultHook::new().on_before_add_liquidity(
139 kind,
140 max_amounts_in_scaled_18,
141 min_bpt_amount_out,
142 balances_scaled_18,
143 hook_state,
144 )
145 }
146
147 fn on_after_add_liquidity(
148 &self,
149 kind: crate::common::types::AddLiquidityKind,
150 amounts_in_scaled_18: &[BigInt],
151 amounts_in_raw: &[BigInt],
152 bpt_amount_out: &BigInt,
153 balances_scaled_18: &[BigInt],
154 hook_state: &HookState,
155 ) -> crate::hooks::types::AfterAddLiquidityResult {
156 DefaultHook::new().on_after_add_liquidity(
157 kind,
158 amounts_in_scaled_18,
159 amounts_in_raw,
160 bpt_amount_out,
161 balances_scaled_18,
162 hook_state,
163 )
164 }
165
166 fn on_before_remove_liquidity(
167 &self,
168 kind: crate::common::types::RemoveLiquidityKind,
169 max_bpt_amount_in: &BigInt,
170 min_amounts_out_scaled_18: &[BigInt],
171 balances_scaled_18: &[BigInt],
172 hook_state: &HookState,
173 ) -> crate::hooks::types::BeforeRemoveLiquidityResult {
174 DefaultHook::new().on_before_remove_liquidity(
175 kind,
176 max_bpt_amount_in,
177 min_amounts_out_scaled_18,
178 balances_scaled_18,
179 hook_state,
180 )
181 }
182
183 fn on_before_swap(
184 &self,
185 swap_params: &crate::common::types::SwapParams,
186 hook_state: &HookState,
187 ) -> crate::hooks::types::BeforeSwapResult {
188 DefaultHook::new().on_before_swap(swap_params, hook_state)
189 }
190
191 fn on_after_swap(
192 &self,
193 after_swap_params: &crate::hooks::types::AfterSwapParams,
194 hook_state: &HookState,
195 ) -> crate::hooks::types::AfterSwapResult {
196 DefaultHook::new().on_after_swap(after_swap_params, hook_state)
197 }
198
199 fn on_compute_dynamic_swap_fee(
200 &self,
201 swap_params: &crate::common::types::SwapParams,
202 static_swap_fee_percentage: &BigInt,
203 hook_state: &HookState,
204 ) -> crate::hooks::types::DynamicSwapFeeResult {
205 DefaultHook::new().on_compute_dynamic_swap_fee(
206 swap_params,
207 static_swap_fee_percentage,
208 hook_state,
209 )
210 }
211}
212
213impl Default for ExitFeeHook {
214 fn default() -> Self {
215 ExitFeeHook::new()
216 }
217}