diff --git a/multisig/proposals/basemainnet/vip-006/index.ts b/multisig/proposals/basemainnet/vip-006/index.ts new file mode 100644 index 000000000..3ed62b83b --- /dev/null +++ b/multisig/proposals/basemainnet/vip-006/index.ts @@ -0,0 +1,19 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +import { makeProposal } from "../../../../src/utils"; + +const { basemainnet } = NETWORK_ADDRESSES; + +export const ACM = "0x9E6CeEfDC6183e4D0DF8092A9B90cDF659687daB"; +const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +export const vip006 = () => { + return makeProposal([ + { + target: ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, basemainnet.NORMAL_TIMELOCK], + }, + ]); +}; +export default vip006; diff --git a/multisig/proposals/basesepolia/vip-006/index.ts b/multisig/proposals/basesepolia/vip-006/index.ts new file mode 100644 index 000000000..b6a4f296f --- /dev/null +++ b/multisig/proposals/basesepolia/vip-006/index.ts @@ -0,0 +1,19 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +import { makeProposal } from "../../../../src/utils"; + +const { basesepolia } = NETWORK_ADDRESSES; + +export const ACM = "0x724138223D8F76b519fdE715f60124E7Ce51e051"; +const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +export const vip007 = () => { + return makeProposal([ + { + target: ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, basesepolia.NORMAL_TIMELOCK], + }, + ]); +}; +export default vip007; diff --git a/multisig/simulations/basemainnet/vip-006/abi/AccessControlManager.json b/multisig/simulations/basemainnet/vip-006/abi/AccessControlManager.json new file mode 100644 index 000000000..4a118fcc4 --- /dev/null +++ b/multisig/simulations/basemainnet/vip-006/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/basemainnet/vip-006/index.ts b/multisig/simulations/basemainnet/vip-006/index.ts new file mode 100644 index 000000000..04ea846e0 --- /dev/null +++ b/multisig/simulations/basemainnet/vip-006/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 vip006, { ACM } from "../../../proposals/basemainnet/vip-006"; +import ACM_ABI from "./abi/AccessControlManager.json"; + +const { basemainnet } = NETWORK_ADDRESSES; + +forking(23531762, 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, basemainnet.NORMAL_TIMELOCK); + expect(hasRole).equals(false); + }); + }); + + describe("Post-VIP behavior", async () => { + before(async () => { + await pretendExecutingVip(await vip006()); + }); + + it("Normal Timelock has default admin role", async () => { + const hasRole = await acm.hasRole(defaultAdminRole, basemainnet.NORMAL_TIMELOCK); + expect(hasRole).equals(true); + }); + }); +}); diff --git a/multisig/simulations/basesepolia/vip-006/abi/AccessControlManager.json b/multisig/simulations/basesepolia/vip-006/abi/AccessControlManager.json new file mode 100644 index 000000000..4a118fcc4 --- /dev/null +++ b/multisig/simulations/basesepolia/vip-006/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/basesepolia/vip-006/index.ts b/multisig/simulations/basesepolia/vip-006/index.ts new file mode 100644 index 000000000..f480f902a --- /dev/null +++ b/multisig/simulations/basesepolia/vip-006/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 vip006, { ACM } from "../../../proposals/basesepolia/vip-006"; +import ACM_ABI from "./abi/AccessControlManager.json"; + +const { basesepolia } = NETWORK_ADDRESSES; + +forking(18477210, 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, basesepolia.NORMAL_TIMELOCK); + expect(hasRole).equals(false); + }); + }); + + describe("Post-VIP behavior", async () => { + before(async () => { + await pretendExecutingVip(await vip006()); + }); + + it("Normal Timelock has default admin role", async () => { + const hasRole = await acm.hasRole(defaultAdminRole, basesepolia.NORMAL_TIMELOCK); + expect(hasRole).equals(true); + }); + }); +}); diff --git a/simulations/vip-408/abi/ACMAggregator.json b/simulations/vip-408/abi/ACMAggregator.json new file mode 100644 index 000000000..6650a3f3c --- /dev/null +++ b/simulations/vip-408/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-408/abi/AccessControlManager_ABI.json b/simulations/vip-408/abi/AccessControlManager_ABI.json new file mode 100644 index 000000000..2ef119947 --- /dev/null +++ b/simulations/vip-408/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-408/abi/ERC20.json b/simulations/vip-408/abi/ERC20.json new file mode 100644 index 000000000..28715d783 --- /dev/null +++ b/simulations/vip-408/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-408/abi/OmnichainExecutorOwner_ABI.json b/simulations/vip-408/abi/OmnichainExecutorOwner_ABI.json new file mode 100644 index 000000000..f75834e6c --- /dev/null +++ b/simulations/vip-408/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-408/abi/OmnichainGovernanceExecutor_ABI.json b/simulations/vip-408/abi/OmnichainGovernanceExecutor_ABI.json new file mode 100644 index 000000000..b40c3cf44 --- /dev/null +++ b/simulations/vip-408/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-408/abi/OmnichainProposalSender.json b/simulations/vip-408/abi/OmnichainProposalSender.json new file mode 100644 index 000000000..66fd4df02 --- /dev/null +++ b/simulations/vip-408/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-408/abi/VtreasuryAbi.json b/simulations/vip-408/abi/VtreasuryAbi.json new file mode 100644 index 000000000..df5a655ee --- /dev/null +++ b/simulations/vip-408/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-408/basemainnet.ts b/simulations/vip-408/basemainnet.ts new file mode 100644 index 000000000..bdf71d845 --- /dev/null +++ b/simulations/vip-408/basemainnet.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 vip006 from "../../multisig/proposals/basemainnet/vip-006"; +import vip408, { + ACM, + ACM_AGGREGATOR, + DEFAULT_ADMIN_ROLE, + OMNICHAIN_EXECUTOR_OWNER, +} from "../../vips/vip-408/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 { basemainnet } = NETWORK_ADDRESSES; +const FAST_TRACK_TIMELOCK = "0x209F73Ee2Fa9A72aF3Fa6aF1933A3B58ed3De5D7"; +const CRITICAL_TIMELOCK = "0x47F65466392ff2aE825d7a170889F7b5b9D8e60D"; + +forking(23531762, async () => { + const provider = ethers.provider; + let lastProposalReceived: BigNumber; + let executor: Contract; + let executorOwner: Contract; + + before(async () => { + executor = new ethers.Contract( + basemainnet.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 vip006()); + }); + + describe("Pre-VIP behaviour", async () => { + it("Normal Timelock has default admin role on base mainnet", async () => { + const acm = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, ACM); + const hasRole = await acm.hasRole(DEFAULT_ADMIN_ROLE, basemainnet.NORMAL_TIMELOCK); + expect(hasRole).equals(true); + }); + }); + + testForkedNetworkVipCommands("vip408 configures bridge", await vip408(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [229]); + 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(basemainnet.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(), basemainnet.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 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, basemainnet.GUARDIAN)).to.be.true; + expect(await acm.hasRole(roleHash, basemainnet.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, basemainnet.GUARDIAN)).to.be.true; + expect(await acm.hasRole(roleHash, basemainnet.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, basemainnet.GUARDIAN)).to.be.false; + expect(await acm.hasRole(roleHash, basemainnet.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-408/basesepolia.ts b/simulations/vip-408/basesepolia.ts new file mode 100644 index 000000000..9eb78ffa4 --- /dev/null +++ b/simulations/vip-408/basesepolia.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 vip006 from "../../multisig/proposals/basesepolia/vip-006"; +import vip408, { + ACM, + ACM_AGGREGATOR, + DEFAULT_ADMIN_ROLE, + OMNICHAIN_EXECUTOR_OWNER, +} from "../../vips/vip-408/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 { basesepolia } = NETWORK_ADDRESSES; +const FAST_TRACK_TIMELOCK = "0x3dFA652D3aaDcb93F9EA7d160d674C441AaA8EE2"; +const CRITICAL_TIMELOCK = "0xbeDb7F2d0617292364bA4D73cf016c0f6BB5542E"; + +forking(18783561, async () => { + const provider = ethers.provider; + let lastProposalReceived: BigNumber; + let executor: Contract; + let executorOwner: Contract; + + before(async () => { + executor = new ethers.Contract( + basesepolia.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 vip006()); + }); + + 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, basesepolia.NORMAL_TIMELOCK); + expect(hasRole).equals(true); + }); + }); + + testForkedNetworkVipCommands("vip408 configures bridge", await vip408(), { + 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(basesepolia.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(), basesepolia.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, basesepolia.GUARDIAN)).to.be.true; + expect(await acm.hasRole(roleHash, basesepolia.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, basesepolia.GUARDIAN)).to.be.true; + expect(await acm.hasRole(roleHash, basesepolia.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, basesepolia.GUARDIAN)).to.be.false; + expect(await acm.hasRole(roleHash, basesepolia.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-408/bscmainnet.ts b/simulations/vip-408/bscmainnet.ts new file mode 100644 index 000000000..81b96e380 --- /dev/null +++ b/simulations/vip-408/bscmainnet.ts @@ -0,0 +1,77 @@ +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 } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import vip408, { + MAX_DAILY_LIMIT, + OMNICHAIN_PROPOSAL_SENDER, + USDT, + USDT_AMOUNT, + VENUS_STARS_TREASURY, +} from "../../vips/vip-408/bscmainnet"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; +import ERC20_ABI from "./abi/ERC20.json"; +import OMNICHAIN_PROPOSAL_SENDER_ABI from "./abi/OmnichainProposalSender.json"; +import VTREASURY_ABI from "./abi/VtreasuryAbi.json"; + +const { basemainnet } = NETWORK_ADDRESSES; +forking(44757538, async () => { + const provider = ethers.provider; + const omnichainProposalSender = new ethers.Contract( + OMNICHAIN_PROPOSAL_SENDER, + OMNICHAIN_PROPOSAL_SENDER_ABI, + provider, + ); + let usdt: Contract; + let balanceOfVenusStartsTreasury: BigNumber; + + describe("Pre-VIP behaviour", () => { + before(async () => { + usdt = new ethers.Contract(USDT, ERC20_ABI, provider); + balanceOfVenusStartsTreasury = await usdt.balanceOf(VENUS_STARS_TREASURY); + }); + + it("Daily limit should be 0", async () => { + expect(await omnichainProposalSender.chainIdToMaxDailyLimit(LzChainId.basemainnet)).to.equals(0); + }); + it("Trusted remote should not be set", async () => { + expect(await omnichainProposalSender.trustedRemoteLookup(LzChainId.basemainnet)).to.be.equals("0x"); + }); + }); + + testVip("vip408 give permissions to timelock", await vip408(), { + callbackAfterExecution: async txResponse => { + await expectEvents( + txResponse, + [ACCESS_CONTROL_MANAGER_ABI, OMNICHAIN_PROPOSAL_SENDER_ABI], + ["SetMaxDailyLimit", "SetTrustedRemoteAddress", "ExecuteRemoteProposal", "StorePayload"], + [1, 1, 1, 0], + ); + await expectEvents(txResponse, [VTREASURY_ABI], ["WithdrawTreasuryBEP20"], [1]); + }, + }); + + describe("Post-VIP behavior", () => { + it("Daily limit should be 100 of basemainnet", async () => { + expect(await omnichainProposalSender.chainIdToMaxDailyLimit(LzChainId.basemainnet)).to.equals(MAX_DAILY_LIMIT); + }); + + it("Trusted remote should be set of basemainnet", async () => { + expect(await omnichainProposalSender.trustedRemoteLookup(LzChainId.basemainnet)).to.be.equals( + ethers.utils.solidityPack( + ["address", "address"], + [basemainnet.OMNICHAIN_GOVERNANCE_EXECUTOR, OMNICHAIN_PROPOSAL_SENDER], + ), + ); + }); + + it("check usdt balance of VenusStartsTreasury", async () => { + const newBalanceOfVenusStartsTreasury = await usdt.balanceOf(VENUS_STARS_TREASURY); + expect(newBalanceOfVenusStartsTreasury).to.equals(balanceOfVenusStartsTreasury.add(USDT_AMOUNT)); + }); + }); +}); diff --git a/simulations/vip-408/bsctestnet.ts b/simulations/vip-408/bsctestnet.ts new file mode 100644 index 000000000..4a3b6bc01 --- /dev/null +++ b/simulations/vip-408/bsctestnet.ts @@ -0,0 +1,55 @@ +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 vip408, { MAX_DAILY_LIMIT, OMNICHAIN_PROPOSAL_SENDER } from "../../vips/vip-408/bsctestnet"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager_ABI.json"; +import OMNICHAIN_PROPOSAL_SENDER_ABI from "./abi/OmnichainProposalSender.json"; + +const { basesepolia } = NETWORK_ADDRESSES; +forking(46020691, 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.basesepolia)).to.equals(0); + }); + it("Trusted remote should not be set", async () => { + expect(await omnichainProposalSender.trustedRemoteLookup(LzChainId.basesepolia)).to.be.equals("0x"); + }); + }); + + testVip("vip408 give permissions to timelock", await vip408(), { + 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 basesepolia", async () => { + expect(await omnichainProposalSender.chainIdToMaxDailyLimit(LzChainId.basesepolia)).to.equals(MAX_DAILY_LIMIT); + }); + + it("Trusted remote should be set of basesepolia", async () => { + expect(await omnichainProposalSender.trustedRemoteLookup(LzChainId.basesepolia)).to.be.equals( + ethers.utils.solidityPack( + ["address", "address"], + [basesepolia.OMNICHAIN_GOVERNANCE_EXECUTOR, OMNICHAIN_PROPOSAL_SENDER], + ), + ); + }); + }); +}); diff --git a/src/networkAddresses.ts b/src/networkAddresses.ts index 7438f4a6c..6400e6126 100644 --- a/src/networkAddresses.ts +++ b/src/networkAddresses.ts @@ -236,8 +236,10 @@ export const NETWORK_ADDRESSES = { GENERIC_TEST_USER_ACCOUNT: "0x6f057A858171e187124ddEDF034dAc63De5dE5dB", REDSTONE_ORACLE: "0x8267FE3f75E0A37ee34e113E767F9C9727206838", POOL_REGISTRY: "0xCa330282BEeb07a81963336d0bf8f5f34317916c", - ENDPOINT: "0x55370E0fBB5f5b8dAeD978BA1c075a499eB107B8", + NORMAL_TIMELOCK: "0xCc84f6122649eDc48f4a426814e6b6C6fF9bBe0a", + OMNICHAIN_GOVERNANCE_EXECUTOR: "0xDD59be81B3B5BFa391bDA3a84c9f5233BfEF52a4", LZ_LIBRARY: "0x35AdD9321507A87471a11EBd4aE4f592d531e620", + ENDPOINT: "0x55370E0fBB5f5b8dAeD978BA1c075a499eB107B8", }, basemainnet: { GUARDIAN: "0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C", @@ -249,5 +251,9 @@ export const NETWORK_ADDRESSES = { XVS: "0xebB7873213c8d1d9913D8eA39Aa12d74cB107995", GENERIC_TEST_USER_ACCOUNT: "0x6f057A858171e187124ddEDF034dAc63De5dE5dB", POOL_REGISTRY: "0xeef902918DdeCD773D4B422aa1C6e1673EB9136F", + NORMAL_TIMELOCK: "0x21c12f2946a1a66cBFf7eb997022a37167eCf517", + OMNICHAIN_GOVERNANCE_EXECUTOR: "0xE7C56EaA4b6eafCe787B3E1AB8BCa0BC6CBDDb9e", + LZ_LIBRARY: "0x38dE71124f7a447a01D67945a51eDcE9FF491251", + ENDPOINT: "0xb6319cC6c8c27A8F5dAF0dD3DF91EA35C4720dd7", }, }; diff --git a/src/types.ts b/src/types.ts index e53729872..f899b3596 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,7 +10,9 @@ export type SUPPORTED_NETWORKS = | "zksyncsepolia" | "zksyncmainnet" | "opsepolia" - | "opmainnet"; + | "opmainnet" + | "basesepolia" + | "basemainnet"; export type REMOTE_NETWORKS = Exclude; @@ -22,7 +24,15 @@ export const REMOTE_TESTNET_NETWORKS = [ "opsepolia", "basesepolia", ]; -export const REMOTE_MAINNET_NETWORKS = ["ethereum", "opbnbmainnet", "arbitrumone", "zksyncmainnet", "opmainnet"]; +export const REMOTE_MAINNET_NETWORKS = [ + "ethereum", + "opbnbmainnet", + "arbitrumone", + "zksyncmainnet", + "opmainnet", + "basemainnet", +]; + export interface ProposalMeta { version: string; title: string; diff --git a/src/vip-framework/index.ts b/src/vip-framework/index.ts index 15e138e8a..61eebc712 100644 --- a/src/vip-framework/index.ts +++ b/src/vip-framework/index.ts @@ -236,6 +236,7 @@ export const testForkedNetworkVipCommands = (description: string, proposal: Prop ENDPOINT_ABI, provider, ); + const srcAddress = ethers.utils.solidityPack( ["address", "address"], [OMNICHAIN_PROPOSAL_SENDER, OMNICHAIN_GOVERNANCE_EXECUTOR], diff --git a/vips/vip-408/bscmainnet.ts b/vips/vip-408/bscmainnet.ts new file mode 100644 index 000000000..5876a89c0 --- /dev/null +++ b/vips/vip-408/bscmainnet.ts @@ -0,0 +1,207 @@ +import { parseUnits } from "ethers/lib/utils"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +const { basemainnet, bscmainnet } = NETWORK_ADDRESSES; +export const OMNICHAIN_PROPOSAL_SENDER = "0x36a69dE601381be7b0DcAc5D5dD058825505F8f6"; + +export const OMNICHAIN_EXECUTOR_OWNER = "0x8BA591f72a90fb379b9a82087b190d51b226F0a9"; +export const ACM = "0x9E6CeEfDC6183e4D0DF8092A9B90cDF659687daB"; +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; +export const ACM_AGGREGATOR = "0xB2770DBD5146f7ee0766Dc9E3931433bb697Aa06"; +export const MAX_DAILY_LIMIT = 100; +export const VENUS_STARS_TREASURY = "0xd7ca847Aa074b28A1DfeFfd3B2C3f9780cA96e1D"; +export const USDT = "0x55d398326f99059fF775485246999027B3197955"; +export const USDT_AMOUNT = parseUnits("19938.50", 18); + +const vip408 = () => { + const meta = { + version: "v2", + title: "VIP-408 [Base] Markets, Prime and Omnichain Governance", + description: `#### Summary + +If passed, this VIP will perform the following actions: + +- Configure the Venus markets on Base, for [cbBTC](https://basescan.org/address/0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf), [WETH](https://basescan.org/address/0x4200000000000000000000000000000000000006) and [USDC](https://basescan.org/token/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913) +- Configure the [ProtocolShareReserve](https://basescan.org/address/0x3565001d57c91062367C3792B74458e3c6eD910a) contract on Base +- Configure the [NativeTokenGateway](https://basescan.org/address/0x8e890ca3829c740895cdEACd4a3BE36ff9343643) contact for the Venus market of WETH, accepting deposits and withdrawals of ETH +- Configure the [Prime](https://basescan.org/address/0xD2e84244f1e9Fca03Ff024af35b8f9612D5d7a30) contract on Base, allowing users to stake XVS into the XVSVault to start their qualification period +- Enable the Omnichain Governance system on the Venus protocol, for Base. Omnichain Governance will allow the Venus Community to propose VIP’s on BNB Chain including commands to be executed on Base + +#### Description + +Following the [Chaos labs recommendations](https://community.venus.io/t/deploy-venus-on-base/4630/13), if passed, this VIP will enable the following Venus markets on Base: + +Underlying token: [cbBTC](https://basescan.org/address/0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf) + +- Borrow cap: 200 +- Supply cap: 400 +- Collateral factor: 0.73 +- Liquidation threshold: 0.78 +- Reserve factor: 0.2 +- Bootstrap liquidity: 0.05 cbBTC - provided by the Venus Treasury +- Interest rate curve: + - kink: 0.45 + - base (yearly): 0 + - multiplier (yearly): 0.15 + - jump multiplier (yearly): 2.5 + +Underlying token: [WETH](https://basescan.org/address/0x4200000000000000000000000000000000000006) + +- Borrow cap: 9,000 +- Supply cap: 10,000 +- Collateral factor: 0.8 +- Liquidation threshold: 0.83 +- Reserve factor: 0.15 +- Bootstrap liquidity: 2 WETH - provided by the Venus Treasury +- Interest rate curve: + - kink: 0.9 + - base (yearly): 0 + - multiplier (yearly): 0.03 + - jump multiplier (yearly): 4.5 + +Underlying token: [USDC](https://basescan.org/token/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913) + +- Borrow cap: 27,000,000 +- Supply cap: 30,000,000 +- Collateral factor: 0.75 +- Liquidation threshold: 0.78 +- Reserve factor: 0.1 +- Bootstrap liquidity: 5,000 USDC - provided by the Venus Treasury +- Interest rate curve: + - kink: 0.8 + - base (yearly): 0 + - multiplier (yearly): 0.08 + - jump multiplier (yearly): 2.5 + +Initial risk parameters for the new pool: + +- Close factor: 50% +- Liquidation incentive: 10% + +Regarding the bootstrap liquidity for the new markets, this VIP will refund 0xd7ca847Aa074b28A1DfeFfd3B2C3f9780cA96e1D with $19,938.50 USDT on BNB Chain, to compensate the provision for [USDC](https://basescan.org/tx/0x84117a3a66a63ba784c07a096b51901eeb7bb0b0ba38f686ad1ab591218730c3), [cbBTC](https://basescan.org/tx/0x7e3021c203b8430d014e678094c59b4e3f7e00966cb241e1c684080c56bcba2c) and [WETH](https://basescan.org/tx/0x4d6fde66b30be733f643a3bebe60b102833160397bbfdeec1de1cdbcbf617c71) on Base and ETH on BNB Chain. + +This VIP will grant permissions to Normal, Fast-track and Critical timelocks on BNB chain to create remote VIP’s on Base. It also performs the necessary configuration of OmnichainProposalSender on BNB Chain and OmnichainProposalExecutor on Base (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 and validating the usual operations on the markets +- **Deployment on testnet**: the same contracts have been deployed to testnet, and used in the Venus Protocol testnet deployment +- **Audit:** [Certik](https://www.certik.com/), [Quantstamp](https://quantstamp.com/) and [Fairyproof](https://fairyproof.com/) have audited the code specific for Base. [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 + +- Time base contracts: + - [Certik audit audit report](https://github.com/VenusProtocol/isolated-pools/blob/aa1f7ae61b07839231ec16e9c4143905785d7aae/audits/088_timeBased_certik_20240117.pdf) (2024/01/17) + - [Quantstamp audit audit report](https://github.com/VenusProtocol/isolated-pools/blob/470416836922656783eab52ded54744489e8c345/audits/089_timeBased_quantstamp_20240319.pdf) (2024/03/19) + - [Fairyproof audit report](https://github.com/VenusProtocol/isolated-pools/blob/aa1f7ae61b07839231ec16e9c4143905785d7aae/audits/094_timeBased_fairyproof_20240304.pdf) (2024/03/04) +- Omnichain Governance: + - [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 Base + +- Pool registry: [0xeef902918DdeCD773D4B422aa1C6e1673EB9136F](https://basescan.org/address/0xeef902918DdeCD773D4B422aa1C6e1673EB9136F) +- Comptroller: [0x0C7973F9598AA62f9e03B94E92C967fD5437426C](https://basescan.org/address/0x0C7973F9598AA62f9e03B94E92C967fD5437426C) +- Markets: + - vcbBTC_Core: [0x7bBd1005bB24Ec84705b04e1f2DfcCad533b6D72](https://basescan.org/address/0x7bBd1005bB24Ec84705b04e1f2DfcCad533b6D72) + - vWETH_Core: [0xEB8A79bD44cF4500943bf94a2b4434c95C008599](https://basescan.org/address/0xEB8A79bD44cF4500943bf94a2b4434c95C008599) + - vUSDC_Core: [0x3cb752d175740043Ec463673094e06ACDa2F9a2e](https://basescan.org/address/0x3cb752d175740043Ec463673094e06ACDa2F9a2e) +- [ProtocolShareReserve](https://basescan.org/address/0x3565001d57c91062367C3792B74458e3c6eD910a) +- [NativeTokenGateway](https://basescan.org/address/0x8e890ca3829c740895cdEACd4a3BE36ff9343643) +- [Prime](https://basescan.org/address/0xD2e84244f1e9Fca03Ff024af35b8f9612D5d7a30) +- [PrimeLiquidityProvider](https://basescan.org/address/0xcB293EB385dEFF2CdeDa4E7060974BB90ee0B208) +- Omnichain Governance: + - Normal Timelock: [0x21c12f2946a1a66cBFf7eb997022a37167eCf517](https://basescan.org/address/0x21c12f2946a1a66cBFf7eb997022a37167eCf517) + - FastTrack Timelock: [0x209F73Ee2Fa9A72aF3Fa6aF1933A3B58ed3De5D7](https://basescan.org/address/0x209F73Ee2Fa9A72aF3Fa6aF1933A3B58ed3De5D7) + - Critical Timelock: [0x47F65466392ff2aE825d7a170889F7b5b9D8e60D](https://basescan.org/address/0x47F65466392ff2aE825d7a170889F7b5b9D8e60D) + - Omnichain Governance Executor: [0xE7C56EaA4b6eafCe787B3E1AB8BCa0BC6CBDDb9e](https://basescan.org/address/0xE7C56EaA4b6eafCe787B3E1AB8BCa0BC6CBDDb9e) + - Omnichain Executor Owner Proxy: [0x8BA591f72a90fb379b9a82087b190d51b226F0a9](https://basescan.org/address/0x8BA591f72a90fb379b9a82087b190d51b226F0a9) + - ACMCommandsAggregator: [0xB2770DBD5146f7ee0766Dc9E3931433bb697Aa06](https://basescan.org/address/0xB2770DBD5146f7ee0766Dc9E3931433bb697Aa06) + +#### References + +- VIP simulations: + - [ProtocolShareReserve and NativeTokenGateway](https://github.com/VenusProtocol/vips/pull/426) + - [Markets](https://github.com/VenusProtocol/vips/pull/427) + - [Prime](https://github.com/VenusProtocol/vips/pull/432) + - [Omnichain Governance](https://github.com/VenusProtocol/vips/pull/433) +- [Deploy Venus on Base](https://community.venus.io/t/deploy-venus-on-base/4630) +- Snapshot ["Deploy Venus on Base"](https://snapshot.box/#/s:venus-xvs.eth/proposal/0x353f5fb23ff895d89c21271ea1904af65e60557aeec317b24ce56d728d29b8c1) +- [Code of Omnichain Governance](https://github.com/VenusProtocol/governance-contracts/pull/21) +- [Documentation - Technical article with more details of the Omnichain Governance feature](https://docs-v4.venus.io/technical-reference/reference-technical-articles/multichain-governance) +- [Documentation](https://docs-v4.venus.io/) + +#### Disclaimer for Base VIPs + +Privilege commands on Base will be executed by the [Guardian wallet](https://basescan.org/address/0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C), until the [Multichain Governance](https://docs-v4.venus.io/technical-reference/reference-technical-articles/multichain-governance) contracts are fully enabled. If this VIP passes, [this](https://app.safe.global/transactions/tx?safe=base:0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C&id=multisig_0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C_0x5514a6ee48bc5a0ab6db631bdc26d69fad62174905bf8f12580a1532c642b300), [this](https://app.safe.global/transactions/tx?safe=base:0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C&id=multisig_0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C_0xdf161ff5e3e1deef14f376ffb72bec2243cd8bf77589fa82290e439d09999aed), [this](https://app.safe.global/transactions/tx?safe=base:0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C&id=multisig_0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C_0xb5f6aaf6aae7b82536aadaac4c68e30a62afcfa51274921ffaabffef2eed2e97) and [this](https://app.safe.global/transactions/tx?safe=base:0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C&id=multisig_0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C_0x532c631053e4f4e926ab78492f6b3263cd4f4785a7d4df2a667e80ae7e1fc65f) multisig transactions will be executed. Otherwise, they will be rejected. +`, + forDescription: "Execute this proposal", + againstDescription: "Do not execute this proposal", + abstainDescription: "Indifferent to execution", + }; + return makeProposal( + [ + { + target: OMNICHAIN_PROPOSAL_SENDER, + signature: "setMaxDailyLimit(uint16,uint256)", + params: [LzChainId.basemainnet, MAX_DAILY_LIMIT], + }, + { + target: OMNICHAIN_PROPOSAL_SENDER, + signature: "setTrustedRemoteAddress(uint16,bytes)", + params: [LzChainId.basemainnet, basemainnet.OMNICHAIN_GOVERNANCE_EXECUTOR], + }, + { + target: OMNICHAIN_EXECUTOR_OWNER, + signature: "acceptOwnership()", + params: [], + dstChainId: LzChainId.basemainnet, + }, + { + target: ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.basemainnet, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [0], + dstChainId: LzChainId.basemainnet, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [1], + dstChainId: LzChainId.basemainnet, + }, + { + target: ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [0], + dstChainId: LzChainId.basemainnet, + }, + { + target: ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.basemainnet, + }, + { + target: bscmainnet.VTREASURY, + signature: "withdrawTreasuryBEP20(address,uint256,address)", + params: [USDT, USDT_AMOUNT, VENUS_STARS_TREASURY], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; +export default vip408; diff --git a/vips/vip-408/bsctestnet.ts b/vips/vip-408/bsctestnet.ts new file mode 100644 index 000000000..4fd793cff --- /dev/null +++ b/vips/vip-408/bsctestnet.ts @@ -0,0 +1,76 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +const { basesepolia } = NETWORK_ADDRESSES; +export const OMNICHAIN_PROPOSAL_SENDER = "0xCfD34AEB46b1CB4779c945854d405E91D27A1899"; + +export const OMNICHAIN_EXECUTOR_OWNER = "0xe3fb08B8817a0c88d39A4DA4eFFD586D3326b73b"; +export const ACM = "0x724138223D8F76b519fdE715f60124E7Ce51e051"; +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; +export const ACM_AGGREGATOR = "0xd82A217713F6c61f3ed4199cdEEDfbB80e5E4562"; +export const MAX_DAILY_LIMIT = 100; + +const vip408 = () => { + const meta = { + version: "v2", + title: "VIP-408 Enable Multichain Governance on base 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.basesepolia, MAX_DAILY_LIMIT], + }, + { + target: OMNICHAIN_PROPOSAL_SENDER, + signature: "setTrustedRemoteAddress(uint16,bytes)", + params: [LzChainId.basesepolia, basesepolia.OMNICHAIN_GOVERNANCE_EXECUTOR], + }, + { + target: OMNICHAIN_EXECUTOR_OWNER, + signature: "acceptOwnership()", + params: [], + dstChainId: LzChainId.basesepolia, + }, + { + target: ACM, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.basesepolia, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [1], + dstChainId: LzChainId.basesepolia, + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [3], + dstChainId: LzChainId.basesepolia, + }, + { + target: ACM_AGGREGATOR, + signature: "executeRevokePermissions(uint256)", + params: [3], + dstChainId: LzChainId.basesepolia, + }, + { + target: ACM, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + dstChainId: LzChainId.basesepolia, + }, + ], + meta, + ProposalType.REGULAR, + ); +}; +export default vip408;