diff --git a/examples/quickstart/main.rs b/examples/quickstart/main.rs index 5b46e1d..ee89104 100644 --- a/examples/quickstart/main.rs +++ b/examples/quickstart/main.rs @@ -4,9 +4,11 @@ use num_bigint::BigUint; use tycho_core::{dto::ProtocolComponent, models::Chain, Bytes}; use tycho_execution::encoding::{ evm::{ - strategy_encoder::strategy_selector::EVMStrategySelector, tycho_encoder::EVMTychoEncoder, + strategy_encoder::strategy_encoder_registry::EVMStrategyEncoderRegistry, + tycho_encoder::EVMTychoEncoder, }, models::{Solution, Swap}, + strategy_encoder::StrategyEncoderRegistry, tycho_encoder::TychoEncoder, }; @@ -17,11 +19,14 @@ fn main() { Some("0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string()); let user_address = Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2") .expect("Failed to create user address"); + let executors_file_path = "src/encoding/config/executor_addresses.json"; // Initialize the encoder - let encoder = - EVMTychoEncoder::new(EVMStrategySelector, router_address, signer_pk, Chain::Ethereum) - .expect("Failed to create encoder"); + let strategy_encoder_registry = + EVMStrategyEncoderRegistry::new(Chain::Ethereum, executors_file_path, signer_pk.clone()) + .expect("Failed to create strategy encoder registry"); + let encoder = EVMTychoEncoder::new(strategy_encoder_registry, router_address) + .expect("Failed to create encoder"); // ------------------- Encode a simple swap ------------------- diff --git a/src/encoding/config/executor_addresses.json b/src/encoding/config/executor_addresses.json index 1be7d99..6e27a2d 100644 --- a/src/encoding/config/executor_addresses.json +++ b/src/encoding/config/executor_addresses.json @@ -1,8 +1,6 @@ { - "executors": { - "ethereum": { - "uniswap_v2": "0x5C2F5a71f67c01775180ADc06909288B4C329308", - "vm:balancer_v2": "0x543778987b293C7E8Cf0722BB2e935ba6f4068D4" - } + "ethereum": { + "uniswap_v2": "0x5C2F5a71f67c01775180ADc06909288B4C329308", + "vm:balancer_v2": "0x543778987b293C7E8Cf0722BB2e935ba6f4068D4" } } \ No newline at end of file diff --git a/src/encoding/evm/strategy_encoder/mod.rs b/src/encoding/evm/strategy_encoder/mod.rs index 0142707..a0cf652 100644 --- a/src/encoding/evm/strategy_encoder/mod.rs +++ b/src/encoding/evm/strategy_encoder/mod.rs @@ -1,2 +1,2 @@ +pub mod strategy_encoder_registry; mod strategy_encoders; -pub mod strategy_selector; diff --git a/src/encoding/evm/strategy_encoder/strategy_encoder_registry.rs b/src/encoding/evm/strategy_encoder/strategy_encoder_registry.rs new file mode 100644 index 0000000..cb11fa0 --- /dev/null +++ b/src/encoding/evm/strategy_encoder/strategy_encoder_registry.rs @@ -0,0 +1,53 @@ +use std::collections::HashMap; + +use tycho_core::models::Chain; + +use crate::encoding::{ + errors::EncodingError, + evm::{ + strategy_encoder::strategy_encoders::{ExecutorStrategyEncoder, SplitSwapStrategyEncoder}, + swap_encoder::registry::SwapEncoderRegistry, + }, + models::Solution, + strategy_encoder::{StrategyEncoder, StrategyEncoderRegistry}, +}; + +pub struct EVMStrategyEncoderRegistry { + strategies: HashMap>, +} + +impl StrategyEncoderRegistry for EVMStrategyEncoderRegistry { + fn new( + chain: Chain, + executors_file_path: &str, + signer_pk: Option, + ) -> Result { + let swap_encoder_registry = SwapEncoderRegistry::new(executors_file_path, Chain::Ethereum)?; + + let mut strategies: HashMap> = HashMap::new(); + strategies.insert( + "executor".to_string(), + Box::new(ExecutorStrategyEncoder::new(swap_encoder_registry.clone())), + ); + if let Some(signer) = signer_pk { + strategies.insert( + "split_swap".to_string(), + Box::new( + SplitSwapStrategyEncoder::new(signer, chain, swap_encoder_registry).unwrap(), + ), + ); + } + Ok(Self { strategies }) + } + fn get_encoder(&self, solution: &Solution) -> Result<&Box, EncodingError> { + if solution.direct_execution { + self.strategies + .get("executor") + .ok_or(EncodingError::FatalError("Executor strategy not found".to_string())) + } else { + self.strategies + .get("split_swap") + .ok_or(EncodingError::FatalError("Split swap strategy not found. Please pass the signer private key to the StrategySelector constructor".to_string())) + } + } +} diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 8dc9eb7..d65d926 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -10,11 +10,12 @@ use crate::encoding::{ evm::{ approvals::permit2::Permit2, constants::WETH_ADDRESS, - swap_encoder::SWAP_ENCODER_REGISTRY, + swap_encoder::registry::SwapEncoderRegistry, utils::{biguint_to_u256, bytes_to_address, encode_input, percentage_to_uint24}, }, models::{EncodingContext, NativeAction, Solution}, strategy_encoder::StrategyEncoder, + swap_encoder::SwapEncoder, }; pub trait EVMStrategyEncoder: StrategyEncoder { @@ -54,14 +55,19 @@ pub trait EVMStrategyEncoder: StrategyEncoder { } pub struct SplitSwapStrategyEncoder { + swap_encoder_registry: SwapEncoderRegistry, permit2: Permit2, selector: String, } impl SplitSwapStrategyEncoder { - pub fn new(signer_pk: String, chain: Chain) -> Result { + pub fn new( + signer_pk: String, + chain: Chain, + swap_encoder_registry: SwapEncoderRegistry, + ) -> Result { let selector = "swap(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string(); - Ok(Self { permit2: Permit2::new(signer_pk, chain)?, selector }) + Ok(Self { permit2: Permit2::new(signer_pk, chain)?, selector, swap_encoder_registry }) } } impl EVMStrategyEncoder for SplitSwapStrategyEncoder {} @@ -134,16 +140,14 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { let mut swaps = vec![]; for swap in solution.swaps.iter() { - let registry = SWAP_ENCODER_REGISTRY - .read() - .map_err(|_| { - EncodingError::FatalError( - "Failed to read the swap encoder registry".to_string(), - ) + let swap_encoder = self + .get_swap_encoder(&swap.component.protocol_system) + .ok_or_else(|| { + EncodingError::InvalidInput(format!( + "Swap encoder not found for protocol: {}", + swap.component.protocol_system + )) })?; - let swap_encoder = registry - .get_encoder(&swap.component.protocol_system) - .expect("Swap encoder not found"); let encoding_context = EncodingContext { receiver: router_address.clone(), @@ -201,11 +205,24 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { let contract_interaction = encode_input(&self.selector, method_calldata); Ok((contract_interaction, router_address)) } + + fn get_swap_encoder(&self, protocol_system: &str) -> Option<&Box> { + self.swap_encoder_registry + .get_encoder(protocol_system) + } } /// This strategy encoder is used for solutions that are sent directly to the pool. /// Only 1 solution with 1 swap is supported. -pub struct ExecutorStrategyEncoder {} +pub struct ExecutorStrategyEncoder { + swap_encoder_registry: SwapEncoderRegistry, +} + +impl ExecutorStrategyEncoder { + pub fn new(swap_encoder_registry: SwapEncoderRegistry) -> Self { + Self { swap_encoder_registry } + } +} impl EVMStrategyEncoder for ExecutorStrategyEncoder {} impl StrategyEncoder for ExecutorStrategyEncoder { fn encode_strategy( @@ -223,13 +240,9 @@ impl StrategyEncoder for ExecutorStrategyEncoder { .swaps .first() .ok_or_else(|| EncodingError::InvalidInput("No swaps found in solution".to_string()))?; - let registry = SWAP_ENCODER_REGISTRY - .read() - .map_err(|_| { - EncodingError::FatalError("Failed to read the swap encoder registry".to_string()) - })?; - let swap_encoder = registry - .get_encoder(&swap.component.protocol_system) + + let swap_encoder = self + .get_swap_encoder(&swap.component.protocol_system) .ok_or_else(|| { EncodingError::InvalidInput(format!( "Swap encoder not found for protocol: {}", @@ -248,6 +261,10 @@ impl StrategyEncoder for ExecutorStrategyEncoder { .map_err(|_| EncodingError::FatalError("Invalid executor address".to_string()))?; Ok((protocol_data, executor_address)) } + fn get_swap_encoder(&self, protocol_system: &str) -> Option<&Box> { + self.swap_encoder_registry + .get_encoder(protocol_system) + } } #[cfg(test)] @@ -265,9 +282,15 @@ mod tests { models::Swap, }; + fn get_swap_encoder_registry() -> SwapEncoderRegistry { + SwapEncoderRegistry::new("src/encoding/config/executor_addresses.json", Chain::Ethereum) + .unwrap() + } + #[test] fn test_executor_strategy_encode() { - let encoder = ExecutorStrategyEncoder {}; + let swap_encoder_registry = get_swap_encoder_registry(); + let encoder = ExecutorStrategyEncoder::new(swap_encoder_registry); let token_in = Bytes::from("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); let token_out = Bytes::from("0x6b175474e89094c44da98b954eedeac495271d0f"); @@ -373,8 +396,10 @@ mod tests { token_out: dai.clone(), split: 0f64, }; - - let encoder = SplitSwapStrategyEncoder::new(private_key, Chain::Ethereum).unwrap(); + let swap_encoder_registry = get_swap_encoder_registry(); + let encoder = + SplitSwapStrategyEncoder::new(private_key, Chain::Ethereum, swap_encoder_registry) + .unwrap(); let solution = Solution { exact_out: false, given_token: weth, @@ -608,8 +633,10 @@ mod tests { token_out: usdc.clone(), split: 0f64, }; - - let encoder = SplitSwapStrategyEncoder::new(private_key, Chain::Ethereum).unwrap(); + let swap_encoder_registry = get_swap_encoder_registry(); + let encoder = + SplitSwapStrategyEncoder::new(private_key, Chain::Ethereum, swap_encoder_registry) + .unwrap(); let solution = Solution { exact_out: false, given_token: weth, diff --git a/src/encoding/evm/strategy_encoder/strategy_selector.rs b/src/encoding/evm/strategy_encoder/strategy_selector.rs deleted file mode 100644 index 3ba9de3..0000000 --- a/src/encoding/evm/strategy_encoder/strategy_selector.rs +++ /dev/null @@ -1,30 +0,0 @@ -use tycho_core::models::Chain; - -use crate::encoding::{ - errors::EncodingError, - evm::strategy_encoder::strategy_encoders::{ExecutorStrategyEncoder, SplitSwapStrategyEncoder}, - models::Solution, - strategy_encoder::{StrategyEncoder, StrategySelector}, -}; - -pub struct EVMStrategySelector; - -impl StrategySelector for EVMStrategySelector { - fn select_strategy( - &self, - solution: &Solution, - signer: Option, - chain: Chain, - ) -> Result, EncodingError> { - if solution.direct_execution { - Ok(Box::new(ExecutorStrategyEncoder {})) - } else { - let signer_pk = signer.ok_or_else(|| { - EncodingError::FatalError( - "Signer is required for SplitSwapStrategyEncoder".to_string(), - ) - })?; - Ok(Box::new(SplitSwapStrategyEncoder::new(signer_pk, chain)?)) - } - } -} diff --git a/src/encoding/evm/swap_encoder/builder.rs b/src/encoding/evm/swap_encoder/builder.rs index cd5525b..d0b8eeb 100644 --- a/src/encoding/evm/swap_encoder/builder.rs +++ b/src/encoding/evm/swap_encoder/builder.rs @@ -1,4 +1,5 @@ use crate::encoding::{ + errors::EncodingError, evm::swap_encoder::swap_encoders::{BalancerV2SwapEncoder, UniswapV2SwapEncoder}, swap_encoder::SwapEncoder, }; @@ -16,11 +17,14 @@ impl SwapEncoderBuilder { } } - pub fn build(self) -> Result, String> { + pub fn build(self) -> Result, EncodingError> { match self.protocol_system.as_str() { "uniswap_v2" => Ok(Box::new(UniswapV2SwapEncoder::new(self.executor_address))), "vm:balancer_v2" => Ok(Box::new(BalancerV2SwapEncoder::new(self.executor_address))), - _ => Err(format!("Unknown protocol system: {}", self.protocol_system)), + _ => Err(EncodingError::FatalError(format!( + "Unknown protocol system: {}", + self.protocol_system + ))), } } } diff --git a/src/encoding/evm/swap_encoder/mod.rs b/src/encoding/evm/swap_encoder/mod.rs index 1148d2d..8d5bb3a 100644 --- a/src/encoding/evm/swap_encoder/mod.rs +++ b/src/encoding/evm/swap_encoder/mod.rs @@ -1,19 +1,3 @@ mod builder; -mod registry; +pub mod registry; mod swap_encoders; - -use std::sync::RwLock; - -use lazy_static::lazy_static; -use tycho_core::dto::Chain; - -use crate::encoding::evm::swap_encoder::registry::{Config, SwapEncoderRegistry}; - -// TODO: init this at the higher level at some point -lazy_static! { - pub static ref SWAP_ENCODER_REGISTRY: RwLock = { - let config = Config::from_file("src/encoding/config/executor_addresses.json") - .expect("Failed to load configuration file"); - RwLock::new(SwapEncoderRegistry::new(config, Chain::Ethereum)) - }; -} diff --git a/src/encoding/evm/swap_encoder/registry.rs b/src/encoding/evm/swap_encoder/registry.rs index 06e6147..639dfc0 100644 --- a/src/encoding/evm/swap_encoder/registry.rs +++ b/src/encoding/evm/swap_encoder/registry.rs @@ -1,33 +1,32 @@ use std::{collections::HashMap, fs}; -use serde::Deserialize; -use tycho_core::dto::Chain; +use tycho_core::models::Chain; use crate::encoding::{ errors::EncodingError, evm::swap_encoder::builder::SwapEncoderBuilder, swap_encoder::SwapEncoder, }; +#[derive(Clone)] pub struct SwapEncoderRegistry { encoders: HashMap>, } impl SwapEncoderRegistry { - pub fn new(config: Config, blockchain: Chain) -> Self { + pub fn new(executors_file_path: &str, blockchain: Chain) -> Result { + let config_str = fs::read_to_string(executors_file_path)?; + let config: HashMap> = serde_json::from_str(&config_str)?; let mut encoders = HashMap::new(); let executors = config - .executors .get(&blockchain) - .unwrap_or_else(|| panic!("No executors found for blockchain: {}", blockchain)); + .ok_or(EncodingError::FatalError("No executors found for blockchain".to_string()))?; for (protocol, executor_address) in executors { let builder = SwapEncoderBuilder::new(protocol, executor_address); - let encoder = builder.build().unwrap_or_else(|_| { - panic!("Failed to build swap encoder for protocol: {}", protocol) - }); + let encoder = builder.build()?; encoders.insert(protocol.to_string(), encoder); } - Self { encoders } + Ok(Self { encoders }) } #[allow(clippy::borrowed_box)] @@ -35,17 +34,3 @@ impl SwapEncoderRegistry { self.encoders.get(protocol_system) } } - -#[derive(Deserialize)] -pub struct Config { - pub executors: HashMap>, /* Blockchain -> {Protocol -> - * Executor address} mapping */ -} - -impl Config { - pub fn from_file(path: &str) -> Result { - let config_str = fs::read_to_string(path)?; - let config: Config = serde_json::from_str(&config_str)?; - Ok(config) - } -} diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 432b2b0..e3c573f 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -12,6 +12,7 @@ use crate::encoding::{ swap_encoder::SwapEncoder, }; +#[derive(Clone)] pub struct UniswapV2SwapEncoder { executor_address: String, executor_selector: String, @@ -59,8 +60,13 @@ impl SwapEncoder for UniswapV2SwapEncoder { fn executor_selector(&self) -> &str { &self.executor_selector } + + fn clone_box(&self) -> Box { + Box::new(self.clone()) + } } +#[derive(Clone)] pub struct UniswapV3SwapEncoder { executor_address: String, executor_selector: String, @@ -129,8 +135,12 @@ impl SwapEncoder for UniswapV3SwapEncoder { fn executor_selector(&self) -> &str { &self.executor_selector } + fn clone_box(&self) -> Box { + Box::new(self.clone()) + } } +#[derive(Clone)] pub struct BalancerV2SwapEncoder { executor_address: String, executor_selector: String, @@ -179,6 +189,9 @@ impl SwapEncoder for BalancerV2SwapEncoder { fn executor_selector(&self) -> &str { &self.executor_selector } + fn clone_box(&self) -> Box { + Box::new(self.clone()) + } } #[cfg(test)] diff --git a/src/encoding/evm/tycho_encoder.rs b/src/encoding/evm/tycho_encoder.rs index 3006ee3..3e41208 100644 --- a/src/encoding/evm/tycho_encoder.rs +++ b/src/encoding/evm/tycho_encoder.rs @@ -1,33 +1,26 @@ use std::str::FromStr; use num_bigint::BigUint; -use tycho_core::{models::Chain, Bytes}; +use tycho_core::Bytes; use crate::encoding::{ errors::EncodingError, evm::constants::{NATIVE_ADDRESS, WETH_ADDRESS}, models::{NativeAction, Solution, Transaction}, - strategy_encoder::StrategySelector, + strategy_encoder::StrategyEncoderRegistry, tycho_encoder::TychoEncoder, }; -pub struct EVMTychoEncoder { +pub struct EVMTychoEncoder { strategy_selector: S, - signer_pk: Option, - chain: Chain, router_address: Bytes, } -impl EVMTychoEncoder { - pub fn new( - strategy_selector: S, - router_address: String, - signer_pk: Option, - chain: Chain, - ) -> Result { +impl EVMTychoEncoder { + pub fn new(strategy_selector: S, router_address: String) -> Result { let router_address = Bytes::from_str(&router_address) .map_err(|_| EncodingError::FatalError("Invalid router address".to_string()))?; - Ok(EVMTychoEncoder { strategy_selector, signer_pk, chain, router_address }) + Ok(EVMTychoEncoder { strategy_selector, router_address }) } } @@ -74,7 +67,7 @@ impl EVMTychoEncoder { } } -impl TychoEncoder for EVMTychoEncoder { +impl TychoEncoder for EVMTychoEncoder { fn encode_router_calldata( &self, solutions: Vec, @@ -88,11 +81,9 @@ impl TychoEncoder for EVMTychoEncoder { .clone() .unwrap_or(self.router_address.clone()); - let strategy = self.strategy_selector.select_strategy( - solution, - self.signer_pk.clone(), - self.chain, - )?; + let strategy = self + .strategy_selector + .get_encoder(solution)?; let (contract_interaction, target_address) = strategy.encode_strategy(solution.clone(), router_address)?; @@ -113,25 +104,36 @@ impl TychoEncoder for EVMTychoEncoder { #[cfg(test)] mod tests { + use tycho_core::models::Chain; + use tycho_core::dto::ProtocolComponent; use super::*; + use crate::encoding::{strategy_encoder::StrategyEncoder, swap_encoder::SwapEncoder}; use crate::encoding::{models::Swap, strategy_encoder::StrategyEncoder}; - struct MockStrategySelector; + struct MockStrategyRegistry { + strategy: Box, + } fn dai() -> Bytes { Bytes::from_str("0x6b175474e89094c44da98b954eedeac495271d0f").unwrap() } - impl StrategySelector for MockStrategySelector { - fn select_strategy( + impl StrategyEncoderRegistry for MockStrategyRegistry { + fn new( + _chain: Chain, + _executors_file_path: &str, + _signer_pk: Option, + ) -> Result { + Ok(Self { strategy: Box::new(MockStrategy) }) + } + + fn get_encoder( &self, _solution: &Solution, - _signer: Option, - _chain: Chain, - ) -> Result, EncodingError> { - Ok(Box::new(MockStrategy)) + ) -> Result<&Box, EncodingError> { + Ok(&self.strategy) } } @@ -150,15 +152,17 @@ mod tests { Bytes::from_str("0xabcd").unwrap(), )) } + + fn get_swap_encoder(&self, _protocol_system: &str) -> Option<&Box> { + None + } } - fn get_mocked_tycho_encoder() -> EVMTychoEncoder { - let strategy_selector = MockStrategySelector; + fn get_mocked_tycho_encoder() -> EVMTychoEncoder { + let strategy_selector = MockStrategyRegistry::new(Chain::Ethereum, "", None).unwrap(); EVMTychoEncoder::new( strategy_selector, "0x1234567890abcdef1234567890abcdef12345678".to_string(), - Some("0xabcdef".to_string()), - Chain::Ethereum, ) .unwrap() } diff --git a/src/encoding/mod.rs b/src/encoding/mod.rs index 255b40d..502e336 100644 --- a/src/encoding/mod.rs +++ b/src/encoding/mod.rs @@ -2,6 +2,6 @@ mod errors; #[cfg(feature = "evm")] pub mod evm; pub mod models; -mod strategy_encoder; +pub mod strategy_encoder; mod swap_encoder; pub mod tycho_encoder; diff --git a/src/encoding/strategy_encoder.rs b/src/encoding/strategy_encoder.rs index 94e4e19..04d23e7 100644 --- a/src/encoding/strategy_encoder.rs +++ b/src/encoding/strategy_encoder.rs @@ -1,6 +1,6 @@ use tycho_core::{models::Chain, Bytes}; -use crate::encoding::{errors::EncodingError, models::Solution}; +use crate::encoding::{errors::EncodingError, models::Solution, swap_encoder::SwapEncoder}; pub trait StrategyEncoder { fn encode_strategy( @@ -8,13 +8,19 @@ pub trait StrategyEncoder { to_encode: Solution, router_address: Bytes, ) -> Result<(Vec, Bytes), EncodingError>; + + #[allow(clippy::borrowed_box)] + fn get_swap_encoder(&self, protocol_system: &str) -> Option<&Box>; } -pub trait StrategySelector { - fn select_strategy( - &self, - solution: &Solution, +pub trait StrategyEncoderRegistry { + fn new( + chain: Chain, + executors_file_path: &str, signer_pk: Option, - chain_id: Chain, - ) -> Result, EncodingError>; + ) -> Result + where + Self: Sized; + #[allow(clippy::borrowed_box)] + fn get_encoder(&self, solution: &Solution) -> Result<&Box, EncodingError>; } diff --git a/src/encoding/swap_encoder.rs b/src/encoding/swap_encoder.rs index d350f1e..4247de5 100644 --- a/src/encoding/swap_encoder.rs +++ b/src/encoding/swap_encoder.rs @@ -2,7 +2,6 @@ use crate::encoding::{ errors::EncodingError, models::{EncodingContext, Swap}, }; -#[allow(dead_code)] pub trait SwapEncoder: Sync + Send { fn new(executor_address: String) -> Self where @@ -14,4 +13,14 @@ pub trait SwapEncoder: Sync + Send { ) -> Result, EncodingError>; fn executor_address(&self) -> &str; fn executor_selector(&self) -> &str; + + /// Clones the swap encoder as a trait object. + /// This allows the encoder to be cloned when it is being used as a `Box`. + fn clone_box(&self) -> Box; +} + +impl Clone for Box { + fn clone(&self) -> Box { + self.clone_box() + } } diff --git a/src/encoding/tycho_encoder.rs b/src/encoding/tycho_encoder.rs index 42d92f6..8ee054e 100644 --- a/src/encoding/tycho_encoder.rs +++ b/src/encoding/tycho_encoder.rs @@ -1,10 +1,10 @@ use crate::encoding::{ errors::EncodingError, models::{Solution, Transaction}, - strategy_encoder::StrategySelector, + strategy_encoder::StrategyEncoderRegistry, }; -pub trait TychoEncoder { +pub trait TychoEncoder { fn encode_router_calldata( &self, solutions: Vec,