feat: Rename split swap interfaces

- In preparation for adding single and sequential swap methods.
This commit is contained in:
TAMARA LIPOWSKI
2025-03-14 13:39:14 -04:00
committed by Diana Carvalho
parent 8539b733db
commit 7fc008a718
6 changed files with 389 additions and 381 deletions

View File

@@ -4,7 +4,7 @@ pragma solidity ^0.8.26;
import "@interfaces/IExecutor.sol"; import "@interfaces/IExecutor.sol";
import "@interfaces/ICallback.sol"; import "@interfaces/ICallback.sol";
error Dispatcher__UnapprovedExecutor(); error Dispatcher__UnapprovedExecutor(address executor);
error Dispatcher__NonContractExecutor(); error Dispatcher__NonContractExecutor();
error Dispatcher__InvalidDataLength(); error Dispatcher__InvalidDataLength();
@@ -59,7 +59,7 @@ contract Dispatcher {
bytes calldata data bytes calldata data
) internal returns (uint256 calculatedAmount) { ) internal returns (uint256 calculatedAmount) {
if (!executors[executor]) { if (!executors[executor]) {
revert Dispatcher__UnapprovedExecutor(); revert Dispatcher__UnapprovedExecutor(executor);
} }
// slither-disable-next-line controlled-delegatecall,low-level-calls // slither-disable-next-line controlled-delegatecall,low-level-calls
@@ -84,7 +84,7 @@ contract Dispatcher {
address executor = address(uint160(bytes20(data[data.length - 20:]))); address executor = address(uint160(bytes20(data[data.length - 20:])));
if (!executors[executor]) { if (!executors[executor]) {
revert Dispatcher__UnapprovedExecutor(); revert Dispatcher__UnapprovedExecutor(executor);
} }
// slither-disable-next-line controlled-delegatecall,low-level-calls // slither-disable-next-line controlled-delegatecall,low-level-calls

View File

@@ -133,7 +133,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* *
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable. * @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable.
*/ */
function swap( function splitSwap(
uint256 amountIn, uint256 amountIn,
address tokenIn, address tokenIn,
address tokenOut, address tokenOut,
@@ -145,7 +145,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
bytes calldata swaps bytes calldata swaps
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn); IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
return _swapChecked( return _splitSwapChecked(
amountIn, amountIn,
tokenIn, tokenIn,
tokenOut, tokenOut,
@@ -185,7 +185,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* *
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable. * @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable.
*/ */
function swapPermit2( function splitSwapPermit2(
uint256 amountIn, uint256 amountIn,
address tokenIn, address tokenIn,
address tokenOut, address tokenOut,
@@ -209,7 +209,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
); );
} }
return _swapChecked( return _splitSwapChecked(
amountIn, amountIn,
tokenIn, tokenIn,
tokenOut, tokenOut,
@@ -230,7 +230,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* swap() and swapPermit2() functions. * swap() and swapPermit2() functions.
* *
*/ */
function _swapChecked( function _splitSwapChecked(
uint256 amountIn, uint256 amountIn,
address tokenIn, address tokenIn,
address tokenOut, address tokenOut,
@@ -258,7 +258,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
? address(this).balance ? address(this).balance
: IERC20(tokenIn).balanceOf(address(this)); : IERC20(tokenIn).balanceOf(address(this));
amountOut = _swap(amountIn, nTokens, swaps); amountOut = _splitSwap(amountIn, nTokens, swaps);
uint256 currentBalance = tokenIn == address(0) uint256 currentBalance = tokenIn == address(0)
? address(this).balance ? address(this).balance
: IERC20(tokenIn).balanceOf(address(this)); : IERC20(tokenIn).balanceOf(address(this));
@@ -314,10 +314,11 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* *
* @return The total amount of the buy token obtained after all swaps have been executed. * @return The total amount of the buy token obtained after all swaps have been executed.
*/ */
function _swap(uint256 amountIn, uint256 nTokens, bytes calldata swaps_) function _splitSwap(
internal uint256 amountIn,
returns (uint256) uint256 nTokens,
{ bytes calldata swaps_
) internal returns (uint256) {
if (swaps_.length == 0) { if (swaps_.length == 0) {
revert TychoRouter__EmptySwaps(); revert TychoRouter__EmptySwaps();
} }

View File

@@ -206,7 +206,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
} }
function testSwapSimple() public { function testSplitSwapSimple() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2 // Trade 1 WETH for DAI with 1 swap on Uniswap V2
// 1 WETH -> DAI // 1 WETH -> DAI
// (USV2) // (USV2)
@@ -217,20 +217,20 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
tychoRouter.exposedSwap(amountIn, 2, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps));
uint256 daiBalance = IERC20(DAI_ADDR).balanceOf(tychoRouterAddr); uint256 daiBalance = IERC20(DAI_ADDR).balanceOf(tychoRouterAddr);
assertEq(daiBalance, 2659881924818443699787); assertEq(daiBalance, 2659881924818443699787);
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
} }
function testSwapSimplePermit2() public { function testSplitSwapSimplePermit2() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2 using Permit2 // Trade 1 WETH for DAI with 1 swap on Uniswap V2 using Permit2
// 1 WETH -> DAI // 1 WETH -> DAI
// (USV2) // (USV2)
@@ -247,13 +247,13 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
tychoRouter.swapPermit2( tychoRouter.splitSwapPermit2(
amountIn, amountIn,
WETH_ADDR, WETH_ADDR,
DAI_ADDR, DAI_ADDR,
@@ -274,7 +274,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapMultipleHops() public { function testSplitSwapMultipleHops() public {
// Trade 1 WETH for USDC through DAI with 2 swaps on Uniswap V2 // Trade 1 WETH for USDC through DAI with 2 swaps on Uniswap V2
// 1 WETH -> DAI -> USDC // 1 WETH -> DAI -> USDC
// (univ2) (univ2) // (univ2) (univ2)
@@ -283,7 +283,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
bytes[] memory swaps = new bytes[](2); bytes[] memory swaps = new bytes[](2);
// WETH -> DAI // WETH -> DAI
swaps[0] = encodeSwap( swaps[0] = encodeSplitSwap(
uint8(0), uint8(0),
uint8(1), uint8(1),
uint24(0), uint24(0),
@@ -294,7 +294,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
); );
// DAI -> USDC // DAI -> USDC
swaps[1] = encodeSwap( swaps[1] = encodeSplitSwap(
uint8(1), uint8(1),
uint8(2), uint8(2),
uint24(0), uint24(0),
@@ -302,14 +302,14 @@ contract TychoRouterTest is TychoRouterTestSetup {
encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, tychoRouterAddr, true) encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, tychoRouterAddr, true)
); );
tychoRouter.exposedSwap(amountIn, 3, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 3, pleEncode(swaps));
uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr); uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr);
assertEq(usdcBalance, 2644659787); assertEq(usdcBalance, 2644659787);
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
} }
function testSwapSplitHops() public { function testSplitSwapSplitHops() public {
// Trade 1 WETH for USDC through DAI and WBTC with 4 swaps on Uniswap V2 // Trade 1 WETH for USDC through DAI and WBTC with 4 swaps on Uniswap V2
// -> DAI -> // -> DAI ->
// 1 WETH USDC // 1 WETH USDC
@@ -320,7 +320,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
bytes[] memory swaps = new bytes[](4); bytes[] memory swaps = new bytes[](4);
// WETH -> WBTC (60%) // WETH -> WBTC (60%)
swaps[0] = encodeSwap( swaps[0] = encodeSplitSwap(
uint8(0), uint8(0),
uint8(1), uint8(1),
(0xffffff * 60) / 100, // 60% (0xffffff * 60) / 100, // 60%
@@ -330,7 +330,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
) )
); );
// WBTC -> USDC // WBTC -> USDC
swaps[1] = encodeSwap( swaps[1] = encodeSplitSwap(
uint8(1), uint8(1),
uint8(2), uint8(2),
uint24(0), uint24(0),
@@ -340,7 +340,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
) )
); );
// WETH -> DAI // WETH -> DAI
swaps[2] = encodeSwap( swaps[2] = encodeSplitSwap(
uint8(0), uint8(0),
uint8(3), uint8(3),
uint24(0), uint24(0),
@@ -351,7 +351,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
); );
// DAI -> USDC // DAI -> USDC
swaps[3] = encodeSwap( swaps[3] = encodeSplitSwap(
uint8(3), uint8(3),
uint8(2), uint8(2),
uint24(0), uint24(0),
@@ -359,14 +359,14 @@ contract TychoRouterTest is TychoRouterTestSetup {
encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, tychoRouterAddr, true) encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, tychoRouterAddr, true)
); );
tychoRouter.exposedSwap(amountIn, 4, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps));
uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr); uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr);
assertEq(usdcBalance, 2615491639); assertEq(usdcBalance, 2615491639);
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
} }
function testSwapChecked() public { function testSplitSwapChecked() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2 // Trade 1 WETH for DAI with 1 swap on Uniswap V2
// Does permit2 token approval and transfer // Does permit2 token approval and transfer
// Checks amount out at the end // Checks amount out at the end
@@ -384,14 +384,14 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
uint256 minAmountOut = 2600 * 1e18; uint256 minAmountOut = 2600 * 1e18;
uint256 amountOut = tychoRouter.swapPermit2( uint256 amountOut = tychoRouter.splitSwapPermit2(
amountIn, amountIn,
WETH_ADDR, WETH_ADDR,
DAI_ADDR, DAI_ADDR,
@@ -414,7 +414,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapCheckedUndefinedMinAmount() public { function testSplitSwapCheckedUndefinedMinAmount() public {
// Min amount should always be non-zero. If zero, swap attempt should revert. // Min amount should always be non-zero. If zero, swap attempt should revert.
uint256 amountIn = 1 ether; uint256 amountIn = 1 ether;
@@ -430,7 +430,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
@@ -438,7 +438,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
uint256 minAmountOut = 0; uint256 minAmountOut = 0;
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector); vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
tychoRouter.swapPermit2( tychoRouter.splitSwapPermit2(
amountIn, amountIn,
WETH_ADDR, WETH_ADDR,
DAI_ADDR, DAI_ADDR,
@@ -454,7 +454,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapCheckedNoPermit2() public { function testSplitSwapCheckedNoPermit2() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2 // Trade 1 WETH for DAI with 1 swap on Uniswap V2
// Checks amount out at the end // Checks amount out at the end
uint256 amountIn = 1 ether; uint256 amountIn = 1 ether;
@@ -468,14 +468,14 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
uint256 minAmountOut = 2600 * 1e18; uint256 minAmountOut = 2600 * 1e18;
uint256 amountOut = tychoRouter.swap( uint256 amountOut = tychoRouter.splitSwap(
amountIn, amountIn,
WETH_ADDR, WETH_ADDR,
DAI_ADDR, DAI_ADDR,
@@ -496,7 +496,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapCheckedLessApprovalFailure() public { function testSplitSwapCheckedLessApprovalFailure() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2 // Trade 1 WETH for DAI with 1 swap on Uniswap V2
// Fails while transferring the tokenIn to the router due to insufficient approval // Fails while transferring the tokenIn to the router due to insufficient approval
uint256 amountIn = 1 ether; uint256 amountIn = 1 ether;
@@ -510,7 +510,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
@@ -518,7 +518,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
uint256 minAmountOut = 2600 * 1e18; uint256 minAmountOut = 2600 * 1e18;
vm.expectRevert(); vm.expectRevert();
tychoRouter.swap( tychoRouter.splitSwap(
amountIn, amountIn,
WETH_ADDR, WETH_ADDR,
DAI_ADDR, DAI_ADDR,
@@ -533,7 +533,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapCheckedNegativeSlippageFailure() public { function testSplitSwapCheckedNegativeSlippageFailure() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2 // Trade 1 WETH for DAI with 1 swap on Uniswap V2
// Does permit2 token approval and transfer // Does permit2 token approval and transfer
// Checks amount out at the end and fails // Checks amount out at the end and fails
@@ -551,7 +551,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
@@ -565,7 +565,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
minAmountOut minAmountOut
) )
); );
tychoRouter.swapPermit2( tychoRouter.splitSwapPermit2(
amountIn, amountIn,
WETH_ADDR, WETH_ADDR,
DAI_ADDR, DAI_ADDR,
@@ -581,7 +581,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapFee() public { function testSplitSwapFee() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2 // Trade 1 WETH for DAI with 1 swap on Uniswap V2
// Does permit2 token approval and transfer // Does permit2 token approval and transfer
// Takes fee at the end // Takes fee at the end
@@ -605,13 +605,13 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
uint256 amountOut = tychoRouter.swapPermit2( uint256 amountOut = tychoRouter.splitSwapPermit2(
amountIn, amountIn,
WETH_ADDR, WETH_ADDR,
DAI_ADDR, DAI_ADDR,
@@ -634,7 +634,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapWrapETH() public { function testSplitSwapWrapETH() public {
// Trade 1 ETH (and wrap it) for DAI with 1 swap on Uniswap V2 // Trade 1 ETH (and wrap it) for DAI with 1 swap on Uniswap V2
uint256 amountIn = 1 ether; uint256 amountIn = 1 ether;
@@ -657,13 +657,13 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
uint256 amountOut = tychoRouter.swapPermit2{value: amountIn}( uint256 amountOut = tychoRouter.splitSwapPermit2{value: amountIn}(
amountIn, amountIn,
address(0), address(0),
DAI_ADDR, DAI_ADDR,
@@ -685,7 +685,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapUnwrapETH() public { function testSplitSwapUnwrapETH() public {
// Trade 3k DAI for WETH with 1 swap on Uniswap V2 and unwrap it at the end // Trade 3k DAI for WETH with 1 swap on Uniswap V2 and unwrap it at the end
uint256 amountIn = 3_000 * 10 ** 18; uint256 amountIn = 3_000 * 10 ** 18;
@@ -701,13 +701,13 @@ contract TychoRouterTest is TychoRouterTestSetup {
bytes memory protocolData = bytes memory protocolData =
encodeUniswapV2Swap(DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true); encodeUniswapV2Swap(DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true);
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
uint256 amountOut = tychoRouter.swapPermit2( uint256 amountOut = tychoRouter.splitSwapPermit2(
amountIn, amountIn,
DAI_ADDR, DAI_ADDR,
address(0), address(0),
@@ -728,7 +728,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapSingleUSV3() public { function testSplitSwapSingleUSV3() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V3 // Trade 1 WETH for DAI with 1 swap on Uniswap V3
// 1 WETH -> DAI // 1 WETH -> DAI
// (USV3) // (USV3)
@@ -740,20 +740,20 @@ contract TychoRouterTest is TychoRouterTestSetup {
bytes memory protocolData = encodeUniswapV3Swap( bytes memory protocolData = encodeUniswapV3Swap(
WETH_ADDR, DAI_ADDR, tychoRouterAddr, DAI_WETH_USV3, zeroForOne WETH_ADDR, DAI_ADDR, tychoRouterAddr, DAI_WETH_USV3, zeroForOne
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv3Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv3Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
tychoRouter.exposedSwap(amountIn, 2, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps));
uint256 finalBalance = IERC20(DAI_ADDR).balanceOf(tychoRouterAddr); uint256 finalBalance = IERC20(DAI_ADDR).balanceOf(tychoRouterAddr);
assertGe(finalBalance, expAmountOut); assertGe(finalBalance, expAmountOut);
} }
function testSwapSingleUSV3Permit2() public { function testSplitSwapSingleUSV3Permit2() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V3 using Permit2 // Trade 1 WETH for DAI with 1 swap on Uniswap V3 using Permit2
// 1 WETH -> DAI // 1 WETH -> DAI
// (USV3) // (USV3)
@@ -770,14 +770,14 @@ contract TychoRouterTest is TychoRouterTestSetup {
bytes memory protocolData = encodeUniswapV3Swap( bytes memory protocolData = encodeUniswapV3Swap(
WETH_ADDR, DAI_ADDR, tychoRouterAddr, DAI_WETH_USV3, zeroForOne WETH_ADDR, DAI_ADDR, tychoRouterAddr, DAI_WETH_USV3, zeroForOne
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv3Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv3Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
tychoRouter.swapPermit2( tychoRouter.splitSwapPermit2(
amountIn, amountIn,
WETH_ADDR, WETH_ADDR,
DAI_ADDR, DAI_ADDR,
@@ -801,236 +801,10 @@ contract TychoRouterTest is TychoRouterTestSetup {
uint256 amountIn = 10 ** 18; uint256 amountIn = 10 ** 18;
bytes memory swaps = ""; bytes memory swaps = "";
vm.expectRevert(TychoRouter__EmptySwaps.selector); vm.expectRevert(TychoRouter__EmptySwaps.selector);
tychoRouter.exposedSwap(amountIn, 2, swaps); tychoRouter.exposedSplitSwap(amountIn, 2, swaps);
} }
function testSingleSwapIntegration() public { function testSplitSwapAmountInNotFullySpent() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Tests swapping WETH -> DAI on a USV2 pool
deal(WETH_ADDR, ALICE, 1 ether);
uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE);
// Approve permit2
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_swap_strategy_encoder_simple`
// but manually replacing the executor address
// `5c2f5a71f67c01775180adc06909288b4c329308` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"d499aa880000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000067e4225a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067bc9c620000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000411fdbe0ac6bdafd51044f24b158235effa29797f468cd4684efa379053d3d15d47ed8b8206e3f6e7349f40aad231cc7e04ed25cbea1ac659b575be8cc168fc2361c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(DAI_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 2659881924818443699787);
}
function testSingleSwapWithoutPermit2Integration() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Tests swapping WETH -> DAI on a USV2 pool without permit2
deal(WETH_ADDR, ALICE, 1 ether);
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), 1 ether);
uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE);
// Encoded solution generated using `test_split_swap_strategy_encoder_simple_route_no_permit2`
// but manually replacing the executor address
// `5c2f5a71f67c01775180adc06909288b4c329308` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"0a83cb080000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae37400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000058005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(DAI_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 2659881924818443699787);
}
function testUSV4Integration() public {
// Test created with calldata from our router encoder.
// Performs a sequential swap from USDC to PEPE though ETH using two
// consecutive USV4 pools
//
// USDC ──(USV4)──> ETH ───(USV4)──> PEPE
//
deal(USDC_ADDR, ALICE, 1 ether);
uint256 balancerBefore = IERC20(PEPE_ADDR).balanceOf(ALICE);
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_encoding_strategy_usv4`
// and ensuring that the encoded executor address is the one in this test
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
(bool success,) = tychoRouterAddr.call(
hex"d499aa88000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000067e4237600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067bc9d7e00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004166b5d3bb274c323e08eeba45d308cc9c11216f9aaafad2a22e94b94fec39293e5480f65f6238d7c8f1e8177f39118373e1041b0ab3a674d3041d119bdb6bc39c1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008c008a0001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d231193300f62849f9a0b5bf2913b396098f7c7019b51a820a0000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(PEPE_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 97191013220606467325121599);
}
function testUSV4IntegrationInputETH() public {
// Test created with calldata from our router encoder.
// Performs a single swap from ETH to PEPE without wrapping or unwrapping
//
// ETH ───(USV4)──> PEPE
//
deal(ALICE, 1 ether);
uint256 balancerBefore = IERC20(PEPE_ADDR).balanceOf(ALICE);
// Encoded solution generated using `test_split_encoding_strategy_usv4_eth_in`
// and ensuring that the encoded executor address is the one in this test
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
hex"d499aa880000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000067f01a7800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c894800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416642950b804a47a0abcb17d81cc2a7967d606e00e8de470e0e7827347658160a28b9892f147248b9bf31aad8faa06181aee0c4a612151e9ef4889991b9930b791b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007200700001000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d231193301f62849f9a0b5bf2913b396098f7c7019b51a820a6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(PEPE_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 242373460199848577067005852);
}
function testUSV4IntegrationOutputETH() public {
// Test created with calldata from our router encoder.
// Performs a single swap from USDC to ETH without wrapping or unwrapping
//
// USDC ───(USV4)──> ETH
//
deal(USDC_ADDR, ALICE, 3000_000000);
uint256 balancerBefore = ALICE.balance;
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_encoding_strategy_usv4_eth_out`
// and ensuring that the encoded executor address is the one in this test
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
(bool success,) = tychoRouterAddr.call(
hex"d499aa8800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000067f01af000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c894f80000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000417811cd10b02278128a9e4df9ef2e099cff6ad46ec6ead5ba0b70dd1db5749d573cf4a8821a524bd6cc5b61ce0faf69d1d4b1f9233b93a4b203e79668f250b1a71c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007200700001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a0000000000000000000000000000000000000000000bb800003c0000000000000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = ALICE.balance;
assertTrue(success, "Call Failed");
console.logUint(balancerAfter - balancerBefore);
assertEq(balancerAfter - balancerBefore, 1117254495486192350);
}
function testSingleSwapWithWrapIntegration() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Tests swapping WETH -> DAI on a USV2 pool, but ETH is received from the user
// and wrapped before the swap
deal(ALICE, 1 ether);
uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE);
// Approve permit2
vm.startPrank(ALICE);
// Encoded solution generated using
// `test_split_swap_strategy_encoder_simple_route_wrap`
// but manually replacing the executor address
// `f6c5be66fff9dc69962d73da0a617a827c382329` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
hex"d499aa880000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000067f0192a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c893320000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000419849ede1f59ad3092a3d8f6b5d7a4d3d854c8013d0a728b8556dc9744ddeed6c7edc4987c7724c280d493ca8dd55dd5aa5f5a66a66d85683f8a5b744908752a21b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058005600020000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(DAI_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 2659881924818443699787);
}
function testSingleSwapWithUnwrapIntegration() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Tests swapping DAI -> WETH on a USV2 pool, and WETH is unwrapped to ETH
// before sending back to the user
deal(DAI_ADDR, ALICE, 3000 ether);
uint256 balancerBefore = ALICE.balance;
// Approve permit2
vm.startPrank(ALICE);
IERC20(DAI_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using
// `test_split_swap_strategy_encoder_simple_route_unwrap`
// but manually replacing the executor address
// `f6c5be66fff9dc69962d73da0a617a827c382329` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"d499aa880000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dbd2fc137a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000067f017d700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c891df00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004181b0d9c7bbf7bd3270e22a7ff337b019b006ea60d9e357035b622bfc8e48126343fa9c1342383d3d072c2ddea2072fd5e447e7b6a4b56f5e7973963d18664e5d1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = ALICE.balance;
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 1120007305574805922);
}
function testSplitSwapIntegration() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Performs a split swap from WETH to USDC though WBTC and DAI using USV2 pools
//
// ┌──(USV2)──> WBTC ───(USV2)──> USDC
// WETH ─┤
// └──(USV2)──> DAI ───(USV2)──> USDC
deal(WETH_ADDR, ALICE, 1 ether);
uint256 balancerBefore = IERC20(USDC_ADDR).balanceOf(ALICE);
// Approve permit2
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_swap_strategy_encoder_complex`
// but manually replacing the executor address
// `f6c5be66FFf9DC69962d73da0A617a827c382329` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"d499aa880000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000067f0198700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c8938f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041308a3ba881e23ac794deca324cfd959b808c86bb239b81c9db8873c8392382411f87902e6ceb8e59636d8d6fab4ead1863727f9a2168246c93b678f3ae4ae37b1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160005600028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d0139500005602030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d53ede3eca2a72b3aecc820e955b36f38437d0139501005601030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d0139501"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(USDC_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertGe(balancerAfter - balancerBefore, 26173932);
// All input tokens are transferred to the router at first. Make sure we used
// all of it (and thus our splits are correct).
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
}
function testSwapAmountInNotFullySpent() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2 // Trade 1 WETH for DAI with 1 swap on Uniswap V2
// Has invalid data as input! There is only one swap with 60% of the input amount // Has invalid data as input! There is only one swap with 60% of the input amount
uint256 amountIn = 1 ether; uint256 amountIn = 1 ether;
@@ -1047,7 +821,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(0),
uint8(1), uint8(1),
(0xffffff * 60) / 100, // 60% (0xffffff * 60) / 100, // 60%
@@ -1066,7 +840,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
) )
); );
tychoRouter.swapPermit2( tychoRouter.splitSwapPermit2(
amountIn, amountIn,
WETH_ADDR, WETH_ADDR,
DAI_ADDR, DAI_ADDR,
@@ -1083,7 +857,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapSingleUSV4Callback() public { function testSplitSwapSingleUSV4Callback() public {
uint256 amountIn = 100 ether; uint256 amountIn = 100 ether;
deal(USDE_ADDR, tychoRouterAddr, amountIn); deal(USDE_ADDR, tychoRouterAddr, amountIn);
@@ -1099,19 +873,19 @@ contract TychoRouterTest is TychoRouterTestSetup {
USDE_ADDR, USDT_ADDR, true, address(usv4Executor), pools USDE_ADDR, USDT_ADDR, true, address(usv4Executor), pools
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
tychoRouter.exposedSwap(amountIn, 2, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps));
assertEq(IERC20(USDT_ADDR).balanceOf(tychoRouterAddr), 99943852); assertEq(IERC20(USDT_ADDR).balanceOf(tychoRouterAddr), 99943852);
} }
function testSwapSingleUSV4CallbackPermit2() public { function testSplitSwapSingleUSV4CallbackPermit2() public {
vm.startPrank(ALICE); vm.startPrank(ALICE);
uint256 amountIn = 100 ether; uint256 amountIn = 100 ether;
deal(USDE_ADDR, ALICE, amountIn); deal(USDE_ADDR, ALICE, amountIn);
@@ -1132,14 +906,14 @@ contract TychoRouterTest is TychoRouterTestSetup {
USDE_ADDR, USDT_ADDR, true, address(usv4Executor), pools USDE_ADDR, USDT_ADDR, true, address(usv4Executor), pools
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
tychoRouter.swapPermit2( tychoRouter.splitSwapPermit2(
amountIn, amountIn,
USDE_ADDR, USDE_ADDR,
USDT_ADDR, USDT_ADDR,
@@ -1157,7 +931,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSwapMultipleUSV4Callback() public { function testSplitSwapMultipleUSV4Callback() public {
// This test has two uniswap v4 hops that will be executed inside of the V4 pool manager // This test has two uniswap v4 hops that will be executed inside of the V4 pool manager
// USDE -> USDT -> WBTC // USDE -> USDT -> WBTC
uint256 amountIn = 100 ether; uint256 amountIn = 100 ether;
@@ -1180,14 +954,14 @@ contract TychoRouterTest is TychoRouterTestSetup {
USDE_ADDR, WBTC_ADDR, true, address(usv4Executor), pools USDE_ADDR, WBTC_ADDR, true, address(usv4Executor), pools
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
tychoRouter.exposedSwap(amountIn, 2, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps));
assertEq(IERC20(WBTC_ADDR).balanceOf(tychoRouterAddr), 102718); assertEq(IERC20(WBTC_ADDR).balanceOf(tychoRouterAddr), 102718);
} }
@@ -1209,7 +983,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
bytes[] memory swaps = new bytes[](2); bytes[] memory swaps = new bytes[](2);
// USDC -> WETH // USDC -> WETH
swaps[0] = encodeSwap( swaps[0] = encodeSplitSwap(
uint8(0), uint8(0),
uint8(1), uint8(1),
uint24(0), uint24(0),
@@ -1217,7 +991,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
usdcWethV3Pool1ZeroOneData usdcWethV3Pool1ZeroOneData
); );
// WETH -> USDC // WETH -> USDC
swaps[1] = encodeSwap( swaps[1] = encodeSplitSwap(
uint8(1), uint8(1),
uint8(0), uint8(0),
uint24(0), uint24(0),
@@ -1225,7 +999,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
usdcWethV3Pool2OneZeroData usdcWethV3Pool2OneZeroData
); );
tychoRouter.exposedSwap(amountIn, 2, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps));
assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99889294); assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99889294);
} }
@@ -1254,7 +1028,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
bytes[] memory swaps = new bytes[](3); bytes[] memory swaps = new bytes[](3);
// USDC -> WETH (60% split) // USDC -> WETH (60% split)
swaps[0] = encodeSwap( swaps[0] = encodeSplitSwap(
uint8(0), uint8(0),
uint8(1), uint8(1),
(0xffffff * 60) / 100, // 60% (0xffffff * 60) / 100, // 60%
@@ -1262,7 +1036,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
usdcWethV3Pool1ZeroOneData usdcWethV3Pool1ZeroOneData
); );
// USDC -> WETH (40% remainder) // USDC -> WETH (40% remainder)
swaps[1] = encodeSwap( swaps[1] = encodeSplitSwap(
uint8(0), uint8(0),
uint8(1), uint8(1),
uint24(0), uint24(0),
@@ -1270,14 +1044,14 @@ contract TychoRouterTest is TychoRouterTestSetup {
usdcWethV3Pool2ZeroOneData usdcWethV3Pool2ZeroOneData
); );
// WETH -> USDC // WETH -> USDC
swaps[2] = encodeSwap( swaps[2] = encodeSplitSwap(
uint8(1), uint8(1),
uint8(0), uint8(0),
uint24(0), uint24(0),
address(usv2Executor), address(usv2Executor),
wethUsdcV2OneZeroData wethUsdcV2OneZeroData
); );
tychoRouter.exposedSwap(amountIn, 2, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps));
assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99574171); assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99574171);
} }
@@ -1307,11 +1081,11 @@ contract TychoRouterTest is TychoRouterTestSetup {
bytes[] memory swaps = new bytes[](3); bytes[] memory swaps = new bytes[](3);
// USDC -> WETH // USDC -> WETH
swaps[0] = encodeSwap( swaps[0] = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), usdcWethV2Data uint8(0), uint8(1), uint24(0), address(usv2Executor), usdcWethV2Data
); );
// WETH -> USDC // WETH -> USDC
swaps[1] = encodeSwap( swaps[1] = encodeSplitSwap(
uint8(1), uint8(1),
uint8(0), uint8(0),
(0xffffff * 60) / 100, (0xffffff * 60) / 100,
@@ -1320,7 +1094,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
); );
// WETH -> USDC // WETH -> USDC
swaps[2] = encodeSwap( swaps[2] = encodeSplitSwap(
uint8(1), uint8(1),
uint8(0), uint8(0),
uint24(0), uint24(0),
@@ -1328,70 +1102,13 @@ contract TychoRouterTest is TychoRouterTestSetup {
usdcWethV3Pool2OneZeroData usdcWethV3Pool2OneZeroData
); );
tychoRouter.exposedSwap(amountIn, 2, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps));
assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99525908); assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99525908);
} }
function testCyclicSequentialSwapIntegration() public {
deal(USDC_ADDR, ALICE, 100 * 10 ** 6);
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_cyclic_sequential_swap`
// but manually replacing the executor address
// `dd8559c917393fc8dd2b4dd289c52ff445fde1b0` with the one in this test
// `2e234dae75c793f67a35089c9d99245e1c58470b`
(bool success,) = tychoRouterAddr.call(
hex"d499aa880000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f4308e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000067f67a8b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067cef493000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c07077fc73bb0f5129006061288fa0583c101631307377281d6b8f3feb50aa2d564f9948c92e0e4abc3771d592bd2f22ebb18ccf21b270459b05f272251ce1c71b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de006d00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564001006d01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8000000"
);
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99889294);
vm.stopPrank();
}
function testSplitInputCyclicSwapIntegration() public {
deal(USDC_ADDR, ALICE, 100 * 10 ** 6);
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_input_cyclic_swap`
// but manually replacing the executor addresses with the ones in this test
// `dd8559c917393fc8dd2b4dd289c52ff445fde1b0` to `2e234dae75c793f67a35089c9d99245e1c58470b`
// `f6c5be66fff9dc69962d73da0a617a827c382329` to `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"d499aa880000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000067f6c08700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067cf3a8f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f248bfa39e6801b4173cd4d61e5e5d0c31942eb3c194785f964a82b2c3e05b4b302bccc0924fa4c4ef90854e42865db11f458d3b6a62afddee833f3eb069cd521b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000136006d00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564001006d00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d801005601000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000"
);
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99574171);
vm.stopPrank();
}
function testSplitOutputCyclicSwapIntegration() public {
deal(USDC_ADDR, ALICE, 100 * 10 ** 6);
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_output_cyclic_swap`
// but manually replacing the executor addresses with the ones in this test
// `dd8559c917393fc8dd2b4dd289c52ff445fde1b0` to `2e234dae75c793f67a35089c9d99245e1c58470b`
// `f6c5be66fff9dc69962d73da0a617a827c382329` to `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"d499aa880000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005eea514000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000067f6be9400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067cf389c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c02ad8eceede50085f35ce8e8313ebbac9b379396c6e72a35bb4df0970cbdaaa1a91e6f787641af55b13b926199c844df42fdd2ae7bb287db7e5cc2a8bc1d7f51b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000136005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d0139501006d01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564000006d01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80000000000000000000000"
);
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99525908);
vm.stopPrank();
}
// Base Network Tests // Base Network Tests
// Make sure to set the RPC_URL to base network // Make sure to set the RPC_URL to base network
function testSwapSingleBase() public { function testSplitSwapSingleBase() public {
vm.skip(true); vm.skip(true);
vm.rollFork(26857267); vm.rollFork(26857267);
uint256 amountIn = 10 * 10 ** 6; uint256 amountIn = 10 * 10 ** 6;
@@ -1401,13 +1118,13 @@ contract TychoRouterTest is TychoRouterTestSetup {
BASE_USDC, USDC_MAG7_POOL, tychoRouterAddr, true BASE_USDC, USDC_MAG7_POOL, tychoRouterAddr, true
); );
bytes memory swap = encodeSwap( bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
); );
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
tychoRouter.exposedSwap(amountIn, 2, pleEncode(swaps)); tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps));
assertGt(IERC20(BASE_MAG7).balanceOf(tychoRouterAddr), 1379830606); assertGt(IERC20(BASE_MAG7).balanceOf(tychoRouterAddr), 1379830606);
} }
} }

View File

@@ -0,0 +1,289 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.26;
import "./TychoRouterTestSetup.sol";
contract TychoRouterTestIntegration is TychoRouterTestSetup {
function testSplitSwapSingleIntegration() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Tests swapping WETH -> DAI on a USV2 pool
deal(WETH_ADDR, ALICE, 1 ether);
uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE);
// Approve permit2
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_swap_strategy_encoder_simple`
// but manually replacing the executor address
// `5c2f5a71f67c01775180adc06909288b4c329308` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000067e4225a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067bc9c620000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000411fdbe0ac6bdafd51044f24b158235effa29797f468cd4684efa379053d3d15d47ed8b8206e3f6e7349f40aad231cc7e04ed25cbea1ac659b575be8cc168fc2361c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(DAI_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 2659881924818443699787);
}
function testSplitSwapSingleWithoutPermit2Integration() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Tests swapping WETH -> DAI on a USV2 pool without permit2
deal(WETH_ADDR, ALICE, 1 ether);
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), 1 ether);
uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE);
// Encoded solution generated using `test_split_swap_strategy_encoder_simple_route_no_permit2`
// but manually replacing the executor address
// `5c2f5a71f67c01775180adc06909288b4c329308` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae37400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000058005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(DAI_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 2659881924818443699787);
}
function testSplitUSV4Integration() public {
// Test created with calldata from our router encoder.
// Performs a sequential swap from USDC to PEPE though ETH using two
// consecutive USV4 pools
//
// USDC ──(USV4)──> ETH ───(USV4)──> PEPE
//
deal(USDC_ADDR, ALICE, 1 ether);
uint256 balancerBefore = IERC20(PEPE_ADDR).balanceOf(ALICE);
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_encoding_strategy_usv4`
// and ensuring that the encoded executor address is the one in this test
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
(bool success,) = tychoRouterAddr.call(
hex"7c553846000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000067e4237600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067bc9d7e00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004166b5d3bb274c323e08eeba45d308cc9c11216f9aaafad2a22e94b94fec39293e5480f65f6238d7c8f1e8177f39118373e1041b0ab3a674d3041d119bdb6bc39c1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008c008a0001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d231193300f62849f9a0b5bf2913b396098f7c7019b51a820a0000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(PEPE_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 97191013220606467325121599);
}
function testSplitUSV4IntegrationInputETH() public {
// Test created with calldata from our router encoder.
// Performs a single swap from ETH to PEPE without wrapping or unwrapping
//
// ETH ───(USV4)──> PEPE
//
deal(ALICE, 1 ether);
uint256 balancerBefore = IERC20(PEPE_ADDR).balanceOf(ALICE);
// Encoded solution generated using `test_split_encoding_strategy_usv4_eth_in`
// and ensuring that the encoded executor address is the one in this test
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000067f01a7800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c894800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416642950b804a47a0abcb17d81cc2a7967d606e00e8de470e0e7827347658160a28b9892f147248b9bf31aad8faa06181aee0c4a612151e9ef4889991b9930b791b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007200700001000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d231193301f62849f9a0b5bf2913b396098f7c7019b51a820a6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(PEPE_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 242373460199848577067005852);
}
function testSplitUSV4IntegrationOutputETH() public {
// Test created with calldata from our router encoder.
// Performs a single swap from USDC to ETH without wrapping or unwrapping
//
// USDC ───(USV4)──> ETH
//
deal(USDC_ADDR, ALICE, 3000_000000);
uint256 balancerBefore = ALICE.balance;
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_encoding_strategy_usv4_eth_out`
// and ensuring that the encoded executor address is the one in this test
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
(bool success,) = tychoRouterAddr.call(
hex"7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000067f01af000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c894f80000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000417811cd10b02278128a9e4df9ef2e099cff6ad46ec6ead5ba0b70dd1db5749d573cf4a8821a524bd6cc5b61ce0faf69d1d4b1f9233b93a4b203e79668f250b1a71c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007200700001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a0000000000000000000000000000000000000000000bb800003c0000000000000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = ALICE.balance;
assertTrue(success, "Call Failed");
console.logUint(balancerAfter - balancerBefore);
assertEq(balancerAfter - balancerBefore, 1117254495486192350);
}
function testSplitSwapSingleWithWrapIntegration() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Tests swapping WETH -> DAI on a USV2 pool, but ETH is received from the user
// and wrapped before the swap
deal(ALICE, 1 ether);
uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE);
// Approve permit2
vm.startPrank(ALICE);
// Encoded solution generated using
// `test_split_swap_strategy_encoder_simple_route_wrap`
// but manually replacing the executor address
// `f6c5be66fff9dc69962d73da0a617a827c382329` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000067f0192a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c893320000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000419849ede1f59ad3092a3d8f6b5d7a4d3d854c8013d0a728b8556dc9744ddeed6c7edc4987c7724c280d493ca8dd55dd5aa5f5a66a66d85683f8a5b744908752a21b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058005600020000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(DAI_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 2659881924818443699787);
}
function testSplitSwapSingleWithUnwrapIntegration() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Tests swapping DAI -> WETH on a USV2 pool, and WETH is unwrapped to ETH
// before sending back to the user
deal(DAI_ADDR, ALICE, 3000 ether);
uint256 balancerBefore = ALICE.balance;
// Approve permit2
vm.startPrank(ALICE);
IERC20(DAI_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using
// `test_split_swap_strategy_encoder_simple_route_unwrap`
// but manually replacing the executor address
// `f6c5be66fff9dc69962d73da0a617a827c382329` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dbd2fc137a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000067f017d700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c891df00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004181b0d9c7bbf7bd3270e22a7ff337b019b006ea60d9e357035b622bfc8e48126343fa9c1342383d3d072c2ddea2072fd5e447e7b6a4b56f5e7973963d18664e5d1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000"
);
vm.stopPrank();
uint256 balancerAfter = ALICE.balance;
assertTrue(success, "Call Failed");
assertEq(balancerAfter - balancerBefore, 1120007305574805922);
}
function testSplitSwapIntegration() public {
// Test created with calldata from our router encoder, replacing the executor
// address with the USV2 executor address.
// Performs a split swap from WETH to USDC though WBTC and DAI using USV2 pools
//
// ┌──(USV2)──> WBTC ───(USV2)──> USDC
// WETH ─┤
// └──(USV2)──> DAI ───(USV2)──> USDC
deal(WETH_ADDR, ALICE, 1 ether);
uint256 balancerBefore = IERC20(USDC_ADDR).balanceOf(ALICE);
// Approve permit2
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_swap_strategy_encoder_complex`
// but manually replacing the executor address
// `f6c5be66FFf9DC69962d73da0A617a827c382329` with the one in this test
// `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000067f0198700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067c8938f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041308a3ba881e23ac794deca324cfd959b808c86bb239b81c9db8873c8392382411f87902e6ceb8e59636d8d6fab4ead1863727f9a2168246c93b678f3ae4ae37b1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160005600028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d0139500005602030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d53ede3eca2a72b3aecc820e955b36f38437d0139501005601030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d0139501"
);
vm.stopPrank();
uint256 balancerAfter = IERC20(USDC_ADDR).balanceOf(ALICE);
assertTrue(success, "Call Failed");
assertGe(balancerAfter - balancerBefore, 26173932);
// All input tokens are transferred to the router at first. Make sure we used
// all of it (and thus our splits are correct).
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
}
function testCyclicSequentialSwapIntegration() public {
deal(USDC_ADDR, ALICE, 100 * 10 ** 6);
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_cyclic_sequential_swap`
// but manually replacing the executor address
// `dd8559c917393fc8dd2b4dd289c52ff445fde1b0` with the one in this test
// `2e234dae75c793f67a35089c9d99245e1c58470b`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f4308e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000067f67a8b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067cef493000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c07077fc73bb0f5129006061288fa0583c101631307377281d6b8f3feb50aa2d564f9948c92e0e4abc3771d592bd2f22ebb18ccf21b270459b05f272251ce1c71b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de006d00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564001006d01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8000000"
);
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99889294);
vm.stopPrank();
}
function testSplitInputCyclicSwapIntegration() public {
deal(USDC_ADDR, ALICE, 100 * 10 ** 6);
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_input_cyclic_swap`
// but manually replacing the executor addresses with the ones in this test
// `dd8559c917393fc8dd2b4dd289c52ff445fde1b0` to `2e234dae75c793f67a35089c9d99245e1c58470b`
// `f6c5be66fff9dc69962d73da0a617a827c382329` to `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000067f6c08700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067cf3a8f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f248bfa39e6801b4173cd4d61e5e5d0c31942eb3c194785f964a82b2c3e05b4b302bccc0924fa4c4ef90854e42865db11f458d3b6a62afddee833f3eb069cd521b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000136006d00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564001006d00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d801005601000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000"
);
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99574171);
vm.stopPrank();
}
function testSplitOutputCyclicSwapIntegration() public {
deal(USDC_ADDR, ALICE, 100 * 10 ** 6);
// Approve permit2
vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_output_cyclic_swap`
// but manually replacing the executor addresses with the ones in this test
// `dd8559c917393fc8dd2b4dd289c52ff445fde1b0` to `2e234dae75c793f67a35089c9d99245e1c58470b`
// `f6c5be66fff9dc69962d73da0a617a827c382329` to `5615deb798bb3e4dfa0139dfa1b3d433cc23b72f`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005eea514000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000067f6be9400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067cf389c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c02ad8eceede50085f35ce8e8313ebbac9b379396c6e72a35bb4df0970cbdaaa1a91e6f787641af55b13b926199c844df42fdd2ae7bb287db7e5cc2a8bc1d7f51b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000136005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d0139501006d01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564000006d01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80000000000000000000000"
);
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99525908);
vm.stopPrank();
}
}

View File

@@ -22,16 +22,16 @@ contract TychoRouterExposed is TychoRouter {
return _unwrapETH(amount); return _unwrapETH(amount);
} }
function exposedSwap( function exposedSplitSwap(
uint256 amountIn, uint256 amountIn,
uint256 nTokens, uint256 nTokens,
bytes calldata swaps bytes calldata swaps
) external returns (uint256) { ) external returns (uint256) {
return _swap(amountIn, nTokens, swaps); return _splitSwap(amountIn, nTokens, swaps);
} }
} }
contract TychoRouterTestSetup is Test, Constants { contract TychoRouterTestSetup is Constants {
TychoRouterExposed tychoRouter; TychoRouterExposed tychoRouter;
address tychoRouterAddr; address tychoRouterAddr;
UniswapV2Executor public usv2Executor; UniswapV2Executor public usv2Executor;
@@ -181,7 +181,7 @@ contract TychoRouterTestSetup is Test, Constants {
} }
} }
function encodeSwap( function encodeSplitSwap(
uint8 tokenInIndex, uint8 tokenInIndex,
uint8 tokenOutIndex, uint8 tokenOutIndex,
uint24 split, uint24 split,

View File

@@ -86,11 +86,12 @@ impl SplitSwapStrategyEncoder {
) -> Result<Self, EncodingError> { ) -> Result<Self, EncodingError> {
let chain = Chain::from(blockchain); let chain = Chain::from(blockchain);
let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk {
(Some(Permit2::new(swapper_pk, chain.clone())?), "swapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) (Some(Permit2::new(swapper_pk, chain.clone())?), "splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string())
} else { } else {
( (
None, None,
"swap(uint256,address,address,uint256,bool,bool,uint256,address,bytes)".to_string(), "splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bytes)"
.to_string(),
) )
}; };
Ok(Self { Ok(Self {
@@ -629,7 +630,7 @@ mod tests {
.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));
let expected_input = [ let expected_input = [
"d499aa88", // Function selector "7c553846", // Function selector
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount out "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount out
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
@@ -950,7 +951,7 @@ mod tests {
.unwrap(); .unwrap();
let expected_input = [ let expected_input = [
"d499aa88", // Function selector "7c553846", // Function selector
"000000000000000000000000000000000000000000000000000000003b9aca00", // amount in "000000000000000000000000000000000000000000000000000000003b9aca00", // amount in
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
"0000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933", // token out "0000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933", // token out
@@ -1060,7 +1061,7 @@ mod tests {
.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));
let expected_input = [ let expected_input = [
"0a83cb08", // Function selector "79b9b93b", // Function selector
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount out "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount out
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
@@ -1300,7 +1301,7 @@ mod tests {
.unwrap(); .unwrap();
let hex_calldata = hex::encode(&calldata); let hex_calldata = hex::encode(&calldata);
let expected_input = [ let expected_input = [
"d499aa88", // selector "7c553846", // selector
"0000000000000000000000000000000000000000000000000000000005f5e100", // given amount "0000000000000000000000000000000000000000000000000000000005f5e100", // given amount
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token
@@ -1452,7 +1453,7 @@ mod tests {
let hex_calldata = hex::encode(&calldata); let hex_calldata = hex::encode(&calldata);
let expected_input = [ let expected_input = [
"d499aa88", // selector "7c553846", // selector
"0000000000000000000000000000000000000000000000000000000005f5e100", // given amount "0000000000000000000000000000000000000000000000000000000005f5e100", // given amount
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token
@@ -1609,7 +1610,7 @@ mod tests {
let hex_calldata = hex::encode(&calldata); let hex_calldata = hex::encode(&calldata);
let expected_input = [ let expected_input = [
"d499aa88", // selector "7c553846", // selector
"0000000000000000000000000000000000000000000000000000000005f5e100", // given amount "0000000000000000000000000000000000000000000000000000000005f5e100", // given amount
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token