balancer_maths_rust/pools/buffer/
buffer_math.rs

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