From 6f8013711734bf7937cc9933b80c7e80f0426397 Mon Sep 17 00:00:00 2001 From: pedrobergamini <41773103+pedrobergamini@users.noreply.github.com> Date: Wed, 4 Jun 2025 19:12:56 -0300 Subject: [PATCH] test: add single, split and sequential scenarios --- foundry/test/Constants.sol | 3 ++ .../test/TychoRouterProtocolIntegration.t.sol | 17 +++++++++ foundry/test/TychoRouterSequentialSwap.t.sol | 23 ++++++++++++ foundry/test/TychoRouterTestSetup.sol | 36 ++++++++++++++++--- 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/foundry/test/Constants.sol b/foundry/test/Constants.sol index cb81d58..559ec7b 100644 --- a/foundry/test/Constants.sol +++ b/foundry/test/Constants.sol @@ -123,6 +123,9 @@ contract Constants is Test, BaseConstants { // Permit2 address PERMIT2_ADDRESS = 0x000000000022D473030F116dDEE9F6B43aC78BA3; + // Bebop Settlement + address BEBOP_SETTLEMENT = 0xbbbbbBB520d69a9775E85b458C58c648259FAD5F; + // Pool Code Init Hashes bytes32 USV2_POOL_CODE_INIT_HASH = 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f; diff --git a/foundry/test/TychoRouterProtocolIntegration.t.sol b/foundry/test/TychoRouterProtocolIntegration.t.sol index 7157310..123a93f 100644 --- a/foundry/test/TychoRouterProtocolIntegration.t.sol +++ b/foundry/test/TychoRouterProtocolIntegration.t.sol @@ -295,4 +295,21 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { vm.stopPrank(); } + + function testSingleBebopIntegration() public { + deal(USDC_ADDR, ALICE, 1000 * 10 ** 6); + uint256 expAmountOut = 1; // Expected minimum WETH amount out + + vm.startPrank(ALICE); + IERC20(USDC_ADDR).approve(tychoRouterAddr, type(uint256).max); + bytes memory callData = loadCallDataFromFile("test_encode_bebop_rfq"); + (bool success,) = tychoRouterAddr.call(callData); + + uint256 finalBalance = IERC20(WETH_ADDR).balanceOf(ALICE); + assertTrue(success, "Call Failed"); + assertGe(finalBalance, expAmountOut); + assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 0); + + vm.stopPrank(); + } } diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index 9c5d710..e5d6ae9 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -494,4 +494,27 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { assertEq(balanceAfter - balanceBefore, 1949668893); assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); } + + function testBebopUSV2Integration() public { + // Performs a sequential swap from USDC to WETH though Bebop and USV2 pools + // + // USDC ──(bebop)──> WETH ───(USV2)──> USDC + deal(USDC_ADDR, ALICE, 1000 * 10 ** 6); + uint256 balanceBefore = IERC20(USDC_ADDR).balanceOf(ALICE); + + // Approve permit2 + vm.startPrank(ALICE); + IERC20(USDC_ADDR).approve(tychoRouterAddr, type(uint256).max); + bytes memory callData = loadCallDataFromFile("test_encode_bebop_rfq"); + (bool success,) = tychoRouterAddr.call(callData); + + vm.stopPrank(); + + uint256 balanceAfter = IERC20(USDC_ADDR).balanceOf(ALICE); + + assertTrue(success, "Call Failed"); + // Expected amount would need to be determined from actual integration test + assertGt(balanceAfter, balanceBefore, "Should receive some tokens"); + assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 0); + } } diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index d8747e4..4f5d661 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.26; import "../src/executors/BalancerV2Executor.sol"; +import "../src/executors/BebopExecutor.sol"; import "../src/executors/CurveExecutor.sol"; import "../src/executors/EkuboExecutor.sol"; import "../src/executors/UniswapV2Executor.sol"; @@ -63,6 +64,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { UniswapV3Executor public pancakev3Executor; UniswapV4Executor public usv4Executor; BalancerV2Executor public balancerv2Executor; + BebopExecutor public bebopExecutor; EkuboExecutor public ekuboExecutor; CurveExecutor public curveExecutor; MaverickV2Executor public maverickv2Executor; @@ -121,20 +123,22 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { factoryPancakeV3, initCodePancakeV3, PERMIT2_ADDRESS ); balancerv2Executor = new BalancerV2Executor(PERMIT2_ADDRESS); + bebopExecutor = new BebopExecutor(BEBOP_SETTLEMENT, PERMIT2_ADDRESS); ekuboExecutor = new EkuboExecutor(ekuboCore, PERMIT2_ADDRESS); curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS); maverickv2Executor = new MaverickV2Executor(MAVERICK_V2_FACTORY, PERMIT2_ADDRESS); - address[] memory executors = new address[](8); + address[] memory executors = new address[](9); executors[0] = address(usv2Executor); executors[1] = address(usv3Executor); executors[2] = address(pancakev3Executor); executors[3] = address(usv4Executor); executors[4] = address(balancerv2Executor); - executors[5] = address(ekuboExecutor); - executors[6] = address(curveExecutor); - executors[7] = address(maverickv2Executor); + executors[5] = address(bebopExecutor); + executors[6] = address(ekuboExecutor); + executors[7] = address(curveExecutor); + executors[8] = address(maverickv2Executor); return executors; } @@ -191,6 +195,30 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { ); } + function encodeBebopSwap( + address tokenIn, + address tokenOut, + RestrictTransferFrom.TransferType transferType, + BebopExecutor.OrderType orderType, + bytes memory quoteData, + uint8 signatureType, + bytes memory signature, + bool approvalNeeded + ) internal pure returns (bytes memory) { + return abi.encodePacked( + tokenIn, + tokenOut, + transferType, + orderType, + uint32(quoteData.length), + quoteData, + signatureType, + uint32(signature.length), + signature, + approvalNeeded ? uint8(1) : uint8(0) + ); + } + function encodeUniswapV2Swap( address tokenIn, address target,