From facdf716bdb972013292918247583a4a74ae0bca Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Wed, 21 May 2025 18:00:19 +0100 Subject: [PATCH] feat: Add interacting_with to EncodedSolution - Remove encode_full_calldata from the TychoEncoder trait - Make the TychoExecutorEncoder use encode_solutions instead of encode_full_calldata - Update tycho-encode.rs accordingly Took 1 hour 3 minutes Took 12 seconds --- examples/encoding-example/main.rs | 24 +- src/bin/tycho-encode.rs | 18 +- src/encoding/evm/encoder_builders.rs | 2 +- src/encoding/evm/encoding_utils.rs | 3 +- .../evm/strategy_encoder/strategy_encoders.rs | 264 +++++------------- src/encoding/evm/tycho_encoders.rs | 141 +++++----- src/encoding/models.rs | 3 + src/encoding/tycho_encoder.rs | 18 +- 8 files changed, 174 insertions(+), 299 deletions(-) diff --git a/examples/encoding-example/main.rs b/examples/encoding-example/main.rs index 81685f9..b489310 100644 --- a/examples/encoding-example/main.rs +++ b/examples/encoding-example/main.rs @@ -61,17 +61,17 @@ fn main() { }; // Encode the solution - let tx = encoder - .encode_calldata(vec![solution.clone()]) + let encoded_solution = encoder + .encode_solutions(vec![solution.clone()]) .expect("Failed to encode router calldata")[0] .clone(); println!(" ====== Simple swap WETH -> USDC ======"); println!( - "The simple swap encoded transaction should be sent to address {:?} with the value of {:?} and the \ + "The simple swap encoded solution should be sent to address {:?} and selector {:?} and the \ following encoded data: {:?}", - tx.to, - tx.value, - hex::encode(tx.data) + encoded_solution.interacting_with, + encoded_solution.selector, + hex::encode(encoded_solution.swaps) ); // ------------------- Encode a swap with multiple splits ------------------- @@ -134,17 +134,17 @@ fn main() { complex_solution.swaps = vec![swap_weth_dai, swap_weth_wbtc, swap_dai_usdc, swap_wbtc_usdc]; // Encode the solution - let complex_tx = encoder - .encode_calldata(vec![complex_solution]) + let complex_encoded_solution = encoder + .encode_solutions(vec![complex_solution]) .expect("Failed to encode router calldata")[0] .clone(); println!(" ====== Complex split swap WETH -> USDC ======"); println!( - "The complex solution encoded transaction should be sent to address {:?} with the value of {:?} and the \ + "The complex swaps encoded solution should be sent to address {:?} and selector {:?} and the \ following encoded data: {:?}", - complex_tx.to, - complex_tx.value, - hex::encode(complex_tx.data) + complex_encoded_solution.interacting_with, + complex_encoded_solution.selector, + hex::encode(complex_encoded_solution.swaps) ); } diff --git a/src/bin/tycho-encode.rs b/src/bin/tycho-encode.rs index a1fcf00..fa21fbd 100644 --- a/src/bin/tycho-encode.rs +++ b/src/bin/tycho-encode.rs @@ -1,5 +1,6 @@ use std::io::{self, Read}; +use alloy_sol_types::SolValue; use clap::{Parser, Subcommand}; use tycho_common::{hex_bytes::Bytes, models::Chain}; use tycho_execution::encoding::{ @@ -99,11 +100,20 @@ fn main() -> Result<(), Box> { .build()?, }; - let transactions = encoder.encode_calldata(vec![solution])?; + let encoded_solutions = encoder.encode_solutions(vec![solution])?; let encoded = serde_json::json!({ - "to": format!("0x{}", hex::encode(&transactions[0].to)), - "value": format!("0x{}", hex::encode(transactions[0].value.to_bytes_be())), - "data": format!("0x{}", hex::encode(&transactions[0].data)), + "swaps": format!("0x{}", hex::encode(&encoded_solutions[0].swaps)), + "interacting_with": format!("0x{}", hex::encode(&encoded_solutions[0].interacting_with)), + "selector": format!("{}",&encoded_solutions[0].selector), + "n_tokens": format!("{}", &encoded_solutions[0].n_tokens), + "permit": encoded_solutions[0].permit + .as_ref() + .map(|permit| format!("0x{}", hex::encode(permit.abi_encode()))) + .unwrap_or_else(String::new), + "signature": encoded_solutions[0].signature + .as_ref() + .map(|signature| format!("0x{}", hex::encode(signature.as_bytes()))) + .unwrap_or_else(String::new), }); // Output the encoded result as JSON to stdout println!( diff --git a/src/encoding/evm/encoder_builders.rs b/src/encoding/evm/encoder_builders.rs index ee412ac..590605b 100644 --- a/src/encoding/evm/encoder_builders.rs +++ b/src/encoding/evm/encoder_builders.rs @@ -145,7 +145,7 @@ impl TychoExecutorEncoderBuilder { if let Some(chain) = self.chain { let swap_encoder_registry = SwapEncoderRegistry::new(self.executors_file_path.clone(), chain.clone())?; - Ok(Box::new(TychoExecutorEncoder::new(chain, swap_encoder_registry)?)) + Ok(Box::new(TychoExecutorEncoder::new(swap_encoder_registry)?)) } else { Err(EncodingError::FatalError( "Please set the chain and strategy before building the encoder".to_string(), diff --git a/src/encoding/evm/encoding_utils.rs b/src/encoding/evm/encoding_utils.rs index a6dae96..64f973a 100644 --- a/src/encoding/evm/encoding_utils.rs +++ b/src/encoding/evm/encoding_utils.rs @@ -87,7 +87,6 @@ pub fn encode_tycho_router_call( encoded_solution: EncodedSolution, solution: &Solution, token_in_already_in_router: bool, - router_address: Bytes, native_address: Bytes, ) -> Result { let (mut unwrap, mut wrap) = (false, false); @@ -246,5 +245,5 @@ pub fn encode_tycho_router_call( } else { BigUint::ZERO }; - Ok(Transaction { to: router_address, value, data: contract_interaction }) + Ok(Transaction { to: encoded_solution.interacting_with, value, data: contract_interaction }) } diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 087178b..7463ae9 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -135,6 +135,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { ); Ok(EncodedSolution { selector: self.selector.clone(), + interacting_with: self.router_address.clone(), swaps: swap_data, permit: None, signature: None, @@ -289,6 +290,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { let encoded_swaps = ple_encode(swaps); Ok(EncodedSolution { + interacting_with: self.router_address.clone(), selector: self.selector.clone(), swaps: encoded_swaps, permit: None, @@ -491,6 +493,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { tokens.len() }; Ok(EncodedSolution { + interacting_with: self.router_address.clone(), selector: self.selector.clone(), swaps: encoded_swaps, permit: None, @@ -624,15 +627,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ "30ace1b1", // Function selector @@ -713,15 +710,9 @@ mod tests { let encoded_solution = encoder .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ "5c4b639c", // Function selector @@ -801,15 +792,9 @@ mod tests { let encoded_solution = encoder .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - true, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, true, eth()) + .unwrap() + .data; let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ "5c4b639c", // Function selector @@ -891,15 +876,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_single_swap_strategy_encoder_wrap", hex_calldata.as_str()); } @@ -951,15 +930,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file( @@ -1033,15 +1006,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_sequential_swap_strategy_encoder", hex_calldata.as_str()); @@ -1102,15 +1069,9 @@ mod tests { .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); @@ -1235,15 +1196,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = hex::encode(&calldata); let expected_input = [ "51bcc7b6", // selector @@ -1359,15 +1314,9 @@ mod tests { .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_uniswap_v3_uniswap_v2", hex_calldata.as_str()); @@ -1450,15 +1399,9 @@ mod tests { .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_uniswap_v3_uniswap_v3", hex_calldata.as_str()); @@ -1550,15 +1493,9 @@ mod tests { .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_uniswap_v3_curve", hex_calldata.as_str()); @@ -1626,15 +1563,9 @@ mod tests { .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_balancer_v2_uniswap_v2", hex_calldata.as_str()); @@ -1787,15 +1718,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth, - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_multi_protocol", hex_calldata.as_str()); @@ -1894,15 +1819,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_split_swap_strategy_encoder", hex_calldata.as_str()); @@ -2015,15 +1934,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = hex::encode(&calldata); let expected_input = [ @@ -2185,15 +2098,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = hex::encode(&calldata); let expected_input = [ @@ -2318,15 +2225,9 @@ mod tests { .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_single_encoding_strategy_ekubo", hex_calldata.as_str()); } @@ -2375,15 +2276,9 @@ mod tests { .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_single_encoding_strategy_maverick", hex_calldata.as_str()); } @@ -2446,10 +2341,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = - encode_tycho_router_call(encoded_solution, &solution, false, router_address(), eth) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file( @@ -2520,10 +2414,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = - encode_tycho_router_call(encoded_solution, &solution, false, router_address(), eth) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file( @@ -2612,10 +2505,9 @@ mod tests { encoded_solution.permit = Some(permit); encoded_solution.signature = Some(signature); - let calldata = - encode_tycho_router_call(encoded_solution, &solution, false, router_address(), eth) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth) + .unwrap() + .data; let expected_input = [ "30ace1b1", // Function selector (single swap) @@ -2722,15 +2614,9 @@ mod tests { .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file("test_single_encoding_strategy_curve", hex_calldata.as_str()); @@ -2793,15 +2679,9 @@ mod tests { let encoded_solution = encoder .encode_strategy(solution.clone()) .unwrap(); - let calldata = encode_tycho_router_call( - encoded_solution, - &solution, - false, - router_address(), - eth(), - ) - .unwrap() - .data; + let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) + .unwrap() + .data; let hex_calldata = encode(&calldata); write_calldata_to_file( diff --git a/src/encoding/evm/tycho_encoders.rs b/src/encoding/evm/tycho_encoders.rs index 8d67a01..0d66c77 100644 --- a/src/encoding/evm/tycho_encoders.rs +++ b/src/encoding/evm/tycho_encoders.rs @@ -1,6 +1,5 @@ use std::{collections::HashSet, str::FromStr}; -use num_bigint::BigUint; use tycho_common::Bytes; use crate::encoding::{ @@ -40,6 +39,7 @@ pub struct TychoRouterEncoder { native_address: Bytes, wrapped_address: Bytes, router_address: Bytes, + #[allow(dead_code)] token_in_already_in_router: bool, permit2: Option, } @@ -130,6 +130,41 @@ impl TychoRouterEncoder { } Ok(encoded_solution) } + + /// Encodes a list of [`Solution`]s directly into executable transactions for the Tycho router. + /// + /// This method wraps around Tycho’s example encoding logic (see [`encode_tycho_router_call`]) + /// and should only be used for **prototyping or development**. + /// + /// # Warning + /// This implementation uses default logic to construct the outer calldata (e.g., for setting + /// `minAmountOut`). This might not be optimal or safe for production use. + /// + /// To ensure correctness, **users should implement their own encoding pipeline** using + /// [`encode_solutions`]. + /// + /// # Returns + /// A vector of fully constructed [`Transaction`]s that can be submitted to a node or bundler. + #[allow(dead_code)] + fn encode_full_calldata( + &self, + solutions: Vec, + ) -> Result, EncodingError> { + let mut transactions: Vec = Vec::new(); + for solution in solutions.iter() { + let encoded_solution = self.encode_solution(solution)?; + + let transaction = encode_tycho_router_call( + encoded_solution, + solution, + self.token_in_already_in_router, + self.native_address.clone(), + )?; + + transactions.push(transaction); + } + Ok(transactions) + } } impl TychoEncoder for TychoRouterEncoder { @@ -145,24 +180,6 @@ impl TychoEncoder for TychoRouterEncoder { Ok(result) } - fn encode_calldata(&self, solutions: Vec) -> Result, EncodingError> { - let mut transactions: Vec = Vec::new(); - for solution in solutions.iter() { - let encoded_solution = self.encode_solution(solution)?; - - let transaction = encode_tycho_router_call( - encoded_solution, - solution, - self.token_in_already_in_router, - self.router_address.clone(), - self.native_address.clone(), - )?; - - transactions.push(transaction); - } - Ok(transactions) - } - /// Raises an `EncodingError` if the solution is not considered valid. /// /// A solution is considered valid if all the following conditions are met: @@ -273,22 +290,17 @@ impl TychoEncoder for TychoRouterEncoder { #[derive(Clone)] pub struct TychoExecutorEncoder { swap_encoder_registry: SwapEncoderRegistry, - native_address: Bytes, } impl TychoExecutorEncoder { - pub fn new( - chain: Chain, - swap_encoder_registry: SwapEncoderRegistry, - ) -> Result { - let native_address = chain.native_token()?; - Ok(TychoExecutorEncoder { swap_encoder_registry, native_address }) + pub fn new(swap_encoder_registry: SwapEncoderRegistry) -> Result { + Ok(TychoExecutorEncoder { swap_encoder_registry }) } fn encode_executor_calldata( &self, solution: Solution, - ) -> Result<(Vec, Bytes), EncodingError> { + ) -> Result { let grouped_swaps = group_swaps(solution.clone().swaps); let number_of_groups = grouped_swaps.len(); if number_of_groups > 1 { @@ -337,37 +349,30 @@ impl TychoExecutorEncoder { let executor_address = Bytes::from_str(swap_encoder.executor_address()) .map_err(|_| EncodingError::FatalError("Invalid executor address".to_string()))?; - Ok((grouped_protocol_data, executor_address)) + Ok(EncodedSolution { + swaps: grouped_protocol_data, + interacting_with: executor_address, + permit: None, + signature: None, + selector: "".to_string(), + n_tokens: 0, + }) } } impl TychoEncoder for TychoExecutorEncoder { fn encode_solutions( &self, - _solutions: Vec, + solutions: Vec, ) -> Result, EncodingError> { - Err(EncodingError::NotImplementedError( - "Encoding solutions for TychoExecutorEncoder is not implemented".to_string(), - )) - } - fn encode_calldata(&self, solutions: Vec) -> Result, EncodingError> { - let mut transactions: Vec = Vec::new(); let solution = solutions .first() .ok_or(EncodingError::FatalError("No solutions found".to_string()))?; self.validate_solution(solution)?; - let (contract_interaction, target_address) = - self.encode_executor_calldata(solution.clone())?; + let encoded_solution = self.encode_executor_calldata(solution.clone())?; - let value = if solution.given_token == self.native_address { - solution.given_amount.clone() - } else { - BigUint::ZERO - }; - - transactions.push(Transaction { value, data: contract_interaction, to: target_address }); - Ok(transactions) + Ok(vec![encoded_solution]) } /// Raises an `EncodingError` if the solution is not considered valid. @@ -388,7 +393,7 @@ impl TychoEncoder for TychoExecutorEncoder { mod tests { use std::{collections::HashMap, str::FromStr}; - use num_bigint::BigInt; + use num_bigint::{BigInt, BigUint}; use tycho_common::models::{protocol::ProtocolComponent, Chain as TychoCommonChain}; use super::*; @@ -508,7 +513,7 @@ mod tests { ..Default::default() }; - let transactions = encoder.encode_calldata(vec![solution]); + let transactions = encoder.encode_full_calldata(vec![solution]); assert!(transactions.is_ok()); let transactions = transactions.unwrap(); assert_eq!(transactions.len(), 1); @@ -536,7 +541,7 @@ mod tests { ..Default::default() }; - let transactions = encoder.encode_calldata(vec![solution]); + let transactions = encoder.encode_full_calldata(vec![solution]); assert!(transactions.is_ok()); let transactions = transactions.unwrap(); assert_eq!(transactions.len(), 1); @@ -582,7 +587,7 @@ mod tests { ..Default::default() }; - let transactions = encoder.encode_calldata(vec![solution]); + let transactions = encoder.encode_full_calldata(vec![solution]); assert!(transactions.is_ok()); let transactions = transactions.unwrap(); assert_eq!(transactions.len(), 1); @@ -1057,9 +1062,7 @@ mod tests { #[test] fn test_executor_encoder_encode() { let swap_encoder_registry = get_swap_encoder_registry(); - let encoder = - TychoExecutorEncoder::new(TychoCommonChain::Ethereum.into(), swap_encoder_registry) - .unwrap(); + let encoder = TychoExecutorEncoder::new(swap_encoder_registry).unwrap(); let token_in = weth(); let token_out = dai(); @@ -1088,15 +1091,15 @@ mod tests { native_action: None, }; - let transactions = encoder - .encode_calldata(vec![solution]) + let encoded_solutions = encoder + .encode_solutions(vec![solution]) .unwrap(); - let transaction = transactions + let encoded = encoded_solutions .first() - .expect("Expected at least one transaction"); - let hex_protocol_data = encode(&transaction.data); + .expect("Expected at least one encoded solution"); + let hex_protocol_data = encode(&encoded.swaps); assert_eq!( - transaction.to, + encoded.interacting_with, Bytes::from_str("0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f").unwrap() ); assert_eq!( @@ -1119,9 +1122,7 @@ mod tests { #[test] fn test_executor_encoder_too_many_swaps() { let swap_encoder_registry = get_swap_encoder_registry(); - let encoder = - TychoExecutorEncoder::new(TychoCommonChain::Ethereum.into(), swap_encoder_registry) - .unwrap(); + let encoder = TychoExecutorEncoder::new(swap_encoder_registry).unwrap(); let token_in = weth(); let token_out = dai(); @@ -1148,16 +1149,14 @@ mod tests { native_action: None, }; - let result = encoder.encode_calldata(vec![solution]); + let result = encoder.encode_solutions(vec![solution]); assert!(result.is_err()); } #[test] fn test_executor_encoder_grouped_swaps() { let swap_encoder_registry = get_swap_encoder_registry(); - let encoder = - TychoExecutorEncoder::new(TychoCommonChain::Ethereum.into(), swap_encoder_registry) - .unwrap(); + let encoder = TychoExecutorEncoder::new(swap_encoder_registry).unwrap(); let usdc = usdc(); let pepe = pepe(); @@ -1174,15 +1173,15 @@ mod tests { ..Default::default() }; - let transactions = encoder - .encode_calldata(vec![solution]) + let encoded_solutions = encoder + .encode_solutions(vec![solution]) .unwrap(); - let transaction = transactions + let encoded_solution = encoded_solutions .first() - .expect("Expected at least one transaction"); - let hex_protocol_data = encode(&transaction.data); + .expect("Expected at least one encoded solution"); + let hex_protocol_data = encode(&encoded_solution.swaps); assert_eq!( - transaction.to, + encoded_solution.interacting_with, Bytes::from_str("0xf62849f9a0b5bf2913b396098f7c7019b51a820a").unwrap() ); assert_eq!( diff --git a/src/encoding/models.rs b/src/encoding/models.rs index 444e1aa..1c95979 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -94,12 +94,15 @@ pub struct Transaction { /// /// # Fields /// * `swaps`: Encoded swaps to be executed. +/// * `interacting_with`: Address of the contract to be called. /// * `selector`: The selector of the function to be called. /// * `n_tokens`: Number of tokens in the swap. /// * `permit`: Optional permit for the swap (if permit2 is enabled). /// * `signature`: Optional signature for the swap (if permit2 is enabled). +#[derive(Clone, Debug)] pub struct EncodedSolution { pub swaps: Vec, + pub interacting_with: Bytes, pub selector: String, pub n_tokens: usize, pub permit: Option, diff --git a/src/encoding/tycho_encoder.rs b/src/encoding/tycho_encoder.rs index 7e0365a..49c2334 100644 --- a/src/encoding/tycho_encoder.rs +++ b/src/encoding/tycho_encoder.rs @@ -1,6 +1,6 @@ use crate::encoding::{ errors::EncodingError, - models::{EncodedSolution, Solution, Transaction}, + models::{EncodedSolution, Solution}, }; /// A high-level interface for encoding solutions into Tycho-compatible transactions or raw call @@ -47,22 +47,6 @@ pub trait TychoEncoder { solutions: Vec, ) -> Result, EncodingError>; - /// Encodes a list of [`Solution`]s directly into executable transactions for the Tycho router. - /// - /// This method wraps around Tycho’s example encoding logic (see [`encode_tycho_router_call`]) - /// and should only be used for **prototyping or development**. - /// - /// # Warning - /// This implementation uses default logic to construct the outer calldata (e.g., for setting - /// `minAmountOut`). This might not be optimal or safe for production use. - /// - /// To ensure correctness, **users should implement their own encoding pipeline** using - /// [`encode_solutions`]. - /// - /// # Returns - /// A vector of fully constructed [`Transaction`]s that can be submitted to a node or bundler. - fn encode_calldata(&self, solutions: Vec) -> Result, EncodingError>; - /// Performs solution-level validation and sanity checks. /// /// This function can be used to verify whether a proposed solution is structurally sound and