Skip to main content

balancer_maths_rust/pools/buffer/
buffer_math.rs

1use crate::common::errors::PoolError;
2use crate::common::maths::{div_down_fixed, div_up_fixed, mul_down_fixed, mul_up_fixed};
3use crate::common::types::{Rounding, SwapKind};
4use crate::pools::buffer::enums::WrappingDirection;
5use alloy_primitives::U256;
6
7/// Calculate buffer amounts for wrap/unwrap operations
8///
9/// # Arguments
10/// * `direction` - Wrapping direction (Wrap or Unwrap)
11/// * `kind` - Swap kind (GivenIn or GivenOut)
12/// * `amount_raw` - Raw amount to convert
13/// * `rate` - Exchange rate (scaled 18)
14/// * `max_deposit` - Maximum deposit limit (optional)
15/// * `max_mint` - Maximum mint limit (optional)
16///
17/// # Returns
18/// Converted amount
19pub fn calculate_buffer_amounts(
20    direction: WrappingDirection,
21    kind: SwapKind,
22    amount_raw: &U256,
23    rate: &U256,
24    max_deposit: Option<&U256>,
25    max_mint: Option<&U256>,
26) -> Result<U256, PoolError> {
27    match direction {
28        WrappingDirection::Wrap => {
29            // Amount in is underlying tokens, amount out is wrapped tokens
30            match kind {
31                SwapKind::GivenIn => {
32                    // previewDeposit
33                    let max_assets = max_deposit.unwrap_or(&U256::MAX);
34                    if amount_raw > max_assets {
35                        return Err(PoolError::Erc4626ExceededMaxDeposit {
36                            requested: *amount_raw,
37                            max: *max_assets,
38                        });
39                    }
40                    _convert_to_shares(amount_raw, rate, Rounding::RoundDown)
41                }
42                SwapKind::GivenOut => {
43                    // previewMint
44                    let max_shares = max_mint.unwrap_or(&U256::MAX);
45                    if amount_raw > max_shares {
46                        return Err(PoolError::Erc4626ExceededMaxMint {
47                            requested: *amount_raw,
48                            max: *max_mint.unwrap_or(&U256::ZERO),
49                        });
50                    }
51                    _convert_to_assets(amount_raw, rate, Rounding::RoundUp)
52                }
53            }
54        }
55        WrappingDirection::Unwrap => {
56            // Amount in is wrapped tokens, amount out is underlying tokens
57            match kind {
58                SwapKind::GivenIn => {
59                    // previewRedeem
60                    _convert_to_assets(amount_raw, rate, Rounding::RoundDown)
61                }
62                SwapKind::GivenOut => {
63                    // previewWithdraw
64                    _convert_to_shares(amount_raw, rate, Rounding::RoundUp)
65                }
66            }
67        }
68    }
69}
70
71/// Convert assets to shares
72fn _convert_to_shares(assets: &U256, rate: &U256, rounding: Rounding) -> Result<U256, PoolError> {
73    match rounding {
74        Rounding::RoundUp => div_up_fixed(assets, rate),
75        Rounding::RoundDown => div_down_fixed(assets, rate),
76    }
77}
78
79/// Convert shares to assets
80fn _convert_to_assets(shares: &U256, rate: &U256, rounding: Rounding) -> Result<U256, PoolError> {
81    match rounding {
82        Rounding::RoundUp => mul_up_fixed(shares, rate),
83        Rounding::RoundDown => mul_down_fixed(shares, rate),
84    }
85}