balancer_maths_rust/hooks/directional_fee/
mod.rs

1use crate::common::maths::div_down_fixed;
2use crate::common::types::HookStateBase;
3use crate::hooks::types::{DynamicSwapFeeResult, HookState};
4use crate::hooks::{DefaultHook, HookBase, HookConfig};
5use alloy_primitives::U256;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9pub struct DirectionalFeeHookState {
10    pub hook_type: String,
11}
12
13impl Default for DirectionalFeeHookState {
14    fn default() -> Self {
15        Self {
16            hook_type: "DirectionalFee".to_string(),
17        }
18    }
19}
20
21impl HookStateBase for DirectionalFeeHookState {
22    fn hook_type(&self) -> &str {
23        &self.hook_type
24    }
25}
26
27pub struct DirectionalFeeHook {
28    config: HookConfig,
29}
30
31impl DirectionalFeeHook {
32    pub fn new() -> Self {
33        let config = HookConfig {
34            should_call_compute_dynamic_swap_fee: true,
35            ..Default::default()
36        };
37        Self { config }
38    }
39}
40
41impl HookBase for DirectionalFeeHook {
42    fn hook_type(&self) -> &str {
43        "DirectionalFee"
44    }
45    fn config(&self) -> &HookConfig {
46        &self.config
47    }
48
49    fn on_compute_dynamic_swap_fee(
50        &self,
51        swap_params: &crate::common::types::SwapParams,
52        static_swap_fee_percentage: &U256,
53        _hook_state: &HookState,
54    ) -> DynamicSwapFeeResult {
55        let balance_in = &swap_params.balances_live_scaled_18[swap_params.token_in_index];
56        let balance_out = &swap_params.balances_live_scaled_18[swap_params.token_out_index];
57        let amount = &swap_params.amount_scaled_18;
58
59        // final balances after gross trade size
60        let final_balance_in = balance_in + amount;
61        let final_balance_out = balance_out - amount;
62
63        let calculated = if final_balance_in > final_balance_out {
64            let diff = final_balance_in - final_balance_out;
65            let total = final_balance_in + final_balance_out;
66            match div_down_fixed(&diff, &total) {
67                Ok(v) => v,
68                Err(_) => U256::ZERO,
69            }
70        } else {
71            U256::ZERO
72        };
73
74        let dynamic_swap_fee = if calculated > *static_swap_fee_percentage {
75            calculated
76        } else {
77            *static_swap_fee_percentage
78        };
79
80        DynamicSwapFeeResult {
81            success: true,
82            dynamic_swap_fee,
83        }
84    }
85
86    // Delegate others to DefaultHook
87    fn on_before_add_liquidity(
88        &self,
89        kind: crate::common::types::AddLiquidityKind,
90        max_amounts_in_scaled_18: &[U256],
91        min_bpt_amount_out: &U256,
92        balances_scaled_18: &[U256],
93        hook_state: &HookState,
94    ) -> crate::hooks::types::BeforeAddLiquidityResult {
95        DefaultHook::new().on_before_add_liquidity(
96            kind,
97            max_amounts_in_scaled_18,
98            min_bpt_amount_out,
99            balances_scaled_18,
100            hook_state,
101        )
102    }
103    fn on_after_add_liquidity(
104        &self,
105        kind: crate::common::types::AddLiquidityKind,
106        amounts_in_scaled_18: &[U256],
107        amounts_in_raw: &[U256],
108        bpt_amount_out: &U256,
109        balances_scaled_18: &[U256],
110        hook_state: &HookState,
111    ) -> crate::hooks::types::AfterAddLiquidityResult {
112        DefaultHook::new().on_after_add_liquidity(
113            kind,
114            amounts_in_scaled_18,
115            amounts_in_raw,
116            bpt_amount_out,
117            balances_scaled_18,
118            hook_state,
119        )
120    }
121    fn on_before_remove_liquidity(
122        &self,
123        kind: crate::common::types::RemoveLiquidityKind,
124        max_bpt_amount_in: &U256,
125        min_amounts_out_scaled_18: &[U256],
126        balances_scaled_18: &[U256],
127        hook_state: &HookState,
128    ) -> crate::hooks::types::BeforeRemoveLiquidityResult {
129        DefaultHook::new().on_before_remove_liquidity(
130            kind,
131            max_bpt_amount_in,
132            min_amounts_out_scaled_18,
133            balances_scaled_18,
134            hook_state,
135        )
136    }
137    fn on_after_remove_liquidity(
138        &self,
139        kind: crate::common::types::RemoveLiquidityKind,
140        bpt_amount_in: &U256,
141        amounts_out_scaled_18: &[U256],
142        amounts_out_raw: &[U256],
143        balances_scaled_18: &[U256],
144        hook_state: &HookState,
145    ) -> crate::hooks::types::AfterRemoveLiquidityResult {
146        DefaultHook::new().on_after_remove_liquidity(
147            kind,
148            bpt_amount_in,
149            amounts_out_scaled_18,
150            amounts_out_raw,
151            balances_scaled_18,
152            hook_state,
153        )
154    }
155    fn on_before_swap(
156        &self,
157        swap_params: &crate::common::types::SwapParams,
158        hook_state: &HookState,
159    ) -> crate::hooks::types::BeforeSwapResult {
160        DefaultHook::new().on_before_swap(swap_params, hook_state)
161    }
162    fn on_after_swap(
163        &self,
164        after_swap_params: &crate::hooks::types::AfterSwapParams,
165        hook_state: &HookState,
166    ) -> crate::hooks::types::AfterSwapResult {
167        DefaultHook::new().on_after_swap(after_swap_params, hook_state)
168    }
169}
170
171impl Default for DirectionalFeeHook {
172    fn default() -> Self {
173        Self::new()
174    }
175}