feat(univ4): Pass user_data as hook_data in execution
Because we don't know the size of hook data, it needs to be at the end of the protocol data. But we also don't know the size of the intermediary swaps. To solve this, we are now ple encoding the intermediary swaps and only then appending the hook data Took 2 hours 50 minutes Took 40 seconds
This commit is contained in:
committed by
Diana Carvalho
parent
a0581773cd
commit
93678d9d19
@@ -121,16 +121,25 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
||||
transfer_type: transfer,
|
||||
};
|
||||
|
||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
||||
let mut initial_protocol_data: Vec<u8> = vec![];
|
||||
for swap in grouped_swap.swaps.iter() {
|
||||
let protocol_data = swap_encoder.encode_swap(swap, &encoding_context)?;
|
||||
grouped_protocol_data.extend(protocol_data);
|
||||
if encoding_context.group_token_in == swap.token_in {
|
||||
initial_protocol_data = protocol_data;
|
||||
} else {
|
||||
grouped_protocol_data.push(protocol_data);
|
||||
}
|
||||
}
|
||||
|
||||
if !grouped_protocol_data.is_empty() {
|
||||
initial_protocol_data.extend(ple_encode(grouped_protocol_data));
|
||||
}
|
||||
|
||||
let swap_data = self.encode_swap_header(
|
||||
Bytes::from_str(swap_encoder.executor_address())
|
||||
.map_err(|_| EncodingError::FatalError("Invalid executor address".to_string()))?,
|
||||
grouped_protocol_data,
|
||||
initial_protocol_data,
|
||||
);
|
||||
Ok(EncodedSolution {
|
||||
function_signature: self.function_signature.clone(),
|
||||
@@ -269,17 +278,26 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
||||
transfer_type: transfer,
|
||||
};
|
||||
|
||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
||||
let mut initial_protocol_data: Vec<u8> = vec![];
|
||||
for swap in grouped_swap.swaps.iter() {
|
||||
let protocol_data = swap_encoder.encode_swap(swap, &encoding_context)?;
|
||||
grouped_protocol_data.extend(protocol_data);
|
||||
if encoding_context.group_token_in == swap.token_in {
|
||||
initial_protocol_data = protocol_data;
|
||||
} else {
|
||||
grouped_protocol_data.push(protocol_data);
|
||||
}
|
||||
}
|
||||
|
||||
if !grouped_protocol_data.is_empty() {
|
||||
initial_protocol_data.extend(ple_encode(grouped_protocol_data));
|
||||
}
|
||||
|
||||
let swap_data = self.encode_swap_header(
|
||||
Bytes::from_str(swap_encoder.executor_address()).map_err(|_| {
|
||||
EncodingError::FatalError("Invalid executor address".to_string())
|
||||
})?,
|
||||
grouped_protocol_data,
|
||||
initial_protocol_data,
|
||||
);
|
||||
swaps.push(swap_data);
|
||||
}
|
||||
@@ -458,10 +476,19 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
||||
transfer_type: transfer,
|
||||
};
|
||||
|
||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
||||
let mut initial_protocol_data: Vec<u8> = vec![];
|
||||
for swap in grouped_swap.swaps.iter() {
|
||||
let protocol_data = swap_encoder.encode_swap(swap, &encoding_context)?;
|
||||
grouped_protocol_data.extend(protocol_data);
|
||||
if encoding_context.group_token_in == swap.token_in {
|
||||
initial_protocol_data = protocol_data;
|
||||
} else {
|
||||
grouped_protocol_data.push(protocol_data);
|
||||
}
|
||||
}
|
||||
|
||||
if !grouped_protocol_data.is_empty() {
|
||||
initial_protocol_data.extend(ple_encode(grouped_protocol_data));
|
||||
}
|
||||
|
||||
let swap_data = self.encode_swap_header(
|
||||
@@ -471,7 +498,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
||||
Bytes::from_str(swap_encoder.executor_address()).map_err(|_| {
|
||||
EncodingError::FatalError("Invalid executor address".to_string())
|
||||
})?,
|
||||
grouped_protocol_data,
|
||||
initial_protocol_data,
|
||||
);
|
||||
swaps.push(swap_data);
|
||||
}
|
||||
|
||||
@@ -180,10 +180,23 @@ impl SwapEncoder for UniswapV4SwapEncoder {
|
||||
Ok(hook) => Address::from_slice(&hook),
|
||||
Err(_) => Address::ZERO,
|
||||
};
|
||||
|
||||
let mut hook_data = AlloyBytes::new();
|
||||
if encoding_context.group_token_out == swap.token_out {
|
||||
// Add hook data if it's only the last swap
|
||||
hook_data = AlloyBytes::from(
|
||||
swap.user_data
|
||||
.unwrap_or_default()
|
||||
.to_vec(),
|
||||
);
|
||||
}
|
||||
// Early check if this is not the first swap
|
||||
if encoding_context.group_token_in != swap.token_in {
|
||||
return Ok((bytes_to_address(&swap.token_out)?, pool_fee_u24, pool_tick_spacing_u24)
|
||||
return Ok((
|
||||
bytes_to_address(&swap.token_out)?,
|
||||
pool_fee_u24,
|
||||
pool_tick_spacing_u24,
|
||||
hook_data,
|
||||
)
|
||||
.abi_encode_packed());
|
||||
}
|
||||
|
||||
@@ -206,6 +219,7 @@ impl SwapEncoder for UniswapV4SwapEncoder {
|
||||
bytes_to_address(&encoding_context.receiver)?,
|
||||
hook_address,
|
||||
pool_params,
|
||||
hook_data,
|
||||
);
|
||||
|
||||
Ok(args.abi_encode_packed())
|
||||
@@ -841,7 +855,7 @@ mod tests {
|
||||
|
||||
mod uniswap_v4 {
|
||||
use super::*;
|
||||
use crate::encoding::evm::utils::write_calldata_to_file;
|
||||
use crate::encoding::evm::utils::{ple_encode, write_calldata_to_file};
|
||||
|
||||
#[test]
|
||||
fn test_encode_uniswap_v4_simple_swap() {
|
||||
@@ -1062,8 +1076,11 @@ mod tests {
|
||||
.encode_swap(&second_swap, &context)
|
||||
.unwrap();
|
||||
|
||||
let combined_hex =
|
||||
format!("{}{}", encode(&initial_encoded_swap), encode(&second_encoded_swap));
|
||||
let combined_hex = format!(
|
||||
"{}{}",
|
||||
encode(&initial_encoded_swap),
|
||||
encode(ple_encode(vec![second_encoded_swap]))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
combined_hex,
|
||||
@@ -1087,6 +1104,9 @@ mod tests {
|
||||
"000064",
|
||||
// - tick spacing
|
||||
"000001",
|
||||
// Second swap
|
||||
// ple encoding
|
||||
"001a",
|
||||
// - intermediary token WBTC
|
||||
"2260fac5e5542a773aa44fbcfedf7c193bc2c599",
|
||||
// - fee
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::encoding::{
|
||||
SequentialSwapStrategyEncoder, SingleSwapStrategyEncoder, SplitSwapStrategyEncoder,
|
||||
},
|
||||
swap_encoder::swap_encoder_registry::SwapEncoderRegistry,
|
||||
utils::ple_encode,
|
||||
},
|
||||
models::{
|
||||
Chain, EncodedSolution, EncodingContext, NativeAction, Solution, Transaction, TransferType,
|
||||
@@ -310,32 +311,44 @@ impl TychoExecutorEncoder {
|
||||
))
|
||||
})?;
|
||||
|
||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||
let transfer = if IN_TRANSFER_REQUIRED_PROTOCOLS.contains(
|
||||
&grouped_swap.swaps[0]
|
||||
.component
|
||||
.protocol_system
|
||||
.as_str(),
|
||||
) {
|
||||
TransferType::Transfer
|
||||
} else {
|
||||
TransferType::None
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
receiver: solution.receiver.clone(),
|
||||
exact_out: solution.exact_out,
|
||||
router_address: None,
|
||||
group_token_in: grouped_swap.token_in.clone(),
|
||||
group_token_out: grouped_swap.token_out.clone(),
|
||||
transfer_type: transfer,
|
||||
};
|
||||
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
||||
let mut initial_protocol_data: Vec<u8> = vec![];
|
||||
for swap in grouped_swap.swaps.iter() {
|
||||
let transfer = if IN_TRANSFER_REQUIRED_PROTOCOLS
|
||||
.contains(&swap.component.protocol_system.as_str())
|
||||
{
|
||||
TransferType::Transfer
|
||||
} else {
|
||||
TransferType::None
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
receiver: solution.receiver.clone(),
|
||||
exact_out: solution.exact_out,
|
||||
router_address: None,
|
||||
group_token_in: grouped_swap.token_in.clone(),
|
||||
group_token_out: grouped_swap.token_out.clone(),
|
||||
transfer_type: transfer,
|
||||
};
|
||||
let protocol_data = swap_encoder.encode_swap(swap, &encoding_context)?;
|
||||
grouped_protocol_data.extend(protocol_data);
|
||||
if encoding_context.group_token_in == swap.token_in {
|
||||
initial_protocol_data = protocol_data;
|
||||
} else {
|
||||
grouped_protocol_data.push(protocol_data);
|
||||
}
|
||||
}
|
||||
|
||||
if !grouped_protocol_data.is_empty() {
|
||||
initial_protocol_data.extend(ple_encode(grouped_protocol_data));
|
||||
}
|
||||
|
||||
let executor_address = Bytes::from_str(swap_encoder.executor_address())
|
||||
.map_err(|_| EncodingError::FatalError("Invalid executor address".to_string()))?;
|
||||
|
||||
Ok(EncodedSolution {
|
||||
swaps: grouped_protocol_data,
|
||||
swaps: initial_protocol_data,
|
||||
interacting_with: executor_address,
|
||||
permit: None,
|
||||
function_signature: "".to_string(),
|
||||
@@ -1261,6 +1274,8 @@ mod tests {
|
||||
"000bb8",
|
||||
// tick spacing
|
||||
"00003c",
|
||||
// ple encoding
|
||||
"001a",
|
||||
// second pool intermediary token (PEPE)
|
||||
"6982508145454ce325ddbe47a25d4ec3d2311933",
|
||||
// fee
|
||||
|
||||
Reference in New Issue
Block a user