Skip to content

Commit

Permalink
Fix address of initializer when deploying L2 token contract
Browse files Browse the repository at this point in the history
  • Loading branch information
matjazv committed Jan 10, 2024
1 parent 118f1b5 commit 4c0db37
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 9 deletions.
4 changes: 1 addition & 3 deletions script/L2LiskToken.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
8 changes: 7 additions & 1 deletion src/L2/L2LiskToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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.
Expand Down
15 changes: 10 additions & 5 deletions test/L2/L2LiskToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit 4c0db37

Please sign in to comment.