diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 29ac360..59ca036 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -345,7 +345,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { currentAmountOut = _callExecutor( swapData.executor(), currentAmountIn, swapData.protocolData() ); - amounts[tokenOutIndex] += currentAmountOut; + amounts[tokenOutIndex] = tokenOutIndex == 0 + ? currentAmountOut + : amounts[tokenOutIndex] + currentAmountOut; remainingAmounts[tokenOutIndex] += currentAmountOut; remainingAmounts[tokenInIndex] -= currentAmountIn; } diff --git a/foundry/test/Constants.sol b/foundry/test/Constants.sol index 6a0eb01..8677b87 100644 --- a/foundry/test/Constants.sol +++ b/foundry/test/Constants.sol @@ -50,6 +50,8 @@ contract Constants is Test, BaseConstants { address USV3_FACTORY_ETHEREUM = 0x1F98431c8aD98523631AE4a59f267346ea31F984; address USV2_FACTORY_ETHEREUM = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f; address DAI_WETH_USV3 = 0xC2e9F25Be6257c210d7Adf0D4Cd6E3E881ba25f8; + address USDC_WETH_USV3 = 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640; // 0.05% fee + address USDC_WETH_USV3_2 = 0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8; // 0.3% fee // Uniswap universal router address UNIVERSAL_ROUTER = 0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af; diff --git a/foundry/test/TychoRouter.t.sol b/foundry/test/TychoRouter.t.sol index 3676b59..b7573d3 100644 --- a/foundry/test/TychoRouter.t.sol +++ b/foundry/test/TychoRouter.t.sol @@ -1192,6 +1192,45 @@ contract TychoRouterTest is TychoRouterTestSetup { assertEq(IERC20(WBTC_ADDR).balanceOf(tychoRouterAddr), 102718); } + function testCyclicSwapWithTwoPools() public { + // This test has start and end tokens that are the same + // The flow is: + // USDC -> WETH -> USDC -> WETH -> USDC using two pools, and four swaps + uint256 amountIn = 100 * 10 ** 6; + deal(USDC_ADDR, tychoRouterAddr, amountIn); + + // First pool: USDC -> WETH, in uniswap v3 + bytes memory usdcWethData = encodeUniswapV3Swap( + USDC_ADDR, WETH_ADDR, tychoRouterAddr, USDC_WETH_USV3, true + ); + + // Second pool: WETH -> USDC, in uniswap v3 + bytes memory wethUsdcData = encodeUniswapV3Swap( + WETH_ADDR, USDC_ADDR, tychoRouterAddr, USDC_WETH_USV3_2, false + ); + + bytes[] memory swaps = new bytes[](4); + // USDC -> WETH + swaps[0] = encodeSwap( + uint8(0), uint8(1), uint24(0), address(usv3Executor), usdcWethData + ); + // WETH -> USDC + swaps[1] = encodeSwap( + uint8(1), uint8(0), uint24(0), address(usv3Executor), wethUsdcData + ); + // USDC -> WETH + swaps[2] = encodeSwap( + uint8(0), uint8(1), uint24(0), address(usv3Executor), usdcWethData + ); + // WETH -> USDC + swaps[3] = encodeSwap( + uint8(1), uint8(0), uint24(0), address(usv3Executor), wethUsdcData + ); + + tychoRouter.exposedSwap(amountIn, 2, pleEncode(swaps)); + assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99778590); + } + // Base Network Tests // Make sure to set the RPC_URL to base network function testSwapSingleBase() public {