pragma solidity ^0.8.26;
import "../TychoRouterTestSetup.sol";
import {CommonBase} from "../../lib/forge-std/src/Base.sol";
import {Constants} from "../Constants.sol";
import {TransferManager} from "../../src/TransferManager.sol";
import {
WethExecutor,
WethExecutor__InvalidDataLength,
IWETH
} from "../../src/executors/WethExecutor.sol";
import {StdAssertions} from "../../lib/forge-std/src/StdAssertions.sol";
import {StdChains} from "../../lib/forge-std/src/StdChains.sol";
import {StdCheats, StdCheatsSafe} from "../../lib/forge-std/src/StdCheats.sol";
import {StdUtils} from "../../lib/forge-std/src/StdUtils.sol";
import {TestUtils} from "../TestUtils.sol";
contract WethExecutorExposed is WethExecutor {
constructor(address wethAddress) WethExecutor(wethAddress) {}
function decodeParams(bytes calldata data)
external
pure
returns (bool isWrapping)
{
return _decodeData(data);
}
}
contract WethExecutorTest is TestUtils, Constants {
WethExecutorExposed wethExecutor;
function setUp() public {
vm.createSelectFork(vm.rpcUrl("mainnet"), 23899254);
wethExecutor = new WethExecutorExposed(WETH_ADDR);
}
function testDecodeParamsWrap() public view {
bytes memory params = abi.encodePacked(
uint8(1) // isWrapping = true
);
bool isWrapping = wethExecutor.decodeParams(params);
assertTrue(isWrapping);
}
function testDecodeParamsUnwrap() public view {
bytes memory params = abi.encodePacked(
uint8(0) // isWrapping = false
);
bool isWrapping = wethExecutor.decodeParams(params);
assertFalse(isWrapping);
}
function testDecodeParamsInvalidDataLength() public {
bytes memory invalidParams = abi.encodePacked(BOB);
vm.expectRevert(WethExecutor__InvalidDataLength.selector);
wethExecutor.decodeParams(invalidParams);
}
function testGetTransferDataWrap() public {
bytes memory params = abi.encodePacked(
uint8(1) // isWrapping = true
);
(
TransferManager.TransferType transferType,
address receiver,
address tokenIn,
address tokenOut,
bool outputToRouter
) = wethExecutor.getTransferData(params);
assertEq(
uint8(transferType),
uint8(TransferManager.TransferType.TransferNativeInExecutor)
);
assertEq(receiver, address(this));
assertEq(tokenIn, ETH_ADDR);
assertEq(tokenOut, WETH_ADDR);
assertEq(outputToRouter, true);
}
function testGetTransferDataUnwrap() public {
bytes memory params = abi.encodePacked(
uint8(0) // isWrapping = false
);
(
TransferManager.TransferType transferType,
address receiver,
address tokenIn,
address tokenOut,
bool outputToRouter
) = wethExecutor.getTransferData(params);
assertEq(
uint8(transferType),
uint8(TransferManager.TransferType.ProtocolWillDebit)
);
assertEq(receiver, address(this));
assertEq(tokenIn, WETH_ADDR);
assertEq(tokenOut, ETH_ADDR);
assertEq(outputToRouter, true);
}
function testSwapWrap() public {
// ETH -> wETH
IWETH WETH = IWETH(WETH_ADDR);
uint256 amountIn = 1 ether;
bytes memory protocolData = abi.encodePacked(
uint8(1) // isWrapping = true
);
// Fund the executor with ETH
vm.deal(address(wethExecutor), amountIn);
wethExecutor.swap(amountIn, protocolData, BOB);
assertEq(WETH.balanceOf(address(wethExecutor)), 1 ether);
}
function testSwapUnwrap() public {
// wETH -> ETH
uint256 amountIn = 1 ether;
bytes memory protocolData = abi.encodePacked(
uint8(0) // isWrapping = false
);
// Fund the executor with wETH
deal(WETH_ADDR, address(wethExecutor), amountIn);
uint256 ethBalanceBefore = address(wethExecutor).balance;
wethExecutor.swap(amountIn, protocolData, BOB);
assertEq(address(wethExecutor).balance - ethBalanceBefore, 1 ether);
}
function testDecodeWrapping() public view {
// Generated by the SwapEncoder - test_encode_weth_wrapping
bytes memory protocolData =
loadCallDataFromFile("test_encode_weth_wrapping");
bool isWrapping = wethExecutor.decodeParams(protocolData);
assertTrue(isWrapping);
}
function testDecodeUnwrapping() public view {
// Generated by the SwapEncoder - test_encode_weth_unwrapping
bytes memory protocolData =
loadCallDataFromFile("test_encode_weth_unwrapping");
bool isWrapping = wethExecutor.decodeParams(protocolData);
assertFalse(isWrapping);
}
}
contract wethWrapTest is TychoRouterTestSetup {
function testSingleSwapWrap() public {
// ETH -> wETH
IWETH WETH = IWETH(WETH_ADDR);
uint256 amountIn = 1 ether;
bytes memory callData =
loadCallDataFromFile("test_single_encoding_strategy_weth_wrapping");
// Fund ALICE with ETH to send with the call
vm.deal(ALICE, amountIn);
vm.startPrank(ALICE);
uint256 wethBalanceBefore = WETH.balanceOf(ALICE);
(bool success,) = tychoRouterAddr.call{value: amountIn}(callData);
uint256 wethBalanceAfter = WETH.balanceOf(ALICE);
// Check balances
assertTrue(success, "Call Failed");
assertEq(wethBalanceAfter - wethBalanceBefore, 1 ether);
assertEq(WETH.balanceOf(tychoRouterAddr), 0);
assertEq(tychoRouterAddr.balance, 0);
}
function testSingleSwapUnwrap() public {
// wETH -> ETH
IWETH WETH = IWETH(WETH_ADDR);
uint256 amountIn = 1 ether;
bytes memory callData = loadCallDataFromFile(
"test_single_encoding_strategy_weth_unwrapping"
);
vm.startPrank(BOB);
deal(WETH_ADDR, BOB, amountIn);
WETH.approve(tychoRouterAddr, amountIn);
uint256 wethBalanceBefore = WETH.balanceOf(BOB);
uint256 ethBalanceBefore = BOB.balance;
(bool success,) = tychoRouterAddr.call(callData);
uint256 wethBalanceAfter = WETH.balanceOf(BOB);
uint256 ethBalanceAfter = BOB.balance;
// Check balances
assertTrue(success, "Call Failed");
assertEq(wethBalanceBefore - wethBalanceAfter, 1 ether);
assertEq(ethBalanceAfter - ethBalanceBefore, 1 ether);
assertEq(WETH.balanceOf(tychoRouterAddr), 0);
assertEq(tychoRouterAddr.balance, 0);
}
function testSequentialSwapWrapAdded() public {
// ETH -> wETH -> DAI
IWETH WETH = IWETH(WETH_ADDR);
IERC20 DAI = IERC20(DAI_ADDR);
uint256 amountIn = 1 ether;
bytes memory callData = loadCallDataFromFile(
"test_sequential_encoding_strategy_weth_wrap_added"
);
// Fund Bob with ETH
vm.deal(BOB, amountIn);
vm.startPrank(BOB);
WETH.approve(tychoRouterAddr, amountIn);
uint256 ethBalanceBefore = BOB.balance;
uint256 daiBalanceBefore = DAI.balanceOf(BOB);
(bool success,) = tychoRouterAddr.call{value: amountIn}(callData);
uint256 ethBalanceAfter = BOB.balance;
uint256 daiBalanceAfter = DAI.balanceOf(BOB);
// Check balances
assertTrue(success, "Call Failed");
assertEq(ethBalanceBefore - ethBalanceAfter, 1 ether);
assertEq(
daiBalanceAfter - daiBalanceBefore, 2_018_817_438_608_734_439_722
);
assertEq(WETH.balanceOf(tychoRouterAddr), 0);
assertEq(tychoRouterAddr.balance, 0);
}
}