diff --git a/hardhat.config.zksync.ts b/hardhat.config.zksync.ts index f883f0dc4..3283d06d8 100644 --- a/hardhat.config.zksync.ts +++ b/hardhat.config.zksync.ts @@ -162,7 +162,7 @@ const config: HardhatUserConfig = { }, zksynctestnode: { url: process.env.ZKSYNC_ERA_LOCAL_TEST_NODE || "http://localhost:8011", - chainId: 300, // change it to 300 for zksyncsepolia + chainId: 300, // change it to 324 for zksyncmainnet accounts: DEPLOYER_PRIVATE_KEY ? [`0x${DEPLOYER_PRIVATE_KEY}`] : [], blockGasLimit: BLOCK_GAS_LIMIT_PER_NETWORK.zksyncsepolia, timeout: 2000000000, diff --git a/package.json b/package.json index 56052b436..611446ae5 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ "prettier:check": "prettier --check \"**/*.{js,json,md,ts,yaml,yml,sol}\"", "docgen": "hardhat docgen", "clean": "hardhat clean && hardhat clean --config hardhat.config.zksync.ts", - "local-test-node:zksyncmainnet": "hardhat node-zksync --fork https://mainnet.era.zksync.io --config hardhat.config.zksync.ts", - "local-test-node:zksyncsepolia": "hardhat node-zksync --fork https://sepolia.era.zksync.dev --config hardhat.config.zksync.ts" + "local-test-node:zksyncmainnet": "hardhat node-zksync --fork https://mainnet.era.zksync.io --config hardhat.config.zksync.ts --tag 0.1.0-alpha.31", + "local-test-node:zksyncsepolia": "hardhat node-zksync --fork https://sepolia.era.zksync.dev --config hardhat.config.zksync.ts --tag 0.1.0-alpha.31" }, "dependencies": { "@morpho-labs/gnosis-tx-builder": "^1.3.1", diff --git a/simulations/vip-403/abi/ACMCommandsAggregator.json b/simulations/vip-403/abi/ACMCommandsAggregator.json new file mode 100644 index 000000000..6650a3f3c --- /dev/null +++ b/simulations/vip-403/abi/ACMCommandsAggregator.json @@ -0,0 +1,242 @@ +[ + { + "inputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "_acm", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EmptyPermissions", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsExecuted", + "type": "event" + }, + { + "inputs": [], + "name": "ACM", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "grantPermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "revokePermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-403/abi/AccessControlManager.json b/simulations/vip-403/abi/AccessControlManager.json new file mode 100644 index 000000000..2ef119947 --- /dev/null +++ b/simulations/vip-403/abi/AccessControlManager.json @@ -0,0 +1,157 @@ +[ + { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "account", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "contractAddress", "type": "address" }, + { "indexed": false, "internalType": "string", "name": "functionSig", "type": "string" } + ], + "name": "PermissionGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "account", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "contractAddress", "type": "address" }, + { "indexed": false, "internalType": "string", "name": "functionSig", "type": "string" } + ], + "name": "PermissionRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "indexed": true, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32" }, + { "indexed": true, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32" } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "indexed": true, "internalType": "address", "name": "account", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "indexed": true, "internalType": "address", "name": "account", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }], + "name": "getRoleAdmin", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "contractAddress", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" }, + { "internalType": "address", "name": "accountToPermit", "type": "address" } + ], + "name": "giveCallPermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" }, + { "internalType": "address", "name": "contractAddress", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" } + ], + "name": "hasPermission", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "hasRole", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" } + ], + "name": "isAllowedToCall", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "contractAddress", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" }, + { "internalType": "address", "name": "accountToRevoke", "type": "address" } + ], + "name": "revokeCallPermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-403/abi/OmnichainProposalSender.json b/simulations/vip-403/abi/OmnichainProposalSender.json new file mode 100644 index 000000000..66fd4df02 --- /dev/null +++ b/simulations/vip-403/abi/OmnichainProposalSender.json @@ -0,0 +1,314 @@ +[ + { + "inputs": [ + { "internalType": "contract ILayerZeroEndpoint", "name": "lzEndpoint_", "type": "address" }, + { "internalType": "address", "name": "accessControlManager_", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "ZeroAddressNotAllowed", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint256", "name": "proposalId", "type": "uint256" }, + { "indexed": false, "internalType": "bytes32", "name": "executionHash", "type": "bytes32" } + ], + "name": "ClearPayload", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint16", "name": "remoteChainId", "type": "uint16" }, + { "indexed": false, "internalType": "uint256", "name": "proposalId", "type": "uint256" }, + { "indexed": false, "internalType": "bytes", "name": "payload", "type": "bytes" } + ], + "name": "ExecuteRemoteProposal", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "receiver", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "FallbackWithdraw", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "oldAccessControlManager", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newAccessControlManager", "type": "address" } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "account", "type": "address" }], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint16", "name": "chainId", "type": "uint16" }, + { "indexed": false, "internalType": "uint256", "name": "oldMaxLimit", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newMaxLimit", "type": "uint256" } + ], + "name": "SetMaxDailyLimit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint16", "name": "remoteChainId", "type": "uint16" }, + { "indexed": false, "internalType": "bytes", "name": "oldRemoteAddress", "type": "bytes" }, + { "indexed": false, "internalType": "bytes", "name": "newRemoteAddress", "type": "bytes" } + ], + "name": "SetTrustedRemoteAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint256", "name": "proposalId", "type": "uint256" }, + { "indexed": true, "internalType": "uint16", "name": "remoteChainId", "type": "uint16" }, + { "indexed": false, "internalType": "bytes", "name": "payload", "type": "bytes" }, + { "indexed": false, "internalType": "bytes", "name": "adapterParams", "type": "bytes" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" }, + { "indexed": false, "internalType": "bytes", "name": "reason", "type": "bytes" } + ], + "name": "StorePayload", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": true, "internalType": "uint16", "name": "chainId", "type": "uint16" }], + "name": "TrustedRemoteRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "account", "type": "address" }], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "LZ_ENDPOINT", + "outputs": [{ "internalType": "contract ILayerZeroEndpoint", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "name": "chainIdToLast24HourCommandsSent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "name": "chainIdToLast24HourWindowStart", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "name": "chainIdToLastProposalSentTimestamp", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "name": "chainIdToMaxDailyLimit", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "remoteChainId_", "type": "uint16" }, + { "internalType": "bytes", "name": "payload_", "type": "bytes" }, + { "internalType": "bool", "name": "useZro_", "type": "bool" }, + { "internalType": "bytes", "name": "adapterParams_", "type": "bytes" } + ], + "name": "estimateFees", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "remoteChainId_", "type": "uint16" }, + { "internalType": "bytes", "name": "payload_", "type": "bytes" }, + { "internalType": "bytes", "name": "adapterParams_", "type": "bytes" }, + { "internalType": "address", "name": "zroPaymentAddress_", "type": "address" } + ], + "name": "execute", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to_", "type": "address" }, + { "internalType": "uint256", "name": "pId_", "type": "uint256" }, + { "internalType": "uint16", "name": "remoteChainId_", "type": "uint16" }, + { "internalType": "bytes", "name": "payload_", "type": "bytes" }, + { "internalType": "bytes", "name": "adapterParams_", "type": "bytes" }, + { "internalType": "uint256", "name": "originalValue_", "type": "uint256" } + ], + "name": "fallbackWithdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "version_", "type": "uint16" }, + { "internalType": "uint16", "name": "chainId_", "type": "uint16" }, + { "internalType": "uint256", "name": "configType_", "type": "uint256" } + ], + "name": "getConfig", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "paused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proposalCount", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "remoteChainId_", "type": "uint16" }], + "name": "removeTrustedRemote", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "uint256", "name": "pId_", "type": "uint256" }, + { "internalType": "uint16", "name": "remoteChainId_", "type": "uint16" }, + { "internalType": "bytes", "name": "payload_", "type": "bytes" }, + { "internalType": "bytes", "name": "adapterParams_", "type": "bytes" }, + { "internalType": "address", "name": "zroPaymentAddress_", "type": "address" }, + { "internalType": "uint256", "name": "originalValue_", "type": "uint256" } + ], + "name": "retryExecute", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "accessControlManager_", "type": "address" }], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "version_", "type": "uint16" }, + { "internalType": "uint16", "name": "chainId_", "type": "uint16" }, + { "internalType": "uint256", "name": "configType_", "type": "uint256" }, + { "internalType": "bytes", "name": "config_", "type": "bytes" } + ], + "name": "setConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "chainId_", "type": "uint16" }, + { "internalType": "uint256", "name": "limit_", "type": "uint256" } + ], + "name": "setMaxDailyLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "version_", "type": "uint16" }], + "name": "setSendVersion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "remoteChainId_", "type": "uint16" }, + { "internalType": "bytes", "name": "newRemoteAddress_", "type": "bytes" } + ], + "name": "setTrustedRemoteAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "storedExecutionHashes", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "name": "trustedRemoteLookup", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function" } +] diff --git a/simulations/vip-403/arbitrumone.ts b/simulations/vip-403/arbitrumone.ts new file mode 100644 index 000000000..5fca5ca8a --- /dev/null +++ b/simulations/vip-403/arbitrumone.ts @@ -0,0 +1,39 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { ARBITRUM_ACM, ARBITRUM_ACM_AGGREGATOR, DEFAULT_ADMIN_ROLE } from "../../vips/vip-403/bscmainnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { arbitrumone } = NETWORK_ADDRESSES; + +forking(280572842, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [2]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [4]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(ARBITRUM_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, ARBITRUM_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack( + ["address", "string"], + [arbitrumone.REDSTONE_ORACLE, "setTokenConfig(TokenConfig)"], + ); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, arbitrumone.GUARDIAN)).to.be.true; + }); + }); +}); diff --git a/simulations/vip-403/arbitrumsepolia.ts b/simulations/vip-403/arbitrumsepolia.ts new file mode 100644 index 000000000..f9dfbe3dd --- /dev/null +++ b/simulations/vip-403/arbitrumsepolia.ts @@ -0,0 +1,43 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { + ARBITRUMSEPOLIA_ACM_AGGREGATOR, + ARBITRUM_SEPOLIA_ACM, + DEFAULT_ADMIN_ROLE, +} from "../../vips/vip-403/bsctestnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { arbitrumsepolia } = NETWORK_ADDRESSES; + +forking(101407909, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [2]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [4]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(ARBITRUM_SEPOLIA_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, ARBITRUMSEPOLIA_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack( + ["address", "string"], + [arbitrumsepolia.REDSTONE_ORACLE, "setTokenConfig(TokenConfig)"], + ); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, arbitrumsepolia.GUARDIAN)).to.be.true; + }); + }); +}); diff --git a/simulations/vip-403/bscmainnet.ts b/simulations/vip-403/bscmainnet.ts new file mode 100644 index 000000000..22256c590 --- /dev/null +++ b/simulations/vip-403/bscmainnet.ts @@ -0,0 +1,45 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +import { expectEvents } from "../../src/utils"; +import { forking, testVip } from "../../src/vip-framework"; +import vip403, { BSC_ACM, BSC_ACM_AGGREGATOR, DEFAULT_ADMIN_ROLE } from "../../vips/vip-403/bscmainnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; +import OMNICHAIN_PROPOSAL_SENDER_ABI from "./abi/OmnichainProposalSender.json"; + +const { bscmainnet } = NETWORK_ADDRESSES; +const GUARDIAN3 = "0x3a3284dc0faffb0b5f0d074c4c704d14326c98cf"; + +forking(44521298, async () => { + testVip("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents( + txResponse, + [OMNICHAIN_PROPOSAL_SENDER_ABI], + ["ExecuteRemoteProposal", "StorePayload"], + [5, 0], + ); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["RoleGranted"], [3]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(BSC_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, BSC_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack( + ["address", "string"], + [bscmainnet.REDSTONE_ORACLE, "setTokenConfig(TokenConfig)"], + ); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, GUARDIAN3)).to.be.true; + }); + }); +}); diff --git a/simulations/vip-403/bsctestnet.ts b/simulations/vip-403/bsctestnet.ts new file mode 100644 index 000000000..939c4bf82 --- /dev/null +++ b/simulations/vip-403/bsctestnet.ts @@ -0,0 +1,22 @@ +import { expectEvents } from "../../src/utils"; +import { forking, testVip } from "../../src/vip-framework"; +import vip403 from "../../vips/vip-403/bsctestnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; +import OMNICHAIN_PROPOSAL_SENDER_ABI from "./abi/OmnichainProposalSender.json"; + +forking(46024012, async () => { + testVip("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents( + txResponse, + [OMNICHAIN_PROPOSAL_SENDER_ABI], + ["ExecuteRemoteProposal", "StorePayload"], + [5, 0], + ); + + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [2]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + }, + }); +}); diff --git a/simulations/vip-403/ethereum.ts b/simulations/vip-403/ethereum.ts new file mode 100644 index 000000000..b128cc165 --- /dev/null +++ b/simulations/vip-403/ethereum.ts @@ -0,0 +1,39 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { DEFAULT_ADMIN_ROLE, ETHEREUM_ACM, ETHEREUM_ACM_AGGREGATOR } from "../../vips/vip-403/bscmainnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { ethereum } = NETWORK_ADDRESSES; + +forking(21327971, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [2]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [4]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(ETHEREUM_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, ETHEREUM_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack( + ["address", "string"], + [ethereum.REDSTONE_ORACLE, "setTokenConfig(TokenConfig)"], + ); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, ethereum.GUARDIAN)).to.be.true; + }); + }); +}); diff --git a/simulations/vip-403/opbnbmainnet.ts b/simulations/vip-403/opbnbmainnet.ts new file mode 100644 index 000000000..9a8cf8b6e --- /dev/null +++ b/simulations/vip-403/opbnbmainnet.ts @@ -0,0 +1,37 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { DEFAULT_ADMIN_ROLE, OPBNB_ACM, OPBNB_ACM_AGGREGATOR } from "../../vips/vip-403/bscmainnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { opbnbmainnet } = NETWORK_ADDRESSES; + +forking(41392857, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [4]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(OPBNB_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, OPBNB_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack( + ["address", "string"], + [opbnbmainnet.XVS_VAULT_PROXY, "add(address,uint256,address,uint256,uint256)"], + ); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, opbnbmainnet.GUARDIAN)).to.be.false; + }); + }); +}); diff --git a/simulations/vip-403/opbnbtestnet.ts b/simulations/vip-403/opbnbtestnet.ts new file mode 100644 index 000000000..98cd47944 --- /dev/null +++ b/simulations/vip-403/opbnbtestnet.ts @@ -0,0 +1,41 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { + DEFAULT_ADMIN_ROLE, + OPBNBTESTNET_ACM, + OPBNBTESTNET_ACM_AGGREGATOR, +} from "../../vips/vip-403/bsctestnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { opbnbtestnet } = NETWORK_ADDRESSES; + +forking(45916044, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [4]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(OPBNBTESTNET_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, OPBNBTESTNET_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack( + ["address", "string"], + [opbnbtestnet.XVS_VAULT_PROXY, "add(address,uint256,address,uint256,uint256)"], + ); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, opbnbtestnet.GUARDIAN)).to.be.false; + }); + }); +}); diff --git a/simulations/vip-403/opmainnet.ts b/simulations/vip-403/opmainnet.ts new file mode 100644 index 000000000..f4c84c17d --- /dev/null +++ b/simulations/vip-403/opmainnet.ts @@ -0,0 +1,59 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { DEFAULT_ADMIN_ROLE, OPMAINNET_ACM, OPMAINNET_ACM_AGGREGATOR } from "../../vips/vip-403/bscmainnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { opmainnet } = NETWORK_ADDRESSES; +const FAST_TRACK_TIMELOCK = "0x508bD9C31E8d6760De04c70fe6c2b24B3cDea7E7"; +const CRITICAL_TIMELOCK = "0xB82479bc345CAA7326D7d21306972033226fC185"; + +forking(128771016, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [190]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [50]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(OPMAINNET_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, OPMAINNET_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack(["address", "string"], [opmainnet.RESILIENT_ORACLE, "pause()"]); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, opmainnet.NORMAL_TIMELOCK)).to.be.true; + + const role2 = ethers.utils.solidityPack( + ["address", "string"], + [opmainnet.XVS_VAULT_PROXY, "set(address,uint256,uint256)"], + ); + + const roleHash2 = ethers.utils.keccak256(role2); + expect(await acm.hasRole(roleHash2, opmainnet.NORMAL_TIMELOCK)).to.be.true; + + const role3 = ethers.utils.solidityPack( + ["address", "string"], + [opmainnet.XVS, "migrateMinterTokens(address,address)"], + ); + + const roleHash3 = ethers.utils.keccak256(role3); + expect(await acm.hasRole(roleHash3, FAST_TRACK_TIMELOCK)).to.be.true; + + const role4 = ethers.utils.solidityPack(["address", "string"], [opmainnet.XVS, "updateBlacklist(address,bool)"]); + + const roleHash4 = ethers.utils.keccak256(role4); + expect(await acm.hasRole(roleHash4, CRITICAL_TIMELOCK)).to.be.true; + }); + }); +}); diff --git a/simulations/vip-403/opsepolia.ts b/simulations/vip-403/opsepolia.ts new file mode 100644 index 000000000..3ea5e8a41 --- /dev/null +++ b/simulations/vip-403/opsepolia.ts @@ -0,0 +1,44 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { DEFAULT_ADMIN_ROLE, OPSEPOLIA_ACM, OPSEPOLIA_ACM_AGGREGATOR } from "../../vips/vip-403/bsctestnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { opsepolia } = NETWORK_ADDRESSES; + +forking(20483821, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [184]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [50]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(OPSEPOLIA_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, OPSEPOLIA_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack(["address", "string"], [opsepolia.RESILIENT_ORACLE, "pause()"]); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, opsepolia.NORMAL_TIMELOCK)).to.be.true; + + const role2 = ethers.utils.solidityPack( + ["address", "string"], + [opsepolia.XVS_VAULT_PROXY, "set(address,uint256,uint256)"], + ); + + const roleHash2 = ethers.utils.keccak256(role2); + expect(await acm.hasRole(roleHash2, opsepolia.NORMAL_TIMELOCK)).to.be.true; + }); + }); +}); diff --git a/simulations/vip-403/sepolia.ts b/simulations/vip-403/sepolia.ts new file mode 100644 index 000000000..53e4bf461 --- /dev/null +++ b/simulations/vip-403/sepolia.ts @@ -0,0 +1,39 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { DEFAULT_ADMIN_ROLE, SEPOLIA_ACM, SEPOLIA_ACM_AGGREGATOR } from "../../vips/vip-403/bsctestnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { sepolia } = NETWORK_ADDRESSES; + +forking(7169767, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [2]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [4]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(SEPOLIA_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, SEPOLIA_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack( + ["address", "string"], + [sepolia.REDSTONE_ORACLE, "setTokenConfig(TokenConfig)"], + ); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, sepolia.GUARDIAN)).to.be.true; + }); + }); +}); diff --git a/simulations/vip-403/zksyncmainnet.ts b/simulations/vip-403/zksyncmainnet.ts new file mode 100644 index 000000000..c21a25251 --- /dev/null +++ b/simulations/vip-403/zksyncmainnet.ts @@ -0,0 +1,63 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { DEFAULT_ADMIN_ROLE, ZKSYNC_ACM, ZKSYNC_ACM_AGGREGATOR } from "../../vips/vip-403/bscmainnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { zksyncmainnet } = NETWORK_ADDRESSES; +const FAST_TRACK_TIMELOCK = "0x32f71c95BC8F9d996f89c642f1a84d06B2484AE9"; +const CRITICAL_TIMELOCK = "0xbfbc79D4198963e4a66270F3EfB1fdA0F382E49c"; + +forking(50316022, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [190]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [54]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(ZKSYNC_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, ZKSYNC_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack(["address", "string"], [zksyncmainnet.RESILIENT_ORACLE, "pause()"]); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, zksyncmainnet.NORMAL_TIMELOCK)).to.be.true; + + const role2 = ethers.utils.solidityPack( + ["address", "string"], + [zksyncmainnet.XVS_VAULT_PROXY, "set(address,uint256,uint256)"], + ); + + const roleHash2 = ethers.utils.keccak256(role2); + expect(await acm.hasRole(roleHash2, zksyncmainnet.NORMAL_TIMELOCK)).to.be.true; + + const role3 = ethers.utils.solidityPack( + ["address", "string"], + [zksyncmainnet.XVS, "migrateMinterTokens(address,address)"], + ); + + const roleHash3 = ethers.utils.keccak256(role3); + expect(await acm.hasRole(roleHash3, FAST_TRACK_TIMELOCK)).to.be.true; + + const role4 = ethers.utils.solidityPack( + ["address", "string"], + [zksyncmainnet.XVS, "updateBlacklist(address,bool)"], + ); + + const roleHash4 = ethers.utils.keccak256(role4); + expect(await acm.hasRole(roleHash4, CRITICAL_TIMELOCK)).to.be.true; + }); + }); +}); diff --git a/simulations/vip-403/zksyncsepolia.ts b/simulations/vip-403/zksyncsepolia.ts new file mode 100644 index 000000000..9dcadb953 --- /dev/null +++ b/simulations/vip-403/zksyncsepolia.ts @@ -0,0 +1,49 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip403, { + DEFAULT_ADMIN_ROLE, + ZKSYNCSEPOLIA_ACM, + ZKSYNCSEPOLIA_ACM_AGGREGATOR, +} from "../../vips/vip-403/bsctestnet"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +const { zksyncsepolia } = NETWORK_ADDRESSES; + +forking(4236122, async () => { + testForkedNetworkVipCommands("VIP 403 Multichain Governance - Permissions", await vip403(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [190]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [54]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + await expectEvents(txResponse, [ACM_COMMANDS_AGGREGATOR_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(ZKSYNCSEPOLIA_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + + it("check if DEFAULT_ROLE has been revoked for ACMAggregator", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, ZKSYNCSEPOLIA_ACM_AGGREGATOR)).to.be.false; + }); + + it("check few permissions", async () => { + const role1 = ethers.utils.solidityPack(["address", "string"], [zksyncsepolia.RESILIENT_ORACLE, "pause()"]); + + const roleHash = ethers.utils.keccak256(role1); + expect(await acm.hasRole(roleHash, zksyncsepolia.NORMAL_TIMELOCK)).to.be.true; + + const role2 = ethers.utils.solidityPack( + ["address", "string"], + [zksyncsepolia.XVS_VAULT_PROXY, "set(address,uint256,uint256)"], + ); + + const roleHash2 = ethers.utils.keccak256(role2); + expect(await acm.hasRole(roleHash2, zksyncsepolia.NORMAL_TIMELOCK)).to.be.true; + }); + }); +}); diff --git a/src/networkAddresses.ts b/src/networkAddresses.ts index 1d2150b8a..13529f536 100644 --- a/src/networkAddresses.ts +++ b/src/networkAddresses.ts @@ -194,7 +194,7 @@ export const NETWORK_ADDRESSES = { OMNICHAIN_GOVERNANCE_EXECUTOR: "0xA1b56f19CA5E5b15EF29d38238930Ce9f0235312", }, opsepolia: { - NORMAL_TIMELOCK: "0xdDe31d7eEEAD7Cf9790F833C4FF4c6e61404402a", // To be deployed + NORMAL_TIMELOCK: "0xdDe31d7eEEAD7Cf9790F833C4FF4c6e61404402a", VTREASURY: "0x5A1a12F47FA7007C9e23cf5e025F3f5d3aC7d755", GUARDIAN: "0xd57365EE4E850e881229e2F8Aa405822f289e78d", XVS_VAULT_PROXY: "0x4d344e48F02234E82D7D1dB84d0A4A18Aa43Dacc", diff --git a/vips/vip-403/bscmainnet.ts b/vips/vip-403/bscmainnet.ts new file mode 100644 index 000000000..075551023 --- /dev/null +++ b/vips/vip-403/bscmainnet.ts @@ -0,0 +1,255 @@ +import { LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +export const ZKSYNC_ACM = "0x526159A92A82afE5327d37Ef446b68FD9a5cA914"; +export const OPMAINNET_ACM = "0xD71b1F33f6B0259683f11174EE4Ddc2bb9cE4eD6"; +export const ETHEREUM_ACM = "0x230058da2D23eb8836EC5DB7037ef7250c56E25E"; +export const OPBNB_ACM = "0xA60Deae5344F1152426cA440fb6552eA0e3005D6"; +export const ARBITRUM_ACM = "0xD9dD18EB0cf10CbA837677f28A8F9Bda4bc2b157"; +export const BSC_ACM = "0x4788629abc6cfca10f9f969efdeaa1cf70c23555"; + +export const OPBNB_ACM_AGGREGATOR = "0x6dB5e303289fea2E83F7d442470210045592AD93"; +export const ARBITRUM_ACM_AGGREGATOR = "0x74AFeA28456a683b8fF907699Ff77138edef00f3"; +export const ETHEREUM_ACM_AGGREGATOR = "0xb78772bed6995551b64e54Cdb8e09800d86C73ee"; +export const ZKSYNC_ACM_AGGREGATOR = "0x88B1452e512c8fcf83889DdCfe54dF37D561Db82"; +export const OPMAINNET_ACM_AGGREGATOR = "0xbbEBaF646e7a3E4064a899e68565B1b439eFdf70"; +export const BSC_ACM_AGGREGATOR = "0x8b443Ea6726E56DF4C4F62f80F0556bB9B2a7c64"; + +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +const vip403 = () => { + const meta = { + version: "v2", + title: "VIP-403 Enable Omnichain Governance on zkSync and Optimism (2/2)", + description: `#### Summary + +If passed, following the Community proposal “[Venus Upgrade - Omnichain Money Markets](https://community.venus.io/t/venus-upgrade-omnichain-money-markets/3027/9)” and [the associated snapshot](https://snapshot.org/#/venus-xvs.eth/proposal/0x62440d98cb7513d4873662203b7a27f9441880afa73105c55a733005de7ac9a1), this VIP will perform the following actions: + +- Authorise timelock contracts (Governance) on Optimism and zkSync Era to execute the same privilege functions they can execute on BNB Chain +- Revoke permissions for the Guardian wallets, to execute the privilege functions that will be authorised for the timelock contracts (Governance) in the previous step +- Minor adjustments on the configured permissions at Ethereum, Arbitrum one, opBNB and BNB Chain + +After executing this VIP, no more Guardian transactions will be needed to execute most of the privilege commands on Optimism and zkSync Era (Guardian will be only required for contract upgrades in those networks, and that will change soon too). + +#### Details + +This VIP will update the following number of permissions: + +- Optimism: grant 190 authorizations to Governance and revoke 50 authorizations for the Guardian wallet +- zkSync Era: grant 190 authorizations to Governance and revoke 54 authorizations for the Guardian wallet +- Ethereum: grant 2 authorizations to the Guardian wallet and revoke 4 authorizations for the Guardian wallet +- Arbitrum one: grant 2 authorizations to the Guardian wallet and revoke 4 authorizations for the Guardian wallet +- opBNB: revoke 4 authorizations for the Guardian wallet +- BNB Chain: grant 2 authorizations to the Guardian wallet + +The numbers of permissions granted and revoked are different because there are different contracts deployed to each network. + +Changes (grants and revokes) are pre-loaded in the ACMCommandsAggregator contracts and the VIP on BNB Chain only sends a message cross-chain to execute specific batches of changes. This reduces the payload sent cross-chain and therefore the gas cost of the VIP execution. + +The specific pre-loaded permissions can be checked in here: + +- Optimism: [grants](https://optimistic.etherscan.io/tx/0x3e04e39fc1a98cdf7ed32ab5e3051aff3677c0cc849f10241e1116ca2d90ee80) and [revokes](https://optimistic.etherscan.io/tx/0x25184837f97167d57983e1c6b05999a94122420aad466f9a3ae8fc01f5bdaba7) +- zkSync Era: [grants](https://explorer.zksync.io/tx/0xae0db72dc1f890ab270327eed6fcf2d3a6b6b28bcd055049863987c6763ae7d5) and [revokes](https://explorer.zksync.io/tx/0x2657af19e7e57177edb95ca476a50355413eee3405dc6d1626a0298da7d696c2) +- Ethereum: [grants](https://etherscan.io/tx/0x7c0de9c13d9fccb44e99e4a9be1f53f533de4885e8568b1d8c8427107bdb4b3b) and [revokes](https://etherscan.io/tx/0xd826bb3b1aea95b2af870e0f231ef1d5d6a12393d4d728d51df0308c1db3a409) +- Arbitrum one: [grants](https://arbiscan.io/tx/0xafb831d17164e1d1fef912899a3249afcbff1b10ffa8a2c13e7d5cbff6e12ad3) and [revokes](https://arbiscan.io/tx/0xe1c854c7722ff3b0f9083f60f0967549cf0fd6c861da19bee431e2bc042b424b) +- opBNB: [revokes](https://opbnbscan.com/tx/0x41d9bae45d163c3c4ab91d324192a6abbf646d46e9ed416ddfd8a25b3aaa0cdd) +- BNB Chain: [grants](https://bscscan.com/tx/0x0706293a8cd600e031244bd3aab0f7c82f12b159a7dd8f5d9a36fb6ab17a83c4) + +The minor adjustments performed on Ethereum, Arbitrum one, opBNB and BNB Chain are: + +- Ethereum, Arbitrum one and BNB Chain. The Guardian wallets are authorized to execute privilege functions (setDirectPrice and setTokenConfig) on the RedStoneOracle, as they are on the ChainlinkOracle contracts. +- Ethereum, Arbitrum one and opBNB. Revoke XVSVault permissions from the Guardian wallets + +Out of scope in this VIP (to be addressed in the future with other VIP’s): + +- Ownership of the contracts. The Guardian wallets will stay as the owner of the contracts on Optimism and zkSync Era. This ownership will be transferred to Governance (specifically to the Normal Timelock contract on each network) after a period confirming everything is working as expected with Omnichain VIP’s + +This VIP is a follow-up of [VIP-399 Enable Omnichain Governance on zkSync and Optimism (1/2)](https://app.venus.io/#/governance/proposal/399?chainId=56). Review these VIP’s for a detailed explanation of the Omnichain Governance feature. + +#### Security and additional considerations + +We applied the following security procedures for this upgrade: + +- **Audits:** [OpenZeppelin](https://www.openzeppelin.com/), [Quantstamp](https://quantstamp.com/), [Cantina](https://cantina.xyz/) and [Certik](https://www.certik.com/) have audited the Omnichain Governance contracts. Certik has audited the ACMCommandsAggregator contract. +- **VIP execution simulation**: in a simulation environment, validating the expected configuration on every network +- **Deployment on testnet**: the same contracts have been deployed to the supported testnets, and used in the Venus Protocol testnet deployment + +#### Audit reports + +- [Openzepplin audit report - 2024/01/19](https://github.com/VenusProtocol/governance-contracts/blob/feat/ven-1918/audits/084_multichainGovernance_openzeppelin_20240119.pdf) +- [Quantstamp audit report - 2024/04/29](https://github.com/VenusProtocol/governance-contracts/blob/feat/ven-1918/audits/106_multichainGovernance_quantstamp_20240429.pdf) +- [Cantina audit report - 2024/04/25](https://github.com/VenusProtocol/governance-contracts/blob/feat/ven-1918/audits/105_multichainGovernance_cantina_20240425.pdf) +- [Certik audit report - 2024/02/26](https://github.com/VenusProtocol/governance-contracts/blob/feat/ven-1918/audits/085_multichainGovernance_certik_20240226.pdf) +- [Certik audit report of ACMCommandsAggregator - 2024/10/07](https://github.com/VenusProtocol/governance-contracts/blob/3a5a2740e86c9137ab17f4f3939c97b145a22803/audits/118_ACMCommandsAggregator_certik_20241007.pdf) + +#### Deployed contracts + +Optimism: + +- Normal Timelock: [0x0C6f1E6B4fDa846f63A0d5a8a73EB811E0e0C04b](https://optimistic.etherscan.io/address/0x0C6f1E6B4fDa846f63A0d5a8a73EB811E0e0C04b) +- FastTrack Timelock: [0x508bD9C31E8d6760De04c70fe6c2b24B3cDea7E7](https://optimistic.etherscan.io/address/0x508bD9C31E8d6760De04c70fe6c2b24B3cDea7E7) +- Critical Timelock: [0xB82479bc345CAA7326D7d21306972033226fC185](https://optimistic.etherscan.io/address/0xB82479bc345CAA7326D7d21306972033226fC185) +- AccessControlManagerCommandsAggregator: [0xbbEBaF646e7a3E4064a899e68565B1b439eFdf70](https://optimistic.etherscan.io/address/0xbbEBaF646e7a3E4064a899e68565B1b439eFdf70) +- ACM: [0xD71b1F33f6B0259683f11174EE4Ddc2bb9cE4eD6](https://optimistic.etherscan.io/address/0xD71b1F33f6B0259683f11174EE4Ddc2bb9cE4eD6) + +zkSync Era: + +- Normal Timelock: [0x093565Bc20AA326F4209eBaF3a26089272627613](https://explorer.zksync.io/address/0x093565Bc20AA326F4209eBaF3a26089272627613) +- Fasttrack Timelock: [0x32f71c95BC8F9d996f89c642f1a84d06B2484AE9](https://explorer.zksync.io/address/0x32f71c95BC8F9d996f89c642f1a84d06B2484AE9) +- Critical Timelock: [0xbfbc79D4198963e4a66270F3EfB1fdA0F382E49c](https://explorer.zksync.io/address/0xbfbc79D4198963e4a66270F3EfB1fdA0F382E49c) +- AccessControlManagerCommandsAggregator: [0x88B1452e512c8fcf83889DdCfe54dF37D561Db82](https://explorer.zksync.io/address/0x88B1452e512c8fcf83889DdCfe54dF37D561Db82) +- ACM: [0x526159A92A82afE5327d37Ef446b68FD9a5cA914](https://explorer.zksync.io/address/0x526159A92A82afE5327d37Ef446b68FD9a5cA914) + +#### References + +- [VIP simulation](https://github.com/VenusProtocol/vips/pull/431) +- Set of permissions configured on each network: [here](https://github.com/VenusProtocol/governance-contracts/pull/100) and [here](https://github.com/VenusProtocol/governance-contracts/pull/102) +- [Code of Omnichain Governance](https://github.com/VenusProtocol/governance-contracts/pull/21) +- [Documentation - Technical article with more details of the Omnichain Governance feature](https://docs-v4.venus.io/technical-reference/reference-technical-articles/multichain-governance) +`, + forDescription: "Execute this proposal", + againstDescription: "Do not execute this proposal", + abstainDescription: "Indifferent to execution", + }; + return makeProposal( + [ + { + target: ZKSYNC_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ZKSYNC_ACM_AGGREGATOR], + dstChainId: LzChainId.zksyncmainnet, + }, + { + target: ZKSYNC_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [1], + dstChainId: LzChainId.zksyncmainnet, + }, + { + target: ZKSYNC_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [0], + dstChainId: LzChainId.zksyncmainnet, + }, + { + target: ZKSYNC_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ZKSYNC_ACM_AGGREGATOR], + dstChainId: LzChainId.zksyncmainnet, + }, + + { + target: OPMAINNET_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, OPMAINNET_ACM_AGGREGATOR], + dstChainId: LzChainId.opmainnet, + }, + { + target: OPMAINNET_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [1], + dstChainId: LzChainId.opmainnet, + }, + { + target: OPMAINNET_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [0], + dstChainId: LzChainId.opmainnet, + }, + { + target: OPMAINNET_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, OPMAINNET_ACM_AGGREGATOR], + dstChainId: LzChainId.opmainnet, + }, + + { + target: ETHEREUM_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ETHEREUM_ACM_AGGREGATOR], + dstChainId: LzChainId.ethereum, + }, + { + target: ETHEREUM_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [2], + dstChainId: LzChainId.ethereum, + }, + { + target: ETHEREUM_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [1], + dstChainId: LzChainId.ethereum, + }, + { + target: ETHEREUM_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ETHEREUM_ACM_AGGREGATOR], + dstChainId: LzChainId.ethereum, + }, + { + target: OPBNB_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, OPBNB_ACM_AGGREGATOR], + dstChainId: LzChainId.opbnbmainnet, + }, + { + target: OPBNB_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [1], + dstChainId: LzChainId.opbnbmainnet, + }, + { + target: OPBNB_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, OPBNB_ACM_AGGREGATOR], + dstChainId: LzChainId.opbnbmainnet, + }, + + { + target: ARBITRUM_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ARBITRUM_ACM_AGGREGATOR], + dstChainId: LzChainId.arbitrumone, + }, + { + target: ARBITRUM_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [1], + dstChainId: LzChainId.arbitrumone, + }, + { + target: ARBITRUM_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [1], + dstChainId: LzChainId.arbitrumone, + }, + { + target: ARBITRUM_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ARBITRUM_ACM_AGGREGATOR], + dstChainId: LzChainId.arbitrumone, + }, + + { + target: BSC_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, BSC_ACM_AGGREGATOR], + }, + { + target: BSC_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [0], + }, + { + target: BSC_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, BSC_ACM_AGGREGATOR], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip403; diff --git a/vips/vip-403/bsctestnet.ts b/vips/vip-403/bsctestnet.ts new file mode 100644 index 000000000..32ee712f5 --- /dev/null +++ b/vips/vip-403/bsctestnet.ts @@ -0,0 +1,170 @@ +import { LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +export const ZKSYNCSEPOLIA_ACM = "0xD07f543d47c3a8997D6079958308e981AC14CD01"; +export const OPSEPOLIA_ACM = "0x1652E12C8ABE2f0D84466F0fc1fA4286491B3BC1"; +export const SEPOLIA_ACM = "0xbf705C00578d43B6147ab4eaE04DBBEd1ccCdc96"; +export const ARBITRUM_SEPOLIA_ACM = "0xa36AD96441cB931D8dFEAAaC97D3FaB4B39E590F"; +export const OPBNBTESTNET_ACM = "0x049f77F7046266d27C3bC96376f53C17Ef09c986"; +export const BSCTESTNET_ACM = "0x45f8a08F534f34A97187626E05d4b6648Eeaa9AA"; + +export const ZKSYNCSEPOLIA_ACM_AGGREGATOR = "0x920Bb18c4bd4D7bc41Bf39933BCAa3D078641502"; +export const OPSEPOLIA_ACM_AGGREGATOR = "0xEEeF13364fD22b8eA6932A9ed337e2638f8E0eD6"; +export const ARBITRUMSEPOLIA_ACM_AGGREGATOR = "0x4fCbfE445396f31005b3Fd2F6DE2A986d6E2dCB5"; +export const OPBNBTESTNET_ACM_AGGREGATOR = "0xbDd501dB1B0D6aab299CE69ef5B86C8578947AD0"; +export const SEPOLIA_ACM_AGGREGATOR = "0x0653830c55035d678e1287b2d4550519fd263d0e"; +export const BSCTESTNET_ACM_AGGREGATOR = "0xB59523628D92f914ec6624Be4281397E8aFD71EF"; + +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +const vip403 = () => { + const meta = { + version: "v2", + title: "VIP-403 Multichain Governance", + description: `#### Summary`, + + forDescription: "I agree that Venus Protocol should proceed with this proposal", + againstDescription: "I do not think that Venus Protocol should proceed with this proposal", + abstainDescription: "I am indifferent to whether Venus Protocol proceeds or not", + }; + return makeProposal( + [ + { + target: ZKSYNCSEPOLIA_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ZKSYNCSEPOLIA_ACM_AGGREGATOR], + dstChainId: LzChainId.zksyncsepolia, + }, + { + target: ZKSYNCSEPOLIA_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [1], + dstChainId: LzChainId.zksyncsepolia, + }, + { + target: ZKSYNCSEPOLIA_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [0], + dstChainId: LzChainId.zksyncsepolia, + }, + { + target: ZKSYNCSEPOLIA_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ZKSYNCSEPOLIA_ACM_AGGREGATOR], + dstChainId: LzChainId.zksyncsepolia, + }, + + { + target: OPSEPOLIA_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, OPSEPOLIA_ACM_AGGREGATOR], + dstChainId: LzChainId.opsepolia, + }, + { + target: OPSEPOLIA_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [1], + dstChainId: LzChainId.opsepolia, + }, + { + target: OPSEPOLIA_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [0], + dstChainId: LzChainId.opsepolia, + }, + { + target: OPSEPOLIA_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, OPSEPOLIA_ACM_AGGREGATOR], + dstChainId: LzChainId.opsepolia, + }, + + { + target: SEPOLIA_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, SEPOLIA_ACM_AGGREGATOR], + dstChainId: LzChainId.sepolia, + }, + { + target: SEPOLIA_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [5], + dstChainId: LzChainId.sepolia, + }, + { + target: SEPOLIA_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [3], + dstChainId: LzChainId.sepolia, + }, + { + target: SEPOLIA_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, SEPOLIA_ACM_AGGREGATOR], + dstChainId: LzChainId.sepolia, + }, + { + target: OPBNBTESTNET_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, OPBNBTESTNET_ACM_AGGREGATOR], + dstChainId: LzChainId.opbnbtestnet, + }, + { + target: OPBNBTESTNET_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [3], + dstChainId: LzChainId.opbnbtestnet, + }, + { + target: OPBNBTESTNET_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, OPBNBTESTNET_ACM_AGGREGATOR], + dstChainId: LzChainId.opbnbtestnet, + }, + + { + target: ARBITRUM_SEPOLIA_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ARBITRUMSEPOLIA_ACM_AGGREGATOR], + dstChainId: LzChainId.arbitrumsepolia, + }, + { + target: ARBITRUMSEPOLIA_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [4], + dstChainId: LzChainId.arbitrumsepolia, + }, + { + target: ARBITRUMSEPOLIA_ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [4], + dstChainId: LzChainId.arbitrumsepolia, + }, + { + target: ARBITRUM_SEPOLIA_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ARBITRUMSEPOLIA_ACM_AGGREGATOR], + dstChainId: LzChainId.arbitrumsepolia, + }, + + { + target: BSCTESTNET_ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, BSCTESTNET_ACM_AGGREGATOR], + }, + { + target: BSCTESTNET_ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [0], + }, + { + target: BSCTESTNET_ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, BSCTESTNET_ACM_AGGREGATOR], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; +export default vip403;