diff --git a/block.txt b/block.txt index cee98f713..b143baff3 100644 --- a/block.txt +++ b/block.txt @@ -1 +1 @@ -15018600 \ No newline at end of file +15039959 \ No newline at end of file diff --git a/proposals/description/fip_x.ts b/proposals/description/fip_x.ts index 3268649dd..d4fee96e4 100644 --- a/proposals/description/fip_x.ts +++ b/proposals/description/fip_x.ts @@ -11,7 +11,10 @@ const fip_x: ProposalDescription = { description: '' } ], - description: 'fip_x will change the game!' + description: ` + [TITLE] /n/n + [BODY OF PROPOSAL] \n\n + ` }; export default fip_x; diff --git a/protocol-configuration/proposalsConfig.ts b/protocol-configuration/proposalsConfig.ts index cbbafd706..c782a96d7 100644 --- a/protocol-configuration/proposalsConfig.ts +++ b/protocol-configuration/proposalsConfig.ts @@ -1,37 +1,5 @@ import { ProposalCategory, TemplatedProposalsConfigMap } from '@custom-types/types'; -import tip_117 from '@proposals/description/tip_117'; -import pod_exec_v2 from '@proposals/description/pod_exec_v2'; -import tip_115 from '@proposals/description/tip_115'; - -const proposals: TemplatedProposalsConfigMap = { - tip_117: { - deploy: false, // deploy flag for whether to run deploy action during e2e tests or use mainnet state - totalValue: 0, // amount of ETH to send to DAO execution - proposal: tip_117, // full proposal file, imported from '@proposals/description/fip_xx.ts' - proposalId: '', - affectedContractSignoff: [], - deprecatedContractSignoff: [], - category: ProposalCategory.DAO - }, - tip_115: { - deploy: false, // deploy flag for whether to run deploy action during e2e tests or use mainnet state - totalValue: 0, // amount of ETH to send to DAO execution - proposal: tip_115, // full proposal file, imported from '@proposals/description/fip_xx.ts' - proposalId: '', - affectedContractSignoff: [], - deprecatedContractSignoff: [], - category: ProposalCategory.TC - }, - pod_exec_v2: { - deploy: false, // deploy flag for whether to run deploy action during e2e tests or use mainnet state - totalValue: 0, // amount of ETH to send to DAO execution - proposal: pod_exec_v2, // full proposal file, imported from '@proposals/description/fip_xx.ts' - proposalId: '', - affectedContractSignoff: [], - deprecatedContractSignoff: [], - category: ProposalCategory.TC - } -}; +const proposals: TemplatedProposalsConfigMap = {}; export default proposals; diff --git a/scripts/utils/constructProposalCalldata.ts b/scripts/utils/constructProposalCalldata.ts index 7a4c67385..f071817bc 100644 --- a/scripts/utils/constructProposalCalldata.ts +++ b/scripts/utils/constructProposalCalldata.ts @@ -4,8 +4,12 @@ import { ethers } from 'hardhat'; import { Interface } from '@ethersproject/abi'; import { utils } from 'ethers'; import { getAllContractAddresses, getAllContracts } from '@test/integration/setup/loadContracts'; -import { ProposalCategory, ProposalDescription, TemplatedProposalDescription } from '@custom-types/types'; +import { ProposalCategory, TemplatedProposalDescription } from '@custom-types/types'; import proposals from '@protocol/proposalsConfig'; +import { TRIBAL_COUNCIL_POD_ID } from '@protocol/optimisticGovernance'; +import { abi as TimelockControllerABI } from '../../artifacts/@openzeppelin/contracts/governance/TimelockController.sol/TimelockController.json'; +import { abi as FeiDAOABI } from '../../artifacts/contracts/dao/governor/FeiDAO.sol/FeiDAO.json'; +import { abi as MetadataRegistryABI } from '../../artifacts/contracts/pods/GovernanceMetadataRegistry.sol/GovernanceMetadataRegistry.json'; type ExtendedAlphaProposal = { targets: string[]; @@ -15,6 +19,11 @@ type ExtendedAlphaProposal = { description: string; }; +export interface PodConfig { + id: number; + timelockAddress: string; +} + /** * Take in a hardhat proposal object and output the proposal calldatas * See `proposals/utils/getProposalCalldata.js` on how to construct the proposal calldata @@ -29,16 +38,18 @@ export async function constructProposalCalldata(proposalName: string): Promise x.toString()), payloads, predecessor, salt] + ); + return ethers.utils.keccak256(dataToHash); } diff --git a/scripts/utils/simulateTimelockProposal.ts b/scripts/utils/simulateTimelockProposal.ts index 3aeb9b7f4..537fd3409 100644 --- a/scripts/utils/simulateTimelockProposal.ts +++ b/scripts/utils/simulateTimelockProposal.ts @@ -1,25 +1,11 @@ import { ethers } from 'hardhat'; -import { - MainnetContracts, - NamedAddresses, - ProposalDescription, - TemplatedProposalDescription -} from '@custom-types/types'; +import { MainnetContracts, NamedAddresses, TemplatedProposalDescription } from '@custom-types/types'; import { OptimisticTimelock } from '@custom-types/contracts'; import { getImpersonatedSigner, time } from '@test/helpers'; import { Contract } from '@ethersproject/contracts'; import { forceEth } from '@test/integration/setup/utils'; - -export async function simulateOAProposal( - proposalInfo: TemplatedProposalDescription, - contracts: MainnetContracts, - contractAddresses: NamedAddresses, - logging = false -) { - const timelockOA = contracts.optimisticTimelock as OptimisticTimelock; - const multisigAddressOA = contractAddresses.optimisticMultisig as string; - await simulateTimelockProposal(timelockOA, multisigAddressOA, proposalInfo, contracts, contractAddresses, logging); -} +import { TRIBAL_COUNCIL_POD_ID } from '@protocol/optimisticGovernance'; +import { PodConfig } from './constructProposalCalldata'; export async function simulateTCProposal( proposalInfo: TemplatedProposalDescription, @@ -29,16 +15,29 @@ export async function simulateTCProposal( ) { const timelockTC = contracts.tribalCouncilTimelock as OptimisticTimelock; const multisigAddressTC = contractAddresses.tribalCouncilSafe as string; - await simulateTimelockProposal(timelockTC, multisigAddressTC, proposalInfo, contracts, contractAddresses, logging); + const podConfig: PodConfig = { + id: TRIBAL_COUNCIL_POD_ID, + timelockAddress: contractAddresses.tribalCouncilTimelock + }; + await simulatePodProposal( + timelockTC, + multisigAddressTC, + proposalInfo, + contracts, + contractAddresses, + logging, + podConfig + ); } -export async function simulateTimelockProposal( +export async function simulatePodProposal( timelock: OptimisticTimelock, multisigAddress: string, proposalInfo: TemplatedProposalDescription, contracts: MainnetContracts, contractAddresses: NamedAddresses, - logging = false + logging = false, + podConfig: PodConfig ) { await forceEth(multisigAddress); const signer = await getImpersonatedSigner(multisigAddress); @@ -88,6 +87,13 @@ export async function simulateTimelockProposal( if (!proposalId || !(await timelock.isOperation(proposalId))) { const schedule = await timelock.connect(signer).scheduleBatch(targets, values, datas, predecessor, salt, delay); console.log('Calldata:', schedule.data); + + // Register the pod's metadata + console.log(`Registering proposal ${proposalId} of pod ${podConfig.id}`); + const registerTx = await contracts.governanceMetadataRegistry + .connect(signer) + .registerProposal(podConfig.id, proposalId, proposalInfo.description); + console.log('Metadata tx: ', registerTx.data); } else { console.log('Already scheduled proposal'); } diff --git a/test/integration/setup/index.ts b/test/integration/setup/index.ts index 9acc6aae3..687d09f77 100644 --- a/test/integration/setup/index.ts +++ b/test/integration/setup/index.ts @@ -5,7 +5,6 @@ import { ContractAccessRights, TestCoordinator, ContractsAndAddresses, - ProposalConfig, TemplatedProposalConfig, namedContractsToNamedAddresses, NamedAddresses, @@ -21,7 +20,6 @@ import { sudo } from '@scripts/utils/sudo'; import constructProposal from '@scripts/utils/constructProposal'; import '@nomiclabs/hardhat-ethers'; import { resetFork } from '@test/helpers'; -import { simulateOAProposal } from '@scripts/utils/simulateTimelockProposal'; import { simulateTCProposal } from '@scripts/utils/simulateTimelockProposal'; import { simulateDEBUGProposal } from '@scripts/utils/simulateDEBUGProposal'; import { forceEth } from '@test/integration/setup/utils'; diff --git a/test/unit/scriptUtils/computeBatchProposalId.ts b/test/unit/scriptUtils/computeBatchProposalId.ts new file mode 100644 index 000000000..71e77fc64 --- /dev/null +++ b/test/unit/scriptUtils/computeBatchProposalId.ts @@ -0,0 +1,36 @@ +import { computeBatchProposalId } from '@scripts/utils/constructProposalCalldata'; +import { expect } from 'chai'; +import { BigNumber } from 'ethers'; + +const toBN = BigNumber.from; + +describe('Compute proposal ID off-chain', () => { + it('should compute proposalId for a batched proposal', () => { + // Fixture is a real-transaction submitted on-chain + const expectedProposalId = '0x81c419dbb3c44645493c214eee0ceaf273ba870d1e7e1c48422e2762f60e0db4'; + const targets = [ + '0x02435948F84d7465FB71dE45ABa6098Fc6eC2993', + '0x02435948F84d7465FB71dE45ABa6098Fc6eC2993', + '0x02435948F84d7465FB71dE45ABa6098Fc6eC2993', + '0xF7991f4698ffb6716982aec7F78964Dd731C4A54', + '0xFF6f59333cfD8f4Ebc14aD0a0E181a83e655d257', + '0xFF6f59333cfD8f4Ebc14aD0a0E181a83e655d257', + '0x98E5F5706897074a4664DD3a32eB80242d6E694B' + ]; + const values = [toBN(0), toBN(0), toBN(0), toBN(0), toBN(0), toBN(0), toBN(0)]; + const payloads = [ + '0x8320357d00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f7991f4698ffb6716982aec7f78964dd731c4a54', + '0xfe68d76e0000000000000000000000005b86887e171bae0c2c826e87e34df8d558c079b9000000000000000000000000f7991f4698ffb6716982aec7f78964dd731c4a5400000000000000000000000000000000000000000000043c33c193756480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + '0xfe68d76e000000000000000000000000e0f73b8d76d2ad33492f995af218b03564b8ce20000000000000000000000000f7991f4698ffb6716982aec7f78964dd731c4a54000000000000000000000000000000000000000000027b46536c66c8e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + '0x8119c065', + '0xdea02892000000000000000000000000df9ff5c077d9f3427ade67ac2d27a864be6f3187', + '0xdea02892000000000000000000000000f24401f6992faeacbc5d6c6991db15b5f8364a1b', + '0x5d841af5000000000000000000000000000000000000000000000000000000000000003c' + ]; + const predecessor = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const salt = '0x0d0c2b4e41c5fdf9375f2b1601caf0af18e81d6257ea3abb3b72a989fc3698da'; + + const proposalId = computeBatchProposalId(targets, values, payloads, predecessor, salt); + expect(proposalId).to.be.equal(expectedProposalId); + }); +}); diff --git a/types/types.ts b/types/types.ts index 0a220c800..36a3b341e 100644 --- a/types/types.ts +++ b/types/types.ts @@ -16,6 +16,7 @@ import { EthCompoundPCVDeposit, Fei, FeiDAO, + GovernanceMetadataRegistry, GovernorAlpha, IAaveIncentivesController, IERC20, @@ -273,6 +274,7 @@ export interface MainnetContracts { rewardsDistributorAdmin: RewardsDistributorAdmin; restrictedPermissions: RestrictedPermissions; tribalCouncilTimelock: TimelockController; + governanceMetadataRegistry: GovernanceMetadataRegistry; } export interface MainnetContractAddresses { @@ -308,6 +310,7 @@ export interface MainnetContractAddresses { rariRewardsDistributorDelegator: string; restrictedPermissions: string; tribalCouncilTimelock: string; + governanceMetadataRegistry: string; } export type ContractAccessRights = {