Skip to content

Commit

Permalink
Add utils for DecentralizeGovernance transaction (#829)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladbochok authored Oct 2, 2024
1 parent bce4b2d commit 939151e
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 0 deletions.
30 changes: 30 additions & 0 deletions l1-contracts/deploy-scripts/EIP712Utils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

library EIP712Utils {
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

function buildDomainHash(
address _verifyingContract,
string memory _name,
string memory _version
) internal view returns (bytes32) {
return
keccak256(
// solhint-disable-next-line func-named-parameters
abi.encode(
TYPE_HASH,
keccak256(bytes(_name)),
keccak256(bytes(_version)),
block.chainid,
_verifyingContract
)
);
}

function buildDigest(bytes32 _domainHash, bytes32 _message) internal view returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", _domainHash, _message));
}
}
133 changes: 133 additions & 0 deletions l1-contracts/deploy-scripts/Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@ import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol";
import {L2_DEPLOYER_SYSTEM_CONTRACT_ADDR} from "contracts/common/L2ContractAddresses.sol";
import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol";
import {IChainAdmin} from "contracts/governance/IChainAdmin.sol";
import {EIP712Utils} from "./EIP712Utils.sol";
import {IProtocolUpgradeHandler} from "./interfaces/IProtocolUpgradeHandler.sol";
import {IEmergencyUpgrageBoard} from "./interfaces/IEmergencyUpgrageBoard.sol";
import {IMultisig} from "./interfaces/IMultisig.sol";
import {ISafe} from "./interfaces/ISafe.sol";

/// @dev EIP-712 TypeHash for the emergency protocol upgrade execution approved by the guardians.
bytes32 constant EXECUTE_EMERGENCY_UPGRADE_GUARDIANS_TYPEHASH = keccak256(
"ExecuteEmergencyUpgradeGuardians(bytes32 id)"
);

/// @dev EIP-712 TypeHash for the emergency protocol upgrade execution approved by the Security Council.
bytes32 constant EXECUTE_EMERGENCY_UPGRADE_SECURITY_COUNCIL_TYPEHASH = keccak256(
"ExecuteEmergencyUpgradeSecurityCouncil(bytes32 id)"
);

/// @dev EIP-712 TypeHash for the emergency protocol upgrade execution approved by the ZK Foundation.
bytes32 constant EXECUTE_EMERGENCY_UPGRADE_ZK_FOUNDATION_TYPEHASH = keccak256(
"ExecuteEmergencyUpgradeZKFoundation(bytes32 id)"
);

library Utils {
// Cheatcodes address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.
Expand Down Expand Up @@ -324,4 +344,117 @@ library Utils {
}
vm.stopBroadcast();
}

function executeEmergencyProtocolUpgrade(
IProtocolUpgradeHandler _protocolUpgradeHandler,
Vm.Wallet memory _governorWallet,
IProtocolUpgradeHandler.Call[] memory _calls,
bytes32 _salt
) internal returns (bytes memory) {
bytes32 upgradeId;
bytes32 emergencyUpgradeBoardDigest;
{
address emergencyUpgradeBoard = _protocolUpgradeHandler.emergencyUpgradeBoard();
IProtocolUpgradeHandler.UpgradeProposal memory upgradeProposal = IProtocolUpgradeHandler.UpgradeProposal({
calls: _calls,
salt: _salt,
executor: emergencyUpgradeBoard
});
upgradeId = keccak256(abi.encode(upgradeProposal));
emergencyUpgradeBoardDigest = EIP712Utils.buildDomainHash(
emergencyUpgradeBoard,
"EmergencyUpgradeBoard",
"1"
);
}

bytes memory guardiansSignatures;
{
address[] memory guardiansMembers = new address[](8);
{
IMultisig guardians = IMultisig(_protocolUpgradeHandler.guardians());
for (uint256 i = 0; i < 8; i++) {
guardiansMembers[i] = guardians.members(i);
}
}
bytes[] memory guardiansRawSignatures = new bytes[](8);
for (uint256 i = 0; i < 8; i++) {
bytes32 safeDigest;
{
bytes32 guardiansDigest = EIP712Utils.buildDigest(
emergencyUpgradeBoardDigest,
keccak256(abi.encode(EXECUTE_EMERGENCY_UPGRADE_GUARDIANS_TYPEHASH, upgradeId))
);
safeDigest = ISafe(guardiansMembers[i]).getMessageHash(abi.encode(guardiansDigest));
}

(uint8 v, bytes32 r, bytes32 s) = vm.sign(_governorWallet, safeDigest);
guardiansRawSignatures[i] = abi.encodePacked(r, s, v);
}
guardiansSignatures = abi.encode(guardiansMembers, guardiansRawSignatures);
}

bytes memory securityCouncilSignatures;
{
address[] memory securityCouncilMembers = new address[](12);
{
IMultisig securityCouncil = IMultisig(_protocolUpgradeHandler.securityCouncil());
for (uint256 i = 0; i < 12; i++) {
securityCouncilMembers[i] = securityCouncil.members(i);
}
}
bytes[] memory securityCouncilRawSignatures = new bytes[](12);
for (uint256 i = 0; i < securityCouncilMembers.length; i++) {
bytes32 safeDigest;
{
bytes32 securityCouncilDigest = EIP712Utils.buildDigest(
emergencyUpgradeBoardDigest,
keccak256(abi.encode(EXECUTE_EMERGENCY_UPGRADE_SECURITY_COUNCIL_TYPEHASH, upgradeId))
);
safeDigest = ISafe(securityCouncilMembers[i]).getMessageHash(abi.encode(securityCouncilDigest));
}
{
(uint8 v, bytes32 r, bytes32 s) = vm.sign(_governorWallet, safeDigest);
securityCouncilRawSignatures[i] = abi.encodePacked(r, s, v);
}
}
securityCouncilSignatures = abi.encode(securityCouncilMembers, securityCouncilRawSignatures);
}

bytes memory zkFoundationSignature;
{
ISafe zkFoundation;
{
IEmergencyUpgrageBoard emergencyUpgradeBoard = IEmergencyUpgrageBoard(
_protocolUpgradeHandler.emergencyUpgradeBoard()
);
zkFoundation = ISafe(emergencyUpgradeBoard.ZK_FOUNDATION_SAFE());
}
bytes32 zkFoundationDigest = EIP712Utils.buildDigest(
emergencyUpgradeBoardDigest,
keccak256(abi.encode(EXECUTE_EMERGENCY_UPGRADE_ZK_FOUNDATION_TYPEHASH, upgradeId))
);
bytes32 safeDigest = ISafe(zkFoundation).getMessageHash(abi.encode(zkFoundationDigest));
{
(uint8 v, bytes32 r, bytes32 s) = vm.sign(_governorWallet, safeDigest);
zkFoundationSignature = abi.encodePacked(r, s, v);
}
}

{
vm.startBroadcast();
IEmergencyUpgrageBoard emergencyUpgradeBoard = IEmergencyUpgrageBoard(
_protocolUpgradeHandler.emergencyUpgradeBoard()
);
// solhint-disable-next-line func-named-parameters
emergencyUpgradeBoard.executeEmergencyUpgrade(
_calls,
_salt,
guardiansSignatures,
securityCouncilSignatures,
zkFoundationSignature
);
vm.stopBroadcast();
}
}
}
23 changes: 23 additions & 0 deletions l1-contracts/deploy-scripts/interfaces/IEmergencyUpgrageBoard.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

import {IProtocolUpgradeHandler} from "./IProtocolUpgradeHandler.sol";

/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IEmergencyUpgrageBoard {
function GUARDIANS() external view returns (address);

function SECURITY_COUNCIL() external view returns (address);

function ZK_FOUNDATION_SAFE() external view returns (address);

function executeEmergencyUpgrade(
IProtocolUpgradeHandler.Call[] calldata _calls,
bytes32 _salt,
bytes calldata _guardiansSignatures,
bytes calldata _securityCouncilSignatures,
bytes calldata _zkFoundationSignatures
) external;
}
9 changes: 9 additions & 0 deletions l1-contracts/deploy-scripts/interfaces/IMultisig.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IMultisig {
function members(uint256) external view returns (address);
}
33 changes: 33 additions & 0 deletions l1-contracts/deploy-scripts/interfaces/IProtocolUpgradeHandler.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IProtocolUpgradeHandler {
/// @dev Represents a call to be made during an upgrade.
/// @param target The address to which the call will be made.
/// @param value The amount of Ether (in wei) to be sent along with the call.
/// @param data The calldata to be executed on the `target` address.
struct Call {
address target;
uint256 value;
bytes data;
}

/// @dev Defines the structure of an upgrade that is executed by Protocol Upgrade Handler.
/// @param executor The L1 address that is authorized to perform the upgrade execution (if address(0) then anyone).
/// @param calls An array of `Call` structs, each representing a call to be made during the upgrade execution.
/// @param salt A bytes32 value used for creating unique upgrade proposal hashes.
struct UpgradeProposal {
Call[] calls;
address executor;
bytes32 salt;
}

function emergencyUpgradeBoard() external view returns (address);

function guardians() external view returns (address);

function securityCouncil() external view returns (address);
}
9 changes: 9 additions & 0 deletions l1-contracts/deploy-scripts/interfaces/ISafe.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

/// @author Matter Labs
/// @custom:security-contact [email protected]
interface ISafe {
function getMessageHash(bytes memory _message) external view returns (bytes32);
}

0 comments on commit 939151e

Please sign in to comment.