github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/L1/L1ERC721Bridge.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 { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
     7  
     8  // Target contract dependencies
     9  import { L2ERC721Bridge } from "src/L2/L2ERC721Bridge.sol";
    10  import { Predeploys } from "src/libraries/Predeploys.sol";
    11  import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
    12  import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol";
    13  
    14  // Target contract
    15  import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
    16  
    17  /// @dev Test ERC721 contract.
    18  contract TestERC721 is ERC721 {
    19      constructor() ERC721("Test", "TST") { }
    20  
    21      function mint(address to, uint256 tokenId) public {
    22          _mint(to, tokenId);
    23      }
    24  }
    25  
    26  contract L1ERC721Bridge_Test is Bridge_Initializer {
    27      TestERC721 internal localToken;
    28      TestERC721 internal remoteToken;
    29      uint256 internal constant tokenId = 1;
    30  
    31      event ERC721BridgeInitiated(
    32          address indexed localToken,
    33          address indexed remoteToken,
    34          address indexed from,
    35          address to,
    36          uint256 tokenId,
    37          bytes extraData
    38      );
    39  
    40      event ERC721BridgeFinalized(
    41          address indexed localToken,
    42          address indexed remoteToken,
    43          address indexed from,
    44          address to,
    45          uint256 tokenId,
    46          bytes extraData
    47      );
    48  
    49      /// @dev Sets up the testing environment.
    50      /// @notice Marked virtual to be overridden in
    51      ///         test/kontrol/deployment/DeploymentSummary.t.sol
    52      function setUp() public virtual override {
    53          super.setUp();
    54  
    55          localToken = new TestERC721();
    56          remoteToken = new TestERC721();
    57  
    58          // Mint alice a token.
    59          localToken.mint(alice, tokenId);
    60  
    61          // Approve the bridge to transfer the token.
    62          vm.prank(alice);
    63          localToken.approve(address(l1ERC721Bridge), tokenId);
    64      }
    65  
    66      /// @dev Tests that the impl is created with the correct values.
    67      /// @notice Marked virtual to be overridden in
    68      ///         test/kontrol/deployment/DeploymentSummary.t.sol
    69      function test_constructor_succeeds() public virtual {
    70          L1ERC721Bridge impl = L1ERC721Bridge(deploy.mustGetAddress("L1ERC721Bridge"));
    71          assertEq(address(impl.MESSENGER()), address(0));
    72          assertEq(address(impl.messenger()), address(0));
    73          assertEq(address(impl.OTHER_BRIDGE()), Predeploys.L2_ERC721_BRIDGE);
    74          assertEq(address(impl.otherBridge()), Predeploys.L2_ERC721_BRIDGE);
    75          assertEq(address(impl.superchainConfig()), address(0));
    76      }
    77  
    78      /// @dev Tests that the proxy is initialized with the correct values.
    79      function test_initialize_succeeds() public {
    80          assertEq(address(l1ERC721Bridge.MESSENGER()), address(l1CrossDomainMessenger));
    81          assertEq(address(l1ERC721Bridge.messenger()), address(l1CrossDomainMessenger));
    82          assertEq(address(l1ERC721Bridge.OTHER_BRIDGE()), Predeploys.L2_ERC721_BRIDGE);
    83          assertEq(address(l1ERC721Bridge.otherBridge()), Predeploys.L2_ERC721_BRIDGE);
    84          assertEq(address(l1ERC721Bridge.superchainConfig()), address(superchainConfig));
    85      }
    86  
    87      /// @dev Tests that the ERC721 can be bridged successfully.
    88      function test_bridgeERC721_succeeds() public {
    89          // Expect a call to the messenger.
    90          vm.expectCall(
    91              address(l1CrossDomainMessenger),
    92              abi.encodeCall(
    93                  l1CrossDomainMessenger.sendMessage,
    94                  (
    95                      address(l2ERC721Bridge),
    96                      abi.encodeCall(
    97                          L2ERC721Bridge.finalizeBridgeERC721,
    98                          (address(remoteToken), address(localToken), alice, alice, tokenId, hex"5678")
    99                          ),
   100                      1234
   101                  )
   102              )
   103          );
   104  
   105          // Expect an event to be emitted.
   106          vm.expectEmit(true, true, true, true);
   107          emit ERC721BridgeInitiated(address(localToken), address(remoteToken), alice, alice, tokenId, hex"5678");
   108  
   109          // Bridge the token.
   110          vm.prank(alice);
   111          l1ERC721Bridge.bridgeERC721(address(localToken), address(remoteToken), tokenId, 1234, hex"5678");
   112  
   113          // Token is locked in the bridge.
   114          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), true);
   115          assertEq(localToken.ownerOf(tokenId), address(l1ERC721Bridge));
   116      }
   117  
   118      /// @dev Tests that the ERC721 bridge reverts for non externally owned accounts.
   119      function test_bridgeERC721_fromContract_reverts() external {
   120          // Bridge the token.
   121          vm.etch(alice, hex"01");
   122          vm.prank(alice);
   123          vm.expectRevert("ERC721Bridge: account is not externally owned");
   124          l1ERC721Bridge.bridgeERC721(address(localToken), address(remoteToken), tokenId, 1234, hex"5678");
   125  
   126          // Token is not locked in the bridge.
   127          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), false);
   128          assertEq(localToken.ownerOf(tokenId), alice);
   129      }
   130  
   131      /// @dev Tests that the ERC721 bridge reverts for a zero address local token.
   132      function test_bridgeERC721_localTokenZeroAddress_reverts() external {
   133          // Bridge the token.
   134          vm.prank(alice);
   135          vm.expectRevert(bytes(""));
   136          l1ERC721Bridge.bridgeERC721(address(0), address(remoteToken), tokenId, 1234, hex"5678");
   137  
   138          // Token is not locked in the bridge.
   139          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), false);
   140          assertEq(localToken.ownerOf(tokenId), alice);
   141      }
   142  
   143      /// @dev Tests that the ERC721 bridge reverts for a zero address remote token.
   144      function test_bridgeERC721_remoteTokenZeroAddress_reverts() external {
   145          // Bridge the token.
   146          vm.prank(alice);
   147          vm.expectRevert("L1ERC721Bridge: remote token cannot be address(0)");
   148          l1ERC721Bridge.bridgeERC721(address(localToken), address(0), tokenId, 1234, hex"5678");
   149  
   150          // Token is not locked in the bridge.
   151          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), false);
   152          assertEq(localToken.ownerOf(tokenId), alice);
   153      }
   154  
   155      /// @dev Tests that the ERC721 bridge reverts for an incorrect owner.
   156      function test_bridgeERC721_wrongOwner_reverts() external {
   157          // Bridge the token.
   158          vm.prank(bob);
   159          vm.expectRevert("ERC721: transfer from incorrect owner");
   160          l1ERC721Bridge.bridgeERC721(address(localToken), address(remoteToken), tokenId, 1234, hex"5678");
   161  
   162          // Token is not locked in the bridge.
   163          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), false);
   164          assertEq(localToken.ownerOf(tokenId), alice);
   165      }
   166  
   167      /// @dev Tests that the ERC721 bridge successfully sends a token
   168      ///      to a different address than the owner.
   169      function test_bridgeERC721To_succeeds() external {
   170          // Expect a call to the messenger.
   171          vm.expectCall(
   172              address(l1CrossDomainMessenger),
   173              abi.encodeCall(
   174                  l1CrossDomainMessenger.sendMessage,
   175                  (
   176                      address(Predeploys.L2_ERC721_BRIDGE),
   177                      abi.encodeCall(
   178                          L2ERC721Bridge.finalizeBridgeERC721,
   179                          (address(remoteToken), address(localToken), alice, bob, tokenId, hex"5678")
   180                          ),
   181                      1234
   182                  )
   183              )
   184          );
   185  
   186          // Expect an event to be emitted.
   187          vm.expectEmit(true, true, true, true);
   188          emit ERC721BridgeInitiated(address(localToken), address(remoteToken), alice, bob, tokenId, hex"5678");
   189  
   190          // Bridge the token.
   191          vm.prank(alice);
   192          l1ERC721Bridge.bridgeERC721To(address(localToken), address(remoteToken), bob, tokenId, 1234, hex"5678");
   193  
   194          // Token is locked in the bridge.
   195          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), true);
   196          assertEq(localToken.ownerOf(tokenId), address(l1ERC721Bridge));
   197      }
   198  
   199      /// @dev Tests that the ERC721 bridge reverts for non externally owned accounts
   200      ///      when sending to a different address than the owner.
   201      function test_bridgeERC721To_localTokenZeroAddress_reverts() external {
   202          // Bridge the token.
   203          vm.prank(alice);
   204          vm.expectRevert(bytes(""));
   205          l1ERC721Bridge.bridgeERC721To(address(0), address(remoteToken), bob, tokenId, 1234, hex"5678");
   206  
   207          // Token is not locked in the bridge.
   208          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), false);
   209          assertEq(localToken.ownerOf(tokenId), alice);
   210      }
   211  
   212      /// @dev Tests that the ERC721 bridge reverts for a zero address remote token
   213      ///      when sending to a different address than the owner.
   214      function test_bridgeERC721To_remoteTokenZeroAddress_reverts() external {
   215          // Bridge the token.
   216          vm.prank(alice);
   217          vm.expectRevert("L1ERC721Bridge: remote token cannot be address(0)");
   218          l1ERC721Bridge.bridgeERC721To(address(localToken), address(0), bob, tokenId, 1234, hex"5678");
   219  
   220          // Token is not locked in the bridge.
   221          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), false);
   222          assertEq(localToken.ownerOf(tokenId), alice);
   223      }
   224  
   225      /// @dev Tests that the ERC721 bridge reverts for an incorrect owner
   226      ////     when sending to a different address than the owner.
   227      function test_bridgeERC721To_wrongOwner_reverts() external {
   228          // Bridge the token.
   229          vm.prank(bob);
   230          vm.expectRevert("ERC721: transfer from incorrect owner");
   231          l1ERC721Bridge.bridgeERC721To(address(localToken), address(remoteToken), bob, tokenId, 1234, hex"5678");
   232  
   233          // Token is not locked in the bridge.
   234          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), false);
   235          assertEq(localToken.ownerOf(tokenId), alice);
   236      }
   237  
   238      /// @dev Tests that the ERC721 bridge successfully finalizes a withdrawal.
   239      function test_finalizeBridgeERC721_succeeds() external {
   240          // Bridge the token.
   241          vm.prank(alice);
   242          l1ERC721Bridge.bridgeERC721(address(localToken), address(remoteToken), tokenId, 1234, hex"5678");
   243  
   244          // Expect an event to be emitted.
   245          vm.expectEmit(true, true, true, true);
   246          emit ERC721BridgeFinalized(address(localToken), address(remoteToken), alice, alice, tokenId, hex"5678");
   247  
   248          // Finalize a withdrawal.
   249          vm.mockCall(
   250              address(l1CrossDomainMessenger),
   251              abi.encodeWithSelector(l1CrossDomainMessenger.xDomainMessageSender.selector),
   252              abi.encode(Predeploys.L2_ERC721_BRIDGE)
   253          );
   254          vm.prank(address(l1CrossDomainMessenger));
   255          l1ERC721Bridge.finalizeBridgeERC721(address(localToken), address(remoteToken), alice, alice, tokenId, hex"5678");
   256  
   257          // Token is not locked in the bridge.
   258          assertEq(l1ERC721Bridge.deposits(address(localToken), address(remoteToken), tokenId), false);
   259          assertEq(localToken.ownerOf(tokenId), alice);
   260      }
   261  
   262      /// @dev Tests that the ERC721 bridge finalize reverts when not called
   263      ///      by the remote bridge.
   264      function test_finalizeBridgeERC721_notViaLocalMessenger_reverts() external {
   265          // Finalize a withdrawal.
   266          vm.prank(alice);
   267          vm.expectRevert("ERC721Bridge: function can only be called from the other bridge");
   268          l1ERC721Bridge.finalizeBridgeERC721(address(localToken), address(remoteToken), alice, alice, tokenId, hex"5678");
   269      }
   270  
   271      /// @dev Tests that the ERC721 bridge finalize reverts when not called
   272      ///      from the remote messenger.
   273      function test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() external {
   274          // Finalize a withdrawal.
   275          vm.mockCall(
   276              address(l1CrossDomainMessenger),
   277              abi.encodeWithSelector(l1CrossDomainMessenger.xDomainMessageSender.selector),
   278              abi.encode(alice)
   279          );
   280          vm.prank(address(l1CrossDomainMessenger));
   281          vm.expectRevert("ERC721Bridge: function can only be called from the other bridge");
   282          l1ERC721Bridge.finalizeBridgeERC721(address(localToken), address(remoteToken), alice, alice, tokenId, hex"5678");
   283      }
   284  
   285      /// @dev Tests that the ERC721 bridge finalize reverts when the local token
   286      ///      is set as the bridge itself.
   287      function test_finalizeBridgeERC721_selfToken_reverts() external {
   288          // Finalize a withdrawal.
   289          vm.mockCall(
   290              address(l1CrossDomainMessenger),
   291              abi.encodeWithSelector(l1CrossDomainMessenger.xDomainMessageSender.selector),
   292              abi.encode(Predeploys.L2_ERC721_BRIDGE)
   293          );
   294          vm.prank(address(l1CrossDomainMessenger));
   295          vm.expectRevert("L1ERC721Bridge: local token cannot be self");
   296          l1ERC721Bridge.finalizeBridgeERC721(
   297              address(l1ERC721Bridge), address(remoteToken), alice, alice, tokenId, hex"5678"
   298          );
   299      }
   300  
   301      /// @dev Tests that the ERC721 bridge finalize reverts when the remote token
   302      ///      is not escrowed in the L1 bridge.
   303      function test_finalizeBridgeERC721_notEscrowed_reverts() external {
   304          // Finalize a withdrawal.
   305          vm.mockCall(
   306              address(l1CrossDomainMessenger),
   307              abi.encodeWithSelector(l1CrossDomainMessenger.xDomainMessageSender.selector),
   308              abi.encode(Predeploys.L2_ERC721_BRIDGE)
   309          );
   310          vm.prank(address(l1CrossDomainMessenger));
   311          vm.expectRevert("L1ERC721Bridge: Token ID is not escrowed in the L1 Bridge");
   312          l1ERC721Bridge.finalizeBridgeERC721(address(localToken), address(remoteToken), alice, alice, tokenId, hex"5678");
   313      }
   314  }
   315  
   316  contract L1ERC721Bridge_Pause_Test is Bridge_Initializer {
   317      /// @dev Verifies that the `paused` accessor returns the same value as the `paused` function of the
   318      ///      `superchainConfig`.
   319      function test_paused_succeeds() external {
   320          assertEq(l1ERC721Bridge.paused(), superchainConfig.paused());
   321      }
   322  
   323      /// @dev Ensures that the `paused` function of the bridge contract actually calls the `paused` function of the
   324      ///      `superchainConfig`.
   325      function test_pause_callsSuperchainConfig_succeeds() external {
   326          vm.expectCall(address(superchainConfig), abi.encodeWithSelector(SuperchainConfig.paused.selector));
   327          l1ERC721Bridge.paused();
   328      }
   329  
   330      /// @dev Checks that the `paused` state of the bridge matches the `paused` state of the `superchainConfig` after
   331      ///      it's been changed.
   332      function test_pause_matchesSuperchainConfig_succeeds() external {
   333          assertFalse(l1StandardBridge.paused());
   334          assertEq(l1StandardBridge.paused(), superchainConfig.paused());
   335  
   336          vm.prank(superchainConfig.guardian());
   337          superchainConfig.pause("identifier");
   338  
   339          assertTrue(l1StandardBridge.paused());
   340          assertEq(l1StandardBridge.paused(), superchainConfig.paused());
   341      }
   342  }
   343  
   344  contract L1ERC721Bridge_Pause_TestFail is Bridge_Initializer {
   345      /// @dev Sets up the test by pausing the bridge, giving ether to the bridge and mocking
   346      ///      the calls to the xDomainMessageSender so that it returns the correct value.
   347      function setUp() public override {
   348          super.setUp();
   349          vm.prank(superchainConfig.guardian());
   350          superchainConfig.pause("identifier");
   351          assertTrue(l1ERC721Bridge.paused());
   352  
   353          vm.mockCall(
   354              address(l1ERC721Bridge.messenger()),
   355              abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector),
   356              abi.encode(address(l1ERC721Bridge.otherBridge()))
   357          );
   358      }
   359  
   360      // @dev Ensures that the `bridgeERC721` function reverts when the bridge is paused.
   361      function test_pause_finalizeBridgeERC721_reverts() external {
   362          vm.prank(address(l1ERC721Bridge.messenger()));
   363          vm.expectRevert("L1ERC721Bridge: paused");
   364          l1ERC721Bridge.finalizeBridgeERC721({
   365              _localToken: address(0),
   366              _remoteToken: address(0),
   367              _from: address(0),
   368              _to: address(0),
   369              _tokenId: 0,
   370              _extraData: hex""
   371          });
   372      }
   373  }