{"id":26167510,"url":"https://github.com/pcaversaccio/zksync-emergency-upgrades","last_synced_at":"2025-07-03T19:33:57.314Z","repository":{"id":281384689,"uuid":"945112088","full_name":"pcaversaccio/zksync-emergency-upgrades","owner":"pcaversaccio","description":"ZKsync emergency upgrade verification tools.","archived":false,"fork":false,"pushed_at":"2025-06-13T15:05:22.000Z","size":77,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-13T16:24:55.878Z","etag":null,"topics":["bash","emergency-upgrades","solidity","zksync-era"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pcaversaccio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"custom":"https://etherscan.io/address/0xe9Fa0c8B5d7F79DeC36D3F448B1Ac4cEdedE4e69"}},"created_at":"2025-03-08T17:28:19.000Z","updated_at":"2025-06-13T15:05:26.000Z","dependencies_parsed_at":"2025-04-16T19:46:48.380Z","dependency_job_id":"011ee26e-e662-426e-8c95-e7e1f4ed0adb","html_url":"https://github.com/pcaversaccio/zksync-emergency-upgrades","commit_stats":null,"previous_names":["pcaversaccio/zksync-emergency-upgrades"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pcaversaccio/zksync-emergency-upgrades","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pcaversaccio%2Fzksync-emergency-upgrades","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pcaversaccio%2Fzksync-emergency-upgrades/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pcaversaccio%2Fzksync-emergency-upgrades/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pcaversaccio%2Fzksync-emergency-upgrades/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pcaversaccio","download_url":"https://codeload.github.com/pcaversaccio/zksync-emergency-upgrades/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pcaversaccio%2Fzksync-emergency-upgrades/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263388821,"owners_count":23459276,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","emergency-upgrades","solidity","zksync-era"],"created_at":"2025-03-11T17:38:12.440Z","updated_at":"2025-07-03T19:33:57.303Z","avatar_url":"https://github.com/pcaversaccio.png","language":"Shell","funding_links":["https://etherscan.io/address/0xe9Fa0c8B5d7F79DeC36D3F448B1Ac4cEdedE4e69"],"categories":[],"sub_categories":[],"readme":"# ZKsync Emergency Upgrade Verification Tools \u003c!-- omit from toc --\u003e\n\n- [Proposal ID Calculation for ZKsync `executeEmergencyUpgrade`s](#proposal-id-calculation-for-zksync-executeemergencyupgrades)\n  - [Usage](#usage)\n    - [Example 1 – Go-Live Emergency Upgrade](#example-1--go-live-emergency-upgrade)\n    - [Example 2 – Accept Ownership After ZIP5 Emergency Upgrade](#example-2--accept-ownership-after-zip5-emergency-upgrade)\n- [EIP-712-Based Off-Chain Message Safe Hashes](#eip-712-based-off-chain-message-safe-hashes)\n- [💸 Donation](#-donation)\n\n## Proposal ID Calculation for ZKsync `executeEmergencyUpgrade`s\n\n\u003e [!NOTE]\n\u003e The original gist can be found [here](https://gist.github.com/pcaversaccio/0ef8fb8034594e012a4903dfa992369e).\n\nThe function `executeEmergencyUpgrade` will be invoked in the following contract:\n\n- `ProtocolUpgradeHandler`: [`0x8f7a9912416e8AdC4D9c21FAe1415D3318A11897`](https://etherscan.io/address/0x8f7a9912416e8AdC4D9c21FAe1415D3318A11897#code)\n\n```solidity\n/// @dev Represents a call to be made during an upgrade.\n/// @param target The address to which the call will be made.\n/// @param value The amount of Ether (in wei) to be sent along with the call.\n/// @param data The calldata to be executed on the `target` address.\nstruct Call {\n    address target;\n    uint256 value;\n    bytes data;\n}\n\n/// @dev Defines the structure of an upgrade that is executed by Protocol Upgrade Handler.\n/// @param executor The L1 address that is authorized to perform the upgrade execution (if address(0) then anyone).\n/// @param calls An array of `Call` structs, each representing a call to be made during the upgrade execution.\n/// @param salt A bytes32 value used for creating unique upgrade proposal hashes.\nstruct UpgradeProposal {\n    Call[] calls;\n    address executor;\n    bytes32 salt;\n}\n\n/// @notice Executes an emergency upgrade proposal initiated by the emergency upgrade board.\n/// @param _proposal The upgrade proposal details including proposed actions and the executor address.\nfunction executeEmergencyUpgrade(UpgradeProposal calldata _proposal) external payable onlyEmergencyUpgradeBoard {\n    bytes32 id = keccak256(abi.encode(_proposal));\n    UpgradeState upgState = upgradeState(id);\n    // 1. Checks\n    require(upgState == UpgradeState.None, \"Upgrade already exists\");\n    require(_proposal.executor == msg.sender, \"msg.sender is not authorized to perform the upgrade\");\n    // 2. Effects\n    upgradeStatus[id].executed = true;\n    // Clear the freeze\n    lastFreezeStatusInUpgradeCycle = FreezeStatus.None;\n    protocolFrozenUntil = 0;\n    _unfreeze();\n    // 3. Interactions\n    _execute(_proposal.calls);\n    emit Unfreeze();\n    emit EmergencyUpgradeExecuted(id);\n}\n```\n\nIn order the retrieve the proposal ID, we need to calculate:\n\n```solidity\nkeccak256(abi.encode(_proposal));\n```\n\n### Usage\n\n\u003e [!NOTE]\n\u003e Ensure that [`forge`](https://github.com/foundry-rs/foundry/tree/master/crates/forge) and [`cast`](https://github.com/foundry-rs/foundry/tree/master/crates/cast) are installed locally. For installation instructions, refer to this [guide](https://getfoundry.sh/introduction/installation/).\n\nAdjust the `executor`, `salt`, and `calls` parameters either in [`ProposalIdGoLive.sol`](./ProposalIdGoLive.sol) or [`proposal_id_go_live.sh`](./proposal_id_go_live.sh) and invoke\n\n```console\nforge script ProposalIdGoLive.sol --target-contract ProposalIdGoLive --sig \"computeProposalId()\"\n```\n\nor\n\n```console\n./proposal_id_go_live.sh\n```\n\n#### Example 1 – Go-Live Emergency Upgrade\n\nThe proposal ID, given by the ZKsync Era UI is `0xdd9aadc3b6e3297fed40a2cf0a7e655ff5af02c9ce918ed0e86f538c1c53ce9d`. So we need to verify that one.\n\nFrom the docs [here](https://hackmd.io/@alishaZK/BJ7-jEv2C#Transaction-20), we know:\n\n```console\nbytes32 salt = 0x646563656e7472616c697a6174696f6e206973206e6f74206f7074696f6e616c\n```\n\nThe executor in our case is [`0xdEFd1eDEE3E8c5965216bd59C866f7f5307C9b29`](https://etherscan.io/address/0xdEFd1eDEE3E8c5965216bd59C866f7f5307C9b29), the `EmergencyUpgradeBoard` contract.\n\n**Proposal ID Calculation**\n\n```solidity\n// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.30;\n\ncontract ProposalIdGoLive {\n    struct Call {\n        address target;\n        uint256 value;\n        bytes data;\n    }\n\n    struct UpgradeProposal {\n        Call[] calls;\n        address executor;\n        bytes32 salt;\n    }\n\n    function computeProposalId() external pure returns (bytes32) {\n        Call[] memory calls = new Call[](4);\n        calls[0] = Call({target: 0xD7f9f54194C633F36CCD5F3da84ad4a1c38cB2cB, value: 0, data: hex\"79ba5097\"});\n        calls[1] = Call({target: 0x303a465B659cBB0ab36eE643eA362c509EEb5213, value: 0, data: hex\"79ba5097\"});\n        calls[2] = Call({target: 0xc2eE6b6af7d616f6e27ce7F4A451Aedc2b0F5f5C, value: 0, data: hex\"79ba5097\"});\n        calls[3] = Call({target: 0x5D8ba173Dc6C3c90C8f7C04C9288BeF5FDbAd06E, value: 0, data: hex\"79ba5097\"});\n\n        address executor = 0xdEFd1eDEE3E8c5965216bd59C866f7f5307C9b29;\n        bytes32 salt = hex\"646563656e7472616c697a6174696f6e206973206e6f74206f7074696f6e616c\";\n\n        UpgradeProposal memory upgradeProposal = UpgradeProposal({calls: calls, executor: executor, salt: salt});\n\n        return keccak256(abi.encode(upgradeProposal));\n    }\n}\n```\n\nNow invoke:\n\n```console\nforge script ProposalIdGoLive.sol --target-contract ProposalIdGoLive --sig \"computeProposalId()\"\n```\n\nwhich will output:\n\n```console\n== Return ==\n0: bytes32 0xdd9aadc3b6e3297fed40a2cf0a7e655ff5af02c9ce918ed0e86f538c1c53ce9d\n```\n\n#### Example 2 – Accept Ownership After ZIP5 Emergency Upgrade\n\nThe upgrade data for the emergency upgrade \"Accept ownership after ZIP5\":\n\n```json\n{\n  \"executor\": \"0xECE8e30bFc92c2A8e11e6cb2e17B70868572E3f6\",\n  \"salt\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n  \"calls\": [\n    {\n      \"target\": \"0x303a465b659cbb0ab36ee643ea362c509eeb5213\",\n      \"value\": \"0x00\",\n      \"data\": \"0x79ba5097\"\n    },\n    {\n      \"target\": \"0xc2ee6b6af7d616f6e27ce7f4a451aedc2b0f5f5c\",\n      \"value\": \"0x00\",\n      \"data\": \"0x79ba5097\"\n    },\n    {\n      \"target\": \"0xd7f9f54194c633f36ccd5f3da84ad4a1c38cb2cb\",\n      \"value\": \"0x00\",\n      \"data\": \"0x79ba5097\"\n    },\n    {\n      \"target\": \"0x5d8ba173dc6c3c90c8f7c04c9288bef5fdbad06e\",\n      \"value\": \"0x00\",\n      \"data\": \"0x79ba5097\"\n    },\n    {\n      \"target\": \"0xf553e6d903aa43420ed7e3bc2313be9286a8f987\",\n      \"value\": \"0x00\",\n      \"data\": \"0x79ba5097\"\n    }\n  ]\n}\n```\n\n**Proposal ID Calculation**\n\nRun the script via:\n\n```console\n./proposal_id_zip5.sh\n```\n\nwhich returns\n\n```console\nEncoded `UpgradeProposal` struct: 0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000ece8e30bfc92c2a8e11e6cb2e17b70868572e3f60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000320000000000000000000000000303a465b659cbb0ab36ee643ea362c509eeb521300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000479ba509700000000000000000000000000000000000000000000000000000000000000000000000000000000c2ee6b6af7d616f6e27ce7f4a451aedc2b0f5f5c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000479ba509700000000000000000000000000000000000000000000000000000000000000000000000000000000d7f9f54194c633f36ccd5f3da84ad4a1c38cb2cb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000479ba5097000000000000000000000000000000000000000000000000000000000000000000000000000000005d8ba173dc6c3c90c8f7c04c9288bef5fdbad06e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000479ba509700000000000000000000000000000000000000000000000000000000000000000000000000000000f553e6d903aa43420ed7e3bc2313be9286a8f98700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000479ba509700000000000000000000000000000000000000000000000000000000\nProposal ID: 0xa34bdc028de549c0fbd0374e64eb5977e78f62331f6a55f4f2211348c4902d13\n```\n\n## EIP-712-Based Off-Chain Message Safe Hashes\n\nConfigure the parameters in [`safe_hashes.sh`](./safe_hashes.sh), then run the script:\n\n```console\n./safe_hashes.sh\n```\n\nThe key parameters to configure for an emergency upgrade are:\n\n- `SAFE_MULTISIG_ADDRESS`: Set your Safe multisig address here.\n- `PROPOSAL_ID`: Set the calculated proposal ID here.\n\n**Example Output**\n\n```console\nSafe message: 0x924182c0ae655857518786673f3026f1c75b754ffbd2716b4af6d78f04745a31\nSafe message hash: 0x0b24f0f27141c3cfddcb6748516b026182fba25945dc2b328f32aa0a02229633\nDomain hash: 0x63127490E98CEB540DB8DCA78EB231476F5B4061DC5139E45031491BAE94ADDF\nMessage hash: 0x021DEF418DA3276B5F47AB23C16FFAEA6B962872D2DDF2EBCC88310E203273ED\n```\n\n## 💸 Donation\n\nI am a strong advocate of the open-source and free software paradigm. However, if you feel my work deserves a donation, you can send it to this address: [`0xe9Fa0c8B5d7F79DeC36D3F448B1Ac4cEdedE4e69`](https://etherscan.io/address/0xe9Fa0c8B5d7F79DeC36D3F448B1Ac4cEdedE4e69). I can pledge that I will use this money to help fix more existing challenges in the Ethereum ecosystem 🤝.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpcaversaccio%2Fzksync-emergency-upgrades","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpcaversaccio%2Fzksync-emergency-upgrades","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpcaversaccio%2Fzksync-emergency-upgrades/lists"}