github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/dispute/DelayedWETH.t.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity ^0.8.15; 3 4 import "src/libraries/DisputeTypes.sol"; 5 import "src/libraries/DisputeErrors.sol"; 6 7 import { Test } from "forge-std/Test.sol"; 8 import { DisputeGameFactory, IDisputeGameFactory } from "src/dispute/DisputeGameFactory.sol"; 9 import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol"; 10 import { DelayedWETH } from "src/dispute/weth/DelayedWETH.sol"; 11 import { Proxy } from "src/universal/Proxy.sol"; 12 import { CommonTest } from "test/setup/CommonTest.sol"; 13 14 contract DelayedWETH_Init is CommonTest { 15 event Approval(address indexed src, address indexed guy, uint256 wad); 16 event Transfer(address indexed src, address indexed dst, uint256 wad); 17 event Deposit(address indexed dst, uint256 wad); 18 event Withdrawal(address indexed src, uint256 wad); 19 event Unwrap(address indexed src, uint256 wad); 20 21 function setUp() public virtual override { 22 super.enableFaultProofs(); 23 super.setUp(); 24 25 // Transfer ownership of delayed WETH to the test contract. 26 vm.prank(deploy.mustGetAddress("SystemOwnerSafe")); 27 delayedWeth.transferOwnership(address(this)); 28 } 29 } 30 31 contract DelayedWETH_Initialize_Test is DelayedWETH_Init { 32 /// @dev Tests that initialization is successful. 33 function test_initialize_succeeds() public { 34 assertEq(delayedWeth.owner(), address(this)); 35 assertEq(address(delayedWeth.config()), address(superchainConfig)); 36 } 37 } 38 39 contract DelayedWETH_Unlock_Test is DelayedWETH_Init { 40 /// @dev Tests that unlocking once is successful. 41 function test_unlock_once_succeeds() public { 42 delayedWeth.unlock(alice, 1 ether); 43 (uint256 amount, uint256 timestamp) = delayedWeth.withdrawals(address(this), alice); 44 assertEq(amount, 1 ether); 45 assertEq(timestamp, block.timestamp); 46 } 47 48 /// @dev TEsts that unlocking twice is successful and timestamp/amount is updated. 49 function test_unlock_twice_succeeds() public { 50 // Unlock once. 51 uint256 ts = block.timestamp; 52 delayedWeth.unlock(alice, 1 ether); 53 (uint256 amount1, uint256 timestamp1) = delayedWeth.withdrawals(address(this), alice); 54 assertEq(amount1, 1 ether); 55 assertEq(timestamp1, ts); 56 57 // Go forward in time. 58 vm.warp(ts + 1); 59 60 // Unlock again works. 61 delayedWeth.unlock(alice, 1 ether); 62 (uint256 amount2, uint256 timestamp2) = delayedWeth.withdrawals(address(this), alice); 63 assertEq(amount2, 2 ether); 64 assertEq(timestamp2, ts + 1); 65 } 66 } 67 68 contract DelayedWETH_Withdraw_Test is DelayedWETH_Init { 69 /// @dev Tests that withdrawing while unlocked and delay has passed is successful. 70 function test_withdraw_whileUnlocked_succeeds() public { 71 // Deposit some WETH. 72 vm.prank(alice); 73 delayedWeth.deposit{ value: 1 ether }(); 74 uint256 balance = address(alice).balance; 75 76 // Unlock the withdrawal. 77 vm.prank(alice); 78 delayedWeth.unlock(alice, 1 ether); 79 80 // Wait for the delay. 81 vm.warp(block.timestamp + delayedWeth.delay() + 1); 82 83 // Withdraw the WETH. 84 vm.expectEmit(true, true, false, false); 85 emit Withdrawal(address(alice), 1 ether); 86 vm.prank(alice); 87 delayedWeth.withdraw(alice, 1 ether); 88 assertEq(address(alice).balance, balance + 1 ether); 89 } 90 91 /// @dev Tests that withdrawing when unlock was not called fails. 92 function test_withdraw_whileLocked_fails() public { 93 // Deposit some WETH. 94 vm.prank(alice); 95 delayedWeth.deposit{ value: 1 ether }(); 96 uint256 balance = address(alice).balance; 97 98 // Withdraw fails when unlock not called. 99 vm.expectRevert("DelayedWETH: withdrawal not unlocked"); 100 vm.prank(alice); 101 delayedWeth.withdraw(alice, 0 ether); 102 assertEq(address(alice).balance, balance); 103 } 104 105 /// @dev Tests that withdrawing while locked and delay has not passed fails. 106 function test_withdraw_whileLockedNotLongEnough_fails() public { 107 // Deposit some WETH. 108 vm.prank(alice); 109 delayedWeth.deposit{ value: 1 ether }(); 110 uint256 balance = address(alice).balance; 111 112 // Call unlock. 113 vm.prank(alice); 114 delayedWeth.unlock(alice, 1 ether); 115 116 // Wait for the delay, but not long enough. 117 vm.warp(block.timestamp + delayedWeth.delay() - 1); 118 119 // Withdraw fails when delay not met. 120 vm.expectRevert("DelayedWETH: withdrawal delay not met"); 121 vm.prank(alice); 122 delayedWeth.withdraw(alice, 1 ether); 123 assertEq(address(alice).balance, balance); 124 } 125 126 /// @dev Tests that withdrawing more than unlocked amount fails. 127 function test_withdraw_tooMuch_fails() public { 128 // Deposit some WETH. 129 vm.prank(alice); 130 delayedWeth.deposit{ value: 1 ether }(); 131 uint256 balance = address(alice).balance; 132 133 // Unlock the withdrawal. 134 vm.prank(alice); 135 delayedWeth.unlock(alice, 1 ether); 136 137 // Wait for the delay. 138 vm.warp(block.timestamp + delayedWeth.delay() + 1); 139 140 // Withdraw too much fails. 141 vm.expectRevert("DelayedWETH: insufficient unlocked withdrawal"); 142 vm.prank(alice); 143 delayedWeth.withdraw(alice, 2 ether); 144 assertEq(address(alice).balance, balance); 145 } 146 147 /// @dev Tests that withdrawing while paused fails. 148 function test_withdraw_whenPaused_fails() public { 149 // Deposit some WETH. 150 vm.prank(alice); 151 delayedWeth.deposit{ value: 1 ether }(); 152 153 // Unlock the withdrawal. 154 vm.prank(alice); 155 delayedWeth.unlock(alice, 1 ether); 156 157 // Wait for the delay. 158 vm.warp(block.timestamp + delayedWeth.delay() + 1); 159 160 // Pause the contract. 161 address guardian = optimismPortal.GUARDIAN(); 162 vm.prank(guardian); 163 superchainConfig.pause("identifier"); 164 165 // Withdraw fails. 166 vm.expectRevert("DelayedWETH: contract is paused"); 167 vm.prank(alice); 168 delayedWeth.withdraw(alice, 1 ether); 169 } 170 } 171 172 contract DelayedWETH_Recover_Test is DelayedWETH_Init { 173 /// @dev Tests that recovering WETH succeeds. 174 function test_recover_succeeds() public { 175 // Transfer ownership to alice. 176 delayedWeth.transferOwnership(alice); 177 178 // Give the contract some WETH to recover. 179 vm.deal(address(delayedWeth), 1 ether); 180 181 // Record the initial balance. 182 uint256 initialBalance = address(alice).balance; 183 184 // Recover the WETH. 185 vm.prank(alice); 186 delayedWeth.recover(1 ether); 187 188 // Verify the WETH was recovered. 189 assertEq(address(delayedWeth).balance, 0); 190 assertEq(address(alice).balance, initialBalance + 1 ether); 191 } 192 193 /// @dev Tests that recovering WETH by non-owner fails. 194 function test_recover_byNonOwner_fails() public { 195 // Pretend to be a non-owner. 196 vm.prank(alice); 197 198 // Recover fails. 199 vm.expectRevert("DelayedWETH: not owner"); 200 delayedWeth.recover(1 ether); 201 } 202 203 /// @dev Tests that recovering more than the balance recovers what it can. 204 function test_recover_moreThanBalance_succeeds() public { 205 // Transfer ownership to alice. 206 delayedWeth.transferOwnership(alice); 207 208 // Give the contract some WETH to recover. 209 vm.deal(address(delayedWeth), 0.5 ether); 210 211 // Record the initial balance. 212 uint256 initialBalance = address(alice).balance; 213 214 // Recover the WETH. 215 vm.prank(alice); 216 delayedWeth.recover(1 ether); 217 218 // Verify the WETH was recovered. 219 assertEq(address(delayedWeth).balance, 0); 220 assertEq(address(alice).balance, initialBalance + 0.5 ether); 221 } 222 } 223 224 contract DelayedWETH_Hold_Test is DelayedWETH_Init { 225 /// @dev Tests that holding WETH succeeds. 226 function test_hold_succeeds() public { 227 uint256 amount = 1 ether; 228 229 // Pretend to be alice and deposit some WETH. 230 vm.prank(alice); 231 delayedWeth.deposit{ value: amount }(); 232 233 // Hold some WETH. 234 vm.expectEmit(true, true, true, false); 235 emit Approval(alice, address(this), amount); 236 delayedWeth.hold(alice, amount); 237 238 // Verify the allowance. 239 assertEq(delayedWeth.allowance(alice, address(this)), amount); 240 241 // We can transfer. 242 delayedWeth.transferFrom(alice, address(this), amount); 243 244 // Verify the transfer. 245 assertEq(delayedWeth.balanceOf(address(this)), amount); 246 } 247 248 /// @dev Tests that holding WETH by non-owner fails. 249 function test_hold_byNonOwner_fails() public { 250 // Pretend to be a non-owner. 251 vm.prank(alice); 252 253 // Hold fails. 254 vm.expectRevert("DelayedWETH: not owner"); 255 delayedWeth.hold(bob, 1 ether); 256 } 257 }