From 07a8dee822b87373abffb9596d6bf7ad75f6fece Mon Sep 17 00:00:00 2001 From: John Feras Date: Thu, 7 Dec 2023 11:13:58 -0500 Subject: [PATCH] Added post-proposal Alpha tests and Bravo tests (#8) Added tests for Alpha governor after upgrade proposal and proposal actions on Bravo governor. --- .github/workflows/ci.yml | 19 + foundry.toml | 3 +- test/Constants.sol | 2 +- test/RadworksGovernor.t.sol | 555 +++++++++++++++++++++++++- test/helpers/RadworksGovernorTest.sol | 10 +- 5 files changed, 578 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 689ffca..e2c0613 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,8 @@ on: env: FOUNDRY_PROFILE: ci MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + DEPLOYER_PRIVATE_KEY: ${{ secrets.DEPLOYER_PRIVATE_KEY }} + PROPOSER_PRIVATE_KEY: ${{ secrets.PROPOSER_PRIVATE_KEY }} jobs: build: @@ -29,10 +31,20 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + with: + fetch-depth: 5 + submodules: "recursive" - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 + # https://twitter.com/PaulRBerg/status/1611116650664796166 + - name: Generate fuzz seed with 1 week TTL + run: > + echo "FOUNDRY_FUZZ_SEED=$( + echo $(($EPOCHSECONDS - $EPOCHSECONDS % 604800)) + )" >> $GITHUB_ENV + - name: Run tests run: forge test @@ -44,6 +56,13 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 + # https://twitter.com/PaulRBerg/status/1611116650664796166 + - name: Recycle the fuzz seed from the test run + run: > + echo "FOUNDRY_FUZZ_SEED=$( + echo $(($EPOCHSECONDS - $EPOCHSECONDS % 604800)) + )" >> $GITHUB_ENV + - name: Run coverage run: forge coverage --report summary --report lcov diff --git a/foundry.toml b/foundry.toml index b4e4768..b85263e 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,5 +1,6 @@ [profile.default] evm_version = "paris" + fuzz = { seed = "1" } optimizer = true optimizer_runs = 10_000_000 remappings = [ @@ -10,7 +11,7 @@ verbosity = 3 [profile.ci] - fuzz = { runs = 5000 } + fuzz = { runs = 256 } invariant = { runs = 1000 } [profile.lite] diff --git a/test/Constants.sol b/test/Constants.sol index 9aee6fe..52e3db4 100644 --- a/test/Constants.sol +++ b/test/Constants.sol @@ -7,7 +7,7 @@ contract Constants { address constant TIMELOCK = 0x8dA8f82d2BbDd896822de723F55D6EdF416130ba; // TODO: resolve the list of large delegates with tallyaddress - address constant PROPOSER = 0x464D78a5C97A2E2E9839C353ee9B6d4204c90B0b; + address constant PROPOSER = 0x464D78a5C97A2E2E9839C353ee9B6d4204c90B0b; // cloudhead.eth address constant USDC_ADDRESS = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address constant GTC_ADDRESS = 0xDe30da39c46104798bB5aA3fe8B9e0e1F348163F; diff --git a/test/RadworksGovernor.t.sol b/test/RadworksGovernor.t.sol index 120763a..6cf06a9 100644 --- a/test/RadworksGovernor.t.sol +++ b/test/RadworksGovernor.t.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.20; +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; import {ERC20VotesComp} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20VotesComp.sol"; - +import {IGovernor} from "@openzeppelin/contracts/governance/IGovernor.sol"; import {IGovernorAlpha} from "src/interfaces/IGovernorAlpha.sol"; import {RadworksGovernorTest} from "test/helpers/RadworksGovernorTest.sol"; import {ProposalTest} from "test/helpers/ProposalTest.sol"; @@ -137,10 +138,556 @@ abstract contract Propose is ProposalTest { // Ensure the governorBravo is now the admin of the timelock assertEq(timelock.admin(), address(governorBravo)); } -} -// TODO: future PR -abstract contract CastVoteWithReasonAndParams is ProposalTest {} + // + // Post proposal tests + // + function testFuzz_OldGovernorSendsETHAfterProposalIsDefeated(uint128 _amount, address _receiver) + public + { + _assumeReceiver(_receiver); + + // Counter-intuitively, the Governor (not the Timelock) must hold the ETH. + // See the deployed GovernorAlpha, line 281: + // https://etherscan.io/address/0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3#code + // The governor transfers ETH to the Timelock in the process of executing + // the proposal. The Timelock then just passes that ETH along. + vm.deal(address(governorAlpha), _amount); + + uint256 _receiverETHBalance = _receiver.balance; + uint256 _governorETHBalance = address(governorAlpha).balance; + + // Defeat the proposal to upgrade the Governor + _defeatUpgradeProposal(); + + // Create a new proposal to send the ETH. + address[] memory _targets = new address[](1); + uint256[] memory _values = new uint256[](1); + _targets[0] = _receiver; + _values[0] = _amount; + + _queueAndVoteAndExecuteProposalWithAlphaGovernor( + _targets, + _values, + new string[](1), // No signature needed for an ETH send. + new bytes[](1), // No calldata needed for an ETH send. + true // GovernorAlpha is still the Timelock admin. + ); + + // Ensure the ETH has been transferred to the receiver + assertEq( + address(governorAlpha).balance, + _governorETHBalance - _amount, + "Governor alpha ETH balance is incorrect" + ); + assertEq(_receiver.balance, _receiverETHBalance + _amount, "Receiver ETH balance is incorrect"); + } + + function testFuzz_OldGovernorCanNotSendTokensAfterUpgradeCompletes( + uint256 _amount, + address _receiver, + uint256 _seed + ) public { + _assumeReceiver(_receiver); + IERC20 _token = _randomERC20Token(_seed); + + uint256 _receiverTokenBalance = _token.balanceOf(_receiver); + uint256 _timelockTokenBalance = _token.balanceOf(TIMELOCK); + // bound by the number of tokens the timelock currently controls + _amount = bound(_amount, 0, _timelockTokenBalance); + + // Pass and execute the proposal to upgrade the Governor + _upgradeToBravoGovernor(); + + // Craft a new proposal to send the token. + address[] memory _targets = new address[](1); + uint256[] memory _values = new uint256[](1); + string[] memory _signatures = new string[](1); + bytes[] memory _calldatas = new bytes[](1); + + _targets[0] = address(_token); + _values[0] = 0; + _signatures[0] = "transfer(address,uint256)"; + _calldatas[0] = abi.encode(_receiver, _amount); + + _queueAndVoteAndExecuteProposalWithAlphaGovernor( + _targets, + _values, + _signatures, + _calldatas, + false // GovernorAlpha is not the Timelock admin anymore. + ); + + // Ensure no tokens have been transferred from the timelock to the receiver. + assertEq(_token.balanceOf(TIMELOCK), _timelockTokenBalance, "Timelock balance is incorrect"); + assertEq(_token.balanceOf(_receiver), _receiverTokenBalance, "Receiver balance is incorrect"); + } + + // + // Bravo proposal tests + // + function testFuzz_NewGovernorCanReceiveNewProposal(uint256 _amount, address _receiver) public { + _assumeReceiver(_receiver); + _upgradeToBravoGovernor(); + _submitTokenSendProposalToGovernorBravo(RAD_TOKEN, _amount, _receiver); + } + + function testFuzz_NewGovernorCanDefeatProposal(uint256 _amount, address _receiver, uint256 _seed) + public + { + IERC20 _token = _randomERC20Token(_seed); + _assumeReceiver(_receiver); + + _upgradeToBravoGovernor(); + + ( + address[] memory _targets, + uint256[] memory _values, + bytes[] memory _calldatas, + string memory _description + ) = _buildTokenSendProposal(address(_token), _amount, _receiver); + + _queueAndVoteAndExecuteProposalWithBravoGovernor( + _targets, + _values, + _calldatas, + _description, + (_amount % 2 == 1 ? AGAINST : ABSTAIN) // Randomize vote type. + ); + + // It should not be possible to queue the proposal + vm.expectRevert("Governor: proposal not successful"); + governorBravo.queue(_targets, _values, _calldatas, keccak256(bytes(_description))); + } + + function testFuzz_NewGovernorCanPassProposalToSendToken( + uint256 _amount, + address _receiver, + uint256 _seed + ) public { + IERC20 _token = _randomERC20Token(_seed); + _assumeReceiver(_receiver); + uint256 _timelockTokenBalance = _token.balanceOf(TIMELOCK); + + // bound by the number of tokens the timelock currently controls + _amount = bound(_amount, 0, _timelockTokenBalance); + uint256 _initialTokenBalance = _token.balanceOf(_receiver); + + _upgradeToBravoGovernor(); + + ( + address[] memory _targets, + uint256[] memory _values, + bytes[] memory _calldatas, + string memory _description + ) = _buildTokenSendProposal(address(_token), _amount, _receiver); + + _queueAndVoteAndExecuteProposalWithBravoGovernor( + _targets, _values, _calldatas, _description, FOR + ); + + // Ensure the tokens have been transferred + assertEq(_token.balanceOf(_receiver), _initialTokenBalance + _amount); + assertEq(_token.balanceOf(TIMELOCK), _timelockTokenBalance - _amount); + } + + function testFuzz_NewGovernorCanPassProposalToSendETH(uint256 _amount, address _receiver) public { + _assumeReceiver(_receiver); + vm.deal(TIMELOCK, _amount); + uint256 _timelockETHBalance = TIMELOCK.balance; + uint256 _receiverETHBalance = _receiver.balance; + + _upgradeToBravoGovernor(); + + // Craft a new proposal to send ETH. + address[] memory _targets = new address[](1); + uint256[] memory _values = new uint256[](1); + _targets[0] = _receiver; + _values[0] = _amount; + + _queueAndVoteAndExecuteProposalWithBravoGovernor( + _targets, + _values, + new bytes[](1), // There is no calldata for a plain ETH call. + "Transfer some ETH via the new Governor", + FOR // Vote/suppport type. + ); + + // Ensure the ETH was transferred. + assertEq(_receiver.balance, _receiverETHBalance + _amount); + assertEq(TIMELOCK.balance, _timelockETHBalance - _amount); + } + + function testFuzz_NewGovernorCanPassProposalToSendETHWithTokens( + uint256 _amountETH, + uint256 _amountToken, + address _receiver, + uint256 _seed + ) public { + IERC20 _token = _randomERC20Token(_seed); + _assumeReceiver(_receiver); + + vm.deal(TIMELOCK, _amountETH); + uint256 _timelockETHBalance = TIMELOCK.balance; + uint256 _receiverETHBalance = _receiver.balance; + + // Bound _amountToken by the number of tokens the timelock currently controls. + uint256 _timelockTokenBalance = _token.balanceOf(TIMELOCK); + uint256 _receiverTokenBalance = _token.balanceOf(_receiver); + _amountToken = bound(_amountToken, 0, _timelockTokenBalance); + + _upgradeToBravoGovernor(); + + // Craft a new proposal to send ETH and tokens. + address[] memory _targets = new address[](2); + uint256[] memory _values = new uint256[](2); + bytes[] memory _calldatas = new bytes[](2); + + // First call transfers tokens. + _targets[0] = address(_token); + _calldatas[0] = + _buildProposalData("transfer(address,uint256)", abi.encode(_receiver, _amountToken)); + + // Second call sends ETH. + _targets[1] = _receiver; + _values[1] = _amountETH; + + _queueAndVoteAndExecuteProposalWithBravoGovernor( + _targets, + _values, + _calldatas, + "Transfer tokens and ETH via the new Governor", + FOR // Vote/suppport type. + ); + + // Ensure the ETH was transferred. + assertEq(_receiver.balance, _receiverETHBalance + _amountETH); + assertEq(TIMELOCK.balance, _timelockETHBalance - _amountETH); + + // Ensure the tokens were transferred. + assertEq(_token.balanceOf(_receiver), _receiverTokenBalance + _amountToken); + assertEq(_token.balanceOf(TIMELOCK), _timelockTokenBalance - _amountToken); + } + + function testFuzz_NewGovernorFailedProposalsCantSendETH(uint256 _amount, address _receiver) + public + { + _assumeReceiver(_receiver); + vm.deal(TIMELOCK, _amount); + uint256 _timelockETHBalance = TIMELOCK.balance; + uint256 _receiverETHBalance = _receiver.balance; + + _upgradeToBravoGovernor(); + + // Craft a new proposal to send ETH. + address[] memory _targets = new address[](1); + uint256[] memory _values = new uint256[](1); + _targets[0] = _receiver; + _values[0] = _amount; + + _queueAndVoteAndExecuteProposalWithBravoGovernor( + _targets, + _values, + new bytes[](1), // There is no calldata for a plain ETH call. + "Transfer some ETH via the new Governor", + (_amount % 2 == 1 ? AGAINST : ABSTAIN) // Randomize vote type. + ); + + // Ensure ETH was *not* transferred. + assertEq(_receiver.balance, _receiverETHBalance); + assertEq(TIMELOCK.balance, _timelockETHBalance); + } + + function testFuzz_NewGovernorCanUpdateSettingsViaSuccessfulProposal( + uint256 _newDelay, + uint256 _newVotingPeriod, + uint256 _newProposalThreshold + ) public { + vm.assume(_newDelay != governorBravo.votingDelay()); + vm.assume(_newVotingPeriod != governorBravo.votingPeriod()); + vm.assume(_newProposalThreshold != governorBravo.proposalThreshold()); + + // The upper bounds are arbitrary here. + _newDelay = bound(_newDelay, 0, 50_000); // about a week at 1 block per 12s + _newVotingPeriod = bound(_newVotingPeriod, 1, 200_000); // about a month + _newProposalThreshold = bound(_newProposalThreshold, 0, 42 ether); + + _upgradeToBravoGovernor(); + + address[] memory _targets = new address[](3); + uint256[] memory _values = new uint256[](3); + bytes[] memory _calldatas = new bytes[](3); + string memory _description = "Update governance settings"; + + _targets[0] = address(governorBravo); + _calldatas[0] = _buildProposalData("setVotingDelay(uint256)", abi.encode(_newDelay)); + + _targets[1] = address(governorBravo); + _calldatas[1] = _buildProposalData("setVotingPeriod(uint256)", abi.encode(_newVotingPeriod)); + + _targets[2] = address(governorBravo); + _calldatas[2] = + _buildProposalData("setProposalThreshold(uint256)", abi.encode(_newProposalThreshold)); + + // Submit the new proposal + vm.prank(PROPOSER); + uint256 _newProposalId = governorBravo.propose(_targets, _values, _calldatas, _description); + + // Ensure proposal is in the expected state + IGovernor.ProposalState _state = governorBravo.state(_newProposalId); + assertEq(_state, IGovernor.ProposalState.Pending); + + _jumpToActiveProposal(_newProposalId); + + _delegatesCastVoteOnBravoGovernor(_newProposalId, FOR); + _jumpToVotingComplete(_newProposalId); + + // Ensure the proposal has succeeded + _state = governorBravo.state(_newProposalId); + assertEq(_state, IGovernor.ProposalState.Succeeded); + + // Queue the proposal + governorBravo.queue(_targets, _values, _calldatas, keccak256(bytes(_description))); + + // Ensure the proposal is queued + _state = governorBravo.state(_newProposalId); + assertEq(_state, IGovernor.ProposalState.Queued); + + _jumpPastProposalEta(_newProposalId); + + // Execute the proposal + governorBravo.execute(_targets, _values, _calldatas, keccak256(bytes(_description))); + + // Ensure the proposal is executed + _state = governorBravo.state(_newProposalId); + assertEq(_state, IGovernor.ProposalState.Executed); + + // Confirm that governance settings have updated. + assertEq(governorBravo.votingDelay(), _newDelay); + assertEq(governorBravo.votingPeriod(), _newVotingPeriod); + assertEq(governorBravo.proposalThreshold(), _newProposalThreshold); + } + + function testFuzz_NewGovernorCanPassMixedProposal( + uint256 _amount, + address _receiver, + uint256 _seed + ) public { + IERC20 _token = _randomERC20Token(_seed); + _assumeReceiver(_receiver); + uint256 _timelockTokenBalance = _token.balanceOf(TIMELOCK); + + // bound by the number of tokens the timelock currently controls + _amount = bound(_amount, 0, _timelockTokenBalance); + uint256 _initialTokenBalance = _token.balanceOf(_receiver); + + _upgradeToBravoGovernor(); + ( + uint256 _newProposalId, + address[] memory _targets, + uint256[] memory _values, + bytes[] memory _calldatas, + string memory _description + ) = _submitTokenSendProposalToGovernorBravo(address(_token), _amount, _receiver); + + _jumpToActiveProposal(_newProposalId); + + // Delegates vote with a mix of For/Against/Abstain with For winning. + // TODO: Need more delegates for this.. pool together had more! + vm.prank(delegates[0].addr); + governorBravo.castVote(_newProposalId, FOR); + vm.prank(delegates[1].addr); + governorBravo.castVote(_newProposalId, FOR); + vm.prank(delegates[2].addr); + governorBravo.castVote(_newProposalId, FOR); + vm.prank(delegates[3].addr); + governorBravo.castVote(_newProposalId, AGAINST); + vm.prank(delegates[4].addr); + governorBravo.castVote(_newProposalId, ABSTAIN); + vm.prank(delegates[5].addr); + governorBravo.castVote(_newProposalId, AGAINST); + + // The vote should pass. We are asserting against the raw delegate voting + // weight as a sanity check. In the event that the fork block is changed and + // voting weights are materially different than they were when the test was + // written, we want this assertion to fail. + assertGt( + delegates[0].votes + delegates[1].votes + delegates[2].votes, // FOR votes. + delegates[3].votes + delegates[5].votes // AGAINST votes. + ); + + _jumpToVotingComplete(_newProposalId); + + // Ensure the proposal has succeeded + IGovernor.ProposalState _state = governorBravo.state(_newProposalId); + assertEq(_state, IGovernor.ProposalState.Succeeded); + + // Queue the proposal + governorBravo.queue(_targets, _values, _calldatas, keccak256(bytes(_description))); + + _jumpPastProposalEta(_newProposalId); + + // Execute the proposal + governorBravo.execute(_targets, _values, _calldatas, keccak256(bytes(_description))); + + // Ensure the proposal is executed + _state = governorBravo.state(_newProposalId); + assertEq(_state, IGovernor.ProposalState.Executed); + + // Ensure the tokens have been transferred + assertEq(_token.balanceOf(_receiver), _initialTokenBalance + _amount); + assertEq(_token.balanceOf(TIMELOCK), _timelockTokenBalance - _amount); + } + + function testFuzz_NewGovernorCanDefeatMixedProposal( + uint256 _amount, + address _receiver, + uint256 _seed + ) public { + IERC20 _token = _randomERC20Token(_seed); + _assumeReceiver(_receiver); + uint256 _timelockTokenBalance = _token.balanceOf(TIMELOCK); + + // bound by the number of tokens the timelock currently controls + _amount = bound(_amount, 0, _timelockTokenBalance); + + _upgradeToBravoGovernor(); + + ( + uint256 _newProposalId, + address[] memory _targets, + uint256[] memory _values, + bytes[] memory _calldatas, + string memory _description + ) = _submitTokenSendProposalToGovernorBravo(address(_token), _amount, _receiver); + + _jumpToActiveProposal(_newProposalId); + + // Delegates vote with a mix of For/Against/Abstain with Against/Abstain winning. + vm.prank(delegates[0].addr); + governorBravo.castVote(_newProposalId, ABSTAIN); + vm.prank(delegates[1].addr); + governorBravo.castVote(_newProposalId, FOR); + vm.prank(delegates[2].addr); + governorBravo.castVote(_newProposalId, AGAINST); + vm.prank(delegates[3].addr); + governorBravo.castVote(_newProposalId, AGAINST); + vm.prank(delegates[4].addr); + governorBravo.castVote(_newProposalId, FOR); + vm.prank(delegates[5].addr); + governorBravo.castVote(_newProposalId, AGAINST); + + // The vote should fail. We are asserting against the raw delegate voting + // weight as a sanity check. In the event that the fork block is changed and + // voting weights are materially different than they were when the test was + // written, we want this assertion to fail. + assertLt( + delegates[1].votes + delegates[4].votes, // FOR votes. + delegates[2].votes + delegates[3].votes + delegates[5].votes // AGAINST votes. + ); + + _jumpToVotingComplete(_newProposalId); + + // Ensure the proposal has failed + IGovernor.ProposalState _state = governorBravo.state(_newProposalId); + assertEq(_state, IGovernor.ProposalState.Defeated); + + // It should not be possible to queue the proposal + vm.expectRevert("Governor: proposal not successful"); + governorBravo.queue(_targets, _values, _calldatas, keccak256(bytes(_description))); + } + + struct NewGovernorUnaffectedByVotesOnOldGovernorVars { + uint256 alphaProposalId; + address[] alphaTargets; + uint256[] alphaValues; + string[] alphaSignatures; + bytes[] alphaCalldatas; + string alphaDescription; + uint256 bravoProposalId; + address[] bravoTargets; + uint256[] bravoValues; + bytes[] bravoCalldatas; + string bravoDescription; + } + + function testFuzz_NewGovernorUnaffectedByVotesOnOldGovernor( + uint256 _amount, + address _receiver, + uint256 _seed + ) public { + NewGovernorUnaffectedByVotesOnOldGovernorVars memory _vars; + IERC20 _token = _randomERC20Token(_seed); + _assumeReceiver(_receiver); + + _upgradeToBravoGovernor(); + + // Create a new proposal to send the token. + _vars.alphaTargets = new address[](1); + _vars.alphaValues = new uint256[](1); + _vars.alphaSignatures = new string[](1); + _vars.alphaCalldatas = new bytes[](1); + _vars.alphaDescription = "Transfer some tokens from the new Governor"; + + _vars.alphaTargets[0] = address(_token); + _vars.alphaSignatures[0] = "transfer(address,uint256)"; + _vars.alphaCalldatas[0] = abi.encode(_receiver, _amount); + + // Submit the new proposal to Governor Alpha, which is now deprecated. + vm.prank(PROPOSER); + _vars.alphaProposalId = governorAlpha.propose( + _vars.alphaTargets, + _vars.alphaValues, + _vars.alphaSignatures, + _vars.alphaCalldatas, + _vars.alphaDescription + ); + + // Now construct and submit an identical proposal on Governor Bravo, which is active. + ( + _vars.bravoProposalId, + _vars.bravoTargets, + _vars.bravoValues, + _vars.bravoCalldatas, + _vars.bravoDescription + ) = _submitTokenSendProposalToGovernorBravo(address(_token), _amount, _receiver); + + assertEq( + uint8(governorAlpha.state(_vars.alphaProposalId)), + uint8(governorBravo.state(_vars.bravoProposalId)) + ); + + _jumpToActiveProposal(_vars.bravoProposalId); + + // Defeat the proposal on Bravo. + assertEq(governorBravo.state(_vars.bravoProposalId), IGovernor.ProposalState.Active); + _delegatesCastVoteOnBravoGovernor(_vars.bravoProposalId, AGAINST); + + // Pass the proposal on Alpha. + for (uint256 _index = 0; _index < delegates.length; _index++) { + vm.prank(delegates[_index].addr); + governorAlpha.castVote(_vars.alphaProposalId, true); + } + + _jumpToVotingComplete(_vars.bravoProposalId); + + // Ensure the Bravo proposal has failed and Alpha has succeeded. + assertEq(governorBravo.state(_vars.bravoProposalId), IGovernor.ProposalState.Defeated); + assertEq(governorAlpha.state(_vars.alphaProposalId), uint8(IGovernor.ProposalState.Succeeded)); + + // It should not be possible to queue either proposal, confirming that votes + // on alpha do not affect votes on bravo. + vm.expectRevert("Governor: proposal not successful"); + governorBravo.queue( + _vars.bravoTargets, + _vars.bravoValues, + _vars.bravoCalldatas, + keccak256(bytes(_vars.bravoDescription)) + ); + vm.expectRevert("Timelock::queueTransaction: Call must come from admin."); + governorAlpha.queue(_vars.alphaProposalId); + } +} // TODO: future PR abstract contract Execute is ProposalTest {} diff --git a/test/helpers/RadworksGovernorTest.sol b/test/helpers/RadworksGovernorTest.sol index 04c5e08..b4f12e7 100644 --- a/test/helpers/RadworksGovernorTest.sol +++ b/test/helpers/RadworksGovernorTest.sol @@ -37,13 +37,13 @@ abstract contract RadworksGovernorTest is Test, DeployInput, Constants { // make sure to update any tests that reference specific delegates. The last delegate is the // proposer and lower in the voting power than the above link. // TODO: resolve the list of large delegates with tally - Delegate[] memory _delegates = new Delegate[](3); + Delegate[] memory _delegates = new Delegate[](6); _delegates[0] = Delegate("Delegate 0", 0x288703AA4e65dD244680FaefA742C488b7CD1992, 4.24e6); _delegates[1] = Delegate("Delegate 1", 0x69dceee155C31eA0c8354F90BDD65C12FaF5A00a, 1.86e6); - // _delegates[2] = Delegate("Delegate 2", 0x464D78a5C97A2E2E9839C353ee9B6d4204c90B0b, 1.58e6); - // _delegates[3] = Delegate("Delegate 3", 0xc74f55155C41dfB90C122A1702b49C8295D9a724, 988.24e3); - // _delegates[4] = Delegate("Delegate 4", 0xBD8d617Ac53c5Efc5fBDBb51d445f7A2350D4940, 680.27e6); - _delegates[2] = Delegate("proposer", PROPOSER, 1.58e6); + _delegates[2] = Delegate("Delegate 2", 0xc74f55155C41dfB90C122A1702b49C8295D9a724, 950e3); + _delegates[3] = Delegate("Delegate 3", 0xBD8d617Ac53c5Efc5fBDBb51d445f7A2350D4940, 680.27e3); + _delegates[4] = Delegate("Delegate 4", 0x6851566a6183Eff8440456a58823B87107eAd707, 590.28e3); + _delegates[5] = Delegate("proposer", PROPOSER, 1.58e6); // Fetch up-to-date voting weight for the top delegates. for (uint256 i; i < _delegates.length; i++) {