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_addresses: Option<String>,
24    router_address: Option<Bytes>,
25    swapper_pk: Option<String>,
26    historical_trade: bool,
27}
28
29impl Default for TychoRouterEncoderBuilder {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35impl TychoRouterEncoderBuilder {
36    pub fn new() -> Self {
37        TychoRouterEncoderBuilder {
38            chain: None,
39            executors_addresses: None,
40            router_address: None,
41            swapper_pk: None,
42            user_transfer_type: None,
43            historical_trade: false,
44        }
45    }
46    pub fn chain(mut self, chain: Chain) -> Self {
47        self.chain = Some(chain);
48        self
49    }
50
51    pub fn user_transfer_type(mut self, user_transfer_type: UserTransferType) -> Self {
52        self.user_transfer_type = Some(user_transfer_type);
53        self
54    }
55
56    /// Sets the `executors_addresses` manually.
57    /// If it's not set, the default value will be used (contents of config/executor_addresses.json)
58    pub fn executors_addresses(mut self, executors_addresses: String) -> Self {
59        self.executors_addresses = Some(executors_addresses);
60        self
61    }
62
63    /// Sets the `router_address` manually.
64    /// If it's not set, the default router address will be used (config/router_addresses.json)
65    pub fn router_address(mut self, router_address: Bytes) -> Self {
66        self.router_address = Some(router_address);
67        self
68    }
69
70    /// Sets the `historical_trade` manually to true.
71    /// If set to true, it means that the encoded trade will be used in an historical block (as a
72    /// test) and not in the current one. This is relevant for checking token approvals in some
73    /// protocols (like Balancer v2).
74    pub fn historical_trade(mut self) -> Self {
75        self.historical_trade = true;
76        self
77    }
78
79    /// Sets the `swapper_pk` for the encoder. This is used to sign permit2 objects. This is only
80    /// needed if you intend to get the full calldata for the transfer. We do not recommend
81    /// using this option, you should sign and create the function calldata entirely on your
82    /// own.
83    #[deprecated(
84        note = "This is deprecated and will be removed in the future. You should sign and create the function calldata on your own."
85    )]
86    pub fn swapper_pk(mut self, swapper_pk: String) -> Self {
87        self.swapper_pk = Some(swapper_pk);
88        self
89    }
90
91    /// Builds the `TychoRouterEncoder` instance using the configured chain.
92    /// Returns an error if either the chain has not been set.
93    pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> {
94        if let (Some(chain), Some(user_transfer_type)) = (self.chain, self.user_transfer_type) {
95            let tycho_router_address;
96            if let Some(address) = self.router_address {
97                tycho_router_address = address;
98            } else {
99                let default_routers: HashMap<Chain, Bytes> =
100                    serde_json::from_str(DEFAULT_ROUTERS_JSON)?;
101                tycho_router_address = default_routers
102                    .get(&chain)
103                    .ok_or(EncodingError::FatalError(
104                        "No default router address found for chain".to_string(),
105                    ))?
106                    .to_owned();
107            }
108
109            let swap_encoder_registry =
110                SwapEncoderRegistry::new(self.executors_addresses.clone(), chain)?;
111
112            let signer = if let Some(pk) = self.swapper_pk {
113                let pk = B256::from_str(&pk).map_err(|_| {
114                    EncodingError::FatalError("Invalid swapper private key provided".to_string())
115                })?;
116                Some(PrivateKeySigner::from_bytes(&pk).map_err(|_| {
117                    EncodingError::FatalError("Failed to create signer".to_string())
118                })?)
119            } else {
120                None
121            };
122
123            Ok(Box::new(TychoRouterEncoder::new(
124                chain,
125                swap_encoder_registry,
126                tycho_router_address,
127                user_transfer_type,
128                signer,
129                self.historical_trade,
130            )?))
131        } else {
132            Err(EncodingError::FatalError(
133                "Please set the chain and user transfer type before building the encoder"
134                    .to_string(),
135            ))
136        }
137    }
138}
139
140/// Builder pattern for constructing a `TychoExecutorEncoder` with customizable options.
141pub struct TychoExecutorEncoderBuilder {
142    chain: Option<Chain>,
143    executors_addresses: Option<String>,
144}
145
146impl Default for TychoExecutorEncoderBuilder {
147    fn default() -> Self {
148        Self::new()
149    }
150}
151
152impl TychoExecutorEncoderBuilder {
153    pub fn new() -> Self {
154        TychoExecutorEncoderBuilder { chain: None, executors_addresses: None }
155    }
156    pub fn chain(mut self, chain: Chain) -> Self {
157        self.chain = Some(chain);
158        self
159    }
160
161    /// Sets the `executors_addresses` manually.
162    /// If it's not set, the default path will be used (config/executor_addresses.json)
163    pub fn executors_addresses(mut self, executors_addresses: String) -> Self {
164        self.executors_addresses = Some(executors_addresses);
165        self
166    }
167
168    /// Builds the `TychoExecutorEncoder` instance using the configured chain and strategy.
169    /// Returns an error if either the chain or strategy has not been set.
170    pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> {
171        if let Some(chain) = self.chain {
172            let swap_encoder_registry =
173                SwapEncoderRegistry::new(self.executors_addresses.clone(), chain)?;
174            Ok(Box::new(TychoExecutorEncoder::new(swap_encoder_registry)?))
175        } else {
176            Err(EncodingError::FatalError(
177                "Please set the chain and strategy before building the encoder".to_string(),
178            ))
179        }
180    }
181}