// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.26; import "../TestUtils.sol"; import "../TychoRouterTestSetup.sol"; import "@src/executors/MaverickV2Executor.sol"; import {Constants} from "../Constants.sol"; contract MaverickV2ExecutorExposed is MaverickV2Executor { constructor(address _factory, address _permit2) MaverickV2Executor(_factory, _permit2) {} function decodeParams(bytes calldata data) external pure returns ( IERC20 tokenIn, address target, address receiver, RestrictTransferFrom.TransferType transferType ) { return _decodeData(data); } } contract MaverickV2ExecutorTest is TestUtils, Constants { using SafeERC20 for IERC20; MaverickV2ExecutorExposed maverickV2Exposed; IERC20 GHO = IERC20(GHO_ADDR); IERC20 USDC = IERC20(USDC_ADDR); function setUp() public { uint256 forkBlock = 22096000; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); maverickV2Exposed = new MaverickV2ExecutorExposed(MAVERICK_V2_FACTORY, PERMIT2_ADDRESS); } function testDecodeParams() public view { bytes memory params = abi.encodePacked( GHO_ADDR, GHO_USDC_POOL, address(2), RestrictTransferFrom.TransferType.Transfer ); ( IERC20 tokenIn, address target, address receiver, RestrictTransferFrom.TransferType transferType ) = maverickV2Exposed.decodeParams(params); assertEq(address(tokenIn), GHO_ADDR); assertEq(target, GHO_USDC_POOL); assertEq(receiver, address(2)); assertEq( uint8(transferType), uint8(RestrictTransferFrom.TransferType.Transfer) ); } function testDecodeParamsInvalidDataLength() public { bytes memory invalidParams = abi.encodePacked(GHO_ADDR, GHO_USDC_POOL, address(2)); vm.expectRevert(MaverickV2Executor__InvalidDataLength.selector); maverickV2Exposed.decodeParams(invalidParams); } function testSwap() public { uint256 amountIn = 10e18; bytes memory protocolData = abi.encodePacked( GHO_ADDR, GHO_USDC_POOL, BOB, RestrictTransferFrom.TransferType.Transfer ); deal(GHO_ADDR, address(maverickV2Exposed), amountIn); uint256 balanceBefore = USDC.balanceOf(BOB); uint256 amountOut = maverickV2Exposed.swap(amountIn, protocolData); uint256 balanceAfter = USDC.balanceOf(BOB); assertGt(balanceAfter, balanceBefore); assertEq(balanceAfter - balanceBefore, amountOut); } function testDecodeIntegration() public view { // Generated by the SwapEncoder - test_encode_maverick_v2 bytes memory protocolData = loadCallDataFromFile("test_encode_maverick_v2"); ( IERC20 tokenIn, address pool, address receiver, RestrictTransferFrom.TransferType transferType ) = maverickV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), GHO_ADDR); assertEq(pool, GHO_USDC_POOL); assertEq(receiver, BOB); assertEq( uint8(transferType), uint8(RestrictTransferFrom.TransferType.Transfer) ); } function testSwapIntegration() public { // Generated by the SwapEncoder - test_encode_maverick_v2 bytes memory protocolData = loadCallDataFromFile("test_encode_maverick_v2"); uint256 amountIn = 10 ** 18; deal(GHO_ADDR, address(maverickV2Exposed), amountIn); uint256 balanceBefore = USDC.balanceOf(BOB); uint256 amountOut = maverickV2Exposed.swap(amountIn, protocolData); uint256 balanceAfter = USDC.balanceOf(BOB); assertGt(balanceAfter, balanceBefore); assertEq(balanceAfter - balanceBefore, amountOut); } function testExportContract() public { exportRuntimeBytecode(address(maverickV2Exposed), "MaverickV2"); } } contract TychoRouterForBalancerV3Test is TychoRouterTestSetup { function testSingleMaverickIntegration() public { deal(GHO_ADDR, ALICE, 1 ether); uint256 balanceBefore = IERC20(USDC_ADDR).balanceOf(ALICE); vm.startPrank(ALICE); IERC20(GHO_ADDR).approve(tychoRouterAddr, type(uint256).max); bytes memory callData = loadCallDataFromFile("test_single_encoding_strategy_maverick"); (bool success,) = tychoRouterAddr.call(callData); uint256 balanceAfter = IERC20(USDC_ADDR).balanceOf(ALICE); assertTrue(success, "Call Failed"); assertGe(balanceAfter - balanceBefore, 999725); assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); } }