tycho_execution/encoding/evm/
encoder_builders.rs

1use std::{collections::HashMap, str::FromStr};
2
3use alloy::{primitives::B256, signers::local::PrivateKeySigner};
4use tycho_common::{models::Chain, Bytes};
5
6use crate::encoding::{
7    errors::EncodingError,
8    evm::{
9        constants::DEFAULT_ROUTERS_JSON,
10        swap_encoder::swap_encoder_registry::SwapEncoderRegistry,
11        tycho_encoders::{TychoExecutorEncoder, TychoRouterEncoder},
12    },
13    models::UserTransferType,
14    tycho_encoder::TychoEncoder,
15};
16
17/// Builder pattern for constructing a `TychoRouterEncoder` with customizable options.
18///
19/// This struct allows setting a chain and strategy encoder before building the final encoder.
20pub struct TychoRouterEncoderBuilder {
21    chain: Option<Chain>,
22    user_transfer_type: Option<UserTransferType>,
23    executors_file_path: Option<String>,
24    router_address: Option<Bytes>,
25    swapper_pk: Option<String>,
26}
27
28impl Default for TychoRouterEncoderBuilder {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34impl TychoRouterEncoderBuilder {
35    pub fn new() -> Self {
36        TychoRouterEncoderBuilder {
37            chain: None,
38            executors_file_path: None,
39            router_address: None,
40            swapper_pk: None,
41            user_transfer_type: None,
42        }
43    }
44    pub fn chain(mut self, chain: Chain) -> Self {
45        self.chain = Some(chain);
46        self
47    }
48
49    pub fn user_transfer_type(mut self, user_transfer_type: UserTransferType) -> Self {
50        self.user_transfer_type = Some(user_transfer_type);
51        self
52    }
53
54    /// Sets the `executors_file_path` manually.
55    /// If it's not set, the default path will be used (config/executor_addresses.json)
56    pub fn executors_file_path(mut self, executors_file_path: String) -> Self {
57        self.executors_file_path = Some(executors_file_path);
58        self
59    }
60
61    /// Sets the `router_address` manually.
62    /// If it's not set, the default router address will be used (config/router_addresses.json)
63    pub fn router_address(mut self, router_address: Bytes) -> Self {
64        self.router_address = Some(router_address);
65        self
66    }
67
68    /// Sets the `swapper_pk` for the encoder. This is used to sign permit2 objects. This is only
69    /// needed if you intend to get the full calldata for the transfer. We do not recommend
70    /// using this option, you should sign and create the function calldata entirely on your
71    /// own.
72    #[deprecated(
73        note = "This is deprecated and will be removed in the future. You should sign and create the function calldata on your own."
74    )]
75    pub fn swapper_pk(mut self, swapper_pk: String) -> Self {
76        self.swapper_pk = Some(swapper_pk);
77        self
78    }
79
80    /// Builds the `TychoRouterEncoder` instance using the configured chain.
81    /// Returns an error if either the chain has not been set.
82    pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> {
83        if let (Some(chain), Some(user_transfer_type)) = (self.chain, self.user_transfer_type) {
84            let tycho_router_address;
85            if let Some(address) = self.router_address {
86                tycho_router_address = address;
87            } else {
88                let default_routers: HashMap<Chain, Bytes> =
89                    serde_json::from_str(DEFAULT_ROUTERS_JSON)?;
90                tycho_router_address = default_routers
91                    .get(&chain)
92                    .ok_or(EncodingError::FatalError(
93                        "No default router address found for chain".to_string(),
94                    ))?
95                    .to_owned();
96            }
97
98            let swap_encoder_registry =
99                SwapEncoderRegistry::new(self.executors_file_path.clone(), chain)?;
100
101            let signer = if let Some(pk) = self.swapper_pk {
102                let pk = B256::from_str(&pk).map_err(|_| {
103                    EncodingError::FatalError("Invalid swapper private key provided".to_string())
104                })?;
105                Some(PrivateKeySigner::from_bytes(&pk).map_err(|_| {
106                    EncodingError::FatalError("Failed to create signer".to_string())
107                })?)
108            } else {
109                None
110            };
111
112            Ok(Box::new(TychoRouterEncoder::new(
113                chain,
114                swap_encoder_registry,
115                tycho_router_address,
116                user_transfer_type,
117                signer,
118            )?))
119        } else {
120            Err(EncodingError::FatalError(
121                "Please set the chain and user transfer type before building the encoder"
122                    .to_string(),
123            ))
124        }
125    }
126}
127
128/// Builder pattern for constructing a `TychoExecutorEncoder` with customizable options.
129pub struct TychoExecutorEncoderBuilder {
130    chain: Option<Chain>,
131    executors_file_path: Option<String>,
132}
133
134impl Default for TychoExecutorEncoderBuilder {
135    fn default() -> Self {
136        Self::new()
137    }
138}
139
140impl TychoExecutorEncoderBuilder {
141    pub fn new() -> Self {
142        TychoExecutorEncoderBuilder { chain: None, executors_file_path: None }
143    }
144    pub fn chain(mut self, chain: Chain) -> Self {
145        self.chain = Some(chain);
146        self
147    }
148
149    /// Sets the `executors_file_path` manually.
150    /// If it's not set, the default path will be used (config/executor_addresses.json)
151    pub fn executors_file_path(mut self, executors_file_path: String) -> Self {
152        self.executors_file_path = Some(executors_file_path);
153        self
154    }
155
156    /// Builds the `TychoExecutorEncoder` instance using the configured chain and strategy.
157    /// Returns an error if either the chain or strategy has not been set.
158    pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> {
159        if let Some(chain) = self.chain {
160            let swap_encoder_registry =
161                SwapEncoderRegistry::new(self.executors_file_path.clone(), chain)?;
162            Ok(Box::new(TychoExecutorEncoder::new(swap_encoder_registry)?))
163        } else {
164            Err(EncodingError::FatalError(
165                "Please set the chain and strategy before building the encoder".to_string(),
166            ))
167        }
168    }
169}