Skip to main content

tycho_simulation/evm/protocol/curve/adapter/
variant.rs

1/// All 11 Curve pool math variants.
2///
3/// Each variant uses a different on-chain smart contract implementation with
4/// different invariant math, fee formulas, and state layouts.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)]
6pub enum CurveVariant {
7    /// Earliest StableSwap (2020): sUSD, Compound, BUSD, y, USDT, Pax, Ren, sBTC.
8    /// A_PRECISION=1, no `-1` offset on dy.
9    StableSwapV0,
10    /// 3pool era (2021): 3pool, hBTC.
11    /// A_PRECISION=1, `-1` offset on dy.
12    StableSwapV1,
13    /// Base/plain template: factory plain pools, FRAX/USDC.
14    /// A_PRECISION=100, `-1` offset, fee before denormalize.
15    StableSwapV2,
16    /// Lido stETH/ETH custom pool (0xDC24316b9AE028F1497c275EB9192a3Ea0f67022).
17    /// Same shape as `StableSwapV2`, but `get_D` adds a `+1` divisor guard.
18    StableSwapSTETH,
19    /// Aave lending template: aave, sAAVE, IB pools.
20    /// A_PRECISION=100, dynamic fee via `offpeg_fee_multiplier`.
21    StableSwapALend,
22    /// StableSwap-NG factory pools.
23    /// A_PRECISION=100, dynamic fee, supports oracle rates (ERC4626).
24    StableSwapNG,
25    /// Meta pool template: pools paired with a base pool LP token (e.g. GUSD/3CRV).
26    /// A_PRECISION=100, `rates[1]` = base pool `virtual_price`.
27    StableSwapMeta,
28    /// Legacy 2-coin CryptoSwap (CRV/ETH era).
29    /// Newton solver for y, inline math (no external MATH contract).
30    TwoCryptoV1,
31    /// TwoCrypto-NG factory pools with CryptoSwap math.
32    /// Cardano cubic solver. MATH contract version v2.0.0 or v2.1.0.
33    TwoCryptoNG,
34    /// TwoCrypto-NG factory pools with StableSwap math.
35    /// Newton solver, gamma parameter ignored. MATH contract version v0.1.0.
36    TwoCryptoStable,
37    /// Legacy 3-coin CryptoSwap (tricrypto2: USDT/WBTC/WETH).
38    /// Newton solver for y.
39    TriCryptoV1,
40    /// TriCrypto-NG factory pools.
41    /// Hybrid cubic + Newton solver.
42    TriCryptoNG,
43}
44
45impl CurveVariant {
46    /// Returns the variant name as used in curve-math's `Pool` enum.
47    pub fn as_str(&self) -> &'static str {
48        match self {
49            Self::StableSwapV0 => "StableSwapV0",
50            Self::StableSwapV1 => "StableSwapV1",
51            Self::StableSwapV2 => "StableSwapV2",
52            Self::StableSwapSTETH => "StableSwapSTETH",
53            Self::StableSwapALend => "StableSwapALend",
54            Self::StableSwapNG => "StableSwapNG",
55            Self::StableSwapMeta => "StableSwapMeta",
56            Self::TwoCryptoV1 => "TwoCryptoV1",
57            Self::TwoCryptoNG => "TwoCryptoNG",
58            Self::TwoCryptoStable => "TwoCryptoStable",
59            Self::TriCryptoV1 => "TriCryptoV1",
60            Self::TriCryptoNG => "TriCryptoNG",
61        }
62    }
63}
64
65impl std::fmt::Display for CurveVariant {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        f.write_str(self.as_str())
68    }
69}
70
71impl std::str::FromStr for CurveVariant {
72    type Err = String;
73
74    fn from_str(s: &str) -> Result<Self, Self::Err> {
75        match s {
76            "StableSwapV0" => Ok(Self::StableSwapV0),
77            "StableSwapV1" => Ok(Self::StableSwapV1),
78            "StableSwapV2" => Ok(Self::StableSwapV2),
79            "StableSwapSTETH" => Ok(Self::StableSwapSTETH),
80            "StableSwapALend" => Ok(Self::StableSwapALend),
81            "StableSwapNG" => Ok(Self::StableSwapNG),
82            "StableSwapMeta" => Ok(Self::StableSwapMeta),
83            "TwoCryptoV1" => Ok(Self::TwoCryptoV1),
84            "TwoCryptoNG" => Ok(Self::TwoCryptoNG),
85            "TwoCryptoStable" => Ok(Self::TwoCryptoStable),
86            "TriCryptoV1" => Ok(Self::TriCryptoV1),
87            "TriCryptoNG" => Ok(Self::TriCryptoNG),
88            _ => Err(format!("unknown CurveVariant: {s}")),
89        }
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn from_str_roundtrip() {
99        let variants = [
100            CurveVariant::StableSwapV0,
101            CurveVariant::StableSwapV1,
102            CurveVariant::StableSwapV2,
103            CurveVariant::StableSwapSTETH,
104            CurveVariant::StableSwapALend,
105            CurveVariant::StableSwapNG,
106            CurveVariant::StableSwapMeta,
107            CurveVariant::TwoCryptoV1,
108            CurveVariant::TwoCryptoNG,
109            CurveVariant::TwoCryptoStable,
110            CurveVariant::TriCryptoV1,
111            CurveVariant::TriCryptoNG,
112        ];
113        for v in variants {
114            let s = v.as_str();
115            let parsed: CurveVariant = s.parse().unwrap();
116            assert_eq!(parsed, v);
117        }
118    }
119
120    #[test]
121    fn from_str_unknown() {
122        let result: Result<CurveVariant, _> = "FooBar".parse();
123        assert!(result.is_err());
124    }
125}