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