1+ // SPDX-License-Identifier: MIT
2+ pragma solidity ^ 0.8.20 ;
3+
4+ import "forge-std/Test.sol " ;
5+ import "../../src/AssetSwapper.sol " ;
6+ import "@openzeppelin/contracts/token/ERC20/IERC20.sol " ;
7+
8+ contract AssetSwapperTest is Test {
9+ AssetSwapper public assetSwapper;
10+
11+ address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 ;
12+ address constant UNISWAP_ROUTER =
13+ 0xE592427A0AEce92De3Edee1F18E0157C05861564 ;
14+ address constant mETH = 0xd5F7838F5C461fefF7FE49ea5ebaF7728bB0ADfa ;
15+ address constant rETH = 0xae78736Cd615f374D3085123A210448E74Fc6393 ;
16+ address _frxETHMinter = 0xbAFA44EFE7901E04E39Dad13167D089C559c1138 ;
17+
18+ address owner = address (0x1234 );
19+
20+ function setUp () public {
21+ vm.createSelectFork (vm.rpcUrl ("https://ethereum-rpc.publicnode.com " ));
22+
23+ vm.prank (owner);
24+ assetSwapper = new AssetSwapper (WETH, UNISWAP_ROUTER, _frxETHMinter);
25+
26+ // Fund owner with ETH
27+ vm.deal (owner, 100 ether);
28+ }
29+
30+ function testSwapWETHToMETH () public {
31+ uint256 amountIn = 1 ether ;
32+
33+ // Wrap ETH to WETH
34+ vm.startPrank (owner);
35+ IWETH (WETH).deposit {value: amountIn}();
36+ IERC20 (WETH).approve (address (assetSwapper), amountIn);
37+
38+ // Prepare swap params
39+ bytes memory routeData = abi.encode (
40+ AssetSwapper.UniswapV3Route ({
41+ pool: 0x04708077eCa6bb527a5BBbD6358ffb043a9c1C14 ,
42+ fee: 500 ,
43+ isMultiHop: false ,
44+ path: ""
45+ })
46+ );
47+
48+ AssetSwapper.SwapParams memory params = AssetSwapper.SwapParams ({
49+ tokenIn: WETH,
50+ tokenOut: mETH,
51+ amountIn: amountIn,
52+ minAmountOut: 0.9 ether, // 10% slippage
53+ protocol: AssetSwapper.Protocol.UniswapV3,
54+ routeData: routeData
55+ });
56+
57+ // Execute swap
58+ uint256 balanceBefore = IERC20 (mETH).balanceOf (owner);
59+ uint256 amountOut = assetSwapper.swapAssets (params);
60+ uint256 balanceAfter = IERC20 (mETH).balanceOf (owner);
61+
62+ // Assertions
63+ assertGt (amountOut, 0 , "Should receive mETH " );
64+ assertEq (
65+ balanceAfter - balanceBefore,
66+ amountOut,
67+ "Balance should increase by amount out "
68+ );
69+ assertGt (amountOut, params.minAmountOut, "Should meet minimum output " );
70+
71+ vm.stopPrank ();
72+ }
73+
74+ function testPauseUnpause () public {
75+ vm.startPrank (owner);
76+
77+ // Test pause
78+ assetSwapper.pause ();
79+ assertTrue (assetSwapper.paused (), "Should be paused " );
80+
81+ // Test unpause
82+ assetSwapper.unpause ();
83+ assertFalse (assetSwapper.paused (), "Should be unpaused " );
84+
85+ vm.stopPrank ();
86+ }
87+
88+ function testOnlyOwnerCanSwap () public {
89+ address notOwner = address (0x5678 );
90+
91+ AssetSwapper.SwapParams memory params = AssetSwapper.SwapParams ({
92+ tokenIn: WETH,
93+ tokenOut: mETH,
94+ amountIn: 1 ether,
95+ minAmountOut: 0.9 ether,
96+ protocol: AssetSwapper.Protocol.UniswapV3,
97+ routeData: ""
98+ });
99+
100+ vm.prank (notOwner);
101+ vm.expectRevert ("Ownable: caller is not the owner " );
102+ assetSwapper.swapAssets (params);
103+ }
104+ }
0 commit comments