fix: usv4 integration tests and remove selector from swap/strategy encoder

This commit is contained in:
royvardhan
2025-02-24 19:48:25 +05:30
parent 69745b18fd
commit 18efe0305b
6 changed files with 30 additions and 89 deletions

View File

@@ -41,7 +41,7 @@ contract UniswapV4ExecutorTest is Test, Constants {
new UniswapV4ExecutorExposed(IPoolManager(poolManager)); new UniswapV4ExecutorExposed(IPoolManager(poolManager));
} }
function testDecodeParamsV4() public view { function testDecodeParams() public view {
bool zeroForOne = true; bool zeroForOne = true;
uint24 pool1Fee = 500; uint24 pool1Fee = 500;
int24 tickSpacing1 = 60; int24 tickSpacing1 = 60;
@@ -86,7 +86,7 @@ contract UniswapV4ExecutorTest is Test, Constants {
assertEq(decodedPools[1].tickSpacing, tickSpacing2); assertEq(decodedPools[1].tickSpacing, tickSpacing2);
} }
function testSingleSwapV4() public { function testSingleSwap() public {
uint256 amountIn = 100 ether; uint256 amountIn = 100 ether;
deal(USDE_ADDR, address(uniswapV4Exposed), amountIn); deal(USDE_ADDR, address(uniswapV4Exposed), amountIn);
uint256 usdeBalanceBeforePool = USDE.balanceOf(poolManager); uint256 usdeBalanceBeforePool = USDE.balanceOf(poolManager);
@@ -118,8 +118,7 @@ contract UniswapV4ExecutorTest is Test, Constants {
// USDE -> USDT // USDE -> USDT
// Generated by the Tycho swap encoder - test_encode_uniswap_v4_simple_swap // Generated by the Tycho swap encoder - test_encode_uniswap_v4_simple_swap
bytes memory protocolData = bytes memory protocolData =
hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec701f62849f9a0b5bf2913b396098f7c7019b51a820a91dd7346dac17f958d2ee523a2206206994597c13d831ec7000064000001"; hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec701f62849f9a0b5bf2913b396098f7c7019b51a820adac17f958d2ee523a2206206994597c13d831ec7000064000001";
uint256 amountIn = 100 ether; uint256 amountIn = 100 ether;
deal(USDE_ADDR, address(uniswapV4Exposed), amountIn); deal(USDE_ADDR, address(uniswapV4Exposed), amountIn);
uint256 usdeBalanceBeforePool = USDE.balanceOf(poolManager); uint256 usdeBalanceBeforePool = USDE.balanceOf(poolManager);
@@ -135,7 +134,7 @@ contract UniswapV4ExecutorTest is Test, Constants {
assertTrue(USDT.balanceOf(address(uniswapV4Exposed)) == amountOut); assertTrue(USDT.balanceOf(address(uniswapV4Exposed)) == amountOut);
} }
function testMultipleSwapV4() public { function testMultipleSwap() public {
// USDE -> USDT -> WBTC // USDE -> USDT -> WBTC
uint256 amountIn = 100 ether; uint256 amountIn = 100 ether;
deal(USDE_ADDR, address(uniswapV4Exposed), amountIn); deal(USDE_ADDR, address(uniswapV4Exposed), amountIn);
@@ -174,8 +173,9 @@ contract UniswapV4ExecutorTest is Test, Constants {
function testMultipleSwapIntegration() public { function testMultipleSwapIntegration() public {
// USDE -> USDT -> WBTC // USDE -> USDT -> WBTC
// Generated by the Tycho swap encoder - test_encode_uniswap_v4_sequential_swap // Generated by the Tycho swap encoder - test_encode_uniswap_v4_sequential_swap
bytes memory protocolData = bytes memory protocolData =
hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c59901f62849f9a0b5bf2913b396098f7c7019b51a820a91dd7346dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c"; hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c59901f62849f9a0b5bf2913b396098f7c7019b51a820adac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c";
uint256 amountIn = 100 ether; uint256 amountIn = 100 ether;
deal(USDE_ADDR, address(uniswapV4Exposed), amountIn); deal(USDE_ADDR, address(uniswapV4Exposed), amountIn);

View File

@@ -30,7 +30,6 @@ pub trait EVMStrategyEncoder: StrategyEncoder {
token_out: U8, token_out: U8,
split: U24, split: U24,
executor_address: Bytes, executor_address: Bytes,
executor_selector: FixedBytes<4>,
protocol_data: Vec<u8>, protocol_data: Vec<u8>,
) -> Vec<u8> { ) -> Vec<u8> {
let mut encoded = Vec::new(); let mut encoded = Vec::new();
@@ -38,17 +37,10 @@ pub trait EVMStrategyEncoder: StrategyEncoder {
encoded.push(token_out.to_be_bytes_vec()[0]); encoded.push(token_out.to_be_bytes_vec()[0]);
encoded.extend_from_slice(&split.to_be_bytes_vec()); encoded.extend_from_slice(&split.to_be_bytes_vec());
encoded.extend(executor_address.to_vec()); encoded.extend(executor_address.to_vec());
encoded.extend(executor_selector);
encoded.extend(protocol_data); encoded.extend(protocol_data);
encoded encoded
} }
/// Encodes a selector string into its 4-byte representation.
fn encode_executor_selector(&self, selector: &str) -> FixedBytes<4> {
let hash = keccak256(selector.as_bytes());
FixedBytes::<4>::from([hash[0], hash[1], hash[2], hash[3]])
}
/// Uses prefix-length encoding to efficient encode action data. /// Uses prefix-length encoding to efficient encode action data.
/// ///
/// Prefix-length encoding is a data encoding method where the beginning of a data segment /// Prefix-length encoding is a data encoding method where the beginning of a data segment
@@ -114,10 +106,7 @@ impl SplitSwapStrategyEncoder {
impl EVMStrategyEncoder for SplitSwapStrategyEncoder {} impl EVMStrategyEncoder for SplitSwapStrategyEncoder {}
impl StrategyEncoder for SplitSwapStrategyEncoder { impl StrategyEncoder for SplitSwapStrategyEncoder {
fn encode_strategy( fn encode_strategy(&self, solution: Solution) -> Result<(Vec<u8>, Bytes), EncodingError> {
&self,
solution: Solution,
) -> Result<(Vec<u8>, Bytes, Option<String>), EncodingError> {
self.split_swap_validator self.split_swap_validator
.validate_split_percentages(&solution.swaps)?; .validate_split_percentages(&solution.swaps)?;
self.split_swap_validator self.split_swap_validator
@@ -209,7 +198,6 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
Bytes::from_str(swap_encoder.executor_address()).map_err(|_| { Bytes::from_str(swap_encoder.executor_address()).map_err(|_| {
EncodingError::FatalError("Invalid executor address".to_string()) EncodingError::FatalError("Invalid executor address".to_string())
})?, })?,
self.encode_executor_selector(swap_encoder.swap_selector()),
grouped_protocol_data, grouped_protocol_data,
); );
swaps.push(swap_data); swaps.push(swap_data);
@@ -253,7 +241,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
}; };
let contract_interaction = encode_input(&self.selector, method_calldata); let contract_interaction = encode_input(&self.selector, method_calldata);
Ok((contract_interaction, solution.router_address, None)) Ok((contract_interaction, solution.router_address))
} }
fn get_swap_encoder(&self, protocol_system: &str) -> Option<&Box<dyn SwapEncoder>> { fn get_swap_encoder(&self, protocol_system: &str) -> Option<&Box<dyn SwapEncoder>> {
@@ -283,10 +271,7 @@ impl ExecutorStrategyEncoder {
} }
impl EVMStrategyEncoder for ExecutorStrategyEncoder {} impl EVMStrategyEncoder for ExecutorStrategyEncoder {}
impl StrategyEncoder for ExecutorStrategyEncoder { impl StrategyEncoder for ExecutorStrategyEncoder {
fn encode_strategy( fn encode_strategy(&self, solution: Solution) -> Result<(Vec<u8>, Bytes), EncodingError> {
&self,
solution: Solution,
) -> Result<(Vec<u8>, Bytes, Option<String>), EncodingError> {
let grouped_swaps = group_swaps(solution.clone().swaps); let grouped_swaps = group_swaps(solution.clone().swaps);
let number_of_groups = grouped_swaps.len(); let number_of_groups = grouped_swaps.len();
if number_of_groups > 1 { if number_of_groups > 1 {
@@ -328,11 +313,7 @@ impl StrategyEncoder for ExecutorStrategyEncoder {
let executor_address = Bytes::from_str(swap_encoder.executor_address()) let executor_address = Bytes::from_str(swap_encoder.executor_address())
.map_err(|_| EncodingError::FatalError("Invalid executor address".to_string()))?; .map_err(|_| EncodingError::FatalError("Invalid executor address".to_string()))?;
Ok(( Ok((grouped_protocol_data, executor_address))
grouped_protocol_data,
executor_address,
Some(swap_encoder.swap_selector().to_string()),
))
} }
fn get_swap_encoder(&self, protocol_system: &str) -> Option<&Box<dyn SwapEncoder>> { fn get_swap_encoder(&self, protocol_system: &str) -> Option<&Box<dyn SwapEncoder>> {
@@ -413,7 +394,7 @@ mod tests {
native_action: None, native_action: None,
}; };
let (protocol_data, executor_address, selector) = encoder let (protocol_data, executor_address) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();
let hex_protocol_data = encode(&protocol_data); let hex_protocol_data = encode(&protocol_data);
@@ -434,7 +415,6 @@ mod tests {
"00", "00",
)) ))
); );
assert_eq!(selector, Some("swap(uint256,bytes)".to_string()));
} }
#[test] #[test]
@@ -539,7 +519,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let (protocol_data, executor_address, selector) = encoder let (protocol_data, executor_address) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();
let hex_protocol_data = encode(&protocol_data); let hex_protocol_data = encode(&protocol_data);
@@ -574,7 +554,6 @@ mod tests {
"0001f4" "0001f4"
)) ))
); );
assert_eq!(selector, Some("swap(uint256,bytes)".to_string()));
} }
#[rstest] #[rstest]
@@ -646,7 +625,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let (calldata, _, _) = encoder let (calldata, _) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
@@ -748,7 +727,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let (calldata, _, _) = encoder let (calldata, _) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();
@@ -797,7 +776,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let (calldata, _, _) = encoder let (calldata, _) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();
@@ -886,7 +865,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let (calldata, _, _) = encoder let (calldata, _) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();
@@ -968,7 +947,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let (calldata, _, _) = encoder let (calldata, _) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();
@@ -1079,7 +1058,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let (calldata, _, _) = encoder let (calldata, _) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
@@ -1171,7 +1150,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let (calldata, _, _) = encoder let (calldata, _) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();
let hex_calldata = encode(&calldata); let hex_calldata = encode(&calldata);
@@ -1235,7 +1214,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let (calldata, _, _) = encoder let (calldata, _) = encoder
.encode_strategy(solution) .encode_strategy(solution)
.unwrap(); .unwrap();

View File

@@ -24,7 +24,6 @@ use crate::encoding::{
#[derive(Clone)] #[derive(Clone)]
pub struct UniswapV2SwapEncoder { pub struct UniswapV2SwapEncoder {
executor_address: String, executor_address: String,
swap_selector: String,
} }
impl UniswapV2SwapEncoder { impl UniswapV2SwapEncoder {
@@ -35,7 +34,7 @@ impl UniswapV2SwapEncoder {
impl SwapEncoder for UniswapV2SwapEncoder { impl SwapEncoder for UniswapV2SwapEncoder {
fn new(executor_address: String) -> Self { fn new(executor_address: String) -> Self {
Self { executor_address, swap_selector: "swap(uint256,bytes)".to_string() } Self { executor_address }
} }
fn encode_swap( fn encode_swap(
@@ -66,10 +65,6 @@ impl SwapEncoder for UniswapV2SwapEncoder {
&self.executor_address &self.executor_address
} }
fn swap_selector(&self) -> &str {
&self.swap_selector
}
fn clone_box(&self) -> Box<dyn SwapEncoder> { fn clone_box(&self) -> Box<dyn SwapEncoder> {
Box::new(self.clone()) Box::new(self.clone())
} }
@@ -83,7 +78,6 @@ impl SwapEncoder for UniswapV2SwapEncoder {
#[derive(Clone)] #[derive(Clone)]
pub struct UniswapV3SwapEncoder { pub struct UniswapV3SwapEncoder {
executor_address: String, executor_address: String,
swap_selector: String,
} }
impl UniswapV3SwapEncoder { impl UniswapV3SwapEncoder {
@@ -94,7 +88,7 @@ impl UniswapV3SwapEncoder {
impl SwapEncoder for UniswapV3SwapEncoder { impl SwapEncoder for UniswapV3SwapEncoder {
fn new(executor_address: String) -> Self { fn new(executor_address: String) -> Self {
Self { executor_address, swap_selector: "swap(uint256,bytes)".to_string() } Self { executor_address }
} }
fn encode_swap( fn encode_swap(
@@ -128,9 +122,6 @@ impl SwapEncoder for UniswapV3SwapEncoder {
fn executor_address(&self) -> &str { fn executor_address(&self) -> &str {
&self.executor_address &self.executor_address
} }
fn swap_selector(&self) -> &str {
&self.swap_selector
}
fn clone_box(&self) -> Box<dyn SwapEncoder> { fn clone_box(&self) -> Box<dyn SwapEncoder> {
Box::new(self.clone()) Box::new(self.clone())
} }
@@ -145,8 +136,6 @@ impl SwapEncoder for UniswapV3SwapEncoder {
#[derive(Clone)] #[derive(Clone)]
pub struct UniswapV4SwapEncoder { pub struct UniswapV4SwapEncoder {
executor_address: String, executor_address: String,
swap_selector: String,
callback_selector: String,
} }
impl UniswapV4SwapEncoder { impl UniswapV4SwapEncoder {
@@ -157,11 +146,7 @@ impl UniswapV4SwapEncoder {
impl SwapEncoder for UniswapV4SwapEncoder { impl SwapEncoder for UniswapV4SwapEncoder {
fn new(executor_address: String) -> Self { fn new(executor_address: String) -> Self {
Self { Self { executor_address }
executor_address,
swap_selector: "swap(uint256,bytes)".to_string(),
callback_selector: "unlockCallback(bytes)".to_string(),
}
} }
fn encode_swap( fn encode_swap(
@@ -206,7 +191,6 @@ impl SwapEncoder for UniswapV4SwapEncoder {
group_token_out_address, group_token_out_address,
zero_to_one, zero_to_one,
callback_executor, callback_executor,
encode_function_selector(&self.callback_selector),
pool_params, pool_params,
); );
@@ -217,10 +201,6 @@ impl SwapEncoder for UniswapV4SwapEncoder {
&self.executor_address &self.executor_address
} }
fn swap_selector(&self) -> &str {
&self.swap_selector
}
fn clone_box(&self) -> Box<dyn SwapEncoder> { fn clone_box(&self) -> Box<dyn SwapEncoder> {
Box::new(self.clone()) Box::new(self.clone())
} }
@@ -230,11 +210,10 @@ impl SwapEncoder for UniswapV4SwapEncoder {
/// ///
/// # Fields /// # Fields
/// * `executor_address` - The address of the executor contract that will perform the swap. /// * `executor_address` - The address of the executor contract that will perform the swap.
/// * `swap_selector` - The selector of the swap function in the executor contract. /// * `vault_address` - The address of the vault contract that will perform the swap.
#[derive(Clone)] #[derive(Clone)]
pub struct BalancerV2SwapEncoder { pub struct BalancerV2SwapEncoder {
executor_address: String, executor_address: String,
swap_selector: String,
vault_address: String, vault_address: String,
} }
@@ -242,7 +221,6 @@ impl SwapEncoder for BalancerV2SwapEncoder {
fn new(executor_address: String) -> Self { fn new(executor_address: String) -> Self {
Self { Self {
executor_address, executor_address,
swap_selector: "swap(uint256,bytes)".to_string(),
vault_address: "0xba12222222228d8ba445958a75a0704d566bf2c8".to_string(), vault_address: "0xba12222222228d8ba445958a75a0704d566bf2c8".to_string(),
} }
} }
@@ -277,9 +255,6 @@ impl SwapEncoder for BalancerV2SwapEncoder {
fn executor_address(&self) -> &str { fn executor_address(&self) -> &str {
&self.executor_address &self.executor_address
} }
fn swap_selector(&self) -> &str {
&self.swap_selector
}
fn clone_box(&self) -> Box<dyn SwapEncoder> { fn clone_box(&self) -> Box<dyn SwapEncoder> {
Box::new(self.clone()) Box::new(self.clone())
} }
@@ -418,7 +393,6 @@ mod tests {
.encode_swap(swap, encoding_context) .encode_swap(swap, encoding_context)
.unwrap(); .unwrap();
let hex_swap = encode(&encoded_swap); let hex_swap = encode(&encoded_swap);
println!("{}", hex_swap);
assert_eq!( assert_eq!(
hex_swap, hex_swap,
@@ -478,6 +452,7 @@ mod tests {
.encode_swap(swap, encoding_context) .encode_swap(swap, encoding_context)
.unwrap(); .unwrap();
let hex_swap = encode(&encoded_swap); let hex_swap = encode(&encoded_swap);
println!("{}", hex_swap);
assert_eq!( assert_eq!(
hex_swap, hex_swap,
@@ -490,8 +465,6 @@ mod tests {
"01", "01",
// executor address // executor address
"f62849f9a0b5bf2913b396098f7c7019b51a820a", "f62849f9a0b5bf2913b396098f7c7019b51a820a",
// callback selector for "unlockCallback(bytes)"
"91dd7346",
// pool params: // pool params:
// - intermediary token // - intermediary token
"dac17f958d2ee523a2206206994597c13d831ec7", "dac17f958d2ee523a2206206994597c13d831ec7",
@@ -637,6 +610,7 @@ mod tests {
let combined_hex = let combined_hex =
format!("{}{}", encode(&initial_encoded_swap), encode(&second_encoded_swap)); format!("{}{}", encode(&initial_encoded_swap), encode(&second_encoded_swap));
println!("{}", combined_hex);
assert_eq!( assert_eq!(
combined_hex, combined_hex,
@@ -649,8 +623,6 @@ mod tests {
"01", "01",
// executor address // executor address
"f62849f9a0b5bf2913b396098f7c7019b51a820a", "f62849f9a0b5bf2913b396098f7c7019b51a820a",
// callback selector for "unlockCallback(bytes)"
"91dd7346",
// pool params: // pool params:
// - intermediary token USDT // - intermediary token USDT
"dac17f958d2ee523a2206206994597c13d831ec7", "dac17f958d2ee523a2206206994597c13d831ec7",

View File

@@ -105,7 +105,7 @@ impl TychoEncoder for EVMTychoEncoder {
for solution in solutions.iter() { for solution in solutions.iter() {
self.validate_solution(solution)?; self.validate_solution(solution)?;
let (contract_interaction, target_address, selector) = self let (contract_interaction, target_address) = self
.strategy_encoder .strategy_encoder
.encode_strategy(solution.clone())?; .encode_strategy(solution.clone())?;
@@ -118,7 +118,7 @@ impl TychoEncoder for EVMTychoEncoder {
value, value,
data: contract_interaction, data: contract_interaction,
to: target_address, to: target_address,
selector, selector: None,
}); });
} }
Ok(transactions) Ok(transactions)
@@ -152,16 +152,12 @@ mod tests {
struct MockStrategy; struct MockStrategy;
impl StrategyEncoder for MockStrategy { impl StrategyEncoder for MockStrategy {
fn encode_strategy( fn encode_strategy(&self, _solution: Solution) -> Result<(Vec<u8>, Bytes), EncodingError> {
&self,
_solution: Solution,
) -> Result<(Vec<u8>, Bytes, Option<String>), EncodingError> {
Ok(( Ok((
Bytes::from_str("0x1234") Bytes::from_str("0x1234")
.unwrap() .unwrap()
.to_vec(), .to_vec(),
Bytes::from_str("0xabcd").unwrap(), Bytes::from_str("0xabcd").unwrap(),
None,
)) ))
} }

View File

@@ -17,10 +17,7 @@ pub trait StrategyEncoder {
/// - The encoded data as bytes /// - The encoded data as bytes
/// - The address of the contract to call (router or executor) /// - The address of the contract to call (router or executor)
/// - Optionally, the function selector to use when calling the contract /// - Optionally, the function selector to use when calling the contract
fn encode_strategy( fn encode_strategy(&self, solution: Solution) -> Result<(Vec<u8>, Bytes), EncodingError>;
&self,
solution: Solution,
) -> Result<(Vec<u8>, Bytes, Option<String>), EncodingError>;
/// Retrieves the swap encoder for a specific protocol system. /// Retrieves the swap encoder for a specific protocol system.
/// ///

View File

@@ -32,9 +32,6 @@ pub trait SwapEncoder: Sync + Send {
/// Returns the address of the protocol-specific executor contract. /// Returns the address of the protocol-specific executor contract.
fn executor_address(&self) -> &str; fn executor_address(&self) -> &str;
/// Returns the function selector used to execute the swap on the protocol.
fn swap_selector(&self) -> &str;
/// Creates a cloned instance of the swap encoder. /// Creates a cloned instance of the swap encoder.
/// ///
/// This allows the encoder to be cloned when it is being used as a `Box<dyn SwapEncoder>`. /// This allows the encoder to be cloned when it is being used as a `Box<dyn SwapEncoder>`.