Skip to main content

tycho_execution/encoding/evm/swap_encoder/
swap_encoder_registry.rs

1use std::{collections::HashMap, str::FromStr};
2
3use tycho_common::{models::Chain, Bytes};
4
5use crate::encoding::{
6    errors::EncodingError,
7    evm::{
8        constants::{DEFAULT_EXECUTORS_JSON, PROTOCOL_SPECIFIC_CONFIG},
9        swap_encoder::{
10            aerodrome_v1::AerodromeV1SwapEncoder, balancer_v2::BalancerV2SwapEncoder,
11            balancer_v3::BalancerV3SwapEncoder, bebop::BebopSwapEncoder, curve::CurveSwapEncoder,
12            ekubo::EkuboSwapEncoder, ekubo_v3::EkuboV3SwapEncoder, erc_4626::ERC4626SwapEncoder,
13            etherfi::EtherfiSwapEncoder, fluid_v1::FluidV1SwapEncoder,
14            hashflow::HashflowSwapEncoder, liquidity_party::LiquidityPartySwapEncoder,
15            liquorice::LiquoriceSwapEncoder, maverick_v2::MaverickV2SwapEncoder,
16            rocketpool::RocketpoolSwapEncoder, slipstreams::SlipstreamsSwapEncoder,
17            uniswap_v2::UniswapV2SwapEncoder, uniswap_v3::UniswapV3SwapEncoder,
18            uniswap_v4::UniswapV4SwapEncoder, weth::WethSwapEncoder,
19        },
20    },
21    swap_encoder::SwapEncoder,
22};
23
24/// Registry containing all supported `SwapEncoders`.
25#[derive(Clone)]
26pub struct SwapEncoderRegistry {
27    chain: Chain,
28    /// A hashmap containing the protocol system as a key and the `SwapEncoder` as a value.
29    encoders: HashMap<String, Box<dyn SwapEncoder>>,
30}
31
32impl SwapEncoderRegistry {
33    pub fn new(chain: Chain) -> Self {
34        Self { chain, encoders: HashMap::new() }
35    }
36
37    /// Creates a new registry pre-populated with all default encoders for the given chain.
38    pub fn new_with_defaults(chain: Chain) -> Result<Self, EncodingError> {
39        Self::new(chain).add_default_encoders(None)
40    }
41
42    /// Populates the registry with the default `SwapEncoders` for the given blockchain by
43    /// parsing the executors' addresses in the file at the given path.
44    pub fn add_default_encoders(
45        mut self,
46        executors_addresses: Option<String>,
47    ) -> Result<Self, EncodingError> {
48        let config_str = if let Some(addresses) = executors_addresses {
49            addresses
50        } else {
51            DEFAULT_EXECUTORS_JSON.to_string()
52        };
53        let config: HashMap<Chain, HashMap<String, String>> = serde_json::from_str(&config_str)?;
54        let executors = config
55            .get(&self.chain)
56            .ok_or(EncodingError::FatalError("No executors found for chain".to_string()))?;
57
58        let protocol_specific_config: HashMap<Chain, HashMap<String, HashMap<String, String>>> =
59            serde_json::from_str(PROTOCOL_SPECIFIC_CONFIG)?;
60        let protocol_specific_config = protocol_specific_config
61            .get(&self.chain)
62            .ok_or(EncodingError::FatalError(
63                "No protocol specific config found for chain".to_string(),
64            ))?;
65        for (protocol, executor_address) in executors {
66            let encoder = self.create_encoder(
67                protocol,
68                Bytes::from_str(executor_address).map_err(|_| {
69                    EncodingError::FatalError(format!(
70                        "Invalid executor address for protocol {}",
71                        protocol
72                    ))
73                })?,
74                protocol_specific_config
75                    .get(protocol)
76                    .cloned(),
77            )?;
78            self.encoders
79                .insert(protocol.to_string(), encoder);
80        }
81        Ok(self)
82    }
83
84    /// Adds an encoder to the registry, replacing any existing encoder for the same protocol.
85    pub fn register_encoder(mut self, protocol: &str, encoder: Box<dyn SwapEncoder>) -> Self {
86        self.encoders
87            .insert(protocol.to_string(), encoder);
88        self
89    }
90
91    #[allow(clippy::borrowed_box)]
92    pub fn get_encoder(&self, protocol_system: &str) -> Option<&Box<dyn SwapEncoder>> {
93        self.encoders.get(protocol_system)
94    }
95
96    fn create_encoder(
97        &self,
98        protocol_system: &str,
99        executor_address: Bytes,
100        config: Option<HashMap<String, String>>,
101    ) -> Result<Box<dyn SwapEncoder>, EncodingError> {
102        match protocol_system {
103            "uniswap_v2" | "sushiswap_v2" | "pancakeswap_v2" | "quickswap_v2" => {
104                Ok(Box::new(UniswapV2SwapEncoder::new(executor_address, self.chain, config)?))
105            }
106            "aerodrome_v1" => {
107                Ok(Box::new(AerodromeV1SwapEncoder::new(executor_address, self.chain, config)?))
108            }
109            "vm:balancer_v2" => {
110                Ok(Box::new(BalancerV2SwapEncoder::new(executor_address, self.chain, config)?))
111            }
112            "uniswap_v3" | "pancakeswap_v3" => {
113                Ok(Box::new(UniswapV3SwapEncoder::new(executor_address, self.chain, config)?))
114            }
115            "uniswap_v4" => {
116                Ok(Box::new(UniswapV4SwapEncoder::new(executor_address, self.chain, config)?))
117            }
118            "ekubo_v2" => {
119                Ok(Box::new(EkuboSwapEncoder::new(executor_address, self.chain, config)?))
120            }
121            "ekubo_v3" => {
122                Ok(Box::new(EkuboV3SwapEncoder::new(executor_address, self.chain, config)?))
123            }
124            "vm:curve" => {
125                Ok(Box::new(CurveSwapEncoder::new(executor_address, self.chain, config)?))
126            }
127            "vm:maverick_v2" => {
128                Ok(Box::new(MaverickV2SwapEncoder::new(executor_address, self.chain, config)?))
129            }
130            "vm:balancer_v3" => {
131                Ok(Box::new(BalancerV3SwapEncoder::new(executor_address, self.chain, config)?))
132            }
133            "rfq:bebop" => {
134                Ok(Box::new(BebopSwapEncoder::new(executor_address, self.chain, config)?))
135            }
136            "rfq:hashflow" => {
137                Ok(Box::new(HashflowSwapEncoder::new(executor_address, self.chain, config)?))
138            }
139            "rfq:liquorice" => {
140                Ok(Box::new(LiquoriceSwapEncoder::new(executor_address, self.chain, config)?))
141            }
142            "fluid_v1" => {
143                Ok(Box::new(FluidV1SwapEncoder::new(executor_address, self.chain, config)?))
144            }
145            "vm:liquidityparty" => {
146                Ok(Box::new(LiquidityPartySwapEncoder::new(executor_address, self.chain, config)?))
147            }
148            "aerodrome_slipstreams" => {
149                Ok(Box::new(SlipstreamsSwapEncoder::new(executor_address, self.chain, config)?))
150            }
151            "rocketpool" => {
152                Ok(Box::new(RocketpoolSwapEncoder::new(executor_address, self.chain, config)?))
153            }
154            "erc4626" => {
155                Ok(Box::new(ERC4626SwapEncoder::new(executor_address, self.chain, config)?))
156            }
157            "velodrome_slipstreams" => {
158                Ok(Box::new(SlipstreamsSwapEncoder::new(executor_address, self.chain, config)?))
159            }
160            "weth" => Ok(Box::new(WethSwapEncoder::new(executor_address, self.chain, config)?)),
161            "etherfi" => {
162                Ok(Box::new(EtherfiSwapEncoder::new(executor_address, self.chain, config)?))
163            }
164            _ => Err(EncodingError::FatalError(format!(
165                "Unknown protocol system: {}",
166                protocol_system
167            ))),
168        }
169    }
170}