diff --git a/script/L2LiskToken.s.sol b/script/L2LiskToken.s.sol index 6189c214..521a574a 100644 --- a/script/L2LiskToken.s.sol +++ b/script/L2LiskToken.s.sol @@ -36,9 +36,7 @@ contract L2LiskTokenScript is Script { // calculate L2LiskToken contract address address l2LiskTokenAddressCalculated = computeCreate2Address( - salt, - hashInitCode(type(L2LiskToken).creationCode, abi.encode(l1AddressesConfig.L1LiskToken)), - CREATE2_FACTORY + salt, hashInitCode(type(L2LiskToken).creationCode, abi.encode(l1AddressesConfig.L1LiskToken)) ); console2.log("Simulation: Calculated L2 Lisk token address: %s", l2LiskTokenAddressCalculated); diff --git a/src/L2/L2LiskToken.sol b/src/L2/L2LiskToken.sol index 1e7382cd..97771263 100644 --- a/src/L2/L2LiskToken.sol +++ b/src/L2/L2LiskToken.sol @@ -28,6 +28,12 @@ contract L2LiskToken is IOptimismMintableERC20, ERC20, ERC20Permit { string private constant SYMBOL = "LSK"; /// @notice Address which deployed this contract. Only this address is able to call initialize() function. + /// Using Foundry's forge script when deploying a contract with CREATE2 opcode, the address of the + /// deployer is a proxy contract address to have a deterministic deployer address. This offers a + /// flexibility that a deployed contract address is calculated only by the hash of the contract's bytecode + /// and a salt. Because initialize() function needs to be called by the actual deployer (EOA), we need to + /// store the address of the original caller of the constructor (tx.origin) and not msg.sender which is the + /// proxy contract address. address private immutable initializer; /// @notice Address of the corresponding version of this token on the remote chain (on L1). @@ -56,7 +62,7 @@ contract L2LiskToken is IOptimismMintableERC20, ERC20, ERC20Permit { /// @param remoteTokenAddr Address of the corresponding L1LiskToken. constructor(address remoteTokenAddr) ERC20(NAME, SYMBOL) ERC20Permit(NAME) { REMOTE_TOKEN = remoteTokenAddr; - initializer = msg.sender; + initializer = tx.origin; } /// @notice Initializes the L2LiskToken contract. diff --git a/test/L2/L2LiskToken.t.sol b/test/L2/L2LiskToken.t.sol index 9719af38..3dcc5bdd 100644 --- a/test/L2/L2LiskToken.t.sol +++ b/test/L2/L2LiskToken.t.sol @@ -24,8 +24,13 @@ contract L2LiskTokenTest is Test { function setUp() public { bridge = vm.addr(uint256(bytes32("bridge"))); remoteToken = vm.addr(uint256(bytes32("remoteToken"))); + + // msg.sender and tx.origin needs to be the same for the contract to be able to call initialize() + vm.prank(address(this), address(this)); l2LiskToken = new L2LiskToken(remoteToken); l2LiskToken.initialize(bridge); + vm.stopPrank(); + sigUtils = new SigUtils(l2LiskToken.DOMAIN_SEPARATOR()); (alice, alicePrivateKey) = makeAddrAndKey("alice"); @@ -51,7 +56,7 @@ contract L2LiskTokenTest is Test { function test_Initialize_ValidInitializer() public { // initialize the contract beeing alice - vm.prank(alice); + vm.prank(alice, alice); L2LiskToken l2LiskTokenNew = new L2LiskToken{ salt: salt }(remoteToken); // initialize the contract beeing alice and the initializer @@ -84,7 +89,7 @@ contract L2LiskTokenTest is Test { computeCreate2Address(salt, hashInitCode(type(L2LiskToken).creationCode, abi.encode(remoteToken)), alice); // use the same salt and the same deployer as in calculated address of L2LiskToken contract - vm.prank(alice); + vm.prank(alice, alice); L2LiskToken l2LiskTokenSalted = new L2LiskToken{ salt: salt }(remoteToken); vm.prank(alice); l2LiskTokenSalted.initialize(bridge); @@ -99,7 +104,7 @@ contract L2LiskTokenTest is Test { computeCreate2Address(salt, hashInitCode(type(L2LiskToken).creationCode, abi.encode(remoteToken)), alice); // use the same salt and the same deployer as in calculated address of L2LiskToken contract - vm.prank(alice); + vm.prank(alice, alice); L2LiskToken l2LiskTokenSalted = new L2LiskToken{ salt: salt }(remoteToken); // use different Standard Bridge addresses @@ -116,7 +121,7 @@ contract L2LiskTokenTest is Test { computeCreate2Address(salt, hashInitCode(type(L2LiskToken).creationCode, abi.encode(remoteToken)), alice); // use the same salt but different deployer as in calculated address of L2LiskToken contract - vm.prank(bob); + vm.prank(bob, bob); L2LiskToken l2LiskTokenSalted = new L2LiskToken{ salt: salt }(remoteToken); vm.prank(bob); l2LiskTokenSalted.initialize(bridge); @@ -131,7 +136,7 @@ contract L2LiskTokenTest is Test { computeCreate2Address(salt, hashInitCode(type(L2LiskToken).creationCode, abi.encode(remoteToken)), alice); // use different salt but the same deployer as in calculated address of L2LiskToken contract - vm.prank(alice); + vm.prank(alice, alice); L2LiskToken l2LiskTokenSalted = new L2LiskToken{ salt: keccak256(bytes("different_salt")) }(remoteToken); vm.prank(alice); l2LiskTokenSalted.initialize(bridge);