feat: Support in between swaps optimizations
--- don't change below this line --- ENG-4314 Took 31 seconds
This commit is contained in:
@@ -340,4 +340,100 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouter.exposedSequentialSwap(amountIn, pleEncode(swaps));
|
tychoRouter.exposedSequentialSwap(amountIn, pleEncode(swaps));
|
||||||
assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99889294);
|
assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99889294);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testUSV3USV2Integration() public {
|
||||||
|
// Performs a sequential swap from WETH to USDC though WBTC and DAI using USV3 and USV2 pools
|
||||||
|
//
|
||||||
|
// WETH ──(USV3)──> WBTC ───(USV2)──> USDC
|
||||||
|
deal(WETH_ADDR, ALICE, 1 ether);
|
||||||
|
uint256 balanceBefore = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
// Approve permit2
|
||||||
|
vm.startPrank(ALICE);
|
||||||
|
IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
||||||
|
// Encoded solution generated using `test_uniswap_v3_uniswap_v2`
|
||||||
|
(bool success,) = tychoRouterAddr.call(
|
||||||
|
hex"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010500"
|
||||||
|
);
|
||||||
|
|
||||||
|
vm.stopPrank();
|
||||||
|
|
||||||
|
uint256 balanceAfter = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
assertTrue(success, "Call Failed");
|
||||||
|
assertEq(balanceAfter - balanceBefore, 2554299052);
|
||||||
|
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testUSV3USV3Integration() public {
|
||||||
|
// Performs a sequential swap from WETH to USDC though WBTC using USV3 pools
|
||||||
|
//
|
||||||
|
// WETH ──(USV3)──> WBTC ───(USV3)──> USDC
|
||||||
|
deal(WETH_ADDR, ALICE, 1 ether);
|
||||||
|
uint256 balanceBefore = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
// Approve permit2
|
||||||
|
vm.startPrank(ALICE);
|
||||||
|
IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
||||||
|
// Encoded solution generated using `test_uniswap_v3_uniswap_v3`
|
||||||
|
(bool success,) = tychoRouterAddr.call(
|
||||||
|
hex"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010000000000000000000000"
|
||||||
|
);
|
||||||
|
|
||||||
|
vm.stopPrank();
|
||||||
|
|
||||||
|
uint256 balanceAfter = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
assertTrue(success, "Call Failed");
|
||||||
|
assertEq(balanceAfter - balanceBefore, 2647438249);
|
||||||
|
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testUSV3CurveIntegration() public {
|
||||||
|
// Performs a sequential swap from WETH to USDT though WBTC using USV3 and Curve pools
|
||||||
|
//
|
||||||
|
// WETH ──(USV3)──> WBTC ───(USV3)──> USDT
|
||||||
|
deal(WETH_ADDR, ALICE, 1 ether);
|
||||||
|
uint256 balanceBefore = IERC20(USDT_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
// Approve permit2
|
||||||
|
vm.startPrank(ALICE);
|
||||||
|
IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
||||||
|
// Encoded solution generated using `test_uniswap_v3_curve`
|
||||||
|
(bool success,) = tychoRouterAddr.call(
|
||||||
|
hex"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000"
|
||||||
|
);
|
||||||
|
|
||||||
|
vm.stopPrank();
|
||||||
|
|
||||||
|
uint256 balanceAfter = IERC20(USDT_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
assertTrue(success, "Call Failed");
|
||||||
|
assertEq(balanceAfter - balanceBefore, 2650183330);
|
||||||
|
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testBalancerV2USV2Integration() public {
|
||||||
|
// Performs a sequential swap from WETH to USDC though WBTC using Balancer v2 and USV2 pools
|
||||||
|
//
|
||||||
|
// WETH ──(balancer)──> WBTC ───(USV2)──> USDC
|
||||||
|
deal(WETH_ADDR, ALICE, 1 ether);
|
||||||
|
uint256 balanceBefore = IERC20(USDT_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
// Approve permit2
|
||||||
|
vm.startPrank(ALICE);
|
||||||
|
IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
||||||
|
// Encoded solution generated using `test_uniswap_v3_curve`
|
||||||
|
(bool success,) = tychoRouterAddr.call(
|
||||||
|
hex"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010300525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000"
|
||||||
|
);
|
||||||
|
|
||||||
|
vm.stopPrank();
|
||||||
|
|
||||||
|
uint256 balanceAfter = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
assertTrue(success, "Call Failed");
|
||||||
|
assertEq(balanceAfter - balanceBefore, 2549391308);
|
||||||
|
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ pub const PROTOCOL_SPECIFIC_CONFIG: &str =
|
|||||||
pub static GROUPABLE_PROTOCOLS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
|
pub static GROUPABLE_PROTOCOLS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
|
||||||
let mut set = HashSet::new();
|
let mut set = HashSet::new();
|
||||||
set.insert("uniswap_v4");
|
set.insert("uniswap_v4");
|
||||||
set.insert("balancer_v3");
|
set.insert("vm:balancer_v3");
|
||||||
set.insert("ekubo_v2");
|
set.insert("ekubo_v2");
|
||||||
set
|
set
|
||||||
});
|
});
|
||||||
@@ -23,18 +23,21 @@ pub static IN_TRANSFER_OPTIMIZABLE_PROTOCOLS: LazyLock<HashSet<&'static str>> =
|
|||||||
LazyLock::new(|| {
|
LazyLock::new(|| {
|
||||||
let mut set = HashSet::new();
|
let mut set = HashSet::new();
|
||||||
set.insert("uniswap_v2");
|
set.insert("uniswap_v2");
|
||||||
|
set.insert("sushiswap_v2");
|
||||||
|
set.insert("pancakeswap_v2");
|
||||||
set.insert("uniswap_v3");
|
set.insert("uniswap_v3");
|
||||||
|
set.insert("pancakeswap_v3");
|
||||||
set.insert("ekubo_v2");
|
set.insert("ekubo_v2");
|
||||||
set
|
set
|
||||||
});
|
});
|
||||||
|
|
||||||
/// These protocols expect funds to be in the router at the time of swap.
|
// These protocols do not support chained swaps from the same protocol. This is the case for uniswap
|
||||||
pub static PROTOCOLS_EXPECTING_FUNDS_IN_ROUTER: LazyLock<HashSet<&'static str>> =
|
// v3 because of the callback logic. The only way for this to work it would be to call the second
|
||||||
|
// swap during the callback of the first swap. This is currently not supported.
|
||||||
|
pub static PROTOCOLS_NOT_OPTIMIZED_CHAINED_SWAPS: LazyLock<HashSet<&'static str>> =
|
||||||
LazyLock::new(|| {
|
LazyLock::new(|| {
|
||||||
let mut set = HashSet::new();
|
let mut set = HashSet::new();
|
||||||
set.insert("vm:curve");
|
set.insert("uniswap_v3");
|
||||||
set.insert("balancer_v2");
|
set.insert("pancakeswap_v3");
|
||||||
// TODO remove uniswap_v4 when we add callback support for transfer optimizations
|
|
||||||
set.insert("uniswap_v4");
|
|
||||||
set
|
set
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ mod tests {
|
|||||||
|
|
||||||
let swap_weth_wbtc = Swap {
|
let swap_weth_wbtc = Swap {
|
||||||
component: ProtocolComponent {
|
component: ProtocolComponent {
|
||||||
protocol_system: "balancer_v3".to_string(),
|
protocol_system: "vm:balancer_v3".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
token_in: weth.clone(),
|
token_in: weth.clone(),
|
||||||
@@ -264,7 +264,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let swap_wbtc_usdc = Swap {
|
let swap_wbtc_usdc = Swap {
|
||||||
component: ProtocolComponent {
|
component: ProtocolComponent {
|
||||||
protocol_system: "balancer_v3".to_string(),
|
protocol_system: "vm:balancer_v3".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
token_in: wbtc.clone(),
|
token_in: wbtc.clone(),
|
||||||
@@ -306,7 +306,7 @@ mod tests {
|
|||||||
swaps: vec![swap_weth_wbtc, swap_wbtc_usdc],
|
swaps: vec![swap_weth_wbtc, swap_wbtc_usdc],
|
||||||
input_token: weth.clone(),
|
input_token: weth.clone(),
|
||||||
output_token: usdc.clone(),
|
output_token: usdc.clone(),
|
||||||
protocol_system: "balancer_v3".to_string(),
|
protocol_system: "vm:balancer_v3".to_string(),
|
||||||
split: 0.5f64,
|
split: 0.5f64,
|
||||||
},
|
},
|
||||||
SwapGroup {
|
SwapGroup {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use crate::encoding::{
|
|||||||
errors::EncodingError,
|
errors::EncodingError,
|
||||||
evm::{
|
evm::{
|
||||||
approvals::permit2::Permit2,
|
approvals::permit2::Permit2,
|
||||||
|
constants::{IN_TRANSFER_OPTIMIZABLE_PROTOCOLS, PROTOCOLS_NOT_OPTIMIZED_CHAINED_SWAPS},
|
||||||
group_swaps::group_swaps,
|
group_swaps::group_swaps,
|
||||||
strategy_encoder::{
|
strategy_encoder::{
|
||||||
strategy_validators::{SequentialSwapValidator, SplitSwapValidator, SwapValidator},
|
strategy_validators::{SequentialSwapValidator, SplitSwapValidator, SwapValidator},
|
||||||
@@ -133,6 +134,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
|||||||
self.wrapped_address.clone(),
|
self.wrapped_address.clone(),
|
||||||
self.permit2.clone().is_some(),
|
self.permit2.clone().is_some(),
|
||||||
wrap,
|
wrap,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
let encoding_context = EncodingContext {
|
let encoding_context = EncodingContext {
|
||||||
@@ -289,6 +291,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut swaps = vec![];
|
let mut swaps = vec![];
|
||||||
|
let mut next_in_between_swap_optimization = true;
|
||||||
for (i, grouped_swap) in grouped_swaps.iter().enumerate() {
|
for (i, grouped_swap) in grouped_swaps.iter().enumerate() {
|
||||||
let protocol = grouped_swap.protocol_system.clone();
|
let protocol = grouped_swap.protocol_system.clone();
|
||||||
let swap_encoder = self
|
let swap_encoder = self
|
||||||
@@ -300,12 +303,31 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// if it is the last swap and there isn't an unwrap at the end, we can set the receiver
|
let in_between_swap_optimization = next_in_between_swap_optimization;
|
||||||
// to the final user
|
let next_swap = grouped_swaps.get(i + 1);
|
||||||
let swap_receiver = if i == grouped_swaps.len() - 1 && !unwrap {
|
// if there is a next swap
|
||||||
solution.receiver.clone()
|
let swap_receiver = if let Some(next) = next_swap {
|
||||||
} else {
|
// if the protocol of the next swap supports transfer in optimization
|
||||||
|
if IN_TRANSFER_OPTIMIZABLE_PROTOCOLS.contains(&next.protocol_system.as_str()) {
|
||||||
|
// if the protocol does not allow for chained swaps, we can't optimize the
|
||||||
|
// receiver of this swap nor the transfer in of the next swap
|
||||||
|
if PROTOCOLS_NOT_OPTIMIZED_CHAINED_SWAPS
|
||||||
|
.contains(&next.protocol_system.as_str()) &&
|
||||||
|
PROTOCOLS_NOT_OPTIMIZED_CHAINED_SWAPS.contains(protocol.as_str())
|
||||||
|
{
|
||||||
|
next_in_between_swap_optimization = false;
|
||||||
self.router_address.clone()
|
self.router_address.clone()
|
||||||
|
} else {
|
||||||
|
Bytes::from_str(&next.swaps[0].component.id.clone()).map_err(|_| {
|
||||||
|
EncodingError::FatalError("Invalid component id".to_string())
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the protocol of the next swap does not support transfer in optimization
|
||||||
|
self.router_address.clone()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
solution.receiver.clone() // last swap - there is not next swap
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||||
@@ -317,6 +339,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
|||||||
self.wrapped_address.clone(),
|
self.wrapped_address.clone(),
|
||||||
self.permit2.clone().is_some(),
|
self.permit2.clone().is_some(),
|
||||||
wrap,
|
wrap,
|
||||||
|
in_between_swap_optimization,
|
||||||
);
|
);
|
||||||
|
|
||||||
let encoding_context = EncodingContext {
|
let encoding_context = EncodingContext {
|
||||||
@@ -553,6 +576,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
|||||||
self.wrapped_address.clone(),
|
self.wrapped_address.clone(),
|
||||||
self.permit2.clone().is_some(),
|
self.permit2.clone().is_some(),
|
||||||
wrap,
|
wrap,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
let encoding_context = EncodingContext {
|
let encoding_context = EncodingContext {
|
||||||
@@ -1148,12 +1172,15 @@ mod tests {
|
|||||||
println!("test_split_swap_strategy_encoder_complex_route: {}", _hex_calldata);
|
println!("test_split_swap_strategy_encoder_complex_route: {}", _hex_calldata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod sequential {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sequential_swap_strategy_encoder_complex_route() {
|
fn test_sequential_swap_strategy_encoder_complex_route() {
|
||||||
// Note: This test does not assert anything. It is only used to obtain integration test
|
// Note: This test does not assert anything. It is only used to obtain integration test
|
||||||
// data for our router solidity test.
|
// data for our router solidity test.
|
||||||
//
|
//
|
||||||
// Performs a split swap from WETH to USDC though WBTC and DAI using USV2 pools
|
// Performs a sequential swap from WETH to USDC though WBTC using USV2 pools
|
||||||
//
|
//
|
||||||
// WETH ───(USV2)──> WBTC ───(USV2)──> USDC
|
// WETH ───(USV2)──> WBTC ───(USV2)──> USDC
|
||||||
|
|
||||||
@@ -1216,7 +1243,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sequential_swap_strategy_encoder_no_permit2() {
|
fn test_sequential_swap_strategy_encoder_no_permit2() {
|
||||||
// Performs a split swap from WETH to USDC though WBTC and DAI using USV2 pools
|
// Performs a sequential swap from WETH to USDC though WBTC using USV2 pools
|
||||||
//
|
//
|
||||||
// WETH ───(USV2)──> WBTC ───(USV2)──> USDC
|
// WETH ───(USV2)──> WBTC ───(USV2)──> USDC
|
||||||
|
|
||||||
@@ -1277,7 +1304,7 @@ mod tests {
|
|||||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou
|
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou
|
||||||
"00000000000000000000000000000000000000000000000000000000018f61ec", // min amount out
|
"00000000000000000000000000000000000000000000000000000000018f61ec", /* min amount out */
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
@@ -1289,7 +1316,7 @@ mod tests {
|
|||||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||||
"bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id
|
"bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id
|
||||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver (router)
|
"004375dff511095cc5a197a54140a24efef3a416", // receiver (next pool)
|
||||||
"00", // zero to one
|
"00", // zero to one
|
||||||
"01", // transfer type
|
"01", // transfer type
|
||||||
// swap 2
|
// swap 2
|
||||||
@@ -1299,13 +1326,312 @@ mod tests {
|
|||||||
"004375dff511095cc5a197a54140a24efef3a416", // component id
|
"004375dff511095cc5a197a54140a24efef3a416", // component id
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user)
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user)
|
||||||
"01", // zero to one
|
"01", // zero to one
|
||||||
"00", // transfer type
|
"05", // transfer type - None
|
||||||
"000000000000000000000000000000000000000000000000", // padding
|
"000000000000000000000000000000000000000000000000", // padding
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(hex_calldata, expected);
|
assert_eq!(hex_calldata, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uniswap_v3_uniswap_v2() {
|
||||||
|
// Note: This test does not assert anything. It is only used to obtain integration test
|
||||||
|
// data for our router solidity test.
|
||||||
|
//
|
||||||
|
// Performs a sequential swap from WETH to USDC though WBTC using USV3 and USV2
|
||||||
|
// pools
|
||||||
|
//
|
||||||
|
// WETH ───(USV3)──> WBTC ───(USV2)──> USDC
|
||||||
|
|
||||||
|
let weth = weth();
|
||||||
|
let wbtc = Bytes::from_str("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599").unwrap();
|
||||||
|
let usdc = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap();
|
||||||
|
|
||||||
|
let swap_weth_wbtc = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: "0xCBCdF9626bC03E24f779434178A73a0B4bad62eD".to_string(),
|
||||||
|
protocol_system: "uniswap_v3".to_string(),
|
||||||
|
static_attributes: {
|
||||||
|
let mut attrs = HashMap::new();
|
||||||
|
attrs.insert(
|
||||||
|
"fee".to_string(),
|
||||||
|
Bytes::from(BigInt::from(3000).to_signed_bytes_be()),
|
||||||
|
);
|
||||||
|
attrs
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: weth.clone(),
|
||||||
|
token_out: wbtc.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
let swap_wbtc_usdc = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: "0x004375Dff511095CC5A197A54140a24eFEF3A416".to_string(),
|
||||||
|
protocol_system: "uniswap_v2".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: wbtc.clone(),
|
||||||
|
token_out: usdc.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
let swap_encoder_registry = get_swap_encoder_registry();
|
||||||
|
let encoder = SequentialSwapStrategyEncoder::new(
|
||||||
|
eth_chain(),
|
||||||
|
swap_encoder_registry,
|
||||||
|
None,
|
||||||
|
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let solution = Solution {
|
||||||
|
exact_out: false,
|
||||||
|
given_token: weth,
|
||||||
|
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||||
|
checked_token: usdc,
|
||||||
|
expected_amount: None,
|
||||||
|
checked_amount: Some(BigUint::from_str("26173932").unwrap()),
|
||||||
|
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
swaps: vec![swap_weth_wbtc, swap_wbtc_usdc],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (calldata, _) = encoder
|
||||||
|
.encode_strategy(solution)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let _hex_calldata = encode(&calldata);
|
||||||
|
println!("test_uniswap_v3_uniswap_v2: {}", _hex_calldata);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uniswap_v3_uniswap_v3() {
|
||||||
|
// Note: This test does not assert anything. It is only used to obtain integration test
|
||||||
|
// data for our router solidity test.
|
||||||
|
//
|
||||||
|
// Performs a sequential swap from WETH to USDC though WBTC using USV3 pools
|
||||||
|
// There is no optimization between the two USV3 pools, this is currently not supported.
|
||||||
|
//
|
||||||
|
// WETH ───(USV3)──> WBTC ───(USV3)──> USDC
|
||||||
|
|
||||||
|
let weth = weth();
|
||||||
|
let wbtc = Bytes::from_str("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599").unwrap();
|
||||||
|
let usdc = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap();
|
||||||
|
|
||||||
|
let swap_weth_wbtc = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: "0xCBCdF9626bC03E24f779434178A73a0B4bad62eD".to_string(),
|
||||||
|
protocol_system: "uniswap_v3".to_string(),
|
||||||
|
static_attributes: {
|
||||||
|
let mut attrs = HashMap::new();
|
||||||
|
attrs.insert(
|
||||||
|
"fee".to_string(),
|
||||||
|
Bytes::from(BigInt::from(3000).to_signed_bytes_be()),
|
||||||
|
);
|
||||||
|
attrs
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: weth.clone(),
|
||||||
|
token_out: wbtc.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
let swap_wbtc_usdc = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: "0x99ac8cA7087fA4A2A1FB6357269965A2014ABc35".to_string(),
|
||||||
|
protocol_system: "uniswap_v3".to_string(),
|
||||||
|
static_attributes: {
|
||||||
|
let mut attrs = HashMap::new();
|
||||||
|
attrs.insert(
|
||||||
|
"fee".to_string(),
|
||||||
|
Bytes::from(BigInt::from(3000).to_signed_bytes_be()),
|
||||||
|
);
|
||||||
|
attrs
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: wbtc.clone(),
|
||||||
|
token_out: usdc.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
let swap_encoder_registry = get_swap_encoder_registry();
|
||||||
|
let encoder = SequentialSwapStrategyEncoder::new(
|
||||||
|
eth_chain(),
|
||||||
|
swap_encoder_registry,
|
||||||
|
None,
|
||||||
|
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let solution = Solution {
|
||||||
|
exact_out: false,
|
||||||
|
given_token: weth,
|
||||||
|
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||||
|
checked_token: usdc,
|
||||||
|
expected_amount: None,
|
||||||
|
checked_amount: Some(BigUint::from_str("26173932").unwrap()),
|
||||||
|
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
swaps: vec![swap_weth_wbtc, swap_wbtc_usdc],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (calldata, _) = encoder
|
||||||
|
.encode_strategy(solution)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let _hex_calldata = encode(&calldata);
|
||||||
|
println!("test_uniswap_v3_uniswap_v3: {}", _hex_calldata);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uniswap_v3_curve() {
|
||||||
|
// Note: This test does not assert anything. It is only used to obtain integration test
|
||||||
|
// data for our router solidity test.
|
||||||
|
//
|
||||||
|
// Performs a sequential swap from WETH to USDT though WBTC using USV3 and curve
|
||||||
|
// pools
|
||||||
|
//
|
||||||
|
// WETH ───(USV3)──> WBTC ───(curve)──> USDT
|
||||||
|
|
||||||
|
let weth = weth();
|
||||||
|
let wbtc = Bytes::from_str("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599").unwrap();
|
||||||
|
let usdt = Bytes::from_str("0xdAC17F958D2ee523a2206206994597C13D831ec7").unwrap();
|
||||||
|
|
||||||
|
let swap_weth_wbtc = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: "0xCBCdF9626bC03E24f779434178A73a0B4bad62eD".to_string(),
|
||||||
|
protocol_system: "uniswap_v3".to_string(),
|
||||||
|
static_attributes: {
|
||||||
|
let mut attrs = HashMap::new();
|
||||||
|
attrs.insert(
|
||||||
|
"fee".to_string(),
|
||||||
|
Bytes::from(BigInt::from(3000).to_signed_bytes_be()),
|
||||||
|
);
|
||||||
|
attrs
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: weth.clone(),
|
||||||
|
token_out: wbtc.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
|
||||||
|
let swap_wbtc_usdt = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: String::from("0xD51a44d3FaE010294C616388b506AcdA1bfAAE46"),
|
||||||
|
protocol_system: String::from("vm:curve"),
|
||||||
|
static_attributes: {
|
||||||
|
let mut attrs: HashMap<String, Bytes> = HashMap::new();
|
||||||
|
attrs.insert(
|
||||||
|
"factory".into(),
|
||||||
|
Bytes::from(
|
||||||
|
"0x0000000000000000000000000000000000000000"
|
||||||
|
.as_bytes()
|
||||||
|
.to_vec(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
attrs
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: wbtc.clone(),
|
||||||
|
token_out: usdt.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
let swap_encoder_registry = get_swap_encoder_registry();
|
||||||
|
let encoder = SequentialSwapStrategyEncoder::new(
|
||||||
|
eth_chain(),
|
||||||
|
swap_encoder_registry,
|
||||||
|
None,
|
||||||
|
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let solution = Solution {
|
||||||
|
exact_out: false,
|
||||||
|
given_token: weth,
|
||||||
|
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||||
|
checked_token: usdt,
|
||||||
|
expected_amount: None,
|
||||||
|
checked_amount: Some(BigUint::from_str("26173932").unwrap()),
|
||||||
|
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
swaps: vec![swap_weth_wbtc, swap_wbtc_usdt],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (calldata, _) = encoder
|
||||||
|
.encode_strategy(solution)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let _hex_calldata = encode(&calldata);
|
||||||
|
println!("test_uniswap_v3_curve: {}", _hex_calldata);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_balancer_v2_uniswap_v2() {
|
||||||
|
// Note: This test does not assert anything. It is only used to obtain integration test
|
||||||
|
// data for our router solidity test.
|
||||||
|
//
|
||||||
|
// Performs a sequential swap from WETH to USDC though WBTC using balancer and USV2
|
||||||
|
// pools
|
||||||
|
//
|
||||||
|
// WETH ───(balancer)──> WBTC ───(USV2)──> USDC
|
||||||
|
|
||||||
|
let weth = weth();
|
||||||
|
let wbtc = Bytes::from_str("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599").unwrap();
|
||||||
|
let usdc = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap();
|
||||||
|
|
||||||
|
let swap_weth_wbtc = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: "0xa6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e"
|
||||||
|
.to_string(),
|
||||||
|
protocol_system: "vm:balancer_v2".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: weth.clone(),
|
||||||
|
token_out: wbtc.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
|
||||||
|
let swap_wbtc_usdc = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: "0x004375Dff511095CC5A197A54140a24eFEF3A416".to_string(),
|
||||||
|
protocol_system: "uniswap_v2".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: wbtc.clone(),
|
||||||
|
token_out: usdc.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
let swap_encoder_registry = get_swap_encoder_registry();
|
||||||
|
let encoder = SequentialSwapStrategyEncoder::new(
|
||||||
|
eth_chain(),
|
||||||
|
swap_encoder_registry,
|
||||||
|
None,
|
||||||
|
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let solution = Solution {
|
||||||
|
exact_out: false,
|
||||||
|
given_token: weth,
|
||||||
|
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||||
|
checked_token: usdc,
|
||||||
|
expected_amount: None,
|
||||||
|
checked_amount: Some(BigUint::from_str("26173932").unwrap()),
|
||||||
|
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
swaps: vec![swap_weth_wbtc, swap_wbtc_usdc],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (calldata, _) = encoder
|
||||||
|
.encode_strategy(solution)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let _hex_calldata = encode(&calldata);
|
||||||
|
println!("test_balancer_v2_uniswap_v2: {}", _hex_calldata);
|
||||||
|
}
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_split_encoding_strategy_usv4() {
|
fn test_split_encoding_strategy_usv4() {
|
||||||
// Performs a sequential swap from USDC to PEPE though ETH using two consecutive USV4 pools
|
// Performs a sequential swap from USDC to PEPE though ETH using two consecutive USV4 pools
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
use tycho_common::Bytes;
|
use tycho_common::Bytes;
|
||||||
|
|
||||||
use crate::encoding::{
|
use crate::encoding::{
|
||||||
evm::constants::{IN_TRANSFER_OPTIMIZABLE_PROTOCOLS, PROTOCOLS_EXPECTING_FUNDS_IN_ROUTER},
|
evm::constants::IN_TRANSFER_OPTIMIZABLE_PROTOCOLS,
|
||||||
models::{Swap, TransferType},
|
models::{Swap, TransferType},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A trait that defines how the tokens will be transferred into the given pool given the solution.
|
/// A trait that defines how the tokens will be transferred into the given pool given the solution.
|
||||||
pub trait TransferOptimization {
|
pub trait TransferOptimization {
|
||||||
/// Returns the transfer method that should be used for the given swap and solution.
|
/// Returns the transfer method that should be used for the given swap and solution.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn get_transfer_type(
|
fn get_transfer_type(
|
||||||
&self,
|
&self,
|
||||||
swap: Swap,
|
swap: Swap,
|
||||||
@@ -16,22 +17,22 @@ pub trait TransferOptimization {
|
|||||||
wrapped_token: Bytes,
|
wrapped_token: Bytes,
|
||||||
permit2: bool,
|
permit2: bool,
|
||||||
wrap: bool,
|
wrap: bool,
|
||||||
|
in_between_swap_optimization: bool,
|
||||||
) -> TransferType {
|
) -> TransferType {
|
||||||
let send_funds_to_pool: bool =
|
let in_transfer_optimizable: bool =
|
||||||
IN_TRANSFER_OPTIMIZABLE_PROTOCOLS.contains(&swap.component.protocol_system.as_str());
|
IN_TRANSFER_OPTIMIZABLE_PROTOCOLS.contains(&swap.component.protocol_system.as_str());
|
||||||
let funds_expected_in_router: bool =
|
|
||||||
PROTOCOLS_EXPECTING_FUNDS_IN_ROUTER.contains(&swap.component.protocol_system.as_str());
|
|
||||||
|
|
||||||
// In the case of wrapping, check if the swap's token in is the wrapped token to
|
|
||||||
// determine if it's the first swap. Otherwise, compare to the given token.
|
|
||||||
let is_first_swap = swap.token_in == given_token;
|
let is_first_swap = swap.token_in == given_token;
|
||||||
|
|
||||||
if swap.token_in == native_token {
|
if swap.token_in == native_token {
|
||||||
// Funds are already in router. All protocols currently take care of native transfers.
|
// Funds are already in router. All protocols currently take care of native transfers.
|
||||||
TransferType::None
|
TransferType::None
|
||||||
} else if (swap.token_in == wrapped_token) && wrap {
|
} else if (swap.token_in == wrapped_token) && wrap {
|
||||||
|
// Wrapping already happened in the router so we can just use a normal transfer.
|
||||||
TransferType::TransferToProtocol
|
TransferType::TransferToProtocol
|
||||||
} else if is_first_swap && send_funds_to_pool {
|
// first swap
|
||||||
|
} else if is_first_swap {
|
||||||
|
if in_transfer_optimizable {
|
||||||
if permit2 {
|
if permit2 {
|
||||||
// Transfer from swapper to pool using permit2.
|
// Transfer from swapper to pool using permit2.
|
||||||
TransferType::TransferPermit2ToProtocol
|
TransferType::TransferPermit2ToProtocol
|
||||||
@@ -39,14 +40,17 @@ pub trait TransferOptimization {
|
|||||||
// Transfer from swapper to pool.
|
// Transfer from swapper to pool.
|
||||||
TransferType::TransferFromToProtocol
|
TransferType::TransferFromToProtocol
|
||||||
}
|
}
|
||||||
} else if is_first_swap && funds_expected_in_router {
|
} else if permit2 {
|
||||||
if permit2 {
|
|
||||||
// Transfer from swapper to router using permit2.
|
// Transfer from swapper to router using permit2.
|
||||||
TransferType::TransferPermit2ToRouter
|
TransferType::TransferPermit2ToRouter
|
||||||
} else {
|
} else {
|
||||||
// Transfer from swapper to router.
|
// Transfer from swapper to router.
|
||||||
TransferType::TransferFromToRouter
|
TransferType::TransferFromToRouter
|
||||||
}
|
}
|
||||||
|
// all other swaps
|
||||||
|
} else if !in_transfer_optimizable || in_between_swap_optimization {
|
||||||
|
// funds should already be in the router or in the next pool
|
||||||
|
TransferType::None
|
||||||
} else {
|
} else {
|
||||||
TransferType::TransferToProtocol
|
TransferType::TransferToProtocol
|
||||||
}
|
}
|
||||||
@@ -93,7 +97,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let strategy = MockStrategy {};
|
let strategy = MockStrategy {};
|
||||||
let transfer_method =
|
let transfer_method =
|
||||||
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), true, false);
|
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), true, false, false);
|
||||||
assert_eq!(transfer_method, TransferType::TransferPermit2ToProtocol);
|
assert_eq!(transfer_method, TransferType::TransferPermit2ToProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +115,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let strategy = MockStrategy {};
|
let strategy = MockStrategy {};
|
||||||
let transfer_method =
|
let transfer_method =
|
||||||
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), false, false);
|
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), false, false, false);
|
||||||
assert_eq!(transfer_method, TransferType::TransferFromToProtocol);
|
assert_eq!(transfer_method, TransferType::TransferFromToProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +134,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let strategy = MockStrategy {};
|
let strategy = MockStrategy {};
|
||||||
let transfer_method =
|
let transfer_method =
|
||||||
strategy.get_transfer_type(swap.clone(), eth(), eth(), weth(), false, false);
|
strategy.get_transfer_type(swap.clone(), eth(), eth(), weth(), false, false, false);
|
||||||
assert_eq!(transfer_method, TransferType::None);
|
assert_eq!(transfer_method, TransferType::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +153,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let strategy = MockStrategy {};
|
let strategy = MockStrategy {};
|
||||||
let transfer_method =
|
let transfer_method =
|
||||||
strategy.get_transfer_type(swap.clone(), eth(), eth(), weth(), false, true);
|
strategy.get_transfer_type(swap.clone(), eth(), eth(), weth(), false, true, false);
|
||||||
assert_eq!(transfer_method, TransferType::TransferToProtocol);
|
assert_eq!(transfer_method, TransferType::TransferToProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +172,45 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let strategy = MockStrategy {};
|
let strategy = MockStrategy {};
|
||||||
let transfer_method =
|
let transfer_method =
|
||||||
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), false, false);
|
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), false, false, false);
|
||||||
assert_eq!(transfer_method, TransferType::TransferToProtocol);
|
assert_eq!(transfer_method, TransferType::TransferToProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_not_first_swap_funds_in_router() {
|
||||||
|
// Not the first swap and the protocol requires the funds to be in the router (which they
|
||||||
|
// already are, so the transfer type is None)
|
||||||
|
let swap = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
protocol_system: "vm:curve".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: usdc(),
|
||||||
|
token_out: dai(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
let strategy = MockStrategy {};
|
||||||
|
let transfer_method =
|
||||||
|
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), false, false, false);
|
||||||
|
assert_eq!(transfer_method, TransferType::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_not_first_swap_in_between_swap_optimization() {
|
||||||
|
// Not the first swap and the in between swaps are optimized. The funds should already be in
|
||||||
|
// the next pool or in the router
|
||||||
|
let swap = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
protocol_system: "uniswap_v2".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: usdc(),
|
||||||
|
token_out: dai(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
let strategy = MockStrategy {};
|
||||||
|
let transfer_method =
|
||||||
|
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), false, false, true);
|
||||||
|
assert_eq!(transfer_method, TransferType::None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user