feat: Support new transfer logic in encoding

The transfer from the user into the router is supposed to happen in the router (we only support this in the executors for callback constrained protocols). This is necessary because of some security concerns that were found in the audit. This way we reduce the space of attack.
- Refactored TransferOptimization not to handle TransferTypes anymore but just return bools.
- Split get_transfer_type into get_transfers and get_in_between_transfer. Updates tests
- Updated the strategies to use this
- Updated function signatures to pass transfer_from and funds_receiver
- Updated SwapEncoders to handle this
- SplitSwapStrategy just assumes all tokens are sent to and from the router at all times

Took 2 hours 46 minutes
This commit is contained in:
Diana Carvalho
2025-05-14 18:00:19 +01:00
parent 9401ce2620
commit 0f9af65846
7 changed files with 318 additions and 339 deletions

View File

@@ -66,7 +66,7 @@ impl SwapEncoder for UniswapV2SwapEncoder {
component_id,
bytes_to_address(&encoding_context.receiver)?,
zero_to_one,
(encoding_context.transfer_type as u8).to_be_bytes(),
encoding_context.transfer,
);
Ok(args.abi_encode_packed())
@@ -129,7 +129,8 @@ impl SwapEncoder for UniswapV3SwapEncoder {
bytes_to_address(&encoding_context.receiver)?,
component_id,
zero_to_one,
(encoding_context.transfer_type as u8).to_be_bytes(),
encoding_context.transfer_from,
encoding_context.transfer,
);
Ok(args.abi_encode_packed())
@@ -206,7 +207,8 @@ impl SwapEncoder for UniswapV4SwapEncoder {
group_token_in_address,
group_token_out_address,
zero_to_one,
(encoding_context.transfer_type as u8).to_be_bytes(),
encoding_context.transfer_from,
encoding_context.transfer,
bytes_to_address(&encoding_context.receiver)?,
pool_params,
);
@@ -282,7 +284,7 @@ impl SwapEncoder for BalancerV2SwapEncoder {
component_id,
bytes_to_address(&encoding_context.receiver)?,
approval_needed,
(encoding_context.transfer_type as u8).to_be_bytes(),
encoding_context.transfer,
);
Ok(args.abi_encode_packed())
}
@@ -344,7 +346,8 @@ impl SwapEncoder for EkuboSwapEncoder {
let mut encoded = vec![];
if encoding_context.group_token_in == swap.token_in {
encoded.extend((encoding_context.transfer_type as u8).to_be_bytes());
encoded.extend((encoding_context.transfer_from as u8).to_be_bytes());
encoded.extend((encoding_context.transfer as u8).to_be_bytes());
encoded.extend(bytes_to_address(&encoding_context.receiver)?);
encoded.extend(bytes_to_address(&swap.token_in)?);
}
@@ -575,7 +578,7 @@ impl SwapEncoder for CurveSwapEncoder {
i.to_be_bytes::<1>(),
j.to_be_bytes::<1>(),
approval_needed,
(encoding_context.transfer_type as u8).to_be_bytes(),
encoding_context.transfer,
bytes_to_address(&encoding_context.receiver)?,
);
@@ -620,7 +623,7 @@ impl SwapEncoder for MaverickV2SwapEncoder {
bytes_to_address(&swap.token_in)?,
component_id,
bytes_to_address(&encoding_context.receiver)?,
(encoding_context.transfer_type as u8).to_be_bytes(),
encoding_context.transfer,
);
Ok(args.abi_encode_packed())
}
@@ -645,7 +648,7 @@ mod tests {
};
use super::*;
use crate::encoding::{evm::utils::write_calldata_to_file, models::TransferType};
use crate::encoding::evm::utils::write_calldata_to_file;
mod uniswap_v2 {
use super::*;
@@ -670,7 +673,8 @@ mod tests {
router_address: Some(Bytes::zero(20)),
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::TransferToProtocol,
transfer: true,
transfer_from: false,
};
let encoder = UniswapV2SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -693,8 +697,8 @@ mod tests {
"0000000000000000000000000000000000000001",
// zero for one
"00",
// transfer type (transfer)
"00",
// transfer true
"01",
))
);
}
@@ -728,7 +732,8 @@ mod tests {
router_address: Some(Bytes::zero(20)),
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::TransferToProtocol,
transfer: true,
transfer_from: false,
};
let encoder = UniswapV3SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -755,8 +760,10 @@ mod tests {
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
// zero for one
"00",
// transfer type (transfer)
// transfer from false
"00",
// transfer true
"01",
))
);
}
@@ -790,7 +797,8 @@ mod tests {
router_address: Some(Bytes::zero(20)),
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
transfer: false,
transfer_from: false,
};
let encoder = BalancerV2SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -819,8 +827,8 @@ mod tests {
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
// approval needed
"01",
// transfer type
"05"
// transfer false
"00",
))
);
write_calldata_to_file("test_encode_balancer_v2", hex_swap.as_str());
@@ -864,7 +872,8 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::TransferToProtocol,
transfer: true,
transfer_from: false,
};
let encoder = UniswapV4SwapEncoder::new(
String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"),
@@ -886,8 +895,10 @@ mod tests {
"dac17f958d2ee523a2206206994597c13d831ec7",
// zero for one
"01",
// transfer type
// transfer from false
"00",
// transfer true
"01",
// receiver
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
// pool params:
@@ -935,7 +946,8 @@ mod tests {
group_token_in: group_token_in.clone(),
// Token out is the same as the group token out
group_token_out: token_out.clone(),
transfer_type: TransferType::TransferToProtocol,
transfer: true,
transfer_from: false,
};
let encoder = UniswapV4SwapEncoder::new(
@@ -978,7 +990,8 @@ mod tests {
router_address: Some(router_address.clone()),
group_token_in: usde_address.clone(),
group_token_out: wbtc_address.clone(),
transfer_type: TransferType::TransferToProtocol,
transfer: true,
transfer_from: false,
};
// Setup - First sequence: USDE -> USDT
@@ -1056,8 +1069,10 @@ mod tests {
"2260fac5e5542a773aa44fbcfedf7c193bc2c599",
// zero for one
"01",
// transfer type
// transfer from false
"00",
// transfer true
"01",
// receiver
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
// pool params:
@@ -1113,7 +1128,8 @@ mod tests {
group_token_out: token_out.clone(),
exact_out: false,
router_address: Some(Bytes::default()),
transfer_type: TransferType::TransferToProtocol,
transfer: true,
transfer_from: false,
};
let encoder =
@@ -1129,8 +1145,10 @@ mod tests {
assert_eq!(
hex_swap,
concat!(
// transfer type
// transfer from false
"00",
// transfer true
"01",
// receiver
"ca4f73fe97d0b987a0d12b39bbd562c779bab6f6",
// group token in
@@ -1159,7 +1177,8 @@ mod tests {
group_token_out: group_token_out.clone(),
exact_out: false,
router_address: Some(Bytes::default()),
transfer_type: TransferType::TransferToProtocol,
transfer: true,
transfer_from: false,
};
let first_swap = Swap {
@@ -1209,8 +1228,10 @@ mod tests {
combined_hex,
// transfer type
concat!(
// transfer type
// transfer from false
"00",
// transfer true
"01",
// receiver
"ca4f73fe97d0b987a0d12b39bbd562c779bab6f6",
// group token in
@@ -1355,7 +1376,8 @@ mod tests {
router_address: None,
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
transfer: false,
transfer_from: false,
};
let encoder = CurveSwapEncoder::new(
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
@@ -1385,8 +1407,8 @@ mod tests {
"01",
// approval needed
"01",
// transfer type
"05",
// transfer false
"00",
// receiver,
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e"
))
@@ -1425,7 +1447,8 @@ mod tests {
router_address: None,
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
transfer: false,
transfer_from: false,
};
let encoder = CurveSwapEncoder::new(
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
@@ -1455,8 +1478,8 @@ mod tests {
"00",
// approval needed
"01",
// transfer type
"05",
// transfer false
"00",
// receiver
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e"
))
@@ -1496,7 +1519,8 @@ mod tests {
router_address: None,
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
transfer: false,
transfer_from: false,
};
let encoder = CurveSwapEncoder::new(
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
@@ -1535,8 +1559,8 @@ mod tests {
"01",
// approval needed
"01",
// transfer type
"05",
// transfer false
"00",
// receiver
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e"
))
@@ -1567,7 +1591,8 @@ mod tests {
router_address: Some(Bytes::default()),
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::TransferToProtocol,
transfer: true,
transfer_from: false,
};
let encoder = MaverickV2SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -1590,8 +1615,8 @@ mod tests {
"14Cf6D2Fe3E1B326114b07d22A6F6bb59e346c67",
// receiver
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
// transfer from router to protocol
"00",
// transfer true
"01",
))
.to_lowercase()
);