From b03eb16036b48ea2f470f33890d8af59c6c20870 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Wed, 12 Feb 2025 20:03:00 +0530 Subject: [PATCH 1/6] feat: add vip for multichain governance on unichainsepolia --- .../unichainsepolia/vip-008/index.ts | 19 + .../vip-008/abi/AccessControlManager.json | 360 ++++++++++++ .../unichainsepolia/vip-008/index.ts | 38 ++ simulations/vip-455/abi/ACMAggregator.json | 242 ++++++++ .../vip-455/abi/AccessControlManager_ABI.json | 157 +++++ simulations/vip-455/abi/ERC20.json | 289 ++++++++++ .../abi/OmnichainExecutorOwner_ABI.json | 145 +++++ .../abi/OmnichainGovernanceExecutor_ABI.json | 539 ++++++++++++++++++ .../vip-455/abi/OmnichainProposalSender.json | 314 ++++++++++ simulations/vip-455/abi/VtreasuryAbi.json | 83 +++ simulations/vip-455/bsctestnet.ts | 57 ++ simulations/vip-455/unichainsepolia.ts | 153 +++++ src/networkAddresses.ts | 5 +- src/types.ts | 5 +- vips/vip-455/bsctestnet.ts | 76 +++ 15 files changed, 2480 insertions(+), 2 deletions(-) create mode 100644 multisig/proposals/unichainsepolia/vip-008/index.ts create mode 100644 multisig/simulations/unichainsepolia/vip-008/abi/AccessControlManager.json create mode 100644 multisig/simulations/unichainsepolia/vip-008/index.ts create mode 100644 simulations/vip-455/abi/ACMAggregator.json create mode 100644 simulations/vip-455/abi/AccessControlManager_ABI.json create mode 100644 simulations/vip-455/abi/ERC20.json create mode 100644 simulations/vip-455/abi/OmnichainExecutorOwner_ABI.json create mode 100644 simulations/vip-455/abi/OmnichainGovernanceExecutor_ABI.json create mode 100644 simulations/vip-455/abi/OmnichainProposalSender.json create mode 100644 simulations/vip-455/abi/VtreasuryAbi.json create mode 100644 simulations/vip-455/bsctestnet.ts create mode 100644 simulations/vip-455/unichainsepolia.ts create mode 100644 vips/vip-455/bsctestnet.ts diff --git a/multisig/proposals/unichainsepolia/vip-008/index.ts b/multisig/proposals/unichainsepolia/vip-008/index.ts new file mode 100644 index 000000000..6478bf9a7 --- /dev/null +++ b/multisig/proposals/unichainsepolia/vip-008/index.ts @@ -0,0 +1,19 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +import { makeProposal } from "../../../../src/utils"; + +const { unichainsepolia } = NETWORK_ADDRESSES; + +export const ACM = "0x854C064EA6b503A97980F481FA3B7279012fdeDd"; +const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +export const vip007 = () => { + return makeProposal([ + { + target: ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, unichainsepolia.NORMAL_TIMELOCK], + }, + ]); +}; +export default vip007; diff --git a/multisig/simulations/unichainsepolia/vip-008/abi/AccessControlManager.json b/multisig/simulations/unichainsepolia/vip-008/abi/AccessControlManager.json new file mode 100644 index 000000000..4a118fcc4 --- /dev/null +++ b/multisig/simulations/unichainsepolia/vip-008/abi/AccessControlManager.json @@ -0,0 +1,360 @@ +[ + { + "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/multisig/simulations/unichainsepolia/vip-008/index.ts b/multisig/simulations/unichainsepolia/vip-008/index.ts new file mode 100644 index 000000000..4f183b93a --- /dev/null +++ b/multisig/simulations/unichainsepolia/vip-008/index.ts @@ -0,0 +1,38 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { forking, pretendExecutingVip } from "src/vip-framework/index"; + +import vip008, { ACM } from "../../../proposals/unichainsepolia/vip-008"; +import ACM_ABI from "./abi/AccessControlManager.json"; + +const { unichainsepolia } = NETWORK_ADDRESSES; + +forking(12516535, async () => { + let acm: Contract; + let defaultAdminRole: string; + + before(async () => { + acm = await ethers.getContractAt(ACM_ABI, ACM); + defaultAdminRole = await acm.DEFAULT_ADMIN_ROLE(); + }); + + describe("Pre-VIP behaviour", async () => { + it("Normal Timelock does not has default admin role", async () => { + const hasRole = await acm.hasRole(defaultAdminRole, unichainsepolia.NORMAL_TIMELOCK); + expect(hasRole).equals(false); + }); + }); + + describe("Post-VIP behavior", async () => { + before(async () => { + await pretendExecutingVip(await vip008()); + }); + + it("Normal Timelock has default admin role", async () => { + const hasRole = await acm.hasRole(defaultAdminRole, unichainsepolia.NORMAL_TIMELOCK); + expect(hasRole).equals(true); + }); + }); +}); diff --git a/simulations/vip-455/abi/ACMAggregator.json b/simulations/vip-455/abi/ACMAggregator.json new file mode 100644 index 000000000..6650a3f3c --- /dev/null +++ b/simulations/vip-455/abi/ACMAggregator.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-455/abi/AccessControlManager_ABI.json b/simulations/vip-455/abi/AccessControlManager_ABI.json new file mode 100644 index 000000000..2ef119947 --- /dev/null +++ b/simulations/vip-455/abi/AccessControlManager_ABI.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-455/abi/ERC20.json b/simulations/vip-455/abi/ERC20.json new file mode 100644 index 000000000..28715d783 --- /dev/null +++ b/simulations/vip-455/abi/ERC20.json @@ -0,0 +1,289 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_initialAmount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_tokenName", + "type": "string" + }, + { + "internalType": "uint8", + "name": "_decimalUnits", + "type": "uint8" + }, + { + "internalType": "string", + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/simulations/vip-455/abi/OmnichainExecutorOwner_ABI.json b/simulations/vip-455/abi/OmnichainExecutorOwner_ABI.json new file mode 100644 index 000000000..f75834e6c --- /dev/null +++ b/simulations/vip-455/abi/OmnichainExecutorOwner_ABI.json @@ -0,0 +1,145 @@ +[ + { + "inputs": [{ "internalType": "address", "name": "omnichainGovernanceExecutor_", "type": "address" }], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { "internalType": "address", "name": "sender", "type": "address" }, + { "internalType": "address", "name": "calledContract", "type": "address" }, + { "internalType": "string", "name": "methodSignature", "type": "string" } + ], + "name": "Unauthorized", + "type": "error" + }, + { "inputs": [], "name": "ZeroAddressNotAllowed", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "string", "name": "signature", "type": "string" }, + { "indexed": false, "internalType": "bool", "name": "active", "type": "bool" } + ], + "name": "FunctionRegistryChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint8", "name": "version", "type": "uint8" }], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldAccessControlManager", "type": "address" }, + { "indexed": false, "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": "OwnershipTransferStarted", + "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" + }, + { "stateMutability": "nonpayable", "type": "fallback" }, + { + "inputs": [], + "name": "OMNICHAIN_GOVERNANCE_EXECUTOR", + "outputs": [{ "internalType": "contract IOmnichainGovernanceExecutor", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "acceptOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [{ "internalType": "contract IAccessControlManagerV8", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes4", "name": "", "type": "bytes4" }], + "name": "functionRegistry", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "accessControlManager_", "type": "address" }], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [{ "internalType": "address", "name": "accessControlManager_", "type": "address" }], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "srcChainId_", "type": "uint16" }, + { "internalType": "bytes", "name": "srcAddress_", "type": "bytes" } + ], + "name": "setTrustedRemoteAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner_", "type": "address" }], + "name": "transferBridgeOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string[]", "name": "signatures_", "type": "string[]" }, + { "internalType": "bool[]", "name": "active_", "type": "bool[]" } + ], + "name": "upsertSignature", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/simulations/vip-455/abi/OmnichainGovernanceExecutor_ABI.json b/simulations/vip-455/abi/OmnichainGovernanceExecutor_ABI.json new file mode 100644 index 000000000..b40c3cf44 --- /dev/null +++ b/simulations/vip-455/abi/OmnichainGovernanceExecutor_ABI.json @@ -0,0 +1,539 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "endpoint_", "type": "address" }, + { "internalType": "address", "name": "guardian_", "type": "address" }, + { "internalType": "uint16", "name": "srcChainId_", "type": "uint16" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "InvalidProposalId", "type": "error" }, + { "inputs": [], "name": "ZeroAddressNotAllowed", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint16", "name": "_srcChainId", "type": "uint16" }, + { "indexed": false, "internalType": "bytes", "name": "_srcAddress", "type": "bytes" }, + { "indexed": false, "internalType": "uint64", "name": "_nonce", "type": "uint64" }, + { "indexed": false, "internalType": "bytes", "name": "_payload", "type": "bytes" }, + { "indexed": false, "internalType": "bytes", "name": "_reason", "type": "bytes" } + ], + "name": "MessageFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "oldGuardian", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newGuardian", "type": "address" } + ], + "name": "NewGuardian", + "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": "uint256", "name": "id", "type": "uint256" }], + "name": "ProposalCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": true, "internalType": "uint256", "name": "id", "type": "uint256" }], + "name": "ProposalExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint256", "name": "id", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "eta", "type": "uint256" } + ], + "name": "ProposalQueued", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint256", "name": "proposalId", "type": "uint256" }, + { "indexed": false, "internalType": "address[]", "name": "targets", "type": "address[]" }, + { "indexed": false, "internalType": "uint256[]", "name": "values", "type": "uint256[]" }, + { "indexed": false, "internalType": "string[]", "name": "signatures", "type": "string[]" }, + { "indexed": false, "internalType": "bytes[]", "name": "calldatas", "type": "bytes[]" }, + { "indexed": false, "internalType": "uint8", "name": "proposalType", "type": "uint8" } + ], + "name": "ProposalReceived", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint16", "name": "srcChainId", "type": "uint16" }, + { "indexed": true, "internalType": "bytes", "name": "srcAddress", "type": "bytes" }, + { "indexed": false, "internalType": "uint64", "name": "nonce", "type": "uint64" }, + { "indexed": false, "internalType": "bytes", "name": "reason", "type": "bytes" } + ], + "name": "ReceivePayloadFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint16", "name": "_srcChainId", "type": "uint16" }, + { "indexed": false, "internalType": "bytes", "name": "_srcAddress", "type": "bytes" }, + { "indexed": false, "internalType": "uint64", "name": "_nonce", "type": "uint64" }, + { "indexed": false, "internalType": "bytes32", "name": "_payloadHash", "type": "bytes32" } + ], + "name": "RetryMessageSuccess", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldMaxLimit", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newMaxLimit", "type": "uint256" } + ], + "name": "SetMaxDailyReceiveLimit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint16", "name": "_dstChainId", "type": "uint16" }, + { "indexed": false, "internalType": "uint16", "name": "_type", "type": "uint16" }, + { "indexed": false, "internalType": "uint256", "name": "_minDstGas", "type": "uint256" } + ], + "name": "SetMinDstGas", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "precrime", "type": "address" }], + "name": "SetPrecrime", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint16", "name": "oldSrcChainId", "type": "uint16" }, + { "indexed": true, "internalType": "uint16", "name": "newSrcChainId", "type": "uint16" } + ], + "name": "SetSrcChainId", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "", "type": "address" }, + { "indexed": false, "internalType": "uint8", "name": "", "type": "uint8" } + ], + "name": "SetTimelockPendingAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint16", "name": "_remoteChainId", "type": "uint16" }, + { "indexed": false, "internalType": "bytes", "name": "_path", "type": "bytes" } + ], + "name": "SetTrustedRemote", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint16", "name": "_remoteChainId", "type": "uint16" }, + { "indexed": false, "internalType": "bytes", "name": "_remoteAddress", "type": "bytes" } + ], + "name": "SetTrustedRemoteAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint8", "name": "routeType", "type": "uint8" }, + { "indexed": true, "internalType": "address", "name": "oldTimelock", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newTimelock", "type": "address" } + ], + "name": "TimelockAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "account", "type": "address" }], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_PAYLOAD_SIZE_LIMIT", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "contract ITimelock[]", "name": "timelocks_", "type": "address[]" }], + "name": "addTimelocks", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "proposalId_", "type": "uint256" }], + "name": "cancel", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "proposalId_", "type": "uint256" }], + "name": "execute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "", "type": "uint16" }, + { "internalType": "bytes", "name": "", "type": "bytes" }, + { "internalType": "uint64", "name": "", "type": "uint64" } + ], + "name": "failedMessages", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "_srcChainId", "type": "uint16" }, + { "internalType": "bytes", "name": "_srcAddress", "type": "bytes" } + ], + "name": "forceResumeReceive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "_version", "type": "uint16" }, + { "internalType": "uint16", "name": "_chainId", "type": "uint16" }, + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "_configType", "type": "uint256" } + ], + "name": "getConfig", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "_remoteChainId", "type": "uint16" }], + "name": "getTrustedRemoteAddress", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "guardian", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "_srcChainId", "type": "uint16" }, + { "internalType": "bytes", "name": "_srcAddress", "type": "bytes" } + ], + "name": "isTrustedRemote", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "last24HourCommandsReceived", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "last24HourReceiveWindowStart", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastProposalReceived", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lzEndpoint", + "outputs": [{ "internalType": "contract ILayerZeroEndpoint", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "_srcChainId", "type": "uint16" }, + { "internalType": "bytes", "name": "_srcAddress", "type": "bytes" }, + { "internalType": "uint64", "name": "_nonce", "type": "uint64" }, + { "internalType": "bytes", "name": "_payload", "type": "bytes" } + ], + "name": "lzReceive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "maxDailyReceiveLimit", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "", "type": "uint16" }, + { "internalType": "uint16", "name": "", "type": "uint16" } + ], + "name": "minDstGasLookup", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "_srcChainId", "type": "uint16" }, + { "internalType": "bytes", "name": "_srcAddress", "type": "bytes" }, + { "internalType": "uint64", "name": "_nonce", "type": "uint64" }, + { "internalType": "bytes", "name": "_payload", "type": "bytes" } + ], + "name": "nonblockingLzReceive", + "outputs": [], + "stateMutability": "nonpayable", + "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": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "name": "payloadSizeLimitLookup", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "precrime", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "proposalTimelocks", + "outputs": [{ "internalType": "contract ITimelock", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "proposals", + "outputs": [ + { "internalType": "uint256", "name": "id", "type": "uint256" }, + { "internalType": "uint256", "name": "eta", "type": "uint256" }, + { "internalType": "bool", "name": "canceled", "type": "bool" }, + { "internalType": "bool", "name": "executed", "type": "bool" }, + { "internalType": "uint8", "name": "proposalType", "type": "uint8" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "queued", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "uint16", "name": "srcChainId_", "type": "uint16" }, + { "internalType": "bytes", "name": "srcAddress_", "type": "bytes" }, + { "internalType": "uint64", "name": "nonce_", "type": "uint64" }, + { "internalType": "bytes", "name": "payload_", "type": "bytes" } + ], + "name": "retryMessage", + "outputs": [], + "stateMutability": "payable", + "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": "address", "name": "newGuardian", "type": "address" }], + "name": "setGuardian", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "limit_", "type": "uint256" }], + "name": "setMaxDailyReceiveLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "_dstChainId", "type": "uint16" }, + { "internalType": "uint16", "name": "_packetType", "type": "uint16" }, + { "internalType": "uint256", "name": "_minGas", "type": "uint256" } + ], + "name": "setMinDstGas", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "_dstChainId", "type": "uint16" }, + { "internalType": "uint256", "name": "_size", "type": "uint256" } + ], + "name": "setPayloadSizeLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_precrime", "type": "address" }], + "name": "setPrecrime", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "_version", "type": "uint16" }], + "name": "setReceiveVersion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "_version", "type": "uint16" }], + "name": "setSendVersion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "srcChainId_", "type": "uint16" }], + "name": "setSrcChainId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "pendingAdmin_", "type": "address" }, + { "internalType": "uint8", "name": "proposalType_", "type": "uint8" } + ], + "name": "setTimelockPendingAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "_remoteChainId", "type": "uint16" }, + { "internalType": "bytes", "name": "_path", "type": "bytes" } + ], + "name": "setTrustedRemote", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint16", "name": "_remoteChainId", "type": "uint16" }, + { "internalType": "bytes", "name": "_remoteAddress", "type": "bytes" } + ], + "name": "setTrustedRemoteAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "srcChainId", + "outputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "proposalId_", "type": "uint256" }], + "name": "state", + "outputs": [{ "internalType": "enum OmnichainGovernanceExecutor.ProposalState", "name": "", "type": "uint8" }], + "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-455/abi/OmnichainProposalSender.json b/simulations/vip-455/abi/OmnichainProposalSender.json new file mode 100644 index 000000000..66fd4df02 --- /dev/null +++ b/simulations/vip-455/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-455/abi/VtreasuryAbi.json b/simulations/vip-455/abi/VtreasuryAbi.json new file mode 100644 index 000000000..df5a655ee --- /dev/null +++ b/simulations/vip-455/abi/VtreasuryAbi.json @@ -0,0 +1,83 @@ +[ + { + "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": "tokenAddress", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "withdrawAmount", "type": "uint256" }, + { "indexed": false, "internalType": "address", "name": "withdrawAddress", "type": "address" } + ], + "name": "WithdrawTreasuryBEP20", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "withdrawAmount", "type": "uint256" }, + { "indexed": false, "internalType": "address", "name": "withdrawAddress", "type": "address" } + ], + "name": "WithdrawTreasuryBNB", + "type": "event" + }, + { "payable": true, "stateMutability": "payable", "type": "fallback" }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "tokenAddress", "type": "address" }, + { "internalType": "uint256", "name": "withdrawAmount", "type": "uint256" }, + { "internalType": "address", "name": "withdrawAddress", "type": "address" } + ], + "name": "withdrawTreasuryBEP20", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "uint256", "name": "withdrawAmount", "type": "uint256" }, + { "internalType": "address payable", "name": "withdrawAddress", "type": "address" } + ], + "name": "withdrawTreasuryBNB", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + } +] diff --git a/simulations/vip-455/bsctestnet.ts b/simulations/vip-455/bsctestnet.ts new file mode 100644 index 000000000..a6ab33100 --- /dev/null +++ b/simulations/vip-455/bsctestnet.ts @@ -0,0 +1,57 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; +import { expectEvents } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import vip455, { MAX_DAILY_LIMIT, OMNICHAIN_PROPOSAL_SENDER } from "../../vips/vip-455/bsctestnet"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; +import OMNICHAIN_PROPOSAL_SENDER_ABI from "./abi/OmnichainProposalSender.json"; + +const { unichainsepolia } = NETWORK_ADDRESSES; +forking(48215809, async () => { + const provider = ethers.provider; + const omnichainProposalSender = new ethers.Contract( + OMNICHAIN_PROPOSAL_SENDER, + OMNICHAIN_PROPOSAL_SENDER_ABI, + provider, + ); + + describe("Pre-VIP behaviour", () => { + it("Daily limit should be 0", async () => { + expect(await omnichainProposalSender.chainIdToMaxDailyLimit(LzChainId.unichainsepolia)).to.equals(0); + }); + it("Trusted remote should not be set", async () => { + expect(await omnichainProposalSender.trustedRemoteLookup(LzChainId.unichainsepolia)).to.be.equals("0x"); + }); + }); + + testVip("vip455 give permissions to timelock", await vip455(), { + callbackAfterExecution: async txResponse => { + await expectEvents( + txResponse, + [ACCESS_CONTROL_MANAGER_ABI, OMNICHAIN_PROPOSAL_SENDER_ABI], + ["SetMaxDailyLimit", "SetTrustedRemoteAddress", "ExecuteRemoteProposal", "StorePayload"], + [1, 1, 1, 0], + ); + }, + }); + + describe("Post-VIP behavior", () => { + it("Daily limit should be 100 of unichainsepolia", async () => { + expect(await omnichainProposalSender.chainIdToMaxDailyLimit(LzChainId.unichainsepolia)).to.equals( + MAX_DAILY_LIMIT, + ); + }); + + it("Trusted remote should be set of unichainsepolia", async () => { + expect(await omnichainProposalSender.trustedRemoteLookup(LzChainId.unichainsepolia)).to.be.equals( + ethers.utils.solidityPack( + ["address", "address"], + [unichainsepolia.OMNICHAIN_GOVERNANCE_EXECUTOR, OMNICHAIN_PROPOSAL_SENDER], + ), + ); + }); + }); +}); diff --git a/simulations/vip-455/unichainsepolia.ts b/simulations/vip-455/unichainsepolia.ts new file mode 100644 index 000000000..c24520a82 --- /dev/null +++ b/simulations/vip-455/unichainsepolia.ts @@ -0,0 +1,153 @@ +import { expect } from "chai"; +import { BigNumber, Contract } from "ethers"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; +import { expectEvents, getOmnichainProposalSenderAddress } from "src/utils"; +import { forking, pretendExecutingVip, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip008 from "../../multisig/proposals/unichainsepolia/vip-008"; +import vip455, { + ACM, + ACM_AGGREGATOR, + DEFAULT_ADMIN_ROLE, + OMNICHAIN_EXECUTOR_OWNER, +} from "../../vips/vip-455/bsctestnet"; +import ACMAggregator_ABI from "./abi/ACMAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; +import OMNICHAIN_EXECUTOR_OWNER_ABI from "./abi/OmnichainExecutorOwner_ABI.json"; +import OMNICHAIN_GOVERNANCE_EXECUTOR_ABI from "./abi/OmnichainGovernanceExecutor_ABI.json"; + +const { unichainsepolia } = NETWORK_ADDRESSES; +const FAST_TRACK_TIMELOCK = "0x668cDb1A414006D0a26e9e13881D4Cd30B8b2a4A"; +const CRITICAL_TIMELOCK = "0x86C093266e824FA4345484a7B9109e9567923DA6"; + +forking(12517026, async () => { + const provider = ethers.provider; + let lastProposalReceived: BigNumber; + let executor: Contract; + let executorOwner: Contract; + + before(async () => { + executor = new ethers.Contract( + unichainsepolia.OMNICHAIN_GOVERNANCE_EXECUTOR, + OMNICHAIN_GOVERNANCE_EXECUTOR_ABI, + provider, + ); + executorOwner = new ethers.Contract(OMNICHAIN_EXECUTOR_OWNER, OMNICHAIN_EXECUTOR_OWNER_ABI, provider); + lastProposalReceived = await executor.lastProposalReceived(); + await pretendExecutingVip(await vip008()); + }); + + describe("Pre-VIP behaviour", async () => { + it("Normal Timelock has default admin role on base sepolia", async () => { + const acm = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, ACM); + const hasRole = await acm.hasRole(DEFAULT_ADMIN_ROLE, unichainsepolia.NORMAL_TIMELOCK); + expect(hasRole).equals(true); + }); + }); + + testForkedNetworkVipCommands("vip455 configures bridge", await vip455(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [233]); + await expectEvents(txResponse, [ACMAggregator_ABI], ["GrantPermissionsExecuted"], [2]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [50]); + await expectEvents(txResponse, [ACMAggregator_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(ACM, ACCESS_CONTROL_MANAGER_ABI, provider); + + it("Proposal id should be incremented", async () => { + expect(await executor.lastProposalReceived()).to.be.equals(lastProposalReceived.add(1)); + }); + it("proposal should be executed", async () => { + const pId = await executor.lastProposalReceived(); + expect(await executor.state(pId)).to.be.equals(2); + }); + it("check configuration", async () => { + // Check Timelock configurations + expect(await executor.proposalTimelocks(0)).equals(unichainsepolia.NORMAL_TIMELOCK); + expect(await executor.proposalTimelocks(1)).equals(FAST_TRACK_TIMELOCK); + expect(await executor.proposalTimelocks(2)).equals(CRITICAL_TIMELOCK); + + // Check trusted remote + expect(await executor.trustedRemoteLookup(LzChainId.bsctestnet)).equals( + ethers.utils.solidityPack( + ["address", "address"], + [getOmnichainProposalSenderAddress(), unichainsepolia.OMNICHAIN_GOVERNANCE_EXECUTOR], + ), + ); + + // Check receiving limit + expect(await executor.maxDailyReceiveLimit()).equals(100); + expect(await executor.last24HourCommandsReceived()).equals(6); + + // Check function registry + const functionSignatures: string[] = [ + "forceResumeReceive(uint16,bytes)", + "pause()", + "unpause()", + "setSendVersion(uint16)", + "setReceiveVersion(uint16)", + "setMaxDailyReceiveLimit(uint256)", + "setTrustedRemoteAddress(uint16,bytes)", + "setPrecrime(address)", + "setMinDstGas(uint16,uint16,uint256)", + "setPayloadSizeLimit(uint16,uint256)", + "setConfig(uint16,uint16,uint256,bytes)", + "addTimelocks(ITimelock[])", + "setTimelockPendingAdmin(address,uint8)", + "retryMessage(uint16,bytes,uint64,bytes)", + "setGuardian(address)", + "setSrcChainId(uint16)", + ]; + const getFunctionSelector = (signature: string): string => { + return ethers.utils.keccak256(ethers.utils.toUtf8Bytes(signature)).substring(0, 10); + }; + + for (const signature of functionSignatures) { + const selector = getFunctionSelector(signature); + expect(await executorOwner.functionRegistry(selector)).equals(signature); + } + }); + it("Default admin role must be revoked from ACMAggregator contract on base sepolia", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR)).to.be.false; + }); + it("Guardian and all timelocks are allowed to call retryMessage ", async () => { + const role = ethers.utils.solidityPack( + ["address", "string"], + [OMNICHAIN_EXECUTOR_OWNER, "retryMessage(uint16,bytes,uint64,bytes)"], + ); + const roleHash = ethers.utils.keccak256(role); + expect(await acm.hasRole(roleHash, unichainsepolia.GUARDIAN)).to.be.true; + expect(await acm.hasRole(roleHash, unichainsepolia.NORMAL_TIMELOCK)).to.be.true; + expect(await acm.hasRole(roleHash, FAST_TRACK_TIMELOCK)).to.be.true; + expect(await acm.hasRole(roleHash, CRITICAL_TIMELOCK)).to.be.true; + }); + + it("Guardian is allowed to call forceResumeReceive but not timelocks", async () => { + const role = ethers.utils.solidityPack( + ["address", "string"], + [OMNICHAIN_EXECUTOR_OWNER, "forceResumeReceive(uint16,bytes)"], + ); + const roleHash = ethers.utils.keccak256(role); + expect(await acm.hasRole(roleHash, unichainsepolia.GUARDIAN)).to.be.true; + expect(await acm.hasRole(roleHash, unichainsepolia.NORMAL_TIMELOCK)).to.be.false; + expect(await acm.hasRole(roleHash, FAST_TRACK_TIMELOCK)).to.be.false; + expect(await acm.hasRole(roleHash, CRITICAL_TIMELOCK)).to.be.false; + }); + it("Normal Timelock is allowed to call setSendVersion but not other timelocks and guardian", async () => { + const role = ethers.utils.solidityPack( + ["address", "string"], + [OMNICHAIN_EXECUTOR_OWNER, "setSendVersion(uint16)"], + ); + const roleHash = ethers.utils.keccak256(role); + expect(await acm.hasRole(roleHash, unichainsepolia.GUARDIAN)).to.be.false; + expect(await acm.hasRole(roleHash, unichainsepolia.NORMAL_TIMELOCK)).to.be.true; + expect(await acm.hasRole(roleHash, FAST_TRACK_TIMELOCK)).to.be.false; + expect(await acm.hasRole(roleHash, CRITICAL_TIMELOCK)).to.be.false; + }); + }); +}); diff --git a/src/networkAddresses.ts b/src/networkAddresses.ts index fa2a37264..7aa0259dd 100644 --- a/src/networkAddresses.ts +++ b/src/networkAddresses.ts @@ -259,7 +259,7 @@ export const NETWORK_ADDRESSES = { ENDPOINT: "0xb6319cC6c8c27A8F5dAF0dD3DF91EA35C4720dd7", }, unichainsepolia: { - NORMAL_TIMELOCK: "", // To be deployed + NORMAL_TIMELOCK: "0x5e20F5A2e23463D39287185DF84607DF7068F314", VTREASURY: "0x0C7CB62F2194cD701bcE8FD8067b43A3Bb76428e", GUARDIAN: "0x9831D3A641E8c7F082EEA75b8249c99be9D09a34", RESILIENT_ORACLE: "0xA469E718BDE2C9939bD29529A38184e97dF0A741", @@ -267,5 +267,8 @@ export const NETWORK_ADDRESSES = { XVS_VAULT_PROXY: "0x3a33d235E23B6B54004E25FF8E622228df16717a", XVS: "0xC0e51E865bc9Fed0a32Cc0B2A65449567Bc5c741", GENERIC_TEST_USER_ACCOUNT: "0x6f057A858171e187124ddEDF034dAc63De5dE5dB", + OMNICHAIN_GOVERNANCE_EXECUTOR: "0x4FD69A0821e35104Fc86B8B7fF09026956B45947", + LZ_LIBRARY: "0x70D8D48abf1f247969aCEB6B7Fd6b1d2b1937914", + ENDPOINT: "0x012f6eaE2A0Bf5916f48b5F37C62Bcfb7C1ffdA1", }, }; diff --git a/src/types.ts b/src/types.ts index f899b3596..f1be36bd3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -12,7 +12,8 @@ export type SUPPORTED_NETWORKS = | "opsepolia" | "opmainnet" | "basesepolia" - | "basemainnet"; + | "basemainnet" + | "unichainsepolia"; export type REMOTE_NETWORKS = Exclude; @@ -23,6 +24,7 @@ export const REMOTE_TESTNET_NETWORKS = [ "zksyncsepolia", "opsepolia", "basesepolia", + "unichainsepolia", ]; export const REMOTE_MAINNET_NETWORKS = [ "ethereum", @@ -94,4 +96,5 @@ export enum LzChainId { opmainnet = 111, basesepolia = 10245, basemainnet = 184, + unichainsepolia = 10333, } diff --git a/vips/vip-455/bsctestnet.ts b/vips/vip-455/bsctestnet.ts new file mode 100644 index 000000000..2f8446f63 --- /dev/null +++ b/vips/vip-455/bsctestnet.ts @@ -0,0 +1,76 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +const { unichainsepolia } = NETWORK_ADDRESSES; +export const OMNICHAIN_PROPOSAL_SENDER = "0xCfD34AEB46b1CB4779c945854d405E91D27A1899"; + +export const OMNICHAIN_EXECUTOR_OWNER = "0xD755873C16Eaeb26993D283292d3F6C605D9BC26"; +export const ACM = "0x854C064EA6b503A97980F481FA3B7279012fdeDd"; +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; +export const ACM_AGGREGATOR = "0xb0067C9CD83B00DE781e9b456Bf0Fec86D687Bb2"; +export const MAX_DAILY_LIMIT = 100; + +const vip455 = () => { + const meta = { + version: "v2", + title: "VIP-455 Enable Multichain Governance on unichain sepolia", + 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: OMNICHAIN_PROPOSAL_SENDER, + signature: "setMaxDailyLimit(uint16,uint256)", + params: [LzChainId.unichainsepolia, MAX_DAILY_LIMIT], + }, + { + target: OMNICHAIN_PROPOSAL_SENDER, + signature: "setTrustedRemoteAddress(uint16,bytes)", + params: [LzChainId.unichainsepolia, unichainsepolia.OMNICHAIN_GOVERNANCE_EXECUTOR], + }, + { + target: OMNICHAIN_EXECUTOR_OWNER, + signature: "acceptOwnership()", + params: [], + dstChainId: LzChainId.unichainsepolia, + }, + { + target: ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.unichainsepolia, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [0], + dstChainId: LzChainId.unichainsepolia, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [1], + dstChainId: LzChainId.unichainsepolia, + }, + { + target: ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [0], + dstChainId: LzChainId.unichainsepolia, + }, + { + target: ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.unichainsepolia, + }, + ], + meta, + ProposalType.REGULAR, + ); +}; +export default vip455; From 5630a0648d3825c588f1bf8573c2f485d7bd4cea Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Thu, 13 Feb 2025 17:28:20 +0530 Subject: [PATCH 2/6] feat: configure multichain governance on unichain mainnet --- .../unichainmainnet/vip-008/index.ts | 19 + .../unichainsepolia/vip-008/index.ts | 4 +- .../vip-008/abi/AccessControlManager.json | 360 ++++++++++++++++++ .../unichainmainnet/vip-008/index.ts | 38 ++ simulations/vip-455/bscmainnet.ts | 57 +++ simulations/vip-455/unichainmainnet.ts | 153 ++++++++ simulations/vip-455/unichainsepolia.ts | 2 +- src/networkAddresses.ts | 5 +- src/types.ts | 2 + src/vip-framework/index.ts | 10 +- vips/vip-455/bscmainnet.ts | 76 ++++ 11 files changed, 721 insertions(+), 5 deletions(-) create mode 100644 multisig/proposals/unichainmainnet/vip-008/index.ts create mode 100644 multisig/simulations/unichainmainnet/vip-008/abi/AccessControlManager.json create mode 100644 multisig/simulations/unichainmainnet/vip-008/index.ts create mode 100644 simulations/vip-455/bscmainnet.ts create mode 100644 simulations/vip-455/unichainmainnet.ts create mode 100644 vips/vip-455/bscmainnet.ts diff --git a/multisig/proposals/unichainmainnet/vip-008/index.ts b/multisig/proposals/unichainmainnet/vip-008/index.ts new file mode 100644 index 000000000..938ea7f84 --- /dev/null +++ b/multisig/proposals/unichainmainnet/vip-008/index.ts @@ -0,0 +1,19 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +import { makeProposal } from "../../../../src/utils"; + +const { unichainmainnet } = NETWORK_ADDRESSES; + +export const ACM = "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0"; +const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +export const vip008 = () => { + return makeProposal([ + { + target: ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, unichainmainnet.NORMAL_TIMELOCK], + }, + ]); +}; +export default vip008; diff --git a/multisig/proposals/unichainsepolia/vip-008/index.ts b/multisig/proposals/unichainsepolia/vip-008/index.ts index 6478bf9a7..a3859f8ec 100644 --- a/multisig/proposals/unichainsepolia/vip-008/index.ts +++ b/multisig/proposals/unichainsepolia/vip-008/index.ts @@ -7,7 +7,7 @@ const { unichainsepolia } = NETWORK_ADDRESSES; export const ACM = "0x854C064EA6b503A97980F481FA3B7279012fdeDd"; const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; -export const vip007 = () => { +export const vip008 = () => { return makeProposal([ { target: ACM, @@ -16,4 +16,4 @@ export const vip007 = () => { }, ]); }; -export default vip007; +export default vip008; diff --git a/multisig/simulations/unichainmainnet/vip-008/abi/AccessControlManager.json b/multisig/simulations/unichainmainnet/vip-008/abi/AccessControlManager.json new file mode 100644 index 000000000..4a118fcc4 --- /dev/null +++ b/multisig/simulations/unichainmainnet/vip-008/abi/AccessControlManager.json @@ -0,0 +1,360 @@ +[ + { + "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/multisig/simulations/unichainmainnet/vip-008/index.ts b/multisig/simulations/unichainmainnet/vip-008/index.ts new file mode 100644 index 000000000..c6f37841f --- /dev/null +++ b/multisig/simulations/unichainmainnet/vip-008/index.ts @@ -0,0 +1,38 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { forking, pretendExecutingVip } from "src/vip-framework/index"; + +import vip008, { ACM } from "../../../proposals/unichainmainnet/vip-008"; +import ACM_ABI from "./abi/AccessControlManager.json"; + +const { unichainmainnet } = NETWORK_ADDRESSES; + +forking(8697951, async () => { + let acm: Contract; + let defaultAdminRole: string; + + before(async () => { + acm = await ethers.getContractAt(ACM_ABI, ACM); + defaultAdminRole = await acm.DEFAULT_ADMIN_ROLE(); + }); + + describe("Pre-VIP behaviour", async () => { + it("Normal Timelock does not has default admin role", async () => { + const hasRole = await acm.hasRole(defaultAdminRole, unichainmainnet.NORMAL_TIMELOCK); + expect(hasRole).equals(false); + }); + }); + + describe("Post-VIP behavior", async () => { + before(async () => { + await pretendExecutingVip(await vip008()); + }); + + it("Normal Timelock has default admin role", async () => { + const hasRole = await acm.hasRole(defaultAdminRole, unichainmainnet.NORMAL_TIMELOCK); + expect(hasRole).equals(true); + }); + }); +}); diff --git a/simulations/vip-455/bscmainnet.ts b/simulations/vip-455/bscmainnet.ts new file mode 100644 index 000000000..e0ba7e431 --- /dev/null +++ b/simulations/vip-455/bscmainnet.ts @@ -0,0 +1,57 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; +import { expectEvents } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import vip455, { MAX_DAILY_LIMIT, OMNICHAIN_PROPOSAL_SENDER } from "../../vips/vip-455/bscmainnet"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; +import OMNICHAIN_PROPOSAL_SENDER_ABI from "./abi/OmnichainProposalSender.json"; + +const { unichainmainnet } = NETWORK_ADDRESSES; +forking(46621583, async () => { + const provider = ethers.provider; + const omnichainProposalSender = new ethers.Contract( + OMNICHAIN_PROPOSAL_SENDER, + OMNICHAIN_PROPOSAL_SENDER_ABI, + provider, + ); + + describe("Pre-VIP behaviour", () => { + it("Daily limit should be 0", async () => { + expect(await omnichainProposalSender.chainIdToMaxDailyLimit(LzChainId.unichainmainnet)).to.equals(0); + }); + it("Trusted remote should not be set", async () => { + expect(await omnichainProposalSender.trustedRemoteLookup(LzChainId.unichainmainnet)).to.be.equals("0x"); + }); + }); + + testVip("vip455 give permissions to timelock", await vip455(), { + callbackAfterExecution: async txResponse => { + await expectEvents( + txResponse, + [ACCESS_CONTROL_MANAGER_ABI, OMNICHAIN_PROPOSAL_SENDER_ABI], + ["SetMaxDailyLimit", "SetTrustedRemoteAddress", "ExecuteRemoteProposal", "StorePayload"], + [1, 1, 1, 0], + ); + }, + }); + + describe("Post-VIP behavior", () => { + it("Daily limit should be 100 of unichainmainnet", async () => { + expect(await omnichainProposalSender.chainIdToMaxDailyLimit(LzChainId.unichainmainnet)).to.equals( + MAX_DAILY_LIMIT, + ); + }); + + it("Trusted remote should be set of unichainmainnet", async () => { + expect(await omnichainProposalSender.trustedRemoteLookup(LzChainId.unichainmainnet)).to.be.equals( + ethers.utils.solidityPack( + ["address", "address"], + [unichainmainnet.OMNICHAIN_GOVERNANCE_EXECUTOR, OMNICHAIN_PROPOSAL_SENDER], + ), + ); + }); + }); +}); diff --git a/simulations/vip-455/unichainmainnet.ts b/simulations/vip-455/unichainmainnet.ts new file mode 100644 index 000000000..ba5b42794 --- /dev/null +++ b/simulations/vip-455/unichainmainnet.ts @@ -0,0 +1,153 @@ +import { expect } from "chai"; +import { BigNumber, Contract } from "ethers"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; +import { expectEvents, getOmnichainProposalSenderAddress } from "src/utils"; +import { forking, pretendExecutingVip, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip008 from "../../multisig/proposals/unichainmainnet/vip-008"; +import vip455, { + ACM, + ACM_AGGREGATOR, + DEFAULT_ADMIN_ROLE, + OMNICHAIN_EXECUTOR_OWNER, +} from "../../vips/vip-455/bscmainnet"; +import ACMAggregator_ABI from "./abi/ACMAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; +import OMNICHAIN_EXECUTOR_OWNER_ABI from "./abi/OmnichainExecutorOwner_ABI.json"; +import OMNICHAIN_GOVERNANCE_EXECUTOR_ABI from "./abi/OmnichainGovernanceExecutor_ABI.json"; + +const { unichainmainnet } = NETWORK_ADDRESSES; +const FAST_TRACK_TIMELOCK = "0x5F4ec2524A670139b760f95D0986Ef6b9d162989"; +const CRITICAL_TIMELOCK = "0x91A58273EA9B2Cae1f72d431a7cB145aB9A3d1F3"; + +forking(8697951, async () => { + const provider = ethers.provider; + let lastProposalReceived: BigNumber; + let executor: Contract; + let executorOwner: Contract; + + before(async () => { + executor = new ethers.Contract( + unichainmainnet.OMNICHAIN_GOVERNANCE_EXECUTOR, + OMNICHAIN_GOVERNANCE_EXECUTOR_ABI, + provider, + ); + executorOwner = new ethers.Contract(OMNICHAIN_EXECUTOR_OWNER, OMNICHAIN_EXECUTOR_OWNER_ABI, provider); + lastProposalReceived = await executor.lastProposalReceived(); + await pretendExecutingVip(await vip008()); + }); + + describe("Pre-VIP behaviour", async () => { + it("Normal Timelock has default admin role on unichainmainnet", async () => { + const acm = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, ACM); + const hasRole = await acm.hasRole(DEFAULT_ADMIN_ROLE, unichainmainnet.NORMAL_TIMELOCK); + expect(hasRole).equals(true); + }); + }); + + testForkedNetworkVipCommands("vip455 configures bridge", await vip455(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [223]); + await expectEvents(txResponse, [ACMAggregator_ABI], ["GrantPermissionsExecuted"], [2]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [50]); + await expectEvents(txResponse, [ACMAggregator_ABI], ["RevokePermissionsExecuted"], [1]); + }, + }); + + describe("Post-VIP behaviour", async () => { + const acm = new ethers.Contract(ACM, ACCESS_CONTROL_MANAGER_ABI, provider); + + it("Proposal id should be incremented", async () => { + expect(await executor.lastProposalReceived()).to.be.equals(lastProposalReceived.add(1)); + }); + it("proposal should be executed", async () => { + const pId = await executor.lastProposalReceived(); + expect(await executor.state(pId)).to.be.equals(2); + }); + it("check configuration", async () => { + // Check Timelock configurations + expect(await executor.proposalTimelocks(0)).equals(unichainmainnet.NORMAL_TIMELOCK); + expect(await executor.proposalTimelocks(1)).equals(FAST_TRACK_TIMELOCK); + expect(await executor.proposalTimelocks(2)).equals(CRITICAL_TIMELOCK); + + // Check trusted remote + expect(await executor.trustedRemoteLookup(LzChainId.bscmainnet)).equals( + ethers.utils.solidityPack( + ["address", "address"], + [getOmnichainProposalSenderAddress(), unichainmainnet.OMNICHAIN_GOVERNANCE_EXECUTOR], + ), + ); + + // Check receiving limit + expect(await executor.maxDailyReceiveLimit()).equals(100); + expect(await executor.last24HourCommandsReceived()).equals(6); + + // Check function registry + const functionSignatures: string[] = [ + "forceResumeReceive(uint16,bytes)", + "pause()", + "unpause()", + "setSendVersion(uint16)", + "setReceiveVersion(uint16)", + "setMaxDailyReceiveLimit(uint256)", + "setTrustedRemoteAddress(uint16,bytes)", + "setPrecrime(address)", + "setMinDstGas(uint16,uint16,uint256)", + "setPayloadSizeLimit(uint16,uint256)", + "setConfig(uint16,uint16,uint256,bytes)", + "addTimelocks(ITimelock[])", + "setTimelockPendingAdmin(address,uint8)", + "retryMessage(uint16,bytes,uint64,bytes)", + "setGuardian(address)", + "setSrcChainId(uint16)", + ]; + const getFunctionSelector = (signature: string): string => { + return ethers.utils.keccak256(ethers.utils.toUtf8Bytes(signature)).substring(0, 10); + }; + + for (const signature of functionSignatures) { + const selector = getFunctionSelector(signature); + expect(await executorOwner.functionRegistry(selector)).equals(signature); + } + }); + it("Default admin role must be revoked from ACMAggregator contract on unichain mainnet", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR)).to.be.false; + }); + it("Guardian and all timelocks are allowed to call retryMessage ", async () => { + const role = ethers.utils.solidityPack( + ["address", "string"], + [OMNICHAIN_EXECUTOR_OWNER, "retryMessage(uint16,bytes,uint64,bytes)"], + ); + const roleHash = ethers.utils.keccak256(role); + expect(await acm.hasRole(roleHash, unichainmainnet.GUARDIAN)).to.be.true; + expect(await acm.hasRole(roleHash, unichainmainnet.NORMAL_TIMELOCK)).to.be.true; + expect(await acm.hasRole(roleHash, FAST_TRACK_TIMELOCK)).to.be.true; + expect(await acm.hasRole(roleHash, CRITICAL_TIMELOCK)).to.be.true; + }); + + it("Guardian is allowed to call forceResumeReceive but not timelocks", async () => { + const role = ethers.utils.solidityPack( + ["address", "string"], + [OMNICHAIN_EXECUTOR_OWNER, "forceResumeReceive(uint16,bytes)"], + ); + const roleHash = ethers.utils.keccak256(role); + expect(await acm.hasRole(roleHash, unichainmainnet.GUARDIAN)).to.be.true; + expect(await acm.hasRole(roleHash, unichainmainnet.NORMAL_TIMELOCK)).to.be.false; + expect(await acm.hasRole(roleHash, FAST_TRACK_TIMELOCK)).to.be.false; + expect(await acm.hasRole(roleHash, CRITICAL_TIMELOCK)).to.be.false; + }); + it("Normal Timelock is allowed to call setSendVersion but not other timelocks and guardian", async () => { + const role = ethers.utils.solidityPack( + ["address", "string"], + [OMNICHAIN_EXECUTOR_OWNER, "setSendVersion(uint16)"], + ); + const roleHash = ethers.utils.keccak256(role); + expect(await acm.hasRole(roleHash, unichainmainnet.GUARDIAN)).to.be.false; + expect(await acm.hasRole(roleHash, unichainmainnet.NORMAL_TIMELOCK)).to.be.true; + expect(await acm.hasRole(roleHash, FAST_TRACK_TIMELOCK)).to.be.false; + expect(await acm.hasRole(roleHash, CRITICAL_TIMELOCK)).to.be.false; + }); + }); +}); diff --git a/simulations/vip-455/unichainsepolia.ts b/simulations/vip-455/unichainsepolia.ts index c24520a82..8308f7ca8 100644 --- a/simulations/vip-455/unichainsepolia.ts +++ b/simulations/vip-455/unichainsepolia.ts @@ -49,7 +49,7 @@ forking(12517026, async () => { testForkedNetworkVipCommands("vip455 configures bridge", await vip455(), { callbackAfterExecution: async txResponse => { - await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [233]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [223]); await expectEvents(txResponse, [ACMAggregator_ABI], ["GrantPermissionsExecuted"], [2]); await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionRevoked"], [50]); await expectEvents(txResponse, [ACMAggregator_ABI], ["RevokePermissionsExecuted"], [1]); diff --git a/src/networkAddresses.ts b/src/networkAddresses.ts index 082b5e277..d38395aef 100644 --- a/src/networkAddresses.ts +++ b/src/networkAddresses.ts @@ -272,8 +272,11 @@ export const NETWORK_ADDRESSES = { ENDPOINT: "0x012f6eaE2A0Bf5916f48b5F37C62Bcfb7C1ffdA1", }, unichainmainnet: { - NORMAL_TIMELOCK: "", // To be deployed + NORMAL_TIMELOCK: "0xCb04dc78c99E20724023e5265fE177aa532E8164", VTREASURY: "0x958F4C84d3ad523Fa9936Dc465A123C7AD43D69B", GUARDIAN: "0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C", + OMNICHAIN_GOVERNANCE_EXECUTOR: "0x07F769044eC16e39c3AD3fE182A44334d6B1193a", + LZ_LIBRARY: "0x38dE71124f7a447a01D67945a51eDcE9FF491251", + ENDPOINT: "0xb6319cC6c8c27A8F5dAF0dD3DF91EA35C4720dd7", }, }; diff --git a/src/types.ts b/src/types.ts index f1be36bd3..495f1d78d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -33,6 +33,7 @@ export const REMOTE_MAINNET_NETWORKS = [ "zksyncmainnet", "opmainnet", "basemainnet", + "unichainmainnet", ]; export interface ProposalMeta { @@ -97,4 +98,5 @@ export enum LzChainId { basesepolia = 10245, basemainnet = 184, unichainsepolia = 10333, + unichainmainnet = 320, } diff --git a/src/vip-framework/index.ts b/src/vip-framework/index.ts index 5763eeaa3..c6217c9e0 100644 --- a/src/vip-framework/index.ts +++ b/src/vip-framework/index.ts @@ -262,7 +262,15 @@ export const testForkedNetworkVipCommands = (description: string, proposal: Prop // Sometimes the gas estimation is wrong with some networks like zksync txnParams.maxFeePerGas = feeData.maxFeePerGas.mul(15).div(10); } - + console.log( + srcChainId, + srcAddress, + OMNICHAIN_GOVERNANCE_EXECUTOR, + inboundNonce.add(1), + gasLimit, + ethers.utils.defaultAbiCoder.encode(["bytes", "uint256"], [payload, proposalId]), + txnParams, + ); await endpoint .connect(impersonatedLibrary) .receivePayload( diff --git a/vips/vip-455/bscmainnet.ts b/vips/vip-455/bscmainnet.ts new file mode 100644 index 000000000..d47936082 --- /dev/null +++ b/vips/vip-455/bscmainnet.ts @@ -0,0 +1,76 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +const { unichainmainnet } = NETWORK_ADDRESSES; +export const OMNICHAIN_PROPOSAL_SENDER = "0x36a69dE601381be7b0DcAc5D5dD058825505F8f6"; + +export const OMNICHAIN_EXECUTOR_OWNER = "0x65df5ba2Fa1F7A5bBDee1789bFd29b593108D15F"; +export const ACM = "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0"; +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; +export const ACM_AGGREGATOR = "0x904D11b00bdB2740d16176cc00DE139d0d626115"; +export const MAX_DAILY_LIMIT = 100; + +const vip455 = () => { + const meta = { + version: "v2", + title: "VIP-455 Enable Multichain Governance on unichain mainnet", + 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: OMNICHAIN_PROPOSAL_SENDER, + signature: "setMaxDailyLimit(uint16,uint256)", + params: [LzChainId.unichainmainnet, MAX_DAILY_LIMIT], + }, + { + target: OMNICHAIN_PROPOSAL_SENDER, + signature: "setTrustedRemoteAddress(uint16,bytes)", + params: [LzChainId.unichainmainnet, unichainmainnet.OMNICHAIN_GOVERNANCE_EXECUTOR], + }, + { + target: OMNICHAIN_EXECUTOR_OWNER, + signature: "acceptOwnership()", + params: [], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [0], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [1], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [0], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.unichainmainnet, + }, + ], + meta, + ProposalType.REGULAR, + ); +}; +export default vip455; From a495475319f55b5f9c88b016e626b0f939cdfca9 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Thu, 13 Feb 2025 17:40:17 +0530 Subject: [PATCH 3/6] fix: lint --- src/types.ts | 3 ++- src/vip-framework/index.ts | 9 --------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/types.ts b/src/types.ts index 495f1d78d..6119f2a5e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,7 +13,8 @@ export type SUPPORTED_NETWORKS = | "opmainnet" | "basesepolia" | "basemainnet" - | "unichainsepolia"; + | "unichainsepolia" + | "unichainmainnet"; export type REMOTE_NETWORKS = Exclude; diff --git a/src/vip-framework/index.ts b/src/vip-framework/index.ts index c6217c9e0..2e28a3029 100644 --- a/src/vip-framework/index.ts +++ b/src/vip-framework/index.ts @@ -262,15 +262,6 @@ export const testForkedNetworkVipCommands = (description: string, proposal: Prop // Sometimes the gas estimation is wrong with some networks like zksync txnParams.maxFeePerGas = feeData.maxFeePerGas.mul(15).div(10); } - console.log( - srcChainId, - srcAddress, - OMNICHAIN_GOVERNANCE_EXECUTOR, - inboundNonce.add(1), - gasLimit, - ethers.utils.defaultAbiCoder.encode(["bytes", "uint256"], [payload, proposalId]), - txnParams, - ); await endpoint .connect(impersonatedLibrary) .receivePayload( From 992f8f837751f08cc6087a6c390daaa2905d4e45 Mon Sep 17 00:00:00 2001 From: Jesus Lanchas Date: Tue, 18 Feb 2025 13:38:53 +0100 Subject: [PATCH 4/6] chore: typo --- simulations/vip-455/unichainsepolia.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simulations/vip-455/unichainsepolia.ts b/simulations/vip-455/unichainsepolia.ts index 8308f7ca8..642075e4c 100644 --- a/simulations/vip-455/unichainsepolia.ts +++ b/simulations/vip-455/unichainsepolia.ts @@ -40,7 +40,7 @@ forking(12517026, async () => { }); describe("Pre-VIP behaviour", async () => { - it("Normal Timelock has default admin role on base sepolia", async () => { + it("Normal Timelock has default admin role on unichain sepolia", async () => { const acm = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, ACM); const hasRole = await acm.hasRole(DEFAULT_ADMIN_ROLE, unichainsepolia.NORMAL_TIMELOCK); expect(hasRole).equals(true); @@ -112,7 +112,7 @@ forking(12517026, async () => { expect(await executorOwner.functionRegistry(selector)).equals(signature); } }); - it("Default admin role must be revoked from ACMAggregator contract on base sepolia", async () => { + it("Default admin role must be revoked from ACMAggregator contract on unichain sepolia", async () => { expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR)).to.be.false; }); it("Guardian and all timelocks are allowed to call retryMessage ", async () => { From cb9dd66d4ec192b2b4dc5d44d23602d0d99b86fe Mon Sep 17 00:00:00 2001 From: GitGuru7 <128375421+GitGuru7@users.noreply.github.com> Date: Tue, 18 Feb 2025 22:16:02 +0530 Subject: [PATCH 5/6] fix: update omnichain executor and timelock addresses --- multisig/simulations/unichainmainnet/vip-008/index.ts | 2 +- simulations/vip-455/bscmainnet.ts | 2 +- simulations/vip-455/unichainmainnet.ts | 6 +++--- src/networkAddresses.ts | 4 ++-- vips/vip-455/bscmainnet.ts | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/multisig/simulations/unichainmainnet/vip-008/index.ts b/multisig/simulations/unichainmainnet/vip-008/index.ts index c6f37841f..e5951610d 100644 --- a/multisig/simulations/unichainmainnet/vip-008/index.ts +++ b/multisig/simulations/unichainmainnet/vip-008/index.ts @@ -9,7 +9,7 @@ import ACM_ABI from "./abi/AccessControlManager.json"; const { unichainmainnet } = NETWORK_ADDRESSES; -forking(8697951, async () => { +forking(9147076, async () => { let acm: Contract; let defaultAdminRole: string; diff --git a/simulations/vip-455/bscmainnet.ts b/simulations/vip-455/bscmainnet.ts index e0ba7e431..db8971f0a 100644 --- a/simulations/vip-455/bscmainnet.ts +++ b/simulations/vip-455/bscmainnet.ts @@ -10,7 +10,7 @@ import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; import OMNICHAIN_PROPOSAL_SENDER_ABI from "./abi/OmnichainProposalSender.json"; const { unichainmainnet } = NETWORK_ADDRESSES; -forking(46621583, async () => { +forking(46771559, async () => { const provider = ethers.provider; const omnichainProposalSender = new ethers.Contract( OMNICHAIN_PROPOSAL_SENDER, diff --git a/simulations/vip-455/unichainmainnet.ts b/simulations/vip-455/unichainmainnet.ts index ba5b42794..b14294488 100644 --- a/simulations/vip-455/unichainmainnet.ts +++ b/simulations/vip-455/unichainmainnet.ts @@ -19,10 +19,10 @@ import OMNICHAIN_EXECUTOR_OWNER_ABI from "./abi/OmnichainExecutorOwner_ABI.json" import OMNICHAIN_GOVERNANCE_EXECUTOR_ABI from "./abi/OmnichainGovernanceExecutor_ABI.json"; const { unichainmainnet } = NETWORK_ADDRESSES; -const FAST_TRACK_TIMELOCK = "0x5F4ec2524A670139b760f95D0986Ef6b9d162989"; -const CRITICAL_TIMELOCK = "0x91A58273EA9B2Cae1f72d431a7cB145aB9A3d1F3"; +const FAST_TRACK_TIMELOCK = "0x4121995b87f9EE8bA0a89e87470255e2E0fe48c7"; +const CRITICAL_TIMELOCK = "0x1b05eCb489842786776a9A10e91AAb56e2CFe15e"; -forking(8697951, async () => { +forking(9147076, async () => { const provider = ethers.provider; let lastProposalReceived: BigNumber; let executor: Contract; diff --git a/src/networkAddresses.ts b/src/networkAddresses.ts index d402b0a5f..8ba5c68cb 100644 --- a/src/networkAddresses.ts +++ b/src/networkAddresses.ts @@ -273,7 +273,7 @@ export const NETWORK_ADDRESSES = { ENDPOINT: "0x012f6eaE2A0Bf5916f48b5F37C62Bcfb7C1ffdA1", }, unichainmainnet: { - NORMAL_TIMELOCK: "0xCb04dc78c99E20724023e5265fE177aa532E8164", + NORMAL_TIMELOCK: "0x918532A78d22419Da4091930d472bDdf532BE89a", VTREASURY: "0x958F4C84d3ad523Fa9936Dc465A123C7AD43D69B", GUARDIAN: "0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C", POOL_REGISTRY: "0x0C52403E16BcB8007C1e54887E1dFC1eC9765D7C", @@ -282,7 +282,7 @@ export const NETWORK_ADDRESSES = { XVS_VAULT_PROXY: "0x5ECa0FBBc5e7bf49dbFb1953a92784F8e4248eF6", XVS: "0x81908BBaad3f6fC74093540Ab2E9B749BB62aA0d", GENERIC_TEST_USER_ACCOUNT: "0x6f057A858171e187124ddEDF034dAc63De5dE5dB", - OMNICHAIN_GOVERNANCE_EXECUTOR: "0x07F769044eC16e39c3AD3fE182A44334d6B1193a", + OMNICHAIN_GOVERNANCE_EXECUTOR: "0x3E281461efb3D53EC20DB207674373Ed8Ef3BbA9", LZ_LIBRARY: "0x38dE71124f7a447a01D67945a51eDcE9FF491251", ENDPOINT: "0xb6319cC6c8c27A8F5dAF0dD3DF91EA35C4720dd7", }, diff --git a/vips/vip-455/bscmainnet.ts b/vips/vip-455/bscmainnet.ts index d47936082..5a84a9f6e 100644 --- a/vips/vip-455/bscmainnet.ts +++ b/vips/vip-455/bscmainnet.ts @@ -5,7 +5,7 @@ import { makeProposal } from "src/utils"; const { unichainmainnet } = NETWORK_ADDRESSES; export const OMNICHAIN_PROPOSAL_SENDER = "0x36a69dE601381be7b0DcAc5D5dD058825505F8f6"; -export const OMNICHAIN_EXECUTOR_OWNER = "0x65df5ba2Fa1F7A5bBDee1789bFd29b593108D15F"; +export const OMNICHAIN_EXECUTOR_OWNER = "0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd"; export const ACM = "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0"; export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; export const ACM_AGGREGATOR = "0x904D11b00bdB2740d16176cc00DE139d0d626115"; @@ -47,19 +47,19 @@ const vip455 = () => { { target: ACM_AGGREGATOR, signature: "executeGrantPermissions(uint256)", - params: [0], + params: [2], dstChainId: LzChainId.unichainmainnet, }, { target: ACM_AGGREGATOR, signature: "executeGrantPermissions(uint256)", - params: [1], + params: [3], dstChainId: LzChainId.unichainmainnet, }, { target: ACM_AGGREGATOR, signature: "executeRevokePermissions(uint256)", - params: [0], + params: [1], dstChainId: LzChainId.unichainmainnet, }, { From 2edfb7811c026a24ac0a7a8b76fe1b7577e8a537 Mon Sep 17 00:00:00 2001 From: Jesus Lanchas Date: Wed, 19 Feb 2025 17:16:10 +0100 Subject: [PATCH 6/6] feat: set ID and description for VIP 456 --- .../{vip-008 => vip-009}/index.ts | 4 +- .../{vip-008 => vip-009}/index.ts | 4 +- .../abi/AccessControlManager.json | 0 .../{vip-008 => vip-009}/index.ts | 4 +- .../abi/AccessControlManager.json | 0 .../{vip-008 => vip-009}/index.ts | 4 +- .../abi/ACMAggregator.json | 0 .../abi/AccessControlManager_ABI.json | 0 .../{vip-455 => vip-456}/abi/ERC20.json | 0 .../abi/OmnichainExecutorOwner_ABI.json | 0 .../abi/OmnichainGovernanceExecutor_ABI.json | 0 .../abi/OmnichainProposalSender.json | 0 .../abi/VtreasuryAbi.json | 0 .../{vip-455 => vip-456}/bscmainnet.ts | 4 +- .../{vip-455 => vip-456}/bsctestnet.ts | 4 +- .../{vip-455 => vip-456}/unichainmainnet.ts | 10 +- .../{vip-455 => vip-456}/unichainsepolia.ts | 10 +- vips/vip-455/bscmainnet.ts | 76 ----------- vips/vip-456/bscmainnet.ts | 120 ++++++++++++++++++ vips/{vip-455 => vip-456}/bsctestnet.ts | 6 +- 20 files changed, 145 insertions(+), 101 deletions(-) rename multisig/proposals/unichainmainnet/{vip-008 => vip-009}/index.ts (90%) rename multisig/proposals/unichainsepolia/{vip-008 => vip-009}/index.ts (90%) rename multisig/simulations/unichainmainnet/{vip-008 => vip-009}/abi/AccessControlManager.json (100%) rename multisig/simulations/unichainmainnet/{vip-008 => vip-009}/index.ts (90%) rename multisig/simulations/unichainsepolia/{vip-008 => vip-009}/abi/AccessControlManager.json (100%) rename multisig/simulations/unichainsepolia/{vip-008 => vip-009}/index.ts (90%) rename simulations/{vip-455 => vip-456}/abi/ACMAggregator.json (100%) rename simulations/{vip-455 => vip-456}/abi/AccessControlManager_ABI.json (100%) rename simulations/{vip-455 => vip-456}/abi/ERC20.json (100%) rename simulations/{vip-455 => vip-456}/abi/OmnichainExecutorOwner_ABI.json (100%) rename simulations/{vip-455 => vip-456}/abi/OmnichainGovernanceExecutor_ABI.json (100%) rename simulations/{vip-455 => vip-456}/abi/OmnichainProposalSender.json (100%) rename simulations/{vip-455 => vip-456}/abi/VtreasuryAbi.json (100%) rename simulations/{vip-455 => vip-456}/bscmainnet.ts (92%) rename simulations/{vip-455 => vip-456}/bsctestnet.ts (92%) rename simulations/{vip-455 => vip-456}/unichainmainnet.ts (96%) rename simulations/{vip-455 => vip-456}/unichainsepolia.ts (96%) delete mode 100644 vips/vip-455/bscmainnet.ts create mode 100644 vips/vip-456/bscmainnet.ts rename vips/{vip-455 => vip-456}/bsctestnet.ts (95%) diff --git a/multisig/proposals/unichainmainnet/vip-008/index.ts b/multisig/proposals/unichainmainnet/vip-009/index.ts similarity index 90% rename from multisig/proposals/unichainmainnet/vip-008/index.ts rename to multisig/proposals/unichainmainnet/vip-009/index.ts index 938ea7f84..703b08b17 100644 --- a/multisig/proposals/unichainmainnet/vip-008/index.ts +++ b/multisig/proposals/unichainmainnet/vip-009/index.ts @@ -7,7 +7,7 @@ const { unichainmainnet } = NETWORK_ADDRESSES; export const ACM = "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0"; const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; -export const vip008 = () => { +export const vip009 = () => { return makeProposal([ { target: ACM, @@ -16,4 +16,4 @@ export const vip008 = () => { }, ]); }; -export default vip008; +export default vip009; diff --git a/multisig/proposals/unichainsepolia/vip-008/index.ts b/multisig/proposals/unichainsepolia/vip-009/index.ts similarity index 90% rename from multisig/proposals/unichainsepolia/vip-008/index.ts rename to multisig/proposals/unichainsepolia/vip-009/index.ts index a3859f8ec..4cd297f74 100644 --- a/multisig/proposals/unichainsepolia/vip-008/index.ts +++ b/multisig/proposals/unichainsepolia/vip-009/index.ts @@ -7,7 +7,7 @@ const { unichainsepolia } = NETWORK_ADDRESSES; export const ACM = "0x854C064EA6b503A97980F481FA3B7279012fdeDd"; const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; -export const vip008 = () => { +export const vip009 = () => { return makeProposal([ { target: ACM, @@ -16,4 +16,4 @@ export const vip008 = () => { }, ]); }; -export default vip008; +export default vip009; diff --git a/multisig/simulations/unichainmainnet/vip-008/abi/AccessControlManager.json b/multisig/simulations/unichainmainnet/vip-009/abi/AccessControlManager.json similarity index 100% rename from multisig/simulations/unichainmainnet/vip-008/abi/AccessControlManager.json rename to multisig/simulations/unichainmainnet/vip-009/abi/AccessControlManager.json diff --git a/multisig/simulations/unichainmainnet/vip-008/index.ts b/multisig/simulations/unichainmainnet/vip-009/index.ts similarity index 90% rename from multisig/simulations/unichainmainnet/vip-008/index.ts rename to multisig/simulations/unichainmainnet/vip-009/index.ts index e5951610d..d5abdd821 100644 --- a/multisig/simulations/unichainmainnet/vip-008/index.ts +++ b/multisig/simulations/unichainmainnet/vip-009/index.ts @@ -4,7 +4,7 @@ import { ethers } from "hardhat"; import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { forking, pretendExecutingVip } from "src/vip-framework/index"; -import vip008, { ACM } from "../../../proposals/unichainmainnet/vip-008"; +import vip009, { ACM } from "../../../proposals/unichainmainnet/vip-009"; import ACM_ABI from "./abi/AccessControlManager.json"; const { unichainmainnet } = NETWORK_ADDRESSES; @@ -27,7 +27,7 @@ forking(9147076, async () => { describe("Post-VIP behavior", async () => { before(async () => { - await pretendExecutingVip(await vip008()); + await pretendExecutingVip(await vip009()); }); it("Normal Timelock has default admin role", async () => { diff --git a/multisig/simulations/unichainsepolia/vip-008/abi/AccessControlManager.json b/multisig/simulations/unichainsepolia/vip-009/abi/AccessControlManager.json similarity index 100% rename from multisig/simulations/unichainsepolia/vip-008/abi/AccessControlManager.json rename to multisig/simulations/unichainsepolia/vip-009/abi/AccessControlManager.json diff --git a/multisig/simulations/unichainsepolia/vip-008/index.ts b/multisig/simulations/unichainsepolia/vip-009/index.ts similarity index 90% rename from multisig/simulations/unichainsepolia/vip-008/index.ts rename to multisig/simulations/unichainsepolia/vip-009/index.ts index 4f183b93a..6ca862550 100644 --- a/multisig/simulations/unichainsepolia/vip-008/index.ts +++ b/multisig/simulations/unichainsepolia/vip-009/index.ts @@ -4,7 +4,7 @@ import { ethers } from "hardhat"; import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { forking, pretendExecutingVip } from "src/vip-framework/index"; -import vip008, { ACM } from "../../../proposals/unichainsepolia/vip-008"; +import vip009, { ACM } from "../../../proposals/unichainsepolia/vip-009"; import ACM_ABI from "./abi/AccessControlManager.json"; const { unichainsepolia } = NETWORK_ADDRESSES; @@ -27,7 +27,7 @@ forking(12516535, async () => { describe("Post-VIP behavior", async () => { before(async () => { - await pretendExecutingVip(await vip008()); + await pretendExecutingVip(await vip009()); }); it("Normal Timelock has default admin role", async () => { diff --git a/simulations/vip-455/abi/ACMAggregator.json b/simulations/vip-456/abi/ACMAggregator.json similarity index 100% rename from simulations/vip-455/abi/ACMAggregator.json rename to simulations/vip-456/abi/ACMAggregator.json diff --git a/simulations/vip-455/abi/AccessControlManager_ABI.json b/simulations/vip-456/abi/AccessControlManager_ABI.json similarity index 100% rename from simulations/vip-455/abi/AccessControlManager_ABI.json rename to simulations/vip-456/abi/AccessControlManager_ABI.json diff --git a/simulations/vip-455/abi/ERC20.json b/simulations/vip-456/abi/ERC20.json similarity index 100% rename from simulations/vip-455/abi/ERC20.json rename to simulations/vip-456/abi/ERC20.json diff --git a/simulations/vip-455/abi/OmnichainExecutorOwner_ABI.json b/simulations/vip-456/abi/OmnichainExecutorOwner_ABI.json similarity index 100% rename from simulations/vip-455/abi/OmnichainExecutorOwner_ABI.json rename to simulations/vip-456/abi/OmnichainExecutorOwner_ABI.json diff --git a/simulations/vip-455/abi/OmnichainGovernanceExecutor_ABI.json b/simulations/vip-456/abi/OmnichainGovernanceExecutor_ABI.json similarity index 100% rename from simulations/vip-455/abi/OmnichainGovernanceExecutor_ABI.json rename to simulations/vip-456/abi/OmnichainGovernanceExecutor_ABI.json diff --git a/simulations/vip-455/abi/OmnichainProposalSender.json b/simulations/vip-456/abi/OmnichainProposalSender.json similarity index 100% rename from simulations/vip-455/abi/OmnichainProposalSender.json rename to simulations/vip-456/abi/OmnichainProposalSender.json diff --git a/simulations/vip-455/abi/VtreasuryAbi.json b/simulations/vip-456/abi/VtreasuryAbi.json similarity index 100% rename from simulations/vip-455/abi/VtreasuryAbi.json rename to simulations/vip-456/abi/VtreasuryAbi.json diff --git a/simulations/vip-455/bscmainnet.ts b/simulations/vip-456/bscmainnet.ts similarity index 92% rename from simulations/vip-455/bscmainnet.ts rename to simulations/vip-456/bscmainnet.ts index db8971f0a..3235f11bc 100644 --- a/simulations/vip-455/bscmainnet.ts +++ b/simulations/vip-456/bscmainnet.ts @@ -5,7 +5,7 @@ import { LzChainId } from "src/types"; import { expectEvents } from "src/utils"; import { forking, testVip } from "src/vip-framework"; -import vip455, { MAX_DAILY_LIMIT, OMNICHAIN_PROPOSAL_SENDER } from "../../vips/vip-455/bscmainnet"; +import vip456, { MAX_DAILY_LIMIT, OMNICHAIN_PROPOSAL_SENDER } from "../../vips/vip-456/bscmainnet"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; import OMNICHAIN_PROPOSAL_SENDER_ABI from "./abi/OmnichainProposalSender.json"; @@ -27,7 +27,7 @@ forking(46771559, async () => { }); }); - testVip("vip455 give permissions to timelock", await vip455(), { + testVip("vip456 give permissions to timelock", await vip456(), { callbackAfterExecution: async txResponse => { await expectEvents( txResponse, diff --git a/simulations/vip-455/bsctestnet.ts b/simulations/vip-456/bsctestnet.ts similarity index 92% rename from simulations/vip-455/bsctestnet.ts rename to simulations/vip-456/bsctestnet.ts index a6ab33100..4c69dc305 100644 --- a/simulations/vip-455/bsctestnet.ts +++ b/simulations/vip-456/bsctestnet.ts @@ -5,7 +5,7 @@ import { LzChainId } from "src/types"; import { expectEvents } from "src/utils"; import { forking, testVip } from "src/vip-framework"; -import vip455, { MAX_DAILY_LIMIT, OMNICHAIN_PROPOSAL_SENDER } from "../../vips/vip-455/bsctestnet"; +import vip456, { MAX_DAILY_LIMIT, OMNICHAIN_PROPOSAL_SENDER } from "../../vips/vip-456/bsctestnet"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; import OMNICHAIN_PROPOSAL_SENDER_ABI from "./abi/OmnichainProposalSender.json"; @@ -27,7 +27,7 @@ forking(48215809, async () => { }); }); - testVip("vip455 give permissions to timelock", await vip455(), { + testVip("vip456 give permissions to timelock", await vip456(), { callbackAfterExecution: async txResponse => { await expectEvents( txResponse, diff --git a/simulations/vip-455/unichainmainnet.ts b/simulations/vip-456/unichainmainnet.ts similarity index 96% rename from simulations/vip-455/unichainmainnet.ts rename to simulations/vip-456/unichainmainnet.ts index b14294488..fc6225301 100644 --- a/simulations/vip-455/unichainmainnet.ts +++ b/simulations/vip-456/unichainmainnet.ts @@ -6,13 +6,13 @@ import { LzChainId } from "src/types"; import { expectEvents, getOmnichainProposalSenderAddress } from "src/utils"; import { forking, pretendExecutingVip, testForkedNetworkVipCommands } from "src/vip-framework"; -import vip008 from "../../multisig/proposals/unichainmainnet/vip-008"; -import vip455, { +import vip009 from "../../multisig/proposals/unichainmainnet/vip-009"; +import vip456, { ACM, ACM_AGGREGATOR, DEFAULT_ADMIN_ROLE, OMNICHAIN_EXECUTOR_OWNER, -} from "../../vips/vip-455/bscmainnet"; +} from "../../vips/vip-456/bscmainnet"; import ACMAggregator_ABI from "./abi/ACMAggregator.json"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; import OMNICHAIN_EXECUTOR_OWNER_ABI from "./abi/OmnichainExecutorOwner_ABI.json"; @@ -36,7 +36,7 @@ forking(9147076, async () => { ); executorOwner = new ethers.Contract(OMNICHAIN_EXECUTOR_OWNER, OMNICHAIN_EXECUTOR_OWNER_ABI, provider); lastProposalReceived = await executor.lastProposalReceived(); - await pretendExecutingVip(await vip008()); + await pretendExecutingVip(await vip009()); }); describe("Pre-VIP behaviour", async () => { @@ -47,7 +47,7 @@ forking(9147076, async () => { }); }); - testForkedNetworkVipCommands("vip455 configures bridge", await vip455(), { + testForkedNetworkVipCommands("vip456 configures bridge", await vip456(), { callbackAfterExecution: async txResponse => { await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [223]); await expectEvents(txResponse, [ACMAggregator_ABI], ["GrantPermissionsExecuted"], [2]); diff --git a/simulations/vip-455/unichainsepolia.ts b/simulations/vip-456/unichainsepolia.ts similarity index 96% rename from simulations/vip-455/unichainsepolia.ts rename to simulations/vip-456/unichainsepolia.ts index 642075e4c..151fad60d 100644 --- a/simulations/vip-455/unichainsepolia.ts +++ b/simulations/vip-456/unichainsepolia.ts @@ -6,13 +6,13 @@ import { LzChainId } from "src/types"; import { expectEvents, getOmnichainProposalSenderAddress } from "src/utils"; import { forking, pretendExecutingVip, testForkedNetworkVipCommands } from "src/vip-framework"; -import vip008 from "../../multisig/proposals/unichainsepolia/vip-008"; -import vip455, { +import vip009 from "../../multisig/proposals/unichainsepolia/vip-009"; +import vip456, { ACM, ACM_AGGREGATOR, DEFAULT_ADMIN_ROLE, OMNICHAIN_EXECUTOR_OWNER, -} from "../../vips/vip-455/bsctestnet"; +} from "../../vips/vip-456/bsctestnet"; import ACMAggregator_ABI from "./abi/ACMAggregator.json"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; import OMNICHAIN_EXECUTOR_OWNER_ABI from "./abi/OmnichainExecutorOwner_ABI.json"; @@ -36,7 +36,7 @@ forking(12517026, async () => { ); executorOwner = new ethers.Contract(OMNICHAIN_EXECUTOR_OWNER, OMNICHAIN_EXECUTOR_OWNER_ABI, provider); lastProposalReceived = await executor.lastProposalReceived(); - await pretendExecutingVip(await vip008()); + await pretendExecutingVip(await vip009()); }); describe("Pre-VIP behaviour", async () => { @@ -47,7 +47,7 @@ forking(12517026, async () => { }); }); - testForkedNetworkVipCommands("vip455 configures bridge", await vip455(), { + testForkedNetworkVipCommands("vip456 configures bridge", await vip456(), { callbackAfterExecution: async txResponse => { await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [223]); await expectEvents(txResponse, [ACMAggregator_ABI], ["GrantPermissionsExecuted"], [2]); diff --git a/vips/vip-455/bscmainnet.ts b/vips/vip-455/bscmainnet.ts deleted file mode 100644 index 5a84a9f6e..000000000 --- a/vips/vip-455/bscmainnet.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { NETWORK_ADDRESSES } from "src/networkAddresses"; -import { LzChainId, ProposalType } from "src/types"; -import { makeProposal } from "src/utils"; - -const { unichainmainnet } = NETWORK_ADDRESSES; -export const OMNICHAIN_PROPOSAL_SENDER = "0x36a69dE601381be7b0DcAc5D5dD058825505F8f6"; - -export const OMNICHAIN_EXECUTOR_OWNER = "0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd"; -export const ACM = "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0"; -export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; -export const ACM_AGGREGATOR = "0x904D11b00bdB2740d16176cc00DE139d0d626115"; -export const MAX_DAILY_LIMIT = 100; - -const vip455 = () => { - const meta = { - version: "v2", - title: "VIP-455 Enable Multichain Governance on unichain mainnet", - 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: OMNICHAIN_PROPOSAL_SENDER, - signature: "setMaxDailyLimit(uint16,uint256)", - params: [LzChainId.unichainmainnet, MAX_DAILY_LIMIT], - }, - { - target: OMNICHAIN_PROPOSAL_SENDER, - signature: "setTrustedRemoteAddress(uint16,bytes)", - params: [LzChainId.unichainmainnet, unichainmainnet.OMNICHAIN_GOVERNANCE_EXECUTOR], - }, - { - target: OMNICHAIN_EXECUTOR_OWNER, - signature: "acceptOwnership()", - params: [], - dstChainId: LzChainId.unichainmainnet, - }, - { - target: ACM, - signature: "grantRole(bytes32,address)", - params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], - dstChainId: LzChainId.unichainmainnet, - }, - { - target: ACM_AGGREGATOR, - signature: "executeGrantPermissions(uint256)", - params: [2], - dstChainId: LzChainId.unichainmainnet, - }, - { - target: ACM_AGGREGATOR, - signature: "executeGrantPermissions(uint256)", - params: [3], - dstChainId: LzChainId.unichainmainnet, - }, - { - target: ACM_AGGREGATOR, - signature: "executeRevokePermissions(uint256)", - params: [1], - dstChainId: LzChainId.unichainmainnet, - }, - { - target: ACM, - signature: "revokeRole(bytes32,address)", - params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], - dstChainId: LzChainId.unichainmainnet, - }, - ], - meta, - ProposalType.REGULAR, - ); -}; -export default vip455; diff --git a/vips/vip-456/bscmainnet.ts b/vips/vip-456/bscmainnet.ts new file mode 100644 index 000000000..75fc3612d --- /dev/null +++ b/vips/vip-456/bscmainnet.ts @@ -0,0 +1,120 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +const { unichainmainnet } = NETWORK_ADDRESSES; +export const OMNICHAIN_PROPOSAL_SENDER = "0x36a69dE601381be7b0DcAc5D5dD058825505F8f6"; + +export const OMNICHAIN_EXECUTOR_OWNER = "0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd"; +export const ACM = "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0"; +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; +export const ACM_AGGREGATOR = "0x904D11b00bdB2740d16176cc00DE139d0d626115"; +export const MAX_DAILY_LIMIT = 100; + +const vip456 = () => { + const meta = { + version: "v2", + title: "VIP-456 [Unichain] Omnichain Governance", + description: `#### Summary + +If passed, this VIP will enable the Omnichain Governance system on the Venus protocol, for Unichain. Omnichain Governance will allow the Venus Community to propose VIP’s on BNB Chain including commands to be executed on Unichain. + +#### Description + +This VIP will grant permissions to [Normal](https://bscscan.com/address/0x939bD8d64c0A9583A7Dcea9933f7b21697ab6396), [Fast-track](https://bscscan.com/address/0x555ba73dB1b006F3f2C7dB7126d6e4343aDBce02) and [Critical](https://bscscan.com/address/0x213c446ec11e45b15a6E29C1C1b402B8897f606d) timelocks on BNB Chain to create remote VIP’s on Unichain. It also performs the necessary configuration of [OmnichainProposalSender](https://bscscan.com/address/0x36a69dE601381be7b0DcAc5D5dD058825505F8f6) on BNB Chain and [OmnichainGovernanceExecutor](https://uniscan.xyz/address/0x3E281461efb3D53EC20DB207674373Ed8Ef3BbA9) on Unichain (set the trustworthiness relationships, configure limits, accept ownerships). + +#### Security and additional considerations + +We applied the following security procedures for this upgrade: + +- **VIP execution simulation**: in a simulation environment, checking ownership of the contracts +- **Deployment on testnet**: the same contracts have been deployed to testnet, and used in the Venus Protocol testnet deployment +- **Audit**: [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. + +#### 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 on Unichain + +- Normal Timelock: [0x918532A78d22419Da4091930d472bDdf532BE89a](https://uniscan.xyz/address/0x918532A78d22419Da4091930d472bDdf532BE89a) +- FastTrack Timelock: [0x4121995b87f9EE8bA0a89e87470255e2E0fe48c7](https://uniscan.xyz/address/0x4121995b87f9EE8bA0a89e87470255e2E0fe48c7) +- Critical Timelock: [0x1b05eCb489842786776a9A10e91AAb56e2CFe15e](https://uniscan.xyz/address/0x1b05eCb489842786776a9A10e91AAb56e2CFe15e) +- Omnichain Governance Executor: [0x3E281461efb3D53EC20DB207674373Ed8Ef3BbA9](https://uniscan.xyz/address/0x3E281461efb3D53EC20DB207674373Ed8Ef3BbA9) +- Omnichain Executor Owner Proxy: [0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd](https://uniscan.xyz/address/0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd) +- ACMCommandsAggregator: [0x904D11b00bdB2740d16176cc00DE139d0d626115](https://uniscan.xyz/address/0x904D11b00bdB2740d16176cc00DE139d0d626115) + +#### References + +- [VIP simulation](https://github.com/VenusProtocol/vips/pull/498) +- [Deploy Venus on Unichain](https://community.venus.io/t/deploy-venus-on-unichain/4859) +- Snapshot ["Deploy Venus on Unichain"](https://snapshot.box/#/s:venus-xvs.eth/proposal/0xbf2fff03c4f84620a8b3ece2e31d879224ee03c42aefc6dc94e9c2b40a5a634b) +- [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/omnichain-governance) +- [Documentation](https://docs-v4.venus.io/) + +#### Disclaimer for Unichain VIPs + +Privilege commands on Unichain will be executed by the [Guardian wallet](https://uniscan.xyz/address/0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C), until the [Omnichain Governance](https://docs-v4.venus.io/technical-reference/reference-technical-articles/omnichain-governance) contracts are fully enabled. If this VIP passes, [this](https://app.safe.global/transactions/tx?safe=unichain:0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C&id=multisig_0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C_0xdf9f020eb83bf3e68d6511c6a4e0ee4ed5f1529b82f7fcd71db27f856ee18ea5) multisig transaction will be executed. Otherwise, it will be rejected.`, + 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: OMNICHAIN_PROPOSAL_SENDER, + signature: "setMaxDailyLimit(uint16,uint256)", + params: [LzChainId.unichainmainnet, MAX_DAILY_LIMIT], + }, + { + target: OMNICHAIN_PROPOSAL_SENDER, + signature: "setTrustedRemoteAddress(uint16,bytes)", + params: [LzChainId.unichainmainnet, unichainmainnet.OMNICHAIN_GOVERNANCE_EXECUTOR], + }, + { + target: OMNICHAIN_EXECUTOR_OWNER, + signature: "acceptOwnership()", + params: [], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [2], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [3], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [1], + dstChainId: LzChainId.unichainmainnet, + }, + { + target: ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.unichainmainnet, + }, + ], + meta, + ProposalType.REGULAR, + ); +}; +export default vip456; diff --git a/vips/vip-455/bsctestnet.ts b/vips/vip-456/bsctestnet.ts similarity index 95% rename from vips/vip-455/bsctestnet.ts rename to vips/vip-456/bsctestnet.ts index 2f8446f63..81e0e83a2 100644 --- a/vips/vip-455/bsctestnet.ts +++ b/vips/vip-456/bsctestnet.ts @@ -11,10 +11,10 @@ export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000 export const ACM_AGGREGATOR = "0xb0067C9CD83B00DE781e9b456Bf0Fec86D687Bb2"; export const MAX_DAILY_LIMIT = 100; -const vip455 = () => { +const vip456 = () => { const meta = { version: "v2", - title: "VIP-455 Enable Multichain Governance on unichain sepolia", + title: "VIP-456 Enable Multichain Governance on unichain sepolia", 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", @@ -73,4 +73,4 @@ const vip455 = () => { ProposalType.REGULAR, ); }; -export default vip455; +export default vip456;