diff --git a/v2/scripts/deploy/deterministic/DeployERC20Custody.s.sol b/v2/scripts/deploy/deterministic/DeployERC20Custody.s.sol index 43c8a135..64cabfcb 100644 --- a/v2/scripts/deploy/deterministic/DeployERC20Custody.s.sol +++ b/v2/scripts/deploy/deterministic/DeployERC20Custody.s.sol @@ -17,41 +17,71 @@ contract DeployERC20Custody is Script { bytes32 implSalt = keccak256("ERC20Custody-2"); bytes32 proxySalt = keccak256("ERC20CustodyProxy-2"); + // Add this specific check to ensure contract is not deployed at deterministic address with wrong admin + require(admin != address(0), "Environment variable ERC20_CUSTODY_ADMIN_ADDRESS_EVM is not set"); + vm.startBroadcast(); + // Compute expected implementation address expectedImplAddress = vm.computeCreate2Address( implSalt, hashInitCode(type(ERC20Custody).creationCode) ); + // Deploy the implementation contract using CREATE2 ERC20Custody erc20CustodyImpl = new ERC20Custody{salt: implSalt}(); require(address(erc20CustodyImpl) != address(0), "erc20CustodyImpl deployment failed"); - require(expectedImplAddress == address(erc20CustodyImpl), "impl address doesn't match expected address"); + // Compute expected proxy address expectedProxyAddress = vm.computeCreate2Address( proxySalt, hashInitCode( type(ERC1967Proxy).creationCode, abi.encode( address(erc20CustodyImpl), - abi.encodeWithSelector(ERC20Custody.initialize.selector, gateway, tss, admin) + abi.encodeWithSelector(ERC20Custody.initialize.selector, gateway, tss, msg.sender) ) ) ); + // Deploy the proxy contract using CREATE2, with deployer as initial admin ERC1967Proxy erc20CustodyProxy = new ERC1967Proxy{salt: proxySalt}( address(erc20CustodyImpl), - abi.encodeWithSelector(ERC20Custody.initialize.selector, gateway, tss, admin) + abi.encodeWithSelector(ERC20Custody.initialize.selector, gateway, tss, msg.sender) ); require(address(erc20CustodyProxy) != address(0), "erc20CustodyProxy deployment failed"); - require(expectedProxyAddress == address(erc20CustodyProxy), "proxy address doesn't match expected address"); ERC20Custody erc20Custody = ERC20Custody(address(erc20CustodyProxy)); + + // Verify initial configuration require(erc20Custody.tssAddress() == tss, "tss not set"); require(address(erc20Custody.gateway()) == gateway, "gateway not set"); + // Transfer admin role from deployer to admin + transferAdmin(erc20Custody, msg.sender, admin); + vm.stopBroadcast(); } + + function transferAdmin(ERC20Custody erc20Custody, address deployer, address newAdmin) internal { + // Grant roles to specified admin and renounce deployer's roles + erc20Custody.grantRole(erc20Custody.PAUSER_ROLE(), newAdmin); + erc20Custody.grantRole(erc20Custody.WHITELISTER_ROLE(), newAdmin); + erc20Custody.grantRole(erc20Custody.DEFAULT_ADMIN_ROLE(), newAdmin); + + // Renounce deployer's roles + erc20Custody.renounceRole(erc20Custody.PAUSER_ROLE(), deployer); + erc20Custody.renounceRole(erc20Custody.WHITELISTER_ROLE(), deployer); + erc20Custody.renounceRole(erc20Custody.DEFAULT_ADMIN_ROLE(), deployer); + + // Assert that the roles are correctly transitioned + require(erc20Custody.hasRole(erc20Custody.PAUSER_ROLE(), newAdmin), "admin does not have PAUSER_ROLE"); + require(erc20Custody.hasRole(erc20Custody.WHITELISTER_ROLE(), newAdmin), "admin does not have WHITELISTER_ROLE"); + require(erc20Custody.hasRole(erc20Custody.DEFAULT_ADMIN_ROLE(), newAdmin), "admin does not have DEFAULT_ADMIN_ROLE"); + require(!erc20Custody.hasRole(erc20Custody.PAUSER_ROLE(), deployer), "deployer still has PAUSER_ROLE"); + require(!erc20Custody.hasRole(erc20Custody.WHITELISTER_ROLE(), deployer), "deployer still has WHITELISTER_ROLE"); + require(!erc20Custody.hasRole(erc20Custody.DEFAULT_ADMIN_ROLE(), deployer), "deployer still has DEFAULT_ADMIN_ROLE"); + } } \ No newline at end of file diff --git a/v2/scripts/deploy/deterministic/DeployGatewayEVM.s.sol b/v2/scripts/deploy/deterministic/DeployGatewayEVM.s.sol index dc047dfa..8d2ce140 100644 --- a/v2/scripts/deploy/deterministic/DeployGatewayEVM.s.sol +++ b/v2/scripts/deploy/deterministic/DeployGatewayEVM.s.sol @@ -18,41 +18,67 @@ contract DeployGatewayEVM is Script { bytes32 implSalt = keccak256("GatewayEVM-2"); bytes32 proxySalt = keccak256("GatewayEVMProxy-2"); + // Add this specific check to ensure contract is not deployed at deterministic address with wrong admin + require(admin != address(0), "Environment variable GATEWAY_ADMIN_ADDRESS_EVM is not set"); + vm.startBroadcast(); + // Compute expected implementation address expectedImplAddress = vm.computeCreate2Address( implSalt, hashInitCode(type(GatewayEVM).creationCode) ); + // Deploy the implementation contract using CREATE2 GatewayEVM gatewayImpl = new GatewayEVM{salt: implSalt}(); require(address(gatewayImpl) != address(0), "gatewayImpl deployment failed"); - require(expectedImplAddress == address(gatewayImpl), "impl address doesn't match expected address"); + // Compute expected proxy address expectedProxyAddress = vm.computeCreate2Address( proxySalt, hashInitCode( type(ERC1967Proxy).creationCode, abi.encode( address(gatewayImpl), - abi.encodeWithSelector(GatewayEVM.initialize.selector, tss, address(zeta), admin) + abi.encodeWithSelector(GatewayEVM.initialize.selector, tss, address(zeta), msg.sender) ) ) ); + // Deploy the proxy contract using CREATE2, with deployer as initial admin ERC1967Proxy gatewayProxy = new ERC1967Proxy{salt: proxySalt}( address(gatewayImpl), - abi.encodeWithSelector(GatewayEVM.initialize.selector, tss, address(zeta), admin) + abi.encodeWithSelector(GatewayEVM.initialize.selector, tss, address(zeta), msg.sender) ); require(address(gatewayProxy) != address(0), "gatewayProxy deployment failed"); - require(expectedProxyAddress == address(gatewayProxy), "proxy address doesn't match expected address"); GatewayEVM gateway = GatewayEVM(address(gatewayProxy)); + + // Verify initial configuration require(gateway.tssAddress() == tss, "tss not set"); require(gateway.zetaToken() == address(zeta), "zeta token not set"); + // Transfer admin role from deployer to admin + transferAdmin(gateway, msg.sender, admin); + vm.stopBroadcast(); } + + function transferAdmin(GatewayEVM gateway, address deployer, address newAdmin) internal { + // Grant roles to specified admin and renounce deployer's roles + gateway.grantRole(gateway.PAUSER_ROLE(), newAdmin); + gateway.grantRole(gateway.DEFAULT_ADMIN_ROLE(), newAdmin); + + // Renounce deployer's roles + gateway.renounceRole(gateway.PAUSER_ROLE(), deployer); + gateway.renounceRole(gateway.DEFAULT_ADMIN_ROLE(), deployer); + + // Assert that the roles are correctly transitioned + require(gateway.hasRole(gateway.PAUSER_ROLE(), newAdmin), "admin does not have PAUSER_ROLE"); + require(gateway.hasRole(gateway.DEFAULT_ADMIN_ROLE(), newAdmin), "admin does not have DEFAULT_ADMIN_ROLE"); + require(!gateway.hasRole(gateway.PAUSER_ROLE(), deployer), "deployer still has PAUSER_ROLE"); + require(!gateway.hasRole(gateway.DEFAULT_ADMIN_ROLE(), deployer), "deployer still has DEFAULT_ADMIN_ROLE"); + } } \ No newline at end of file diff --git a/v2/scripts/deploy/deterministic/DeployGatewayZEVM.s.sol b/v2/scripts/deploy/deterministic/DeployGatewayZEVM.s.sol index f25c0eb8..21582bfd 100644 --- a/v2/scripts/deploy/deterministic/DeployGatewayZEVM.s.sol +++ b/v2/scripts/deploy/deterministic/DeployGatewayZEVM.s.sol @@ -16,40 +16,66 @@ contract DeployGatewayZEVM is Script { bytes32 implSalt = keccak256("GatewayZEVM"); bytes32 proxySalt = keccak256("GatewayZEVMProxy"); + // Add this specific check to ensure contract is not deployed at deterministic address with wrong admin + require(admin != address(0), "Environment variable GATEWAY_ADMIN_ADDRESS_ZEVM is not set"); + vm.startBroadcast(); + // Compute expected implementation address expectedImplAddress = vm.computeCreate2Address( implSalt, hashInitCode(type(GatewayZEVM).creationCode) ); + // Deploy the implementation contract using CREATE2 GatewayZEVM gatewayImpl = new GatewayZEVM{salt: implSalt}(); require(address(gatewayImpl) != address(0), "gatewayImpl deployment failed"); - require(expectedImplAddress == address(gatewayImpl), "impl address doesn't match expected address"); + // Compute expected proxy address expectedProxyAddress = vm.computeCreate2Address( proxySalt, hashInitCode( type(ERC1967Proxy).creationCode, abi.encode( address(gatewayImpl), - abi.encodeWithSelector(GatewayZEVM.initialize.selector, zeta, admin) + abi.encodeWithSelector(GatewayZEVM.initialize.selector, zeta, msg.sender) ) ) ); + // Deploy the proxy contract using CREATE2, with deployer as initial admin ERC1967Proxy gatewayProxy = new ERC1967Proxy{salt: proxySalt}( address(gatewayImpl), - abi.encodeWithSelector(GatewayZEVM.initialize.selector, zeta, admin) + abi.encodeWithSelector(GatewayZEVM.initialize.selector, zeta, msg.sender) ); require(address(gatewayProxy) != address(0), "gatewayProxy deployment failed"); - require(expectedProxyAddress == address(gatewayProxy), "proxy address doesn't match expected address"); GatewayZEVM gateway = GatewayZEVM(payable(address(gatewayProxy))); + + // Verify initial configuration require(gateway.zetaToken() == zeta, "zeta token not set"); + // Transfer admin role from deployer to admin + transferAdmin(gateway, msg.sender, admin); + vm.stopBroadcast(); } + + function transferAdmin(GatewayZEVM gateway, address deployer, address newAdmin) internal { + // Grant roles to specified admin and renounce deployer's roles + gateway.grantRole(gateway.PAUSER_ROLE(), newAdmin); + gateway.grantRole(gateway.DEFAULT_ADMIN_ROLE(), newAdmin); + + // Renounce deployer's roles + gateway.renounceRole(gateway.PAUSER_ROLE(), deployer); + gateway.renounceRole(gateway.DEFAULT_ADMIN_ROLE(), deployer); + + // Assert that the roles are correctly transitioned + require(gateway.hasRole(gateway.PAUSER_ROLE(), newAdmin), "admin does not have PAUSER_ROLE"); + require(gateway.hasRole(gateway.DEFAULT_ADMIN_ROLE(), newAdmin), "admin does not have DEFAULT_ADMIN_ROLE"); + require(!gateway.hasRole(gateway.PAUSER_ROLE(), deployer), "deployer still has PAUSER_ROLE"); + require(!gateway.hasRole(gateway.DEFAULT_ADMIN_ROLE(), deployer), "deployer still has DEFAULT_ADMIN_ROLE"); + } } \ No newline at end of file