github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/L1/L1CrossDomainMessenger.t.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 // Testing utilities 5 import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; 6 import { Reverter, ConfigurableCaller } from "test/mocks/Callers.sol"; 7 8 // Libraries 9 import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; 10 import { Predeploys } from "src/libraries/Predeploys.sol"; 11 import { Hashing } from "src/libraries/Hashing.sol"; 12 import { Encoding } from "src/libraries/Encoding.sol"; 13 import { Constants } from "src/libraries/Constants.sol"; 14 15 // Target contract dependencies 16 import { L1CrossDomainMessenger } from "src/L1/L1CrossDomainMessenger.sol"; 17 import { OptimismPortal } from "src/L1/OptimismPortal.sol"; 18 import { SuperchainConfig } from "src/L1/SuperchainConfig.sol"; 19 20 contract L1CrossDomainMessenger_Test is Bridge_Initializer { 21 /// @dev The receiver address 22 address recipient = address(0xabbaacdc); 23 24 /// @dev The storage slot of the l2Sender 25 uint256 constant senderSlotIndex = 50; 26 27 /// @dev Tests that the implementation is initialized correctly. 28 /// @notice Marked virtual to be overridden in 29 /// test/kontrol/deployment/DeploymentSummary.t.sol 30 function test_constructor_succeeds() external virtual { 31 L1CrossDomainMessenger impl = L1CrossDomainMessenger(deploy.mustGetAddress("L1CrossDomainMessenger")); 32 assertEq(address(impl.superchainConfig()), address(0)); 33 assertEq(address(impl.PORTAL()), address(0)); 34 assertEq(address(impl.portal()), address(0)); 35 assertEq(address(impl.OTHER_MESSENGER()), Predeploys.L2_CROSS_DOMAIN_MESSENGER); 36 assertEq(address(impl.otherMessenger()), Predeploys.L2_CROSS_DOMAIN_MESSENGER); 37 } 38 39 /// @dev Tests that the proxy is initialized correctly. 40 function test_initialize_succeeds() external { 41 assertEq(address(l1CrossDomainMessenger.superchainConfig()), address(superchainConfig)); 42 assertEq(address(l1CrossDomainMessenger.PORTAL()), address(optimismPortal)); 43 assertEq(address(l1CrossDomainMessenger.portal()), address(optimismPortal)); 44 assertEq(address(l1CrossDomainMessenger.OTHER_MESSENGER()), Predeploys.L2_CROSS_DOMAIN_MESSENGER); 45 assertEq(address(l1CrossDomainMessenger.otherMessenger()), Predeploys.L2_CROSS_DOMAIN_MESSENGER); 46 } 47 48 /// @dev Tests that the version can be decoded from the message nonce. 49 function test_messageVersion_succeeds() external { 50 (, uint16 version) = Encoding.decodeVersionedNonce(l1CrossDomainMessenger.messageNonce()); 51 assertEq(version, l1CrossDomainMessenger.MESSAGE_VERSION()); 52 } 53 54 /// @dev Tests that the sendMessage function is able to send a single message. 55 /// TODO: this same test needs to be done with the legacy message type 56 /// by setting the message version to 0 57 function test_sendMessage_succeeds() external { 58 // deposit transaction on the optimism portal should be called 59 vm.expectCall( 60 address(optimismPortal), 61 abi.encodeWithSelector( 62 OptimismPortal.depositTransaction.selector, 63 Predeploys.L2_CROSS_DOMAIN_MESSENGER, 64 0, 65 l1CrossDomainMessenger.baseGas(hex"ff", 100), 66 false, 67 Encoding.encodeCrossDomainMessage( 68 l1CrossDomainMessenger.messageNonce(), alice, recipient, 0, 100, hex"ff" 69 ) 70 ) 71 ); 72 73 // TransactionDeposited event 74 vm.expectEmit(address(optimismPortal)); 75 emitTransactionDeposited( 76 AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)), 77 Predeploys.L2_CROSS_DOMAIN_MESSENGER, 78 0, 79 0, 80 l1CrossDomainMessenger.baseGas(hex"ff", 100), 81 false, 82 Encoding.encodeCrossDomainMessage(l1CrossDomainMessenger.messageNonce(), alice, recipient, 0, 100, hex"ff") 83 ); 84 85 // SentMessage event 86 vm.expectEmit(address(l1CrossDomainMessenger)); 87 emit SentMessage(recipient, alice, hex"ff", l1CrossDomainMessenger.messageNonce(), 100); 88 89 // SentMessageExtension1 event 90 vm.expectEmit(address(l1CrossDomainMessenger)); 91 emit SentMessageExtension1(alice, 0); 92 93 vm.prank(alice); 94 l1CrossDomainMessenger.sendMessage(recipient, hex"ff", uint32(100)); 95 } 96 97 /// @dev Tests that the sendMessage function is able to send 98 /// the same message twice. 99 function test_sendMessage_twice_succeeds() external { 100 uint256 nonce = l1CrossDomainMessenger.messageNonce(); 101 l1CrossDomainMessenger.sendMessage(recipient, hex"aa", uint32(500_000)); 102 l1CrossDomainMessenger.sendMessage(recipient, hex"aa", uint32(500_000)); 103 // the nonce increments for each message sent 104 assertEq(nonce + 2, l1CrossDomainMessenger.messageNonce()); 105 } 106 107 /// @dev Tests that the xDomainMessageSender reverts when not set. 108 function test_xDomainSender_notSet_reverts() external { 109 vm.expectRevert("CrossDomainMessenger: xDomainMessageSender is not set"); 110 l1CrossDomainMessenger.xDomainMessageSender(); 111 } 112 113 /// @dev Tests that the relayMessage function reverts when 114 /// the message version is not 0 or 1. 115 /// @notice Marked virtual to be overridden in 116 /// test/kontrol/deployment/DeploymentSummary.t.sol 117 function test_relayMessage_v2_reverts() external virtual { 118 address target = address(0xabcd); 119 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 120 121 // Set the value of op.l2Sender() to be the L2 Cross Domain Messenger. 122 vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); 123 124 // Expect a revert. 125 vm.expectRevert("CrossDomainMessenger: only version 0 or 1 messages are supported at this time"); 126 127 // Try to relay a v2 message. 128 vm.prank(address(optimismPortal)); 129 l2CrossDomainMessenger.relayMessage( 130 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 2 }), // nonce 131 sender, 132 target, 133 0, // value 134 0, 135 hex"1111" 136 ); 137 } 138 139 /// @dev Tests that the relayMessage function is able to relay a message 140 /// successfully by calling the target contract. 141 function test_relayMessage_succeeds() external { 142 address target = address(0xabcd); 143 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 144 145 vm.expectCall(target, hex"1111"); 146 147 // set the value of op.l2Sender() to be the L2 Cross Domain Messenger. 148 vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); 149 vm.prank(address(optimismPortal)); 150 151 vm.expectEmit(address(l1CrossDomainMessenger)); 152 153 bytes32 hash = Hashing.hashCrossDomainMessage( 154 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, hex"1111" 155 ); 156 157 emit RelayedMessage(hash); 158 159 l1CrossDomainMessenger.relayMessage( 160 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), // nonce 161 sender, 162 target, 163 0, // value 164 0, 165 hex"1111" 166 ); 167 168 // the message hash is in the successfulMessages mapping 169 assert(l1CrossDomainMessenger.successfulMessages(hash)); 170 // it is not in the received messages mapping 171 assertEq(l1CrossDomainMessenger.failedMessages(hash), false); 172 } 173 174 /// @dev Tests that relayMessage reverts if attempting to relay a message 175 /// sent to an L1 system contract. 176 function test_relayMessage_toSystemContract_reverts() external { 177 // set the target to be the OptimismPortal 178 address target = address(optimismPortal); 179 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 180 bytes memory message = hex"1111"; 181 182 vm.prank(address(optimismPortal)); 183 vm.expectRevert("CrossDomainMessenger: message cannot be replayed"); 184 l1CrossDomainMessenger.relayMessage( 185 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, message 186 ); 187 188 vm.store(address(optimismPortal), 0, bytes32(abi.encode(sender))); 189 vm.expectRevert("CrossDomainMessenger: message cannot be replayed"); 190 l1CrossDomainMessenger.relayMessage( 191 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, message 192 ); 193 } 194 195 /// @dev Tests that the relayMessage function reverts if eth is 196 /// sent from a contract other than the standard bridge. 197 function test_replayMessage_withValue_reverts() external { 198 address target = address(0xabcd); 199 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 200 bytes memory message = hex"1111"; 201 202 vm.expectRevert("CrossDomainMessenger: value must be zero unless message is from a system address"); 203 l1CrossDomainMessenger.relayMessage{ value: 100 }( 204 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, message 205 ); 206 } 207 208 /// @dev Tests that the xDomainMessageSender is reset to the original value 209 /// after a message is relayed. 210 function test_xDomainMessageSender_reset_succeeds() external { 211 vm.expectRevert("CrossDomainMessenger: xDomainMessageSender is not set"); 212 l1CrossDomainMessenger.xDomainMessageSender(); 213 214 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 215 216 vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); 217 vm.prank(address(optimismPortal)); 218 l1CrossDomainMessenger.relayMessage( 219 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), address(0), address(0), 0, 0, hex"" 220 ); 221 222 vm.expectRevert("CrossDomainMessenger: xDomainMessageSender is not set"); 223 l1CrossDomainMessenger.xDomainMessageSender(); 224 } 225 226 /// @dev Tests that relayMessage should successfully call the target contract after 227 /// the first message fails and ETH is stuck, but the second message succeeds 228 /// with a version 1 message. 229 function test_relayMessage_retryAfterFailure_succeeds() external { 230 address target = address(0xabcd); 231 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 232 uint256 value = 100; 233 234 vm.expectCall(target, hex"1111"); 235 236 bytes32 hash = Hashing.hashCrossDomainMessage( 237 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, value, 0, hex"1111" 238 ); 239 240 vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); 241 vm.etch(target, address(new Reverter()).code); 242 vm.deal(address(optimismPortal), value); 243 vm.prank(address(optimismPortal)); 244 l1CrossDomainMessenger.relayMessage{ value: value }( 245 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), // nonce 246 sender, 247 target, 248 value, 249 0, 250 hex"1111" 251 ); 252 253 assertEq(address(l1CrossDomainMessenger).balance, value); 254 assertEq(address(target).balance, 0); 255 assertEq(l1CrossDomainMessenger.successfulMessages(hash), false); 256 assertEq(l1CrossDomainMessenger.failedMessages(hash), true); 257 258 vm.expectEmit(address(l1CrossDomainMessenger)); 259 260 emit RelayedMessage(hash); 261 262 vm.etch(target, address(0).code); 263 vm.prank(address(sender)); 264 l1CrossDomainMessenger.relayMessage( 265 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), // nonce 266 sender, 267 target, 268 value, 269 0, 270 hex"1111" 271 ); 272 273 assertEq(address(l1CrossDomainMessenger).balance, 0); 274 assertEq(address(target).balance, value); 275 assertEq(l1CrossDomainMessenger.successfulMessages(hash), true); 276 assertEq(l1CrossDomainMessenger.failedMessages(hash), true); 277 } 278 279 /// @dev Tests that relayMessage should successfully call the target contract after 280 /// the first message fails and ETH is stuck, but the second message succeeds 281 /// with a legacy message. 282 function test_relayMessage_legacy_succeeds() external { 283 address target = address(0xabcd); 284 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 285 286 // Compute the message hash. 287 bytes32 hash = Hashing.hashCrossDomainMessageV1( 288 // Using a legacy nonce with version 0. 289 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), 290 sender, 291 target, 292 0, 293 0, 294 hex"1111" 295 ); 296 297 // Set the value of op.l2Sender() to be the L2 Cross Domain Messenger. 298 vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); 299 300 // Target should be called with expected data. 301 vm.expectCall(target, hex"1111"); 302 303 // Expect RelayedMessage event to be emitted. 304 vm.expectEmit(address(l1CrossDomainMessenger)); 305 emit RelayedMessage(hash); 306 307 // Relay the message. 308 vm.prank(address(optimismPortal)); 309 l1CrossDomainMessenger.relayMessage( 310 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), // nonce 311 sender, 312 target, 313 0, // value 314 0, 315 hex"1111" 316 ); 317 318 // Message was successfully relayed. 319 assertEq(l1CrossDomainMessenger.successfulMessages(hash), true); 320 assertEq(l1CrossDomainMessenger.failedMessages(hash), false); 321 } 322 323 /// @dev Tests that relayMessage should revert if the message is already replayed. 324 function test_relayMessage_legacyOldReplay_reverts() external { 325 address target = address(0xabcd); 326 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 327 328 // Compute the message hash. 329 bytes32 hash = Hashing.hashCrossDomainMessageV1( 330 // Using a legacy nonce with version 0. 331 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), 332 sender, 333 target, 334 0, 335 0, 336 hex"1111" 337 ); 338 339 // Set the value of op.l2Sender() to be the L2 Cross Domain Messenger. 340 vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); 341 // Mark legacy message as already relayed. 342 uint256 successfulMessagesSlot = 203; 343 bytes32 oldHash = Hashing.hashCrossDomainMessageV0(target, sender, hex"1111", 0); 344 bytes32 slot = keccak256(abi.encode(oldHash, successfulMessagesSlot)); 345 vm.store(address(l1CrossDomainMessenger), slot, bytes32(uint256(1))); 346 347 // Expect revert. 348 vm.expectRevert("CrossDomainMessenger: legacy withdrawal already relayed"); 349 350 // Relay the message. 351 vm.prank(address(optimismPortal)); 352 l1CrossDomainMessenger.relayMessage( 353 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), // nonce 354 sender, 355 target, 356 0, // value 357 0, 358 hex"1111" 359 ); 360 361 // Message was not relayed. 362 assertEq(l1CrossDomainMessenger.successfulMessages(hash), false); 363 assertEq(l1CrossDomainMessenger.failedMessages(hash), false); 364 } 365 366 /// @dev Tests that relayMessage can be retried after a failure with a legacy message. 367 function test_relayMessage_legacyRetryAfterFailure_succeeds() external { 368 address target = address(0xabcd); 369 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 370 uint256 value = 100; 371 372 // Compute the message hash. 373 bytes32 hash = Hashing.hashCrossDomainMessageV1( 374 // Using a legacy nonce with version 0. 375 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), 376 sender, 377 target, 378 value, 379 0, 380 hex"1111" 381 ); 382 383 // Set the value of op.l2Sender() to be the L2 Cross Domain Messenger. 384 vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); 385 386 // Turn the target into a Reverter. 387 vm.etch(target, address(new Reverter()).code); 388 389 // Target should be called with expected data. 390 vm.expectCall(target, hex"1111"); 391 392 // Expect FailedRelayedMessage event to be emitted. 393 vm.expectEmit(address(l1CrossDomainMessenger)); 394 emit FailedRelayedMessage(hash); 395 396 // Relay the message. 397 vm.deal(address(optimismPortal), value); 398 vm.prank(address(optimismPortal)); 399 l1CrossDomainMessenger.relayMessage{ value: value }( 400 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), // nonce 401 sender, 402 target, 403 value, 404 0, 405 hex"1111" 406 ); 407 408 // Message failed. 409 assertEq(address(l1CrossDomainMessenger).balance, value); 410 assertEq(address(target).balance, 0); 411 assertEq(l1CrossDomainMessenger.successfulMessages(hash), false); 412 assertEq(l1CrossDomainMessenger.failedMessages(hash), true); 413 414 // Make the target not revert anymore. 415 vm.etch(target, address(0).code); 416 417 // Target should be called with expected data. 418 vm.expectCall(target, hex"1111"); 419 420 // Expect RelayedMessage event to be emitted. 421 vm.expectEmit(address(l1CrossDomainMessenger)); 422 emit RelayedMessage(hash); 423 424 // Retry the message. 425 vm.prank(address(sender)); 426 l1CrossDomainMessenger.relayMessage( 427 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), // nonce 428 sender, 429 target, 430 value, 431 0, 432 hex"1111" 433 ); 434 435 // Message was successfully relayed. 436 assertEq(address(l1CrossDomainMessenger).balance, 0); 437 assertEq(address(target).balance, value); 438 assertEq(l1CrossDomainMessenger.successfulMessages(hash), true); 439 assertEq(l1CrossDomainMessenger.failedMessages(hash), true); 440 } 441 442 /// @dev Tests that relayMessage cannot be retried after success with a legacy message. 443 function test_relayMessage_legacyRetryAfterSuccess_reverts() external { 444 address target = address(0xabcd); 445 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 446 uint256 value = 100; 447 448 // Compute the message hash. 449 bytes32 hash = Hashing.hashCrossDomainMessageV1( 450 // Using a legacy nonce with version 0. 451 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), 452 sender, 453 target, 454 value, 455 0, 456 hex"1111" 457 ); 458 459 // Set the value of op.l2Sender() to be the L2 Cross Domain Messenger. 460 vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); 461 462 // Target should be called with expected data. 463 vm.expectCall(target, hex"1111"); 464 465 // Expect RelayedMessage event to be emitted. 466 vm.expectEmit(address(l1CrossDomainMessenger)); 467 emit RelayedMessage(hash); 468 469 // Relay the message. 470 vm.deal(address(optimismPortal), value); 471 vm.prank(address(optimismPortal)); 472 l1CrossDomainMessenger.relayMessage{ value: value }( 473 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), // nonce 474 sender, 475 target, 476 value, 477 0, 478 hex"1111" 479 ); 480 481 // Message was successfully relayed. 482 assertEq(address(l1CrossDomainMessenger).balance, 0); 483 assertEq(address(target).balance, value); 484 assertEq(l1CrossDomainMessenger.successfulMessages(hash), true); 485 assertEq(l1CrossDomainMessenger.failedMessages(hash), false); 486 487 // Expect a revert. 488 vm.expectRevert("CrossDomainMessenger: message cannot be replayed"); 489 490 // Retry the message. 491 vm.prank(address(sender)); 492 l1CrossDomainMessenger.relayMessage( 493 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), // nonce 494 sender, 495 target, 496 value, 497 0, 498 hex"1111" 499 ); 500 } 501 502 /// @dev Tests that relayMessage cannot be called after a failure and a successful replay. 503 function test_relayMessage_legacyRetryAfterFailureThenSuccess_reverts() external { 504 address target = address(0xabcd); 505 address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 506 uint256 value = 100; 507 508 // Compute the message hash. 509 bytes32 hash = Hashing.hashCrossDomainMessageV1( 510 // Using a legacy nonce with version 0. 511 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), 512 sender, 513 target, 514 value, 515 0, 516 hex"1111" 517 ); 518 519 // Set the value of op.l2Sender() to be the L2 Cross Domain Messenger. 520 vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); 521 522 // Turn the target into a Reverter. 523 vm.etch(target, address(new Reverter()).code); 524 525 // Target should be called with expected data. 526 vm.expectCall(target, hex"1111"); 527 528 // Relay the message. 529 vm.deal(address(optimismPortal), value); 530 vm.prank(address(optimismPortal)); 531 l1CrossDomainMessenger.relayMessage{ value: value }( 532 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), // nonce 533 sender, 534 target, 535 value, 536 0, 537 hex"1111" 538 ); 539 540 // Message failed. 541 assertEq(address(l1CrossDomainMessenger).balance, value); 542 assertEq(address(target).balance, 0); 543 assertEq(l1CrossDomainMessenger.successfulMessages(hash), false); 544 assertEq(l1CrossDomainMessenger.failedMessages(hash), true); 545 546 // Make the target not revert anymore. 547 vm.etch(target, address(0).code); 548 549 // Target should be called with expected data. 550 vm.expectCall(target, hex"1111"); 551 552 // Expect RelayedMessage event to be emitted. 553 vm.expectEmit(address(l1CrossDomainMessenger)); 554 emit RelayedMessage(hash); 555 556 // Retry the message 557 vm.prank(address(sender)); 558 l1CrossDomainMessenger.relayMessage( 559 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), // nonce 560 sender, 561 target, 562 value, 563 0, 564 hex"1111" 565 ); 566 567 // Message was successfully relayed. 568 assertEq(address(l1CrossDomainMessenger).balance, 0); 569 assertEq(address(target).balance, value); 570 assertEq(l1CrossDomainMessenger.successfulMessages(hash), true); 571 assertEq(l1CrossDomainMessenger.failedMessages(hash), true); 572 573 // Expect a revert. 574 vm.expectRevert("CrossDomainMessenger: message has already been relayed"); 575 576 // Retry the message again. 577 vm.prank(address(sender)); 578 l1CrossDomainMessenger.relayMessage( 579 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 0 }), // nonce 580 sender, 581 target, 582 value, 583 0, 584 hex"1111" 585 ); 586 } 587 588 /// @dev Tests that the relayMessage function is able to relay a message 589 /// successfully by calling the target contract. 590 function test_relayMessage_paused_reverts() external { 591 vm.prank(superchainConfig.guardian()); 592 superchainConfig.pause("identifier"); 593 vm.expectRevert("CrossDomainMessenger: paused"); 594 595 l1CrossDomainMessenger.relayMessage( 596 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), // nonce 597 address(0), 598 address(0), 599 0, // value 600 0, 601 hex"1111" 602 ); 603 } 604 605 /// @dev Tests that the superchain config is called by the messengers paused function 606 function test_pause_callsSuperchainConfig_succeeds() external { 607 vm.expectCall(address(superchainConfig), abi.encodeWithSelector(SuperchainConfig.paused.selector)); 608 l1CrossDomainMessenger.paused(); 609 } 610 611 /// @dev Tests that changing the superchain config paused status changes the return value of the messenger 612 function test_pause_matchesSuperchainConfig_succeeds() external { 613 assertFalse(l1CrossDomainMessenger.paused()); 614 assertEq(l1CrossDomainMessenger.paused(), superchainConfig.paused()); 615 616 vm.prank(superchainConfig.guardian()); 617 superchainConfig.pause("identifier"); 618 619 assertTrue(l1CrossDomainMessenger.paused()); 620 assertEq(l1CrossDomainMessenger.paused(), superchainConfig.paused()); 621 } 622 } 623 624 /// @dev A regression test against a reentrancy vulnerability in the CrossDomainMessenger contract, which 625 /// was possible by intercepting and sandwhiching a signed Safe Transaction to upgrade it. 626 contract L1CrossDomainMessenger_ReinitReentryTest is Bridge_Initializer { 627 bool attacked; 628 629 // Common values used across functions 630 uint256 constant messageValue = 50; 631 bytes constant selector = abi.encodeWithSelector(this.reinitAndReenter.selector); 632 address sender; 633 bytes32 hash; 634 address target; 635 636 function setUp() public override { 637 super.setUp(); 638 target = address(this); 639 sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; 640 hash = Hashing.hashCrossDomainMessage( 641 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, messageValue, 0, selector 642 ); 643 vm.deal(address(l1CrossDomainMessenger), messageValue * 2); 644 } 645 646 /// @dev This method will be called by the relayed message, and will attempt to reenter the relayMessage function 647 /// exactly once. 648 function reinitAndReenter() public payable { 649 // only attempt the attack once 650 if (!attacked) { 651 attacked = true; 652 // set initialized to false 653 vm.store(address(l1CrossDomainMessenger), 0, bytes32(uint256(0))); 654 655 // call the initializer function 656 l1CrossDomainMessenger.initialize(SuperchainConfig(superchainConfig), OptimismPortal(optimismPortal)); 657 658 // attempt to re-replay the withdrawal 659 vm.expectEmit(address(l1CrossDomainMessenger)); 660 emit FailedRelayedMessage(hash); 661 l1CrossDomainMessenger.relayMessage( 662 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), // nonce 663 sender, 664 target, 665 messageValue, 666 0, 667 selector 668 ); 669 } 670 } 671 672 /// @dev Tests that the relayMessage function cannot be reentered by calling the `initialize()` function within the 673 /// relayed message. 674 function test_relayMessage_replayStraddlingReinit_reverts() external { 675 uint256 balanceBeforeThis = address(this).balance; 676 uint256 balanceBeforeMessenger = address(l1CrossDomainMessenger).balance; 677 678 // A requisite for the attack is that the message has already been attempted and written to the failedMessages 679 // mapping, so that it can be replayed. 680 vm.store(address(l1CrossDomainMessenger), keccak256(abi.encode(hash, 206)), bytes32(uint256(1))); 681 assertTrue(l1CrossDomainMessenger.failedMessages(hash)); 682 683 vm.expectEmit(address(l1CrossDomainMessenger)); 684 emit FailedRelayedMessage(hash); 685 l1CrossDomainMessenger.relayMessage( 686 Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), // nonce 687 sender, 688 target, 689 messageValue, 690 0, 691 selector 692 ); 693 694 // The message hash is not in the successfulMessages mapping. 695 assertFalse(l1CrossDomainMessenger.successfulMessages(hash)); 696 // The balance of this contract is unchanged. 697 assertEq(address(this).balance, balanceBeforeThis); 698 // The balance of the messenger contract is unchanged. 699 assertEq(address(l1CrossDomainMessenger).balance, balanceBeforeMessenger); 700 } 701 }