github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/universal/OptimismMintableERC20Factory.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 { NextImpl } from "test/mocks/NextImpl.sol"; 7 import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; 8 9 // Target contract dependencies 10 import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; 11 import { Proxy } from "src/universal/Proxy.sol"; 12 13 // Target contract 14 import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC20Factory.sol"; 15 16 contract OptimismMintableTokenFactory_Test is Bridge_Initializer { 17 event StandardL2TokenCreated(address indexed remoteToken, address indexed localToken); 18 event OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer); 19 20 /// @dev Tests that the constructor is initialized correctly. 21 function test_constructor_succeeds() external { 22 OptimismMintableERC20Factory impl = new OptimismMintableERC20Factory(); 23 assertEq(address(impl.BRIDGE()), address(0)); 24 assertEq(address(impl.bridge()), address(0)); 25 } 26 27 /// @dev Tests that the proxy is initialized correctly. 28 function test_initialize_succeeds() external { 29 assertEq(address(l1OptimismMintableERC20Factory.BRIDGE()), address(l1StandardBridge)); 30 assertEq(address(l1OptimismMintableERC20Factory.bridge()), address(l1StandardBridge)); 31 } 32 33 function test_upgrading_succeeds() external { 34 Proxy proxy = Proxy(deploy.mustGetAddress("OptimismMintableERC20FactoryProxy")); 35 // Check an unused slot before upgrading. 36 bytes32 slot21Before = vm.load(address(l1OptimismMintableERC20Factory), bytes32(uint256(21))); 37 assertEq(bytes32(0), slot21Before); 38 39 NextImpl nextImpl = new NextImpl(); 40 vm.startPrank(EIP1967Helper.getAdmin(address(proxy))); 41 // Reviewer note: the NextImpl() still uses reinitializer. If we want to remove that, we'll need to use a 42 // two step upgrade with the Storage lib. 43 proxy.upgradeToAndCall(address(nextImpl), abi.encodeWithSelector(NextImpl.initialize.selector, 2)); 44 assertEq(proxy.implementation(), address(nextImpl)); 45 46 // Verify that the NextImpl contract initialized its values according as expected 47 bytes32 slot21After = vm.load(address(l1OptimismMintableERC20Factory), bytes32(uint256(21))); 48 bytes32 slot21Expected = NextImpl(address(l1OptimismMintableERC20Factory)).slot21Init(); 49 assertEq(slot21Expected, slot21After); 50 } 51 52 function test_createStandardL2Token_succeeds() external { 53 address remote = address(4); 54 55 // Defaults to 18 decimals 56 address local = calculateTokenAddress(remote, "Beep", "BOOP", 18); 57 58 vm.expectEmit(true, true, true, true); 59 emit StandardL2TokenCreated(remote, local); 60 61 vm.expectEmit(true, true, true, true); 62 emit OptimismMintableERC20Created(local, remote, alice); 63 64 vm.prank(alice); 65 address addr = l2OptimismMintableERC20Factory.createStandardL2Token(remote, "Beep", "BOOP"); 66 assertTrue(addr == local); 67 assertTrue(OptimismMintableERC20(local).decimals() == 18); 68 } 69 70 function test_createStandardL2TokenWithDecimals_succeeds() external { 71 address remote = address(4); 72 address local = calculateTokenAddress(remote, "Beep", "BOOP", 6); 73 74 vm.expectEmit(true, true, true, true); 75 emit StandardL2TokenCreated(remote, local); 76 77 vm.expectEmit(true, true, true, true); 78 emit OptimismMintableERC20Created(local, remote, alice); 79 80 vm.prank(alice); 81 address addr = l2OptimismMintableERC20Factory.createOptimismMintableERC20WithDecimals(remote, "Beep", "BOOP", 6); 82 assertTrue(addr == local); 83 84 assertTrue(OptimismMintableERC20(local).decimals() == 6); 85 } 86 87 function test_createStandardL2Token_sameTwice_reverts() external { 88 address remote = address(4); 89 90 vm.prank(alice); 91 l2OptimismMintableERC20Factory.createStandardL2Token(remote, "Beep", "BOOP"); 92 93 vm.expectRevert(bytes("")); 94 95 vm.prank(alice); 96 l2OptimismMintableERC20Factory.createStandardL2Token(remote, "Beep", "BOOP"); 97 } 98 99 function test_createStandardL2Token_remoteIsZero_reverts() external { 100 address remote = address(0); 101 vm.expectRevert("OptimismMintableERC20Factory: must provide remote token address"); 102 l2OptimismMintableERC20Factory.createStandardL2Token(remote, "Beep", "BOOP"); 103 } 104 105 function calculateTokenAddress( 106 address _remote, 107 string memory _name, 108 string memory _symbol, 109 uint8 _decimals 110 ) 111 internal 112 view 113 returns (address) 114 { 115 bytes memory constructorArgs = abi.encode(address(l2StandardBridge), _remote, _name, _symbol, _decimals); 116 bytes memory bytecode = abi.encodePacked(type(OptimismMintableERC20).creationCode, constructorArgs); 117 bytes32 salt = keccak256(abi.encode(_remote, _name, _symbol, _decimals)); 118 bytes32 hash = keccak256( 119 abi.encodePacked(bytes1(0xff), address(l2OptimismMintableERC20Factory), salt, keccak256(bytecode)) 120 ); 121 return address(uint160(uint256(hash))); 122 } 123 }