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