github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/L1/L1StandardBridge.t.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 // Testing utilities 5 import { stdStorage, StdStorage } from "forge-std/Test.sol"; 6 import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 7 import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; 8 9 // Libraries 10 import { Predeploys } from "src/libraries/Predeploys.sol"; 11 12 // Target contract dependencies 13 import { StandardBridge } from "src/universal/StandardBridge.sol"; 14 import { L1StandardBridge } from "src/L1/L1StandardBridge.sol"; 15 import { L2StandardBridge } from "src/L2/L2StandardBridge.sol"; 16 import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol"; 17 import { SuperchainConfig } from "src/L1/SuperchainConfig.sol"; 18 import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; 19 20 // Target contract 21 import { OptimismPortal } from "src/L1/OptimismPortal.sol"; 22 23 contract L1StandardBridge_Getter_Test is Bridge_Initializer { 24 /// @dev Test that the accessors return the correct initialized values. 25 function test_getters_succeeds() external view { 26 assert(l1StandardBridge.l2TokenBridge() == address(l2StandardBridge)); 27 assert(l1StandardBridge.OTHER_BRIDGE() == l2StandardBridge); 28 assert(l1StandardBridge.messenger() == l1CrossDomainMessenger); 29 assert(l1StandardBridge.MESSENGER() == l1CrossDomainMessenger); 30 } 31 } 32 33 contract L1StandardBridge_Initialize_Test is Bridge_Initializer { 34 /// @dev Test that the constructor sets the correct values. 35 /// @notice Marked virtual to be overridden in 36 /// test/kontrol/deployment/DeploymentSummary.t.sol 37 function test_constructor_succeeds() external virtual { 38 L1StandardBridge impl = L1StandardBridge(deploy.mustGetAddress("L1StandardBridge")); 39 assertEq(address(impl.superchainConfig()), address(0)); 40 assertEq(address(impl.MESSENGER()), address(0)); 41 assertEq(address(impl.messenger()), address(0)); 42 assertEq(address(impl.OTHER_BRIDGE()), Predeploys.L2_STANDARD_BRIDGE); 43 assertEq(address(impl.otherBridge()), Predeploys.L2_STANDARD_BRIDGE); 44 assertEq(address(l2StandardBridge), Predeploys.L2_STANDARD_BRIDGE); 45 } 46 47 /// @dev Test that the initialize function sets the correct values. 48 function test_initialize_succeeds() external { 49 assertEq(address(l1StandardBridge.superchainConfig()), address(superchainConfig)); 50 assertEq(address(l1StandardBridge.MESSENGER()), address(l1CrossDomainMessenger)); 51 assertEq(address(l1StandardBridge.messenger()), address(l1CrossDomainMessenger)); 52 assertEq(address(l1StandardBridge.OTHER_BRIDGE()), Predeploys.L2_STANDARD_BRIDGE); 53 assertEq(address(l1StandardBridge.otherBridge()), Predeploys.L2_STANDARD_BRIDGE); 54 assertEq(address(l2StandardBridge), Predeploys.L2_STANDARD_BRIDGE); 55 } 56 } 57 58 contract L1StandardBridge_Pause_Test is Bridge_Initializer { 59 /// @dev Verifies that the `paused` accessor returns the same value as the `paused` function of the 60 /// `superchainConfig`. 61 function test_paused_succeeds() external { 62 assertEq(l1StandardBridge.paused(), superchainConfig.paused()); 63 } 64 65 /// @dev Ensures that the `paused` function of the bridge contract actually calls the `paused` function of the 66 /// `superchainConfig`. 67 function test_pause_callsSuperchainConfig_succeeds() external { 68 vm.expectCall(address(superchainConfig), abi.encodeWithSelector(SuperchainConfig.paused.selector)); 69 l1StandardBridge.paused(); 70 } 71 72 /// @dev Checks that the `paused` state of the bridge matches the `paused` state of the `superchainConfig` after 73 /// it's been changed. 74 function test_pause_matchesSuperchainConfig_succeeds() external { 75 assertFalse(l1StandardBridge.paused()); 76 assertEq(l1StandardBridge.paused(), superchainConfig.paused()); 77 78 vm.prank(superchainConfig.guardian()); 79 superchainConfig.pause("identifier"); 80 81 assertTrue(l1StandardBridge.paused()); 82 assertEq(l1StandardBridge.paused(), superchainConfig.paused()); 83 } 84 } 85 86 contract L1StandardBridge_Pause_TestFail is Bridge_Initializer { 87 /// @dev Sets up the test by pausing the bridge, giving ether to the bridge and mocking 88 /// the calls to the xDomainMessageSender so that it returns the correct value. 89 function setUp() public override { 90 super.setUp(); 91 vm.prank(superchainConfig.guardian()); 92 superchainConfig.pause("identifier"); 93 assertTrue(l1StandardBridge.paused()); 94 95 vm.deal(address(l1StandardBridge.messenger()), 1 ether); 96 97 vm.mockCall( 98 address(l1StandardBridge.messenger()), 99 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 100 abi.encode(address(l1StandardBridge.otherBridge())) 101 ); 102 } 103 104 /// @dev Confirms that the `finalizeBridgeETH` function reverts when the bridge is paused. 105 function test_pause_finalizeBridgeETH_reverts() external { 106 vm.prank(address(l1StandardBridge.messenger())); 107 vm.expectRevert("StandardBridge: paused"); 108 l1StandardBridge.finalizeBridgeETH{ value: 100 }({ 109 _from: address(2), 110 _to: address(3), 111 _amount: 100, 112 _extraData: hex"" 113 }); 114 } 115 116 /// @dev Confirms that the `finalizeETHWithdrawal` function reverts when the bridge is paused. 117 function test_pause_finalizeETHWithdrawal_reverts() external { 118 vm.prank(address(l1StandardBridge.messenger())); 119 vm.expectRevert("StandardBridge: paused"); 120 l1StandardBridge.finalizeETHWithdrawal{ value: 100 }({ 121 _from: address(2), 122 _to: address(3), 123 _amount: 100, 124 _extraData: hex"" 125 }); 126 } 127 128 /// @dev Confirms that the `finalizeERC20Withdrawal` function reverts when the bridge is paused. 129 function test_pause_finalizeERC20Withdrawal_reverts() external { 130 vm.prank(address(l1StandardBridge.messenger())); 131 vm.expectRevert("StandardBridge: paused"); 132 l1StandardBridge.finalizeERC20Withdrawal({ 133 _l1Token: address(0), 134 _l2Token: address(0), 135 _from: address(0), 136 _to: address(0), 137 _amount: 0, 138 _extraData: hex"" 139 }); 140 } 141 142 /// @dev Confirms that the `finalizeBridgeERC20` function reverts when the bridge is paused. 143 function test_pause_finalizeBridgeERC20_reverts() external { 144 vm.prank(address(l1StandardBridge.messenger())); 145 vm.expectRevert("StandardBridge: paused"); 146 l1StandardBridge.finalizeBridgeERC20({ 147 _localToken: address(0), 148 _remoteToken: address(0), 149 _from: address(0), 150 _to: address(0), 151 _amount: 0, 152 _extraData: hex"" 153 }); 154 } 155 } 156 157 contract L1StandardBridge_Initialize_TestFail is Bridge_Initializer { } 158 159 contract L1StandardBridge_Receive_Test is Bridge_Initializer { 160 /// @dev Tests receive bridges ETH successfully. 161 function test_receive_succeeds() external { 162 assertEq(address(optimismPortal).balance, 0); 163 164 // The legacy event must be emitted for backwards compatibility 165 vm.expectEmit(address(l1StandardBridge)); 166 emit ETHDepositInitiated(alice, alice, 100, hex""); 167 168 vm.expectEmit(address(l1StandardBridge)); 169 emit ETHBridgeInitiated(alice, alice, 100, hex""); 170 171 vm.expectCall( 172 address(l1CrossDomainMessenger), 173 abi.encodeWithSelector( 174 CrossDomainMessenger.sendMessage.selector, 175 address(l2StandardBridge), 176 abi.encodeWithSelector(StandardBridge.finalizeBridgeETH.selector, alice, alice, 100, hex""), 177 200_000 178 ) 179 ); 180 181 vm.prank(alice, alice); 182 (bool success,) = address(l1StandardBridge).call{ value: 100 }(hex""); 183 assertEq(success, true); 184 assertEq(address(optimismPortal).balance, 100); 185 } 186 } 187 188 contract L1StandardBridge_Receive_TestFail { } 189 190 contract PreBridgeETH is Bridge_Initializer { 191 /// @dev Asserts the expected calls and events for bridging ETH depending 192 /// on whether the bridge call is legacy or not. 193 function _preBridgeETH(bool isLegacy) internal { 194 assertEq(address(optimismPortal).balance, 0); 195 uint256 nonce = l1CrossDomainMessenger.messageNonce(); 196 uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION 197 address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); 198 199 bytes memory message = 200 abi.encodeWithSelector(StandardBridge.finalizeBridgeETH.selector, alice, alice, 500, hex"dead"); 201 202 if (isLegacy) { 203 vm.expectCall( 204 address(l1StandardBridge), 205 500, 206 abi.encodeWithSelector(l1StandardBridge.depositETH.selector, 50000, hex"dead") 207 ); 208 } else { 209 vm.expectCall( 210 address(l1StandardBridge), 211 500, 212 abi.encodeWithSelector(l1StandardBridge.bridgeETH.selector, 50000, hex"dead") 213 ); 214 } 215 vm.expectCall( 216 address(l1CrossDomainMessenger), 217 500, 218 abi.encodeWithSelector(CrossDomainMessenger.sendMessage.selector, address(l2StandardBridge), message, 50000) 219 ); 220 221 bytes memory innerMessage = abi.encodeWithSelector( 222 CrossDomainMessenger.relayMessage.selector, 223 nonce, 224 address(l1StandardBridge), 225 address(l2StandardBridge), 226 500, 227 50000, 228 message 229 ); 230 231 uint64 baseGas = l1CrossDomainMessenger.baseGas(message, 50000); 232 vm.expectCall( 233 address(optimismPortal), 234 500, 235 abi.encodeWithSelector( 236 OptimismPortal.depositTransaction.selector, 237 address(l2CrossDomainMessenger), 238 500, 239 baseGas, 240 false, 241 innerMessage 242 ) 243 ); 244 245 bytes memory opaqueData = abi.encodePacked(uint256(500), uint256(500), baseGas, false, innerMessage); 246 247 vm.expectEmit(address(l1StandardBridge)); 248 emit ETHDepositInitiated(alice, alice, 500, hex"dead"); 249 250 vm.expectEmit(address(l1StandardBridge)); 251 emit ETHBridgeInitiated(alice, alice, 500, hex"dead"); 252 253 // OptimismPortal emits a TransactionDeposited event on `depositTransaction` call 254 vm.expectEmit(address(optimismPortal)); 255 emit TransactionDeposited(l1MessengerAliased, address(l2CrossDomainMessenger), version, opaqueData); 256 257 // SentMessage event emitted by the CrossDomainMessenger 258 vm.expectEmit(address(l1CrossDomainMessenger)); 259 emit SentMessage(address(l2StandardBridge), address(l1StandardBridge), message, nonce, 50000); 260 261 // SentMessageExtension1 event emitted by the CrossDomainMessenger 262 vm.expectEmit(address(l1CrossDomainMessenger)); 263 emit SentMessageExtension1(address(l1StandardBridge), 500); 264 265 vm.prank(alice, alice); 266 } 267 } 268 269 contract L1StandardBridge_DepositETH_Test is PreBridgeETH { 270 /// @dev Tests that depositing ETH succeeds. 271 /// Emits ETHDepositInitiated and ETHBridgeInitiated events. 272 /// Calls depositTransaction on the OptimismPortal. 273 /// Only EOA can call depositETH. 274 /// ETH ends up in the optimismPortal. 275 function test_depositETH_succeeds() external { 276 _preBridgeETH({ isLegacy: true }); 277 l1StandardBridge.depositETH{ value: 500 }(50000, hex"dead"); 278 assertEq(address(optimismPortal).balance, 500); 279 } 280 } 281 282 contract L1StandardBridge_BridgeETH_Test is PreBridgeETH { 283 /// @dev Tests that bridging ETH succeeds. 284 /// Emits ETHDepositInitiated and ETHBridgeInitiated events. 285 /// Calls depositTransaction on the OptimismPortal. 286 /// Only EOA can call bridgeETH. 287 /// ETH ends up in the optimismPortal. 288 function test_bridgeETH_succeeds() external { 289 _preBridgeETH({ isLegacy: false }); 290 l1StandardBridge.bridgeETH{ value: 500 }(50000, hex"dead"); 291 assertEq(address(optimismPortal).balance, 500); 292 } 293 } 294 295 contract L1StandardBridge_DepositETH_TestFail is Bridge_Initializer { 296 /// @dev Tests that depositing ETH reverts if the call is not from an EOA. 297 function test_depositETH_notEoa_reverts() external { 298 vm.etch(alice, address(L1Token).code); 299 vm.expectRevert("StandardBridge: function can only be called from an EOA"); 300 vm.prank(alice); 301 l1StandardBridge.depositETH{ value: 1 }(300, hex""); 302 } 303 } 304 305 contract PreBridgeETHTo is Bridge_Initializer { 306 /// @dev Asserts the expected calls and events for bridging ETH to a different 307 /// address depending on whether the bridge call is legacy or not. 308 function _preBridgeETHTo(bool isLegacy) internal { 309 assertEq(address(optimismPortal).balance, 0); 310 uint256 nonce = l1CrossDomainMessenger.messageNonce(); 311 uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION 312 address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); 313 314 if (isLegacy) { 315 vm.expectCall( 316 address(l1StandardBridge), 317 600, 318 abi.encodeWithSelector(l1StandardBridge.depositETHTo.selector, bob, 60000, hex"dead") 319 ); 320 } else { 321 vm.expectCall( 322 address(l1StandardBridge), 323 600, 324 abi.encodeWithSelector(l1StandardBridge.bridgeETHTo.selector, bob, 60000, hex"dead") 325 ); 326 } 327 328 bytes memory message = 329 abi.encodeWithSelector(StandardBridge.finalizeBridgeETH.selector, alice, bob, 600, hex"dead"); 330 331 // the L1 bridge should call 332 // L1CrossDomainMessenger.sendMessage 333 vm.expectCall( 334 address(l1CrossDomainMessenger), 335 abi.encodeWithSelector(CrossDomainMessenger.sendMessage.selector, address(l2StandardBridge), message, 60000) 336 ); 337 338 bytes memory innerMessage = abi.encodeWithSelector( 339 CrossDomainMessenger.relayMessage.selector, 340 nonce, 341 address(l1StandardBridge), 342 address(l2StandardBridge), 343 600, 344 60000, 345 message 346 ); 347 348 uint64 baseGas = l1CrossDomainMessenger.baseGas(message, 60000); 349 vm.expectCall( 350 address(optimismPortal), 351 abi.encodeWithSelector( 352 OptimismPortal.depositTransaction.selector, 353 address(l2CrossDomainMessenger), 354 600, 355 baseGas, 356 false, 357 innerMessage 358 ) 359 ); 360 361 bytes memory opaqueData = abi.encodePacked(uint256(600), uint256(600), baseGas, false, innerMessage); 362 363 vm.expectEmit(address(l1StandardBridge)); 364 emit ETHDepositInitiated(alice, bob, 600, hex"dead"); 365 366 vm.expectEmit(address(l1StandardBridge)); 367 emit ETHBridgeInitiated(alice, bob, 600, hex"dead"); 368 369 // OptimismPortal emits a TransactionDeposited event on `depositTransaction` call 370 vm.expectEmit(address(optimismPortal)); 371 emit TransactionDeposited(l1MessengerAliased, address(l2CrossDomainMessenger), version, opaqueData); 372 373 // SentMessage event emitted by the CrossDomainMessenger 374 vm.expectEmit(address(l1CrossDomainMessenger)); 375 emit SentMessage(address(l2StandardBridge), address(l1StandardBridge), message, nonce, 60000); 376 377 // SentMessageExtension1 event emitted by the CrossDomainMessenger 378 vm.expectEmit(address(l1CrossDomainMessenger)); 379 emit SentMessageExtension1(address(l1StandardBridge), 600); 380 381 // deposit eth to bob 382 vm.prank(alice, alice); 383 } 384 } 385 386 contract L1StandardBridge_DepositETHTo_Test is PreBridgeETHTo { 387 /// @dev Tests that depositing ETH to a different address succeeds. 388 /// Emits ETHDepositInitiated event. 389 /// Calls depositTransaction on the OptimismPortal. 390 /// EOA or contract can call depositETHTo. 391 /// ETH ends up in the optimismPortal. 392 function test_depositETHTo_succeeds() external { 393 _preBridgeETHTo({ isLegacy: true }); 394 l1StandardBridge.depositETHTo{ value: 600 }(bob, 60000, hex"dead"); 395 assertEq(address(optimismPortal).balance, 600); 396 } 397 } 398 399 contract L1StandardBridge_BridgeETHTo_Test is PreBridgeETHTo { 400 /// @dev Tests that bridging ETH to a different address succeeds. 401 /// Emits ETHDepositInitiated and ETHBridgeInitiated events. 402 /// Calls depositTransaction on the OptimismPortal. 403 /// Only EOA can call bridgeETHTo. 404 /// ETH ends up in the optimismPortal. 405 function test_bridgeETHTo_succeeds() external { 406 _preBridgeETHTo({ isLegacy: false }); 407 l1StandardBridge.bridgeETHTo{ value: 600 }(bob, 60000, hex"dead"); 408 assertEq(address(optimismPortal).balance, 600); 409 } 410 } 411 412 contract L1StandardBridge_DepositETHTo_TestFail is Bridge_Initializer { } 413 414 contract L1StandardBridge_DepositERC20_Test is Bridge_Initializer { 415 using stdStorage for StdStorage; 416 417 // depositERC20 418 // - updates bridge.deposits 419 // - emits ERC20DepositInitiated 420 // - calls optimismPortal.depositTransaction 421 // - only callable by EOA 422 423 /// @dev Tests that depositing ERC20 to the bridge succeeds. 424 /// Bridge deposits are updated. 425 /// Emits ERC20DepositInitiated event. 426 /// Calls depositTransaction on the OptimismPortal. 427 /// Only EOA can call depositERC20. 428 function test_depositERC20_succeeds() external { 429 uint256 nonce = l1CrossDomainMessenger.messageNonce(); 430 uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION 431 address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); 432 433 // Deal Alice's ERC20 State 434 deal(address(L1Token), alice, 100000, true); 435 vm.prank(alice); 436 L1Token.approve(address(l1StandardBridge), type(uint256).max); 437 438 // The l1StandardBridge should transfer alice's tokens to itself 439 vm.expectCall( 440 address(L1Token), abi.encodeWithSelector(ERC20.transferFrom.selector, alice, address(l1StandardBridge), 100) 441 ); 442 443 bytes memory message = abi.encodeWithSelector( 444 StandardBridge.finalizeBridgeERC20.selector, address(L2Token), address(L1Token), alice, alice, 100, hex"" 445 ); 446 447 // the L1 bridge should call L1CrossDomainMessenger.sendMessage 448 vm.expectCall( 449 address(l1CrossDomainMessenger), 450 abi.encodeWithSelector(CrossDomainMessenger.sendMessage.selector, address(l2StandardBridge), message, 10000) 451 ); 452 453 bytes memory innerMessage = abi.encodeWithSelector( 454 CrossDomainMessenger.relayMessage.selector, 455 nonce, 456 address(l1StandardBridge), 457 address(l2StandardBridge), 458 0, 459 10000, 460 message 461 ); 462 463 uint64 baseGas = l1CrossDomainMessenger.baseGas(message, 10000); 464 vm.expectCall( 465 address(optimismPortal), 466 abi.encodeWithSelector( 467 OptimismPortal.depositTransaction.selector, 468 address(l2CrossDomainMessenger), 469 0, 470 baseGas, 471 false, 472 innerMessage 473 ) 474 ); 475 476 bytes memory opaqueData = abi.encodePacked(uint256(0), uint256(0), baseGas, false, innerMessage); 477 478 // Should emit both the bedrock and legacy events 479 vm.expectEmit(address(l1StandardBridge)); 480 emit ERC20DepositInitiated(address(L1Token), address(L2Token), alice, alice, 100, hex""); 481 482 vm.expectEmit(address(l1StandardBridge)); 483 emit ERC20BridgeInitiated(address(L1Token), address(L2Token), alice, alice, 100, hex""); 484 485 // OptimismPortal emits a TransactionDeposited event on `depositTransaction` call 486 vm.expectEmit(address(optimismPortal)); 487 emit TransactionDeposited(l1MessengerAliased, address(l2CrossDomainMessenger), version, opaqueData); 488 489 // SentMessage event emitted by the CrossDomainMessenger 490 vm.expectEmit(address(l1CrossDomainMessenger)); 491 emit SentMessage(address(l2StandardBridge), address(l1StandardBridge), message, nonce, 10000); 492 493 // SentMessageExtension1 event emitted by the CrossDomainMessenger 494 vm.expectEmit(address(l1CrossDomainMessenger)); 495 emit SentMessageExtension1(address(l1StandardBridge), 0); 496 497 vm.prank(alice); 498 l1StandardBridge.depositERC20(address(L1Token), address(L2Token), 100, 10000, hex""); 499 assertEq(l1StandardBridge.deposits(address(L1Token), address(L2Token)), 100); 500 } 501 } 502 503 contract L1StandardBridge_DepositERC20_TestFail is Bridge_Initializer { 504 /// @dev Tests that depositing an ERC20 to the bridge reverts 505 /// if the caller is not an EOA. 506 function test_depositERC20_notEoa_reverts() external { 507 // turn alice into a contract 508 vm.etch(alice, hex"ffff"); 509 510 vm.expectRevert("StandardBridge: function can only be called from an EOA"); 511 vm.prank(alice, alice); 512 l1StandardBridge.depositERC20(address(0), address(0), 100, 100, hex""); 513 } 514 } 515 516 contract L1StandardBridge_DepositERC20To_Test is Bridge_Initializer { 517 /// @dev Tests that depositing ERC20 to the bridge succeeds when 518 /// sent to a different address. 519 /// Bridge deposits are updated. 520 /// Emits ERC20DepositInitiated event. 521 /// Calls depositTransaction on the OptimismPortal. 522 /// Contracts can call depositERC20. 523 function test_depositERC20To_succeeds() external { 524 uint256 nonce = l1CrossDomainMessenger.messageNonce(); 525 uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION 526 address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); 527 528 bytes memory message = abi.encodeWithSelector( 529 StandardBridge.finalizeBridgeERC20.selector, address(L2Token), address(L1Token), alice, bob, 1000, hex"" 530 ); 531 532 bytes memory innerMessage = abi.encodeWithSelector( 533 CrossDomainMessenger.relayMessage.selector, 534 nonce, 535 address(l1StandardBridge), 536 address(l2StandardBridge), 537 0, 538 10000, 539 message 540 ); 541 542 uint64 baseGas = l1CrossDomainMessenger.baseGas(message, 10000); 543 bytes memory opaqueData = abi.encodePacked(uint256(0), uint256(0), baseGas, false, innerMessage); 544 545 deal(address(L1Token), alice, 100000, true); 546 547 vm.prank(alice); 548 L1Token.approve(address(l1StandardBridge), type(uint256).max); 549 550 // Should emit both the bedrock and legacy events 551 vm.expectEmit(address(l1StandardBridge)); 552 emit ERC20DepositInitiated(address(L1Token), address(L2Token), alice, bob, 1000, hex""); 553 554 vm.expectEmit(address(l1StandardBridge)); 555 emit ERC20BridgeInitiated(address(L1Token), address(L2Token), alice, bob, 1000, hex""); 556 557 // OptimismPortal emits a TransactionDeposited event on `depositTransaction` call 558 vm.expectEmit(address(optimismPortal)); 559 emit TransactionDeposited(l1MessengerAliased, address(l2CrossDomainMessenger), version, opaqueData); 560 561 // SentMessage event emitted by the CrossDomainMessenger 562 vm.expectEmit(address(l1CrossDomainMessenger)); 563 emit SentMessage(address(l2StandardBridge), address(l1StandardBridge), message, nonce, 10000); 564 565 // SentMessageExtension1 event emitted by the CrossDomainMessenger 566 vm.expectEmit(address(l1CrossDomainMessenger)); 567 emit SentMessageExtension1(address(l1StandardBridge), 0); 568 569 // the L1 bridge should call L1CrossDomainMessenger.sendMessage 570 vm.expectCall( 571 address(l1CrossDomainMessenger), 572 abi.encodeWithSelector(CrossDomainMessenger.sendMessage.selector, address(l2StandardBridge), message, 10000) 573 ); 574 // The L1 XDM should call OptimismPortal.depositTransaction 575 vm.expectCall( 576 address(optimismPortal), 577 abi.encodeWithSelector( 578 OptimismPortal.depositTransaction.selector, 579 address(l2CrossDomainMessenger), 580 0, 581 baseGas, 582 false, 583 innerMessage 584 ) 585 ); 586 vm.expectCall( 587 address(L1Token), 588 abi.encodeWithSelector(ERC20.transferFrom.selector, alice, address(l1StandardBridge), 1000) 589 ); 590 591 vm.prank(alice); 592 l1StandardBridge.depositERC20To(address(L1Token), address(L2Token), bob, 1000, 10000, hex""); 593 594 assertEq(l1StandardBridge.deposits(address(L1Token), address(L2Token)), 1000); 595 } 596 } 597 598 contract L1StandardBridge_FinalizeETHWithdrawal_Test is Bridge_Initializer { 599 using stdStorage for StdStorage; 600 601 /// @dev Tests that finalizing an ETH withdrawal succeeds. 602 /// Emits ETHWithdrawalFinalized event. 603 /// Only callable by the L2 bridge. 604 function test_finalizeETHWithdrawal_succeeds() external { 605 uint256 aliceBalance = alice.balance; 606 607 vm.expectEmit(address(l1StandardBridge)); 608 emit ETHWithdrawalFinalized(alice, alice, 100, hex""); 609 610 vm.expectEmit(address(l1StandardBridge)); 611 emit ETHBridgeFinalized(alice, alice, 100, hex""); 612 613 vm.expectCall(alice, hex""); 614 615 vm.mockCall( 616 address(l1StandardBridge.messenger()), 617 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 618 abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) 619 ); 620 // ensure that the messenger has ETH to call with 621 vm.deal(address(l1StandardBridge.messenger()), 100); 622 vm.prank(address(l1StandardBridge.messenger())); 623 l1StandardBridge.finalizeETHWithdrawal{ value: 100 }(alice, alice, 100, hex""); 624 625 assertEq(address(l1StandardBridge.messenger()).balance, 0); 626 assertEq(aliceBalance + 100, alice.balance); 627 } 628 } 629 630 contract L1StandardBridge_FinalizeETHWithdrawal_TestFail is Bridge_Initializer { } 631 632 contract L1StandardBridge_FinalizeERC20Withdrawal_Test is Bridge_Initializer { 633 using stdStorage for StdStorage; 634 635 /// @dev Tests that finalizing an ERC20 withdrawal succeeds. 636 /// Bridge deposits are updated. 637 /// Emits ERC20WithdrawalFinalized event. 638 /// Only callable by the L2 bridge. 639 function test_finalizeERC20Withdrawal_succeeds() external { 640 deal(address(L1Token), address(l1StandardBridge), 100, true); 641 642 uint256 slot = stdstore.target(address(l1StandardBridge)).sig("deposits(address,address)").with_key( 643 address(L1Token) 644 ).with_key(address(L2Token)).find(); 645 646 // Give the L1 bridge some ERC20 tokens 647 vm.store(address(l1StandardBridge), bytes32(slot), bytes32(uint256(100))); 648 assertEq(l1StandardBridge.deposits(address(L1Token), address(L2Token)), 100); 649 650 vm.expectEmit(address(l1StandardBridge)); 651 emit ERC20WithdrawalFinalized(address(L1Token), address(L2Token), alice, alice, 100, hex""); 652 653 vm.expectEmit(address(l1StandardBridge)); 654 emit ERC20BridgeFinalized(address(L1Token), address(L2Token), alice, alice, 100, hex""); 655 656 vm.expectCall(address(L1Token), abi.encodeWithSelector(ERC20.transfer.selector, alice, 100)); 657 658 vm.mockCall( 659 address(l1StandardBridge.messenger()), 660 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 661 abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) 662 ); 663 vm.prank(address(l1StandardBridge.messenger())); 664 l1StandardBridge.finalizeERC20Withdrawal(address(L1Token), address(L2Token), alice, alice, 100, hex""); 665 666 assertEq(L1Token.balanceOf(address(l1StandardBridge)), 0); 667 assertEq(L1Token.balanceOf(address(alice)), 100); 668 } 669 } 670 671 contract L1StandardBridge_FinalizeERC20Withdrawal_TestFail is Bridge_Initializer { 672 /// @dev Tests that finalizing an ERC20 withdrawal reverts if the caller is not the L2 bridge. 673 function test_finalizeERC20Withdrawal_notMessenger_reverts() external { 674 vm.mockCall( 675 address(l1StandardBridge.messenger()), 676 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 677 abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) 678 ); 679 vm.prank(address(28)); 680 vm.expectRevert("StandardBridge: function can only be called from the other bridge"); 681 l1StandardBridge.finalizeERC20Withdrawal(address(L1Token), address(L2Token), alice, alice, 100, hex""); 682 } 683 684 /// @dev Tests that finalizing an ERC20 withdrawal reverts if the caller is not the L2 bridge. 685 function test_finalizeERC20Withdrawal_notOtherBridge_reverts() external { 686 vm.mockCall( 687 address(l1StandardBridge.messenger()), 688 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 689 abi.encode(address(address(0))) 690 ); 691 vm.prank(address(l1StandardBridge.messenger())); 692 vm.expectRevert("StandardBridge: function can only be called from the other bridge"); 693 l1StandardBridge.finalizeERC20Withdrawal(address(L1Token), address(L2Token), alice, alice, 100, hex""); 694 } 695 } 696 697 contract L1StandardBridge_FinalizeBridgeETH_Test is Bridge_Initializer { 698 /// @dev Tests that finalizing bridged ETH succeeds. 699 function test_finalizeBridgeETH_succeeds() external { 700 address messenger = address(l1StandardBridge.messenger()); 701 vm.mockCall( 702 messenger, 703 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 704 abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) 705 ); 706 vm.deal(messenger, 100); 707 vm.prank(messenger); 708 709 vm.expectEmit(address(l1StandardBridge)); 710 emit ETHBridgeFinalized(alice, alice, 100, hex""); 711 712 l1StandardBridge.finalizeBridgeETH{ value: 100 }(alice, alice, 100, hex""); 713 } 714 } 715 716 contract L1StandardBridge_FinalizeBridgeETH_TestFail is Bridge_Initializer { 717 /// @dev Tests that finalizing bridged ETH reverts if the amount is incorrect. 718 function test_finalizeBridgeETH_incorrectValue_reverts() external { 719 address messenger = address(l1StandardBridge.messenger()); 720 vm.mockCall( 721 messenger, 722 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 723 abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) 724 ); 725 vm.deal(messenger, 100); 726 vm.prank(messenger); 727 vm.expectRevert("StandardBridge: amount sent does not match amount required"); 728 l1StandardBridge.finalizeBridgeETH{ value: 50 }(alice, alice, 100, hex""); 729 } 730 731 /// @dev Tests that finalizing bridged ETH reverts if the destination is the L1 bridge. 732 function test_finalizeBridgeETH_sendToSelf_reverts() external { 733 address messenger = address(l1StandardBridge.messenger()); 734 vm.mockCall( 735 messenger, 736 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 737 abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) 738 ); 739 vm.deal(messenger, 100); 740 vm.prank(messenger); 741 vm.expectRevert("StandardBridge: cannot send to self"); 742 l1StandardBridge.finalizeBridgeETH{ value: 100 }(alice, address(l1StandardBridge), 100, hex""); 743 } 744 745 /// @dev Tests that finalizing bridged ETH reverts if the destination is the messenger. 746 function test_finalizeBridgeETH_sendToMessenger_reverts() external { 747 address messenger = address(l1StandardBridge.messenger()); 748 vm.mockCall( 749 messenger, 750 abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), 751 abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) 752 ); 753 vm.deal(messenger, 100); 754 vm.prank(messenger); 755 vm.expectRevert("StandardBridge: cannot send to messenger"); 756 l1StandardBridge.finalizeBridgeETH{ value: 100 }(alice, messenger, 100, hex""); 757 } 758 }