diff --git a/packages/nouns-contracts/contracts/Rewards.sol b/packages/nouns-contracts/contracts/Rewards.sol index 3f70a449a5..771ad79727 100644 --- a/packages/nouns-contracts/contracts/Rewards.sol +++ b/packages/nouns-contracts/contracts/Rewards.sol @@ -17,7 +17,7 @@ pragma solidity ^0.8.19; import { INounsDAOLogicV3 } from './interfaces/INounsDAOLogicV3.sol'; import { INounsAuctionHouseV2 } from './interfaces/INounsAuctionHouseV2.sol'; -import { NounsDAOStorageV3 } from './governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from './governance/NounsDAOInterfaces.sol'; import { ERC721 } from '@openzeppelin/contracts-v5/token/ERC721/ERC721.sol'; import { IERC20 } from '@openzeppelin/contracts-v5/token/ERC20/IERC20.sol'; @@ -72,7 +72,7 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives') { uint256 actualNumEligibleVotes; uint256 rewardPerProposal; uint256 rewardPerVote; - NounsDAOStorageV3.ProposalForRewards proposal; + NounsDAOV3Types.ProposalForRewards proposal; } function updateRewardsForAuctions(uint256 lastNounId) public { @@ -164,7 +164,7 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives') { uint256 votesInProposal; - NounsDAOStorageV3.ClientVoteData[] memory voteData = nounsDAO.proposalVoteClientsData(pid, votingClientIds); + NounsDAOV3Types.ClientVoteData[] memory voteData = nounsDAO.proposalVoteClientsData(pid, votingClientIds); uint256 votes; for (uint256 i; i < votingClientIds.length; ++i) { @@ -204,7 +204,7 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives') { } function getParamsForUpdatingProposalRewards() public view returns (ProposalRewardsParams memory p) { - NounsDAOStorageV3.ProposalForRewards memory proposal; + NounsDAOV3Types.ProposalForRewards memory proposal; uint256 maxProposalId = nounsDAO.proposalCount(); uint32[] memory allClientIds = new uint32[](nextTokenId); @@ -229,7 +229,7 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives') { p.lastProposalId = pid; - NounsDAOStorageV3.ClientVoteData[] memory voteData = nounsDAO.proposalVoteClientsData(pid, allClientIds); + NounsDAOV3Types.ClientVoteData[] memory voteData = nounsDAO.proposalVoteClientsData(pid, allClientIds); for (uint256 i; i < nextTokenId; i++) { if (voteData[i].votes > 0) { if (votingClientIds[i] == 0) { @@ -312,7 +312,7 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives') { return tokenId; } - function requireProposalEligibleForRewards(NounsDAOStorageV3.ProposalCondensed memory proposal) internal view { + function requireProposalEligibleForRewards(NounsDAOV3Types.ProposalCondensed memory proposal) internal view { require(proposal.forVotes >= proposal.quorumVotes, 'must reach quorum'); // voting has ended diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOInterfaces.sol b/packages/nouns-contracts/contracts/governance/NounsDAOInterfaces.sol index 8818bd9e67..7a362a495e 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOInterfaces.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOInterfaces.sol @@ -32,9 +32,9 @@ // NounsDAOStorageV3 // See NounsDAOLogicV3.sol for more details. -pragma solidity ^0.8.6; +pragma solidity ^0.8.19; -contract NounsDAOEvents { +interface NounsDAOEventsV3 { /// @notice An event emitted when a new proposal is created event ProposalCreated( uint256 id, @@ -89,9 +89,6 @@ contract NounsDAOEvents { /// @notice An event emitted when the voting period is set event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod); - /// @notice Emitted when implementation is changed - event NewImplementation(address oldImplementation, address newImplementation); - /// @notice Emitted when proposal threshold basis points is set event ProposalThresholdBPSSet(uint256 oldProposalThresholdBPS, uint256 newProposalThresholdBPS); @@ -106,9 +103,7 @@ contract NounsDAOEvents { /// @notice Emitted when vetoer is changed event NewVetoer(address oldVetoer, address newVetoer); -} -contract NounsDAOEventsV2 is NounsDAOEvents { /// @notice Emitted when minQuorumVotesBPS is set event MinQuorumVotesBPSSet(uint16 oldMinQuorumVotesBPS, uint16 newMinQuorumVotesBPS); @@ -126,15 +121,13 @@ contract NounsDAOEventsV2 is NounsDAOEvents { /// @notice Emitted when pendingVetoer is changed event NewPendingVetoer(address oldPendingVetoer, address newPendingVetoer); -} -contract NounsDAOEventsV3 is NounsDAOEventsV2 { /// @notice An event emitted when a new proposal is created, which includes additional information /// @dev V3 adds `signers`, `updatePeriodEndBlock` compared to the V1/V2 event. /// @dev V4: Removed data that's already emitted in `ProposalCreated`, added clientId event ProposalCreatedWithRequirements( - uint256 id, - address[] signers, + uint256 id, + address[] signers, uint256 updatePeriodEndBlock, uint256 proposalThreshold, uint256 quorumVotes, @@ -259,285 +252,6 @@ contract NounsDAOEventsV3 is NounsDAOEventsV2 { event VoteCastWithClientId(address indexed voter, uint256 indexed proposalId, uint32 indexed clientId); } -contract NounsDAOProxyStorage { - /// @notice Administrator for this contract - address public admin; - - /// @notice Pending administrator for this contract - address public pendingAdmin; - - /// @notice Active brains of Governor - address public implementation; -} - -/** - * @title Storage for Governor Bravo Delegate - * @notice For future upgrades, do not change NounsDAOStorageV1. Create a new - * contract which implements NounsDAOStorageV1 and following the naming convention - * NounsDAOStorageVX. - */ -contract NounsDAOStorageV1 is NounsDAOProxyStorage { - /// @notice Vetoer who has the ability to veto any proposal - address public vetoer; - - /// @notice The delay before voting on a proposal may take place, once proposed, in blocks - uint256 public votingDelay; - - /// @notice The duration of voting on a proposal, in blocks - uint256 public votingPeriod; - - /// @notice The basis point number of votes required in order for a voter to become a proposer. *DIFFERS from GovernerBravo - uint256 public proposalThresholdBPS; - - /// @notice The basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. *DIFFERS from GovernerBravo - uint256 public quorumVotesBPS; - - /// @notice The total number of proposals - uint256 public proposalCount; - - /// @notice The address of the Nouns DAO Executor NounsDAOExecutor - INounsDAOExecutor public timelock; - - /// @notice The address of the Nouns tokens - NounsTokenLike public nouns; - - /// @notice The official record of all proposals ever proposed - mapping(uint256 => Proposal) public proposals; - - /// @notice The latest proposal for each proposer - mapping(address => uint256) public latestProposalIds; - - struct Proposal { - /// @notice Unique id for looking up a proposal - uint256 id; - /// @notice Creator of the proposal - address proposer; - /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo - uint256 proposalThreshold; - /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo - uint256 quorumVotes; - /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds - uint256 eta; - /// @notice the ordered list of target addresses for calls to be made - address[] targets; - /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made - uint256[] values; - /// @notice The ordered list of function signatures to be called - string[] signatures; - /// @notice The ordered list of calldata to be passed to each call - bytes[] calldatas; - /// @notice The block at which voting begins: holders must delegate their votes prior to this block - uint256 startBlock; - /// @notice The block at which voting ends: votes must be cast prior to this block - uint256 endBlock; - /// @notice Current number of votes in favor of this proposal - uint256 forVotes; - /// @notice Current number of votes in opposition to this proposal - uint256 againstVotes; - /// @notice Current number of votes for abstaining for this proposal - uint256 abstainVotes; - /// @notice Flag marking whether the proposal has been canceled - bool canceled; - /// @notice Flag marking whether the proposal has been vetoed - bool vetoed; - /// @notice Flag marking whether the proposal has been executed - bool executed; - /// @notice Receipts of ballots for the entire set of voters - mapping(address => Receipt) receipts; - } - - /// @notice Ballot receipt record for a voter - struct Receipt { - /// @notice Whether or not a vote has been cast - bool hasVoted; - /// @notice Whether or not the voter supports the proposal or abstains - uint8 support; - /// @notice The number of votes the voter had, which were cast - uint96 votes; - } - - /// @notice Possible states that a proposal may be in - enum ProposalState { - Pending, - Active, - Canceled, - Defeated, - Succeeded, - Queued, - Expired, - Executed, - Vetoed - } -} - -/** - * @title Extra fields added to the `Proposal` struct from NounsDAOStorageV1 - * @notice The following fields were added to the `Proposal` struct: - * - `Proposal.totalSupply` - * - `Proposal.creationBlock` - */ -contract NounsDAOStorageV1Adjusted is NounsDAOProxyStorage { - /// @notice Vetoer who has the ability to veto any proposal - address public vetoer; - - /// @notice The delay before voting on a proposal may take place, once proposed, in blocks - uint256 public votingDelay; - - /// @notice The duration of voting on a proposal, in blocks - uint256 public votingPeriod; - - /// @notice The basis point number of votes required in order for a voter to become a proposer. *DIFFERS from GovernerBravo - uint256 public proposalThresholdBPS; - - /// @notice The basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. *DIFFERS from GovernerBravo - uint256 public quorumVotesBPS; - - /// @notice The total number of proposals - uint256 public proposalCount; - - /// @notice The address of the Nouns DAO Executor NounsDAOExecutor - INounsDAOExecutor public timelock; - - /// @notice The address of the Nouns tokens - NounsTokenLike public nouns; - - /// @notice The official record of all proposals ever proposed - mapping(uint256 => Proposal) internal _proposals; - - /// @notice The latest proposal for each proposer - mapping(address => uint256) public latestProposalIds; - - struct Proposal { - /// @notice Unique id for looking up a proposal - uint256 id; - /// @notice Creator of the proposal - address proposer; - /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo - uint256 proposalThreshold; - /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo - uint256 quorumVotes; - /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds - uint256 eta; - /// @notice the ordered list of target addresses for calls to be made - address[] targets; - /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made - uint256[] values; - /// @notice The ordered list of function signatures to be called - string[] signatures; - /// @notice The ordered list of calldata to be passed to each call - bytes[] calldatas; - /// @notice The block at which voting begins: holders must delegate their votes prior to this block - uint256 startBlock; - /// @notice The block at which voting ends: votes must be cast prior to this block - uint256 endBlock; - /// @notice Current number of votes in favor of this proposal - uint256 forVotes; - /// @notice Current number of votes in opposition to this proposal - uint256 againstVotes; - /// @notice Current number of votes for abstaining for this proposal - uint256 abstainVotes; - /// @notice Flag marking whether the proposal has been canceled - bool canceled; - /// @notice Flag marking whether the proposal has been vetoed - bool vetoed; - /// @notice Flag marking whether the proposal has been executed - bool executed; - /// @notice Receipts of ballots for the entire set of voters - mapping(address => Receipt) receipts; - /// @notice The total supply at the time of proposal creation - uint256 totalSupply; - /// @notice The block at which this proposal was created - uint256 creationBlock; - } - - /// @notice Ballot receipt record for a voter - struct Receipt { - /// @notice Whether or not a vote has been cast - bool hasVoted; - /// @notice Whether or not the voter supports the proposal or abstains - uint8 support; - /// @notice The number of votes the voter had, which were cast - uint96 votes; - } - - /// @notice Possible states that a proposal may be in - enum ProposalState { - Pending, - Active, - Canceled, - Defeated, - Succeeded, - Queued, - Expired, - Executed, - Vetoed - } -} - -/** - * @title Storage for Governor Bravo Delegate - * @notice For future upgrades, do not change NounsDAOStorageV2. Create a new - * contract which implements NounsDAOStorageV2 and following the naming convention - * NounsDAOStorageVX. - */ -contract NounsDAOStorageV2 is NounsDAOStorageV1Adjusted { - DynamicQuorumParamsCheckpoint[] public quorumParamsCheckpoints; - - /// @notice Pending new vetoer - address public pendingVetoer; - - struct DynamicQuorumParams { - /// @notice The minimum basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. - uint16 minQuorumVotesBPS; - /// @notice The maximum basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. - uint16 maxQuorumVotesBPS; - /// @notice The dynamic quorum coefficient - /// @dev Assumed to be fixed point integer with 6 decimals, i.e 0.2 is represented as 0.2 * 1e6 = 200000 - uint32 quorumCoefficient; - } - - /// @notice A checkpoint for storing dynamic quorum params from a given block - struct DynamicQuorumParamsCheckpoint { - /// @notice The block at which the new values were set - uint32 fromBlock; - /// @notice The parameter values of this checkpoint - DynamicQuorumParams params; - } - - struct ProposalCondensed { - /// @notice Unique id for looking up a proposal - uint256 id; - /// @notice Creator of the proposal - address proposer; - /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo - uint256 proposalThreshold; - /// @notice The minimum number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo - uint256 quorumVotes; - /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds - uint256 eta; - /// @notice The block at which voting begins: holders must delegate their votes prior to this block - uint256 startBlock; - /// @notice The block at which voting ends: votes must be cast prior to this block - uint256 endBlock; - /// @notice Current number of votes in favor of this proposal - uint256 forVotes; - /// @notice Current number of votes in opposition to this proposal - uint256 againstVotes; - /// @notice Current number of votes for abstaining for this proposal - uint256 abstainVotes; - /// @notice Flag marking whether the proposal has been canceled - bool canceled; - /// @notice Flag marking whether the proposal has been vetoed - bool vetoed; - /// @notice Flag marking whether the proposal has been executed - bool executed; - /// @notice The total supply at the time of proposal creation - uint256 totalSupply; - /// @notice The block at which this proposal was created - uint256 creationBlock; - } -} - interface INounsDAOExecutor { function delay() external view returns (uint256); @@ -577,17 +291,9 @@ interface NounsTokenLike { function totalSupply() external view returns (uint256); - function transferFrom( - address from, - address to, - uint256 tokenId - ) external; + function transferFrom(address from, address to, uint256 tokenId) external; - function safeTransferFrom( - address from, - address to, - uint256 tokenId - ) external; + function safeTransferFrom(address from, address to, uint256 tokenId) external; function balanceOf(address owner) external view returns (uint256 balance); @@ -601,9 +307,10 @@ interface NounsTokenLike { } interface IForkDAODeployer { - function deployForkDAO(uint256 forkingPeriodEndTimestamp, INounsDAOForkEscrow forkEscrowAddress) - external - returns (address treasury, address token); + function deployForkDAO( + uint256 forkingPeriodEndTimestamp, + INounsDAOForkEscrow forkEscrowAddress + ) external returns (address treasury, address token); function tokenImpl() external view returns (address); @@ -617,11 +324,7 @@ interface IForkDAODeployer { interface INounsDAOExecutorV2 is INounsDAOExecutor { function sendETH(address recipient, uint256 ethToSend) external; - function sendERC20( - address recipient, - address erc20Token, - uint256 tokensToSend - ) external; + function sendERC20(address recipient, address erc20Token, uint256 tokensToSend) external; } interface INounsDAOForkEscrow { @@ -646,9 +349,7 @@ interface INounsDAOForkEscrow { function ownerOfEscrowedToken(uint32 forkId_, uint256 tokenId) external view returns (address); } -contract NounsDAOStorageV3 { - StorageV3 ds; - +interface NounsDAOV3Types { struct StorageV3 { // ================ PROXY ================ // /// @notice Administrator for this contract @@ -865,6 +566,39 @@ contract NounsDAOStorageV3 { bool executeOnTimelockV1; } + struct ProposalCondensedV2 { + /// @notice Unique id for looking up a proposal + uint256 id; + /// @notice Creator of the proposal + address proposer; + /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo + uint256 proposalThreshold; + /// @notice The minimum number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo + uint256 quorumVotes; + /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds + uint256 eta; + /// @notice The block at which voting begins: holders must delegate their votes prior to this block + uint256 startBlock; + /// @notice The block at which voting ends: votes must be cast prior to this block + uint256 endBlock; + /// @notice Current number of votes in favor of this proposal + uint256 forVotes; + /// @notice Current number of votes in opposition to this proposal + uint256 againstVotes; + /// @notice Current number of votes for abstaining for this proposal + uint256 abstainVotes; + /// @notice Flag marking whether the proposal has been canceled + bool canceled; + /// @notice Flag marking whether the proposal has been vetoed + bool vetoed; + /// @notice Flag marking whether the proposal has been executed + bool executed; + /// @notice The total supply at the time of proposal creation + uint256 totalSupply; + /// @notice The block at which this proposal was created + uint256 creationBlock; + } + struct DynamicQuorumParams { /// @notice The minimum basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. uint16 minQuorumVotesBPS; @@ -907,3 +641,7 @@ contract NounsDAOStorageV3 { Updatable } } + +contract NounsDAOStorageV3 is NounsDAOV3Types { + StorageV3 ds; +} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV1.sol b/packages/nouns-contracts/contracts/governance/NounsDAOLogicV1.sol deleted file mode 100644 index 5654382d05..0000000000 --- a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV1.sol +++ /dev/null @@ -1,683 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/// @title The Nouns DAO logic version 1 - -/********************************* - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░██░░░████░░██░░░████░░░ * - * ░░██████░░░████████░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - *********************************/ - -// LICENSE -// NounsDAOLogicV1.sol is a modified version of Compound Lab's GovernorBravoDelegate.sol: -// https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoDelegate.sol -// -// GovernorBravoDelegate.sol source code Copyright 2020 Compound Labs, Inc. licensed under the BSD-3-Clause license. -// With modifications by Nounders DAO. -// -// Additional conditions of BSD-3-Clause can be found here: https://opensource.org/licenses/BSD-3-Clause -// -// MODIFICATIONS -// NounsDAOLogicV1 adds: -// - Proposal Threshold basis points instead of fixed number -// due to the Noun token's increasing supply -// -// - Quorum Votes basis points instead of fixed number -// due to the Noun token's increasing supply -// -// - Per proposal storing of fixed `proposalThreshold` -// and `quorumVotes` calculated using the Noun token's total supply -// at the block the proposal was created and the basis point parameters -// -// - `ProposalCreatedWithRequirements` event that emits `ProposalCreated` parameters with -// the addition of `proposalThreshold` and `quorumVotes` -// -// - Votes are counted from the block a proposal is created instead of -// the proposal's voting start block to align with the parameters -// stored with the proposal -// -// - Veto ability which allows `veteor` to halt any proposal at any stage unless -// the proposal is executed. -// The `veto(uint proposalId)` logic is a modified version of `cancel(uint proposalId)` -// A `vetoed` flag was added to the `Proposal` struct to support this. -// -// NounsDAOLogicV1 removes: -// - `initialProposalId` and `_initiate()` due to this being the -// first instance of the governance contract unlike -// GovernorBravo which upgrades GovernorAlpha -// -// - Value passed along using `timelock.executeTransaction{value: proposal.value}` -// in `execute(uint proposalId)`. This contract should not hold funds and does not -// implement `receive()` or `fallback()` functions. -// - -pragma solidity ^0.8.6; - -import './NounsDAOInterfaces.sol'; - -contract NounsDAOLogicV1 is NounsDAOStorageV1, NounsDAOEvents { - /// @notice The name of this contract - string public constant name = 'Nouns DAO'; - - /// @notice The minimum setable proposal threshold - uint256 public constant MIN_PROPOSAL_THRESHOLD_BPS = 1; // 1 basis point or 0.01% - - /// @notice The maximum setable proposal threshold - uint256 public constant MAX_PROPOSAL_THRESHOLD_BPS = 1_000; // 1,000 basis points or 10% - - /// @notice The minimum setable voting period - uint256 public constant MIN_VOTING_PERIOD = 5_760; // About 24 hours - - /// @notice The max setable voting period - uint256 public constant MAX_VOTING_PERIOD = 80_640; // About 2 weeks - - /// @notice The min setable voting delay - uint256 public constant MIN_VOTING_DELAY = 1; - - /// @notice The max setable voting delay - uint256 public constant MAX_VOTING_DELAY = 40_320; // About 1 week - - /// @notice The minimum setable quorum votes basis points - uint256 public constant MIN_QUORUM_VOTES_BPS = 200; // 200 basis points or 2% - - /// @notice The maximum setable quorum votes basis points - uint256 public constant MAX_QUORUM_VOTES_BPS = 2_000; // 2,000 basis points or 20% - - /// @notice The maximum number of actions that can be included in a proposal - uint256 public constant proposalMaxOperations = 10; // 10 actions - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)'); - - /// @notice The EIP-712 typehash for the ballot struct used by the contract - bytes32 public constant BALLOT_TYPEHASH = keccak256('Ballot(uint256 proposalId,uint8 support)'); - - /** - * @notice Used to initialize the contract during delegator contructor - * @param timelock_ The address of the NounsDAOExecutor - * @param nouns_ The address of the NOUN tokens - * @param vetoer_ The address allowed to unilaterally veto proposals - * @param votingPeriod_ The initial voting period - * @param votingDelay_ The initial voting delay - * @param proposalThresholdBPS_ The initial proposal threshold in basis points - * * @param quorumVotesBPS_ The initial quorum votes threshold in basis points - */ - function initialize( - address timelock_, - address nouns_, - address vetoer_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - uint256 quorumVotesBPS_ - ) public virtual { - require(address(timelock) == address(0), 'NounsDAO::initialize: can only initialize once'); - require(msg.sender == admin, 'NounsDAO::initialize: admin only'); - require(timelock_ != address(0), 'NounsDAO::initialize: invalid timelock address'); - require(nouns_ != address(0), 'NounsDAO::initialize: invalid nouns address'); - require( - votingPeriod_ >= MIN_VOTING_PERIOD && votingPeriod_ <= MAX_VOTING_PERIOD, - 'NounsDAO::initialize: invalid voting period' - ); - require( - votingDelay_ >= MIN_VOTING_DELAY && votingDelay_ <= MAX_VOTING_DELAY, - 'NounsDAO::initialize: invalid voting delay' - ); - require( - proposalThresholdBPS_ >= MIN_PROPOSAL_THRESHOLD_BPS && proposalThresholdBPS_ <= MAX_PROPOSAL_THRESHOLD_BPS, - 'NounsDAO::initialize: invalid proposal threshold' - ); - require( - quorumVotesBPS_ >= MIN_QUORUM_VOTES_BPS && quorumVotesBPS_ <= MAX_QUORUM_VOTES_BPS, - 'NounsDAO::initialize: invalid proposal threshold' - ); - - emit VotingPeriodSet(votingPeriod, votingPeriod_); - emit VotingDelaySet(votingDelay, votingDelay_); - emit ProposalThresholdBPSSet(proposalThresholdBPS, proposalThresholdBPS_); - emit QuorumVotesBPSSet(quorumVotesBPS, quorumVotesBPS_); - - timelock = INounsDAOExecutor(timelock_); - nouns = NounsTokenLike(nouns_); - vetoer = vetoer_; - votingPeriod = votingPeriod_; - votingDelay = votingDelay_; - proposalThresholdBPS = proposalThresholdBPS_; - quorumVotesBPS = quorumVotesBPS_; - } - - struct ProposalTemp { - uint256 totalSupply; - uint256 proposalThreshold; - uint256 latestProposalId; - uint256 startBlock; - uint256 endBlock; - } - - /** - * @notice Function used to propose a new proposal. Sender must have delegates above the proposal threshold - * @param targets Target addresses for proposal calls - * @param values Eth values for proposal calls - * @param signatures Function signatures for proposal calls - * @param calldatas Calldatas for proposal calls - * @param description String description of the proposal - * @return Proposal id of new proposal - */ - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) public returns (uint256) { - ProposalTemp memory temp; - - temp.totalSupply = nouns.totalSupply(); - - temp.proposalThreshold = bps2Uint(proposalThresholdBPS, temp.totalSupply); - - require( - nouns.getPriorVotes(msg.sender, block.number - 1) > temp.proposalThreshold, - 'NounsDAO::propose: proposer votes below proposal threshold' - ); - require( - targets.length == values.length && - targets.length == signatures.length && - targets.length == calldatas.length, - 'NounsDAO::propose: proposal function information arity mismatch' - ); - require(targets.length != 0, 'NounsDAO::propose: must provide actions'); - require(targets.length <= proposalMaxOperations, 'NounsDAO::propose: too many actions'); - - temp.latestProposalId = latestProposalIds[msg.sender]; - if (temp.latestProposalId != 0) { - ProposalState proposersLatestProposalState = state(temp.latestProposalId); - require( - proposersLatestProposalState != ProposalState.Active, - 'NounsDAO::propose: one live proposal per proposer, found an already active proposal' - ); - require( - proposersLatestProposalState != ProposalState.Pending, - 'NounsDAO::propose: one live proposal per proposer, found an already pending proposal' - ); - } - - temp.startBlock = block.number + votingDelay; - temp.endBlock = temp.startBlock + votingPeriod; - - proposalCount++; - Proposal storage newProposal = proposals[proposalCount]; - - newProposal.id = proposalCount; - newProposal.proposer = msg.sender; - newProposal.proposalThreshold = temp.proposalThreshold; - newProposal.quorumVotes = bps2Uint(quorumVotesBPS, temp.totalSupply); - newProposal.eta = 0; - newProposal.targets = targets; - newProposal.values = values; - newProposal.signatures = signatures; - newProposal.calldatas = calldatas; - newProposal.startBlock = temp.startBlock; - newProposal.endBlock = temp.endBlock; - newProposal.forVotes = 0; - newProposal.againstVotes = 0; - newProposal.abstainVotes = 0; - newProposal.canceled = false; - newProposal.executed = false; - newProposal.vetoed = false; - - latestProposalIds[newProposal.proposer] = newProposal.id; - - /// @notice Maintains backwards compatibility with GovernorBravo events - emit ProposalCreated( - newProposal.id, - msg.sender, - targets, - values, - signatures, - calldatas, - newProposal.startBlock, - newProposal.endBlock, - description - ); - - /// @notice Updated event with `proposalThreshold` and `quorumVotes` - emit ProposalCreatedWithRequirements( - newProposal.id, - msg.sender, - targets, - values, - signatures, - calldatas, - newProposal.startBlock, - newProposal.endBlock, - newProposal.proposalThreshold, - newProposal.quorumVotes, - description - ); - - return newProposal.id; - } - - /** - * @notice Queues a proposal of state succeeded - * @param proposalId The id of the proposal to queue - */ - function queue(uint256 proposalId) external { - require( - state(proposalId) == ProposalState.Succeeded, - 'NounsDAO::queue: proposal can only be queued if it is succeeded' - ); - Proposal storage proposal = proposals[proposalId]; - uint256 eta = block.timestamp + timelock.delay(); - for (uint256 i = 0; i < proposal.targets.length; i++) { - queueOrRevertInternal( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - eta - ); - } - proposal.eta = eta; - emit ProposalQueued(proposalId, eta); - } - - function queueOrRevertInternal( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) internal { - require( - !timelock.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta))), - 'NounsDAO::queueOrRevertInternal: identical proposal action already queued at eta' - ); - timelock.queueTransaction(target, value, signature, data, eta); - } - - /** - * @notice Executes a queued proposal if eta has passed - * @param proposalId The id of the proposal to execute - */ - function execute(uint256 proposalId) external { - require( - state(proposalId) == ProposalState.Queued, - 'NounsDAO::execute: proposal can only be executed if it is queued' - ); - Proposal storage proposal = proposals[proposalId]; - proposal.executed = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.executeTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - emit ProposalExecuted(proposalId); - } - - /** - * @notice Cancels a proposal only if sender is the proposer, or proposer delegates dropped below proposal threshold - * @param proposalId The id of the proposal to cancel - */ - function cancel(uint256 proposalId) external { - require(state(proposalId) != ProposalState.Executed, 'NounsDAO::cancel: cannot cancel executed proposal'); - - Proposal storage proposal = proposals[proposalId]; - require( - msg.sender == proposal.proposer || - nouns.getPriorVotes(proposal.proposer, block.number - 1) < proposal.proposalThreshold, - 'NounsDAO::cancel: proposer above threshold' - ); - - proposal.canceled = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.cancelTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - - emit ProposalCanceled(proposalId); - } - - /** - * @notice Vetoes a proposal only if sender is the vetoer and the proposal has not been executed. - * @param proposalId The id of the proposal to veto - */ - function veto(uint256 proposalId) external { - require(vetoer != address(0), 'NounsDAO::veto: veto power burned'); - require(msg.sender == vetoer, 'NounsDAO::veto: only vetoer'); - require(state(proposalId) != ProposalState.Executed, 'NounsDAO::veto: cannot veto executed proposal'); - - Proposal storage proposal = proposals[proposalId]; - - proposal.vetoed = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.cancelTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - - emit ProposalVetoed(proposalId); - } - - /** - * @notice Gets actions of a proposal - * @param proposalId the id of the proposal - * @return targets - * @return values - * @return signatures - * @return calldatas - */ - function getActions(uint256 proposalId) - external - view - returns ( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas - ) - { - Proposal storage p = proposals[proposalId]; - return (p.targets, p.values, p.signatures, p.calldatas); - } - - /** - * @notice Gets the receipt for a voter on a given proposal - * @param proposalId the id of proposal - * @param voter The address of the voter - * @return The voting receipt - */ - function getReceipt(uint256 proposalId, address voter) external view returns (Receipt memory) { - return proposals[proposalId].receipts[voter]; - } - - /** - * @notice Gets the state of a proposal - * @param proposalId The id of the proposal - * @return Proposal state - */ - function state(uint256 proposalId) public view returns (ProposalState) { - require(proposalCount >= proposalId, 'NounsDAO::state: invalid proposal id'); - Proposal storage proposal = proposals[proposalId]; - if (proposal.vetoed) { - return ProposalState.Vetoed; - } else if (proposal.canceled) { - return ProposalState.Canceled; - } else if (block.number <= proposal.startBlock) { - return ProposalState.Pending; - } else if (block.number <= proposal.endBlock) { - return ProposalState.Active; - } else if (proposal.forVotes <= proposal.againstVotes || proposal.forVotes < proposal.quorumVotes) { - return ProposalState.Defeated; - } else if (proposal.eta == 0) { - return ProposalState.Succeeded; - } else if (proposal.executed) { - return ProposalState.Executed; - } else if (block.timestamp >= proposal.eta + timelock.GRACE_PERIOD()) { - return ProposalState.Expired; - } else { - return ProposalState.Queued; - } - } - - /** - * @notice Cast a vote for a proposal - * @param proposalId The id of the proposal to vote on - * @param support The support value for the vote. 0=against, 1=for, 2=abstain - */ - function castVote(uint256 proposalId, uint8 support) external { - emit VoteCast(msg.sender, proposalId, support, castVoteInternal(msg.sender, proposalId, support), ''); - } - - /** - * @notice Cast a vote for a proposal with a reason - * @param proposalId The id of the proposal to vote on - * @param support The support value for the vote. 0=against, 1=for, 2=abstain - * @param reason The reason given for the vote by the voter - */ - function castVoteWithReason( - uint256 proposalId, - uint8 support, - string calldata reason - ) external { - emit VoteCast(msg.sender, proposalId, support, castVoteInternal(msg.sender, proposalId, support), reason); - } - - /** - * @notice Cast a vote for a proposal by signature - * @dev External function that accepts EIP-712 signatures for voting on proposals. - */ - function castVoteBySig( - uint256 proposalId, - uint8 support, - uint8 v, - bytes32 r, - bytes32 s - ) external { - bytes32 domainSeparator = keccak256( - abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainIdInternal(), address(this)) - ); - bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support)); - bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); - address signatory = ecrecover(digest, v, r, s); - require(signatory != address(0), 'NounsDAO::castVoteBySig: invalid signature'); - emit VoteCast(signatory, proposalId, support, castVoteInternal(signatory, proposalId, support), ''); - } - - /** - * @notice Internal function that caries out voting logic - * @param voter The voter that is casting their vote - * @param proposalId The id of the proposal to vote on - * @param support The support value for the vote. 0=against, 1=for, 2=abstain - * @return The number of votes cast - */ - function castVoteInternal( - address voter, - uint256 proposalId, - uint8 support - ) internal returns (uint96) { - require(state(proposalId) == ProposalState.Active, 'NounsDAO::castVoteInternal: voting is closed'); - require(support <= 2, 'NounsDAO::castVoteInternal: invalid vote type'); - Proposal storage proposal = proposals[proposalId]; - Receipt storage receipt = proposal.receipts[voter]; - require(receipt.hasVoted == false, 'NounsDAO::castVoteInternal: voter already voted'); - - /// @notice: Unlike GovernerBravo, votes are considered from the block the proposal was created in order to normalize quorumVotes and proposalThreshold metrics - uint96 votes = nouns.getPriorVotes(voter, proposal.startBlock - votingDelay); - - if (support == 0) { - proposal.againstVotes = proposal.againstVotes + votes; - } else if (support == 1) { - proposal.forVotes = proposal.forVotes + votes; - } else if (support == 2) { - proposal.abstainVotes = proposal.abstainVotes + votes; - } - - receipt.hasVoted = true; - receipt.support = support; - receipt.votes = votes; - - return votes; - } - - /** - * @notice Admin function for setting the voting delay - * @param newVotingDelay new voting delay, in blocks - */ - function _setVotingDelay(uint256 newVotingDelay) external { - require(msg.sender == admin, 'NounsDAO::_setVotingDelay: admin only'); - require( - newVotingDelay >= MIN_VOTING_DELAY && newVotingDelay <= MAX_VOTING_DELAY, - 'NounsDAO::_setVotingDelay: invalid voting delay' - ); - uint256 oldVotingDelay = votingDelay; - votingDelay = newVotingDelay; - - emit VotingDelaySet(oldVotingDelay, votingDelay); - } - - /** - * @notice Admin function for setting the voting period - * @param newVotingPeriod new voting period, in blocks - */ - function _setVotingPeriod(uint256 newVotingPeriod) external { - require(msg.sender == admin, 'NounsDAO::_setVotingPeriod: admin only'); - require( - newVotingPeriod >= MIN_VOTING_PERIOD && newVotingPeriod <= MAX_VOTING_PERIOD, - 'NounsDAO::_setVotingPeriod: invalid voting period' - ); - uint256 oldVotingPeriod = votingPeriod; - votingPeriod = newVotingPeriod; - - emit VotingPeriodSet(oldVotingPeriod, votingPeriod); - } - - /** - * @notice Admin function for setting the proposal threshold basis points - * @dev newProposalThresholdBPS must be greater than the hardcoded min - * @param newProposalThresholdBPS new proposal threshold - */ - function _setProposalThresholdBPS(uint256 newProposalThresholdBPS) external { - require(msg.sender == admin, 'NounsDAO::_setProposalThresholdBPS: admin only'); - require( - newProposalThresholdBPS >= MIN_PROPOSAL_THRESHOLD_BPS && - newProposalThresholdBPS <= MAX_PROPOSAL_THRESHOLD_BPS, - 'NounsDAO::_setProposalThreshold: invalid proposal threshold' - ); - uint256 oldProposalThresholdBPS = proposalThresholdBPS; - proposalThresholdBPS = newProposalThresholdBPS; - - emit ProposalThresholdBPSSet(oldProposalThresholdBPS, proposalThresholdBPS); - } - - /** - * @notice Admin function for setting the quorum votes basis points - * @dev newQuorumVotesBPS must be greater than the hardcoded min - * @param newQuorumVotesBPS new proposal threshold - */ - function _setQuorumVotesBPS(uint256 newQuorumVotesBPS) external { - require(msg.sender == admin, 'NounsDAO::_setQuorumVotesBPS: admin only'); - require( - newQuorumVotesBPS >= MIN_QUORUM_VOTES_BPS && newQuorumVotesBPS <= MAX_QUORUM_VOTES_BPS, - 'NounsDAO::_setProposalThreshold: invalid proposal threshold' - ); - uint256 oldQuorumVotesBPS = quorumVotesBPS; - quorumVotesBPS = newQuorumVotesBPS; - - emit QuorumVotesBPSSet(oldQuorumVotesBPS, quorumVotesBPS); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - */ - function _setPendingAdmin(address newPendingAdmin) external { - // Check caller = admin - require(msg.sender == admin, 'NounsDAO::_setPendingAdmin: admin only'); - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - */ - function _acceptAdmin() external { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - require(msg.sender == pendingAdmin && msg.sender != address(0), 'NounsDAO::_acceptAdmin: pending admin only'); - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - } - - /** - * @notice Changes vetoer address - * @dev Vetoer function for updating vetoer address - */ - function _setVetoer(address newVetoer) public { - require(msg.sender == vetoer, 'NounsDAO::_setVetoer: vetoer only'); - - emit NewVetoer(vetoer, newVetoer); - - vetoer = newVetoer; - } - - /** - * @notice Burns veto priviledges - * @dev Vetoer function destroying veto power forever - */ - function _burnVetoPower() public { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - require(msg.sender == vetoer, 'NounsDAO::_burnVetoPower: vetoer only'); - - _setVetoer(address(0)); - } - - /** - * @notice Current proposal threshold using Noun Total Supply - * Differs from `GovernerBravo` which uses fixed amount - */ - function proposalThreshold() public view returns (uint256) { - return bps2Uint(proposalThresholdBPS, nouns.totalSupply()); - } - - /** - * @notice Current quorum votes using Noun Total Supply - * Differs from `GovernerBravo` which uses fixed amount - */ - function quorumVotes() public view returns (uint256) { - return bps2Uint(quorumVotesBPS, nouns.totalSupply()); - } - - function bps2Uint(uint256 bps, uint256 number) internal pure returns (uint256) { - return (number * bps) / 10000; - } - - function getChainIdInternal() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } -} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV2.sol b/packages/nouns-contracts/contracts/governance/NounsDAOLogicV2.sol deleted file mode 100644 index ff426a8108..0000000000 --- a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV2.sol +++ /dev/null @@ -1,1091 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/// @title The Nouns DAO logic version 2 - -/********************************* - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░██░░░████░░██░░░████░░░ * - * ░░██████░░░████████░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - *********************************/ - -// LICENSE -// NounsDAOLogicV2.sol is a modified version of Compound Lab's GovernorBravoDelegate.sol: -// https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoDelegate.sol -// -// GovernorBravoDelegate.sol source code Copyright 2020 Compound Labs, Inc. licensed under the BSD-3-Clause license. -// With modifications by Nounders DAO. -// -// Additional conditions of BSD-3-Clause can be found here: https://opensource.org/licenses/BSD-3-Clause -// -// MODIFICATIONS -// See NounsDAOLogicV1 for initial GovernorBravoDelegate modifications. - -// NounsDAOLogicV2 adds: -// - `quorumParamsCheckpoints`, which store dynamic quorum parameters checkpoints -// to be used when calculating the dynamic quorum. -// - `_setDynamicQuorumParams(DynamicQuorumParams memory params)`, which allows the -// DAO to update the dynamic quorum parameters' values. -// - `getDynamicQuorumParamsAt(uint256 blockNumber_)` -// - Individual setters of the DynamicQuorumParams members: -// - `_setMinQuorumVotesBPS(uint16 newMinQuorumVotesBPS)` -// - `_setMaxQuorumVotesBPS(uint16 newMaxQuorumVotesBPS)` -// - `_setQuorumCoefficient(uint32 newQuorumCoefficient)` -// - `minQuorumVotes` and `maxQuorumVotes`, which returns the current min and -// max quorum votes using the current Noun supply. -// - New `Proposal` struct member: -// - `totalSupply` used in dynamic quorum calculation. -// - `creationBlock` used for retrieving checkpoints of votes and dynamic quorum params. This now -// allows changing `votingDelay` without affecting the checkpoints lookup. -// - `quorumVotes(uint256 proposalId)`, which calculates and returns the dynamic -// quorum for a specific proposal. -// - `proposals(uint256 proposalId)` instead of the implicit getter, to avoid stack-too-deep error -// -// NounsDAOLogicV2 removes: -// - `quorumVotes()` has been replaced by `quorumVotes(uint256 proposalId)`. - -pragma solidity ^0.8.6; - -import './NounsDAOInterfaces.sol'; - -contract NounsDAOLogicV2 is NounsDAOStorageV2, NounsDAOEventsV2 { - /// @notice The name of this contract - string public constant name = 'Nouns DAO'; - - /// @notice The minimum setable proposal threshold - uint256 public constant MIN_PROPOSAL_THRESHOLD_BPS = 1; // 1 basis point or 0.01% - - /// @notice The maximum setable proposal threshold - uint256 public constant MAX_PROPOSAL_THRESHOLD_BPS = 1_000; // 1,000 basis points or 10% - - /// @notice The minimum setable voting period - uint256 public constant MIN_VOTING_PERIOD = 5_760; // About 24 hours - - /// @notice The max setable voting period - uint256 public constant MAX_VOTING_PERIOD = 80_640; // About 2 weeks - - /// @notice The min setable voting delay - uint256 public constant MIN_VOTING_DELAY = 1; - - /// @notice The max setable voting delay - uint256 public constant MAX_VOTING_DELAY = 40_320; // About 1 week - - /// @notice The lower bound of minimum quorum votes basis points - uint256 public constant MIN_QUORUM_VOTES_BPS_LOWER_BOUND = 200; // 200 basis points or 2% - - /// @notice The upper bound of minimum quorum votes basis points - uint256 public constant MIN_QUORUM_VOTES_BPS_UPPER_BOUND = 2_000; // 2,000 basis points or 20% - - /// @notice The upper bound of maximum quorum votes basis points - uint256 public constant MAX_QUORUM_VOTES_BPS_UPPER_BOUND = 6_000; // 4,000 basis points or 60% - - /// @notice The maximum setable quorum votes basis points - uint256 public constant MAX_QUORUM_VOTES_BPS = 2_000; // 2,000 basis points or 20% - - /// @notice The maximum number of actions that can be included in a proposal - uint256 public constant proposalMaxOperations = 10; // 10 actions - - /// @notice The maximum priority fee used to cap gas refunds in `castRefundableVote` - uint256 public constant MAX_REFUND_PRIORITY_FEE = 2 gwei; - - /// @notice The vote refund gas overhead, including 7K for ETH transfer and 29K for general transaction overhead - uint256 public constant REFUND_BASE_GAS = 36000; - - /// @notice The maximum gas units the DAO will refund voters on; supports about 9,190 characters - uint256 public constant MAX_REFUND_GAS_USED = 200_000; - - /// @notice The maximum basefee the DAO will refund voters on - uint256 public constant MAX_REFUND_BASE_FEE = 200 gwei; - - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)'); - - /// @notice The EIP-712 typehash for the ballot struct used by the contract - bytes32 public constant BALLOT_TYPEHASH = keccak256('Ballot(uint256 proposalId,uint8 support)'); - - /// @dev Introduced these errors to reduce contract size, to avoid deployment failure - error AdminOnly(); - error InvalidMinQuorumVotesBPS(); - error InvalidMaxQuorumVotesBPS(); - error MinQuorumBPSGreaterThanMaxQuorumBPS(); - error UnsafeUint16Cast(); - error VetoerOnly(); - error PendingVetoerOnly(); - error VetoerBurned(); - error CantVetoExecutedProposal(); - error CantCancelExecutedProposal(); - - /** - * @notice Used to initialize the contract during delegator contructor - * @param timelock_ The address of the NounsDAOExecutor - * @param nouns_ The address of the NOUN tokens - * @param vetoer_ The address allowed to unilaterally veto proposals - * @param votingPeriod_ The initial voting period - * @param votingDelay_ The initial voting delay - * @param proposalThresholdBPS_ The initial proposal threshold in basis points - * @param dynamicQuorumParams_ The initial dynamic quorum parameters - */ - function initialize( - address timelock_, - address nouns_, - address vetoer_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - DynamicQuorumParams calldata dynamicQuorumParams_ - ) public virtual { - require(address(timelock) == address(0), 'NounsDAO::initialize: can only initialize once'); - if (msg.sender != admin) { - revert AdminOnly(); - } - require(timelock_ != address(0), 'NounsDAO::initialize: invalid timelock address'); - require(nouns_ != address(0), 'NounsDAO::initialize: invalid nouns address'); - require( - votingPeriod_ >= MIN_VOTING_PERIOD && votingPeriod_ <= MAX_VOTING_PERIOD, - 'NounsDAO::initialize: invalid voting period' - ); - require( - votingDelay_ >= MIN_VOTING_DELAY && votingDelay_ <= MAX_VOTING_DELAY, - 'NounsDAO::initialize: invalid voting delay' - ); - require( - proposalThresholdBPS_ >= MIN_PROPOSAL_THRESHOLD_BPS && proposalThresholdBPS_ <= MAX_PROPOSAL_THRESHOLD_BPS, - 'NounsDAO::initialize: invalid proposal threshold bps' - ); - - emit VotingPeriodSet(votingPeriod, votingPeriod_); - emit VotingDelaySet(votingDelay, votingDelay_); - emit ProposalThresholdBPSSet(proposalThresholdBPS, proposalThresholdBPS_); - - timelock = INounsDAOExecutor(timelock_); - nouns = NounsTokenLike(nouns_); - vetoer = vetoer_; - votingPeriod = votingPeriod_; - votingDelay = votingDelay_; - proposalThresholdBPS = proposalThresholdBPS_; - _setDynamicQuorumParams( - dynamicQuorumParams_.minQuorumVotesBPS, - dynamicQuorumParams_.maxQuorumVotesBPS, - dynamicQuorumParams_.quorumCoefficient - ); - } - - struct ProposalTemp { - uint256 totalSupply; - uint256 proposalThreshold; - uint256 latestProposalId; - uint256 startBlock; - uint256 endBlock; - } - - /** - * @notice Function used to propose a new proposal. Sender must have delegates above the proposal threshold - * @param targets Target addresses for proposal calls - * @param values Eth values for proposal calls - * @param signatures Function signatures for proposal calls - * @param calldatas Calldatas for proposal calls - * @param description String description of the proposal - * @return Proposal id of new proposal - */ - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) public returns (uint256) { - ProposalTemp memory temp; - - temp.totalSupply = nouns.totalSupply(); - - temp.proposalThreshold = bps2Uint(proposalThresholdBPS, temp.totalSupply); - - require( - nouns.getPriorVotes(msg.sender, block.number - 1) > temp.proposalThreshold, - 'NounsDAO::propose: proposer votes below proposal threshold' - ); - require( - targets.length == values.length && - targets.length == signatures.length && - targets.length == calldatas.length, - 'NounsDAO::propose: proposal function information arity mismatch' - ); - require(targets.length != 0, 'NounsDAO::propose: must provide actions'); - require(targets.length <= proposalMaxOperations, 'NounsDAO::propose: too many actions'); - - temp.latestProposalId = latestProposalIds[msg.sender]; - if (temp.latestProposalId != 0) { - ProposalState proposersLatestProposalState = state(temp.latestProposalId); - require( - proposersLatestProposalState != ProposalState.Active, - 'NounsDAO::propose: one live proposal per proposer, found an already active proposal' - ); - require( - proposersLatestProposalState != ProposalState.Pending, - 'NounsDAO::propose: one live proposal per proposer, found an already pending proposal' - ); - } - - temp.startBlock = block.number + votingDelay; - temp.endBlock = temp.startBlock + votingPeriod; - - proposalCount++; - Proposal storage newProposal = _proposals[proposalCount]; - newProposal.id = proposalCount; - newProposal.proposer = msg.sender; - newProposal.proposalThreshold = temp.proposalThreshold; - newProposal.eta = 0; - newProposal.targets = targets; - newProposal.values = values; - newProposal.signatures = signatures; - newProposal.calldatas = calldatas; - newProposal.startBlock = temp.startBlock; - newProposal.endBlock = temp.endBlock; - newProposal.forVotes = 0; - newProposal.againstVotes = 0; - newProposal.abstainVotes = 0; - newProposal.canceled = false; - newProposal.executed = false; - newProposal.vetoed = false; - newProposal.totalSupply = temp.totalSupply; - newProposal.creationBlock = block.number; - - latestProposalIds[newProposal.proposer] = newProposal.id; - - /// @notice Maintains backwards compatibility with GovernorBravo events - emit ProposalCreated( - newProposal.id, - msg.sender, - targets, - values, - signatures, - calldatas, - newProposal.startBlock, - newProposal.endBlock, - description - ); - - /// @notice Updated event with `proposalThreshold` and `minQuorumVotes` - /// @notice `minQuorumVotes` is always zero since V2 introduces dynamic quorum with checkpoints - emit ProposalCreatedWithRequirements( - newProposal.id, - msg.sender, - targets, - values, - signatures, - calldatas, - newProposal.startBlock, - newProposal.endBlock, - newProposal.proposalThreshold, - minQuorumVotes(), - description - ); - - return newProposal.id; - } - - /** - * @notice Queues a proposal of state succeeded - * @param proposalId The id of the proposal to queue - */ - function queue(uint256 proposalId) external { - require( - state(proposalId) == ProposalState.Succeeded, - 'NounsDAO::queue: proposal can only be queued if it is succeeded' - ); - Proposal storage proposal = _proposals[proposalId]; - uint256 eta = block.timestamp + timelock.delay(); - for (uint256 i = 0; i < proposal.targets.length; i++) { - queueOrRevertInternal( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - eta - ); - } - proposal.eta = eta; - emit ProposalQueued(proposalId, eta); - } - - function queueOrRevertInternal( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) internal { - require( - !timelock.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta))), - 'NounsDAO::queueOrRevertInternal: identical proposal action already queued at eta' - ); - timelock.queueTransaction(target, value, signature, data, eta); - } - - /** - * @notice Executes a queued proposal if eta has passed - * @param proposalId The id of the proposal to execute - */ - function execute(uint256 proposalId) external { - require( - state(proposalId) == ProposalState.Queued, - 'NounsDAO::execute: proposal can only be executed if it is queued' - ); - Proposal storage proposal = _proposals[proposalId]; - proposal.executed = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.executeTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - emit ProposalExecuted(proposalId); - } - - /** - * @notice Cancels a proposal only if sender is the proposer, or proposer delegates dropped below proposal threshold - * @param proposalId The id of the proposal to cancel - */ - function cancel(uint256 proposalId) external { - if (state(proposalId) == ProposalState.Executed) { - revert CantCancelExecutedProposal(); - } - - Proposal storage proposal = _proposals[proposalId]; - require( - msg.sender == proposal.proposer || - nouns.getPriorVotes(proposal.proposer, block.number - 1) <= proposal.proposalThreshold, - 'NounsDAO::cancel: proposer above threshold' - ); - - proposal.canceled = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.cancelTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - - emit ProposalCanceled(proposalId); - } - - /** - * @notice Vetoes a proposal only if sender is the vetoer and the proposal has not been executed. - * @param proposalId The id of the proposal to veto - */ - function veto(uint256 proposalId) external { - if (vetoer == address(0)) { - revert VetoerBurned(); - } - - if (msg.sender != vetoer) { - revert VetoerOnly(); - } - - if (state(proposalId) == ProposalState.Executed) { - revert CantVetoExecutedProposal(); - } - - Proposal storage proposal = _proposals[proposalId]; - - proposal.vetoed = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.cancelTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - - emit ProposalVetoed(proposalId); - } - - /** - * @notice Gets actions of a proposal - * @param proposalId the id of the proposal - * @return targets - * @return values - * @return signatures - * @return calldatas - */ - function getActions(uint256 proposalId) - external - view - returns ( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas - ) - { - Proposal storage p = _proposals[proposalId]; - return (p.targets, p.values, p.signatures, p.calldatas); - } - - /** - * @notice Gets the receipt for a voter on a given proposal - * @param proposalId the id of proposal - * @param voter The address of the voter - * @return The voting receipt - */ - function getReceipt(uint256 proposalId, address voter) external view returns (Receipt memory) { - return _proposals[proposalId].receipts[voter]; - } - - /** - * @notice Gets the state of a proposal - * @param proposalId The id of the proposal - * @return Proposal state - */ - function state(uint256 proposalId) public view returns (ProposalState) { - require(proposalCount >= proposalId, 'NounsDAO::state: invalid proposal id'); - Proposal storage proposal = _proposals[proposalId]; - if (proposal.vetoed) { - return ProposalState.Vetoed; - } else if (proposal.canceled) { - return ProposalState.Canceled; - } else if (block.number <= proposal.startBlock) { - return ProposalState.Pending; - } else if (block.number <= proposal.endBlock) { - return ProposalState.Active; - } else if (proposal.forVotes <= proposal.againstVotes || proposal.forVotes < quorumVotes(proposal.id)) { - return ProposalState.Defeated; - } else if (proposal.eta == 0) { - return ProposalState.Succeeded; - } else if (proposal.executed) { - return ProposalState.Executed; - } else if (block.timestamp >= proposal.eta + timelock.GRACE_PERIOD()) { - return ProposalState.Expired; - } else { - return ProposalState.Queued; - } - } - - /** - * @notice Returns the proposal details given a proposal id. - * The `quorumVotes` member holds the *current* quorum, given the current votes. - * @param proposalId the proposal id to get the data for - * @return A `ProposalCondensed` struct with the proposal data - */ - function proposals(uint256 proposalId) external view returns (ProposalCondensed memory) { - Proposal storage proposal = _proposals[proposalId]; - return - ProposalCondensed({ - id: proposal.id, - proposer: proposal.proposer, - proposalThreshold: proposal.proposalThreshold, - quorumVotes: quorumVotes(proposal.id), - eta: proposal.eta, - startBlock: proposal.startBlock, - endBlock: proposal.endBlock, - forVotes: proposal.forVotes, - againstVotes: proposal.againstVotes, - abstainVotes: proposal.abstainVotes, - canceled: proposal.canceled, - vetoed: proposal.vetoed, - executed: proposal.executed, - totalSupply: proposal.totalSupply, - creationBlock: proposal.creationBlock - }); - } - - /** - * @notice Cast a vote for a proposal - * @param proposalId The id of the proposal to vote on - * @param support The support value for the vote. 0=against, 1=for, 2=abstain - */ - function castVote(uint256 proposalId, uint8 support) external { - emit VoteCast(msg.sender, proposalId, support, castVoteInternal(msg.sender, proposalId, support), ''); - } - - /** - * @notice Cast a vote for a proposal, asking the DAO to refund gas costs. - * Users with > 0 votes receive refunds. Refunds are partial when using a gas priority fee higher than the DAO's cap. - * Refunds are partial when the DAO's balance is insufficient. - * No refund is sent when the DAO's balance is empty. No refund is sent to users with no votes. - * Voting takes place regardless of refund success. - * @param proposalId The id of the proposal to vote on - * @param support The support value for the vote. 0=against, 1=for, 2=abstain - * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. - */ - function castRefundableVote(uint256 proposalId, uint8 support) external { - castRefundableVoteInternal(proposalId, support, ''); - } - - /** - * @notice Cast a vote for a proposal, asking the DAO to refund gas costs. - * Users with > 0 votes receive refunds. Refunds are partial when using a gas priority fee higher than the DAO's cap. - * Refunds are partial when the DAO's balance is insufficient. - * No refund is sent when the DAO's balance is empty. No refund is sent to users with no votes. - * Voting takes place regardless of refund success. - * @param proposalId The id of the proposal to vote on - * @param support The support value for the vote. 0=against, 1=for, 2=abstain - * @param reason The reason given for the vote by the voter - * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. - */ - function castRefundableVoteWithReason( - uint256 proposalId, - uint8 support, - string calldata reason - ) external { - castRefundableVoteInternal(proposalId, support, reason); - } - - /** - * @notice Internal function that carries out refundable voting logic - * @param proposalId The id of the proposal to vote on - * @param support The support value for the vote. 0=against, 1=for, 2=abstain - * @param reason The reason given for the vote by the voter - * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. - */ - function castRefundableVoteInternal( - uint256 proposalId, - uint8 support, - string memory reason - ) internal { - uint256 startGas = gasleft(); - uint96 votes = castVoteInternal(msg.sender, proposalId, support); - emit VoteCast(msg.sender, proposalId, support, votes, reason); - if (votes > 0) { - _refundGas(startGas); - } - } - - /** - * @notice Cast a vote for a proposal with a reason - * @param proposalId The id of the proposal to vote on - * @param support The support value for the vote. 0=against, 1=for, 2=abstain - * @param reason The reason given for the vote by the voter - */ - function castVoteWithReason( - uint256 proposalId, - uint8 support, - string calldata reason - ) external { - emit VoteCast(msg.sender, proposalId, support, castVoteInternal(msg.sender, proposalId, support), reason); - } - - /** - * @notice Cast a vote for a proposal by signature - * @dev External function that accepts EIP-712 signatures for voting on proposals. - */ - function castVoteBySig( - uint256 proposalId, - uint8 support, - uint8 v, - bytes32 r, - bytes32 s - ) external { - bytes32 domainSeparator = keccak256( - abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainIdInternal(), address(this)) - ); - bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support)); - bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); - address signatory = ecrecover(digest, v, r, s); - require(signatory != address(0), 'NounsDAO::castVoteBySig: invalid signature'); - emit VoteCast(signatory, proposalId, support, castVoteInternal(signatory, proposalId, support), ''); - } - - /** - * @notice Internal function that caries out voting logic - * @param voter The voter that is casting their vote - * @param proposalId The id of the proposal to vote on - * @param support The support value for the vote. 0=against, 1=for, 2=abstain - * @return The number of votes cast - */ - function castVoteInternal( - address voter, - uint256 proposalId, - uint8 support - ) internal returns (uint96) { - require(state(proposalId) == ProposalState.Active, 'NounsDAO::castVoteInternal: voting is closed'); - require(support <= 2, 'NounsDAO::castVoteInternal: invalid vote type'); - Proposal storage proposal = _proposals[proposalId]; - Receipt storage receipt = proposal.receipts[voter]; - require(receipt.hasVoted == false, 'NounsDAO::castVoteInternal: voter already voted'); - - /// @notice: Unlike GovernerBravo, votes are considered from the block the proposal was created in order to normalize quorumVotes and proposalThreshold metrics - uint96 votes = nouns.getPriorVotes(voter, proposalCreationBlock(proposal)); - - if (support == 0) { - proposal.againstVotes = proposal.againstVotes + votes; - } else if (support == 1) { - proposal.forVotes = proposal.forVotes + votes; - } else if (support == 2) { - proposal.abstainVotes = proposal.abstainVotes + votes; - } - - receipt.hasVoted = true; - receipt.support = support; - receipt.votes = votes; - - return votes; - } - - /** - * @notice Admin function for setting the voting delay - * @param newVotingDelay new voting delay, in blocks - */ - function _setVotingDelay(uint256 newVotingDelay) external { - if (msg.sender != admin) { - revert AdminOnly(); - } - require( - newVotingDelay >= MIN_VOTING_DELAY && newVotingDelay <= MAX_VOTING_DELAY, - 'NounsDAO::_setVotingDelay: invalid voting delay' - ); - uint256 oldVotingDelay = votingDelay; - votingDelay = newVotingDelay; - - emit VotingDelaySet(oldVotingDelay, votingDelay); - } - - /** - * @notice Admin function for setting the voting period - * @param newVotingPeriod new voting period, in blocks - */ - function _setVotingPeriod(uint256 newVotingPeriod) external { - if (msg.sender != admin) { - revert AdminOnly(); - } - require( - newVotingPeriod >= MIN_VOTING_PERIOD && newVotingPeriod <= MAX_VOTING_PERIOD, - 'NounsDAO::_setVotingPeriod: invalid voting period' - ); - uint256 oldVotingPeriod = votingPeriod; - votingPeriod = newVotingPeriod; - - emit VotingPeriodSet(oldVotingPeriod, votingPeriod); - } - - /** - * @notice Admin function for setting the proposal threshold basis points - * @dev newProposalThresholdBPS must be greater than the hardcoded min - * @param newProposalThresholdBPS new proposal threshold - */ - function _setProposalThresholdBPS(uint256 newProposalThresholdBPS) external { - if (msg.sender != admin) { - revert AdminOnly(); - } - require( - newProposalThresholdBPS >= MIN_PROPOSAL_THRESHOLD_BPS && - newProposalThresholdBPS <= MAX_PROPOSAL_THRESHOLD_BPS, - 'NounsDAO::_setProposalThreshold: invalid proposal threshold bps' - ); - uint256 oldProposalThresholdBPS = proposalThresholdBPS; - proposalThresholdBPS = newProposalThresholdBPS; - - emit ProposalThresholdBPSSet(oldProposalThresholdBPS, proposalThresholdBPS); - } - - /** - * @notice Admin function for setting the minimum quorum votes bps - * @param newMinQuorumVotesBPS minimum quorum votes bps - * Must be between `MIN_QUORUM_VOTES_BPS_LOWER_BOUND` and `MIN_QUORUM_VOTES_BPS_UPPER_BOUND` - * Must be lower than or equal to maxQuorumVotesBPS - */ - function _setMinQuorumVotesBPS(uint16 newMinQuorumVotesBPS) external { - if (msg.sender != admin) { - revert AdminOnly(); - } - DynamicQuorumParams memory params = getDynamicQuorumParamsAt(block.number); - - require( - newMinQuorumVotesBPS >= MIN_QUORUM_VOTES_BPS_LOWER_BOUND && - newMinQuorumVotesBPS <= MIN_QUORUM_VOTES_BPS_UPPER_BOUND, - 'NounsDAO::_setMinQuorumVotesBPS: invalid min quorum votes bps' - ); - require( - newMinQuorumVotesBPS <= params.maxQuorumVotesBPS, - 'NounsDAO::_setMinQuorumVotesBPS: min quorum votes bps greater than max' - ); - - uint16 oldMinQuorumVotesBPS = params.minQuorumVotesBPS; - params.minQuorumVotesBPS = newMinQuorumVotesBPS; - - _writeQuorumParamsCheckpoint(params); - - emit MinQuorumVotesBPSSet(oldMinQuorumVotesBPS, newMinQuorumVotesBPS); - } - - /** - * @notice Admin function for setting the maximum quorum votes bps - * @param newMaxQuorumVotesBPS maximum quorum votes bps - * Must be lower than `MAX_QUORUM_VOTES_BPS_UPPER_BOUND` - * Must be higher than or equal to minQuorumVotesBPS - */ - function _setMaxQuorumVotesBPS(uint16 newMaxQuorumVotesBPS) external { - if (msg.sender != admin) { - revert AdminOnly(); - } - DynamicQuorumParams memory params = getDynamicQuorumParamsAt(block.number); - - require( - newMaxQuorumVotesBPS <= MAX_QUORUM_VOTES_BPS_UPPER_BOUND, - 'NounsDAO::_setMaxQuorumVotesBPS: invalid max quorum votes bps' - ); - require( - params.minQuorumVotesBPS <= newMaxQuorumVotesBPS, - 'NounsDAO::_setMaxQuorumVotesBPS: min quorum votes bps greater than max' - ); - - uint16 oldMaxQuorumVotesBPS = params.maxQuorumVotesBPS; - params.maxQuorumVotesBPS = newMaxQuorumVotesBPS; - - _writeQuorumParamsCheckpoint(params); - - emit MaxQuorumVotesBPSSet(oldMaxQuorumVotesBPS, newMaxQuorumVotesBPS); - } - - /** - * @notice Admin function for setting the dynamic quorum coefficient - * @param newQuorumCoefficient the new coefficient, as a fixed point integer with 6 decimals - */ - function _setQuorumCoefficient(uint32 newQuorumCoefficient) external { - if (msg.sender != admin) { - revert AdminOnly(); - } - DynamicQuorumParams memory params = getDynamicQuorumParamsAt(block.number); - - uint32 oldQuorumCoefficient = params.quorumCoefficient; - params.quorumCoefficient = newQuorumCoefficient; - - _writeQuorumParamsCheckpoint(params); - - emit QuorumCoefficientSet(oldQuorumCoefficient, newQuorumCoefficient); - } - - /** - * @notice Admin function for setting all the dynamic quorum parameters - * @param newMinQuorumVotesBPS minimum quorum votes bps - * Must be between `MIN_QUORUM_VOTES_BPS_LOWER_BOUND` and `MIN_QUORUM_VOTES_BPS_UPPER_BOUND` - * Must be lower than or equal to maxQuorumVotesBPS - * @param newMaxQuorumVotesBPS maximum quorum votes bps - * Must be lower than `MAX_QUORUM_VOTES_BPS_UPPER_BOUND` - * Must be higher than or equal to minQuorumVotesBPS - * @param newQuorumCoefficient the new coefficient, as a fixed point integer with 6 decimals - */ - function _setDynamicQuorumParams( - uint16 newMinQuorumVotesBPS, - uint16 newMaxQuorumVotesBPS, - uint32 newQuorumCoefficient - ) public { - if (msg.sender != admin) { - revert AdminOnly(); - } - if ( - newMinQuorumVotesBPS < MIN_QUORUM_VOTES_BPS_LOWER_BOUND || - newMinQuorumVotesBPS > MIN_QUORUM_VOTES_BPS_UPPER_BOUND - ) { - revert InvalidMinQuorumVotesBPS(); - } - if (newMaxQuorumVotesBPS > MAX_QUORUM_VOTES_BPS_UPPER_BOUND) { - revert InvalidMaxQuorumVotesBPS(); - } - if (newMinQuorumVotesBPS > newMaxQuorumVotesBPS) { - revert MinQuorumBPSGreaterThanMaxQuorumBPS(); - } - - DynamicQuorumParams memory oldParams = getDynamicQuorumParamsAt(block.number); - - DynamicQuorumParams memory params = DynamicQuorumParams({ - minQuorumVotesBPS: newMinQuorumVotesBPS, - maxQuorumVotesBPS: newMaxQuorumVotesBPS, - quorumCoefficient: newQuorumCoefficient - }); - _writeQuorumParamsCheckpoint(params); - - emit MinQuorumVotesBPSSet(oldParams.minQuorumVotesBPS, params.minQuorumVotesBPS); - emit MaxQuorumVotesBPSSet(oldParams.maxQuorumVotesBPS, params.maxQuorumVotesBPS); - emit QuorumCoefficientSet(oldParams.quorumCoefficient, params.quorumCoefficient); - } - - function _withdraw() external returns (uint256, bool) { - if (msg.sender != admin) { - revert AdminOnly(); - } - - uint256 amount = address(this).balance; - (bool sent, ) = msg.sender.call{ value: amount }(''); - - emit Withdraw(amount, sent); - - return (amount, sent); - } - - /** - * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. - * @param newPendingAdmin New pending admin. - */ - function _setPendingAdmin(address newPendingAdmin) external { - // Check caller = admin - require(msg.sender == admin, 'NounsDAO::_setPendingAdmin: admin only'); - - // Save current value, if any, for inclusion in log - address oldPendingAdmin = pendingAdmin; - - // Store pendingAdmin with value newPendingAdmin - pendingAdmin = newPendingAdmin; - - // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) - emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); - } - - /** - * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin - * @dev Admin function for pending admin to accept role and update admin - */ - function _acceptAdmin() external { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - require(msg.sender == pendingAdmin && msg.sender != address(0), 'NounsDAO::_acceptAdmin: pending admin only'); - - // Save current values for inclusion in log - address oldAdmin = admin; - address oldPendingAdmin = pendingAdmin; - - // Store admin with value pendingAdmin - admin = pendingAdmin; - - // Clear the pending value - pendingAdmin = address(0); - - emit NewAdmin(oldAdmin, admin); - emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); - } - - /** - * @notice Begins transition of vetoer. The newPendingVetoer must call _acceptVetoer to finalize the transfer. - * @param newPendingVetoer New Pending Vetoer - */ - function _setPendingVetoer(address newPendingVetoer) public { - if (msg.sender != vetoer) { - revert VetoerOnly(); - } - - emit NewPendingVetoer(pendingVetoer, newPendingVetoer); - - pendingVetoer = newPendingVetoer; - } - - function _acceptVetoer() external { - if (msg.sender != pendingVetoer) { - revert PendingVetoerOnly(); - } - - // Update vetoer - emit NewVetoer(vetoer, pendingVetoer); - vetoer = pendingVetoer; - - // Clear the pending value - emit NewPendingVetoer(pendingVetoer, address(0)); - pendingVetoer = address(0); - } - - /** - * @notice Burns veto priviledges - * @dev Vetoer function destroying veto power forever - */ - function _burnVetoPower() public { - // Check caller is vetoer - require(msg.sender == vetoer, 'NounsDAO::_burnVetoPower: vetoer only'); - - // Update vetoer to 0x0 - emit NewVetoer(vetoer, address(0)); - vetoer = address(0); - - // Clear the pending value - emit NewPendingVetoer(pendingVetoer, address(0)); - pendingVetoer = address(0); - } - - /** - * @notice Current proposal threshold using Noun Total Supply - * Differs from `GovernerBravo` which uses fixed amount - */ - function proposalThreshold() public view returns (uint256) { - return bps2Uint(proposalThresholdBPS, nouns.totalSupply()); - } - - function proposalCreationBlock(Proposal storage proposal) internal view returns (uint256) { - if (proposal.creationBlock == 0) { - return proposal.startBlock - votingDelay; - } - return proposal.creationBlock; - } - - /** - * @notice Quorum votes required for a specific proposal to succeed - * Differs from `GovernerBravo` which uses fixed amount - */ - function quorumVotes(uint256 proposalId) public view returns (uint256) { - Proposal storage proposal = _proposals[proposalId]; - if (proposal.totalSupply == 0) { - return proposal.quorumVotes; - } - - return - dynamicQuorumVotes( - proposal.againstVotes, - proposal.totalSupply, - getDynamicQuorumParamsAt(proposal.creationBlock) - ); - } - - /** - * @notice Calculates the required quorum of for-votes based on the amount of against-votes - * The more against-votes there are for a proposal, the higher the required quorum is. - * The quorum BPS is between `params.minQuorumVotesBPS` and params.maxQuorumVotesBPS. - * The additional quorum is calculated as: - * quorumCoefficient * againstVotesBPS - * @dev Note the coefficient is a fixed point integer with 6 decimals - * @param againstVotes Number of against-votes in the proposal - * @param totalSupply The total supply of Nouns at the time of proposal creation - * @param params Configurable parameters for calculating the quorum based on againstVotes. See `DynamicQuorumParams` definition for additional details. - * @return quorumVotes The required quorum - */ - function dynamicQuorumVotes( - uint256 againstVotes, - uint256 totalSupply, - DynamicQuorumParams memory params - ) public pure returns (uint256) { - uint256 againstVotesBPS = (10000 * againstVotes) / totalSupply; - uint256 quorumAdjustmentBPS = (params.quorumCoefficient * againstVotesBPS) / 1e6; - uint256 adjustedQuorumBPS = params.minQuorumVotesBPS + quorumAdjustmentBPS; - uint256 quorumBPS = min(params.maxQuorumVotesBPS, adjustedQuorumBPS); - return bps2Uint(quorumBPS, totalSupply); - } - - /** - * @notice returns the dynamic quorum parameters values at a certain block number - * @dev The checkpoints array must not be empty, and the block number must be higher than or equal to - * the block of the first checkpoint - * @param blockNumber_ the block number to get the params at - * @return The dynamic quorum parameters that were set at the given block number - */ - function getDynamicQuorumParamsAt(uint256 blockNumber_) public view returns (DynamicQuorumParams memory) { - uint32 blockNumber = safe32(blockNumber_, 'NounsDAO::getDynamicQuorumParamsAt: block number exceeds 32 bits'); - uint256 len = quorumParamsCheckpoints.length; - - if (len == 0) { - return - DynamicQuorumParams({ - minQuorumVotesBPS: safe16(quorumVotesBPS), - maxQuorumVotesBPS: safe16(quorumVotesBPS), - quorumCoefficient: 0 - }); - } - - if (quorumParamsCheckpoints[len - 1].fromBlock <= blockNumber) { - return quorumParamsCheckpoints[len - 1].params; - } - - if (quorumParamsCheckpoints[0].fromBlock > blockNumber) { - return - DynamicQuorumParams({ - minQuorumVotesBPS: safe16(quorumVotesBPS), - maxQuorumVotesBPS: safe16(quorumVotesBPS), - quorumCoefficient: 0 - }); - } - - uint256 lower = 0; - uint256 upper = len - 1; - while (upper > lower) { - uint256 center = upper - (upper - lower) / 2; - DynamicQuorumParamsCheckpoint memory cp = quorumParamsCheckpoints[center]; - if (cp.fromBlock == blockNumber) { - return cp.params; - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - return quorumParamsCheckpoints[lower].params; - } - - function _writeQuorumParamsCheckpoint(DynamicQuorumParams memory params) internal { - uint32 blockNumber = safe32(block.number, 'block number exceeds 32 bits'); - uint256 pos = quorumParamsCheckpoints.length; - if (pos > 0 && quorumParamsCheckpoints[pos - 1].fromBlock == blockNumber) { - quorumParamsCheckpoints[pos - 1].params = params; - } else { - quorumParamsCheckpoints.push(DynamicQuorumParamsCheckpoint({ fromBlock: blockNumber, params: params })); - } - } - - function _refundGas(uint256 startGas) internal { - unchecked { - uint256 balance = address(this).balance; - if (balance == 0) { - return; - } - uint256 basefee = min(block.basefee, MAX_REFUND_BASE_FEE); - uint256 gasPrice = min(tx.gasprice, basefee + MAX_REFUND_PRIORITY_FEE); - uint256 gasUsed = min(startGas - gasleft() + REFUND_BASE_GAS, MAX_REFUND_GAS_USED); - uint256 refundAmount = min(gasPrice * gasUsed, balance); - (bool refundSent, ) = tx.origin.call{ value: refundAmount }(''); - emit RefundableVote(tx.origin, refundAmount, refundSent); - } - } - - function min(uint256 a, uint256 b) internal pure returns (uint256) { - return a < b ? a : b; - } - - /** - * @notice Current min quorum votes using Noun total supply - */ - function minQuorumVotes() public view returns (uint256) { - return bps2Uint(getDynamicQuorumParamsAt(block.number).minQuorumVotesBPS, nouns.totalSupply()); - } - - /** - * @notice Current max quorum votes using Noun total supply - */ - function maxQuorumVotes() public view returns (uint256) { - return bps2Uint(getDynamicQuorumParamsAt(block.number).maxQuorumVotesBPS, nouns.totalSupply()); - } - - function bps2Uint(uint256 bps, uint256 number) internal pure returns (uint256) { - return (number * bps) / 10000; - } - - function getChainIdInternal() internal view returns (uint256) { - uint256 chainId; - assembly { - chainId := chainid() - } - return chainId; - } - - function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) { - require(n <= type(uint32).max, errorMessage); - return uint32(n); - } - - function safe16(uint256 n) internal pure returns (uint16) { - if (n > type(uint16).max) { - revert UnsafeUint16Cast(); - } - return uint16(n); - } - - receive() external payable {} -} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol b/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol index 7cc212c84b..864c0c04ee 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol @@ -454,7 +454,7 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * @param proposalId the proposal id to get the data for * @return A `ProposalCondensed` struct with the proposal data, backwards compatible with V1 and V2 */ - function proposals(uint256 proposalId) external view returns (NounsDAOStorageV2.ProposalCondensed memory) { + function proposals(uint256 proposalId) external view returns (NounsDAOV3Types.ProposalCondensedV2 memory) { return ds.proposals(proposalId); } diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOProxy.sol b/packages/nouns-contracts/contracts/governance/NounsDAOProxy.sol deleted file mode 100644 index f42e3bf60e..0000000000 --- a/packages/nouns-contracts/contracts/governance/NounsDAOProxy.sol +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/// @title The Nouns DAO proxy contract - -/********************************* - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░██░░░████░░██░░░████░░░ * - * ░░██████░░░████████░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - *********************************/ - -// LICENSE -// NounsDAOProxy.sol is a modified version of Compound Lab's GovernorBravoDelegator.sol: -// https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoDelegator.sol -// -// GovernorBravoDelegator.sol source code Copyright 2020 Compound Labs, Inc. licensed under the BSD-3-Clause license. -// With modifications by Nounders DAO. -// -// Additional conditions of BSD-3-Clause can be found here: https://opensource.org/licenses/BSD-3-Clause -// -// -// NounsDAOProxy.sol uses parts of Open Zeppelin's Proxy.sol: -// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5c8746f56b4bed8cc9e0e044f5f69ab2f9428ce1/contracts/proxy/Proxy.sol -// -// Proxy.sol source code licensed under MIT License. -// -// MODIFICATIONS -// The fallback() and receive() functions of Proxy.sol have been used to allow Solidity > 0.6.0 compatibility - -pragma solidity ^0.8.6; - -import './NounsDAOInterfaces.sol'; - -contract NounsDAOProxy is NounsDAOProxyStorage, NounsDAOEvents { - constructor( - address timelock_, - address nouns_, - address vetoer_, - address admin_, - address implementation_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - uint256 quorumVotesBPS_ - ) { - // Admin set to msg.sender for initialization - admin = msg.sender; - - delegateTo( - implementation_, - abi.encodeWithSignature( - 'initialize(address,address,address,uint256,uint256,uint256,uint256)', - timelock_, - nouns_, - vetoer_, - votingPeriod_, - votingDelay_, - proposalThresholdBPS_, - quorumVotesBPS_ - ) - ); - - _setImplementation(implementation_); - - admin = admin_; - } - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - */ - function _setImplementation(address implementation_) public { - require(msg.sender == admin, 'NounsDAOProxy::_setImplementation: admin only'); - require(implementation_ != address(0), 'NounsDAOProxy::_setImplementation: invalid implementation address'); - - address oldImplementation = implementation; - implementation = implementation_; - - emit NewImplementation(oldImplementation, implementation); - } - - /** - * @notice Internal method to delegate execution to another contract - * @dev It returns to the external caller whatever the implementation returns or forwards reverts - * @param callee The contract to delegatecall - * @param data The raw data to delegatecall - */ - function delegateTo(address callee, bytes memory data) internal { - (bool success, bytes memory returnData) = callee.delegatecall(data); - assembly { - if eq(success, 0) { - revert(add(returnData, 0x20), returndatasize()) - } - } - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function _fallback() internal { - // delegate all other functions to current implementation - (bool success, ) = implementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - /** - * @dev Fallback function that delegates calls to the `implementation`. Will run if no other - * function in the contract matches the call data. - */ - fallback() external payable { - _fallback(); - } - - /** - * @dev Fallback function that delegates calls to `implementation`. Will run if call data - * is empty. - */ - receive() external payable { - _fallback(); - } -} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOProxyV2.sol b/packages/nouns-contracts/contracts/governance/NounsDAOProxyV2.sol deleted file mode 100644 index ca05e50616..0000000000 --- a/packages/nouns-contracts/contracts/governance/NounsDAOProxyV2.sol +++ /dev/null @@ -1,144 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/// @title The Nouns DAO proxy contract for V2 - -/********************************* - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░██░░░████░░██░░░████░░░ * - * ░░██████░░░████████░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - *********************************/ - -// NounsDAOProxyV2.sol is a modified version of NounsDAOProxy.sol, tailored for the DAO's V2. -// Its main purpose is to support people wishing to deploy V2 directly, without having to deploy V1 first and then upgrade. - -// LICENSE -// NounsDAOProxy.sol is a modified version of Compound Lab's GovernorBravoDelegator.sol: -// https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoDelegator.sol -// -// GovernorBravoDelegator.sol source code Copyright 2020 Compound Labs, Inc. licensed under the BSD-3-Clause license. -// With modifications by Nounders DAO. -// -// Additional conditions of BSD-3-Clause can be found here: https://opensource.org/licenses/BSD-3-Clause -// -// -// NounsDAOProxy.sol uses parts of Open Zeppelin's Proxy.sol: -// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5c8746f56b4bed8cc9e0e044f5f69ab2f9428ce1/contracts/proxy/Proxy.sol -// -// Proxy.sol source code licensed under MIT License. -// -// MODIFICATIONS -// The fallback() and receive() functions of Proxy.sol have been used to allow Solidity > 0.6.0 compatibility - -pragma solidity ^0.8.6; - -import './NounsDAOInterfaces.sol'; - -contract NounsDAOProxyV2 is NounsDAOStorageV2, NounsDAOEvents { - constructor( - address timelock_, - address nouns_, - address vetoer_, - address admin_, - address implementation_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - DynamicQuorumParams memory dynamicQuorumParams_ - ) { - // Admin set to msg.sender for initialization - admin = msg.sender; - - delegateTo( - implementation_, - abi.encodeWithSignature( - 'initialize(address,address,address,uint256,uint256,uint256,(uint16,uint16,uint32))', - timelock_, - nouns_, - vetoer_, - votingPeriod_, - votingDelay_, - proposalThresholdBPS_, - dynamicQuorumParams_ - ) - ); - - _setImplementation(implementation_); - - admin = admin_; - } - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - */ - function _setImplementation(address implementation_) public { - require(msg.sender == admin, 'NounsDAOProxy::_setImplementation: admin only'); - require(implementation_ != address(0), 'NounsDAOProxy::_setImplementation: invalid implementation address'); - - address oldImplementation = implementation; - implementation = implementation_; - - emit NewImplementation(oldImplementation, implementation); - } - - /** - * @notice Internal method to delegate execution to another contract - * @dev It returns to the external caller whatever the implementation returns or forwards reverts - * @param callee The contract to delegatecall - * @param data The raw data to delegatecall - */ - function delegateTo(address callee, bytes memory data) internal { - (bool success, bytes memory returnData) = callee.delegatecall(data); - assembly { - if eq(success, 0) { - revert(add(returnData, 0x20), returndatasize()) - } - } - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function _fallback() internal { - // delegate all other functions to current implementation - (bool success, ) = implementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - /** - * @dev Fallback function that delegates calls to the `implementation`. Will run if no other - * function in the contract matches the call data. - */ - fallback() external payable { - _fallback(); - } - - /** - * @dev Fallback function that delegates calls to `implementation`. Will run if call data - * is empty. - */ - receive() external payable { - _fallback(); - } -} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOProxyV3.sol b/packages/nouns-contracts/contracts/governance/NounsDAOProxyV3.sol index 490c02c100..c494bf0546 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOProxyV3.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOProxyV3.sol @@ -38,9 +38,21 @@ pragma solidity ^0.8.19; -import './NounsDAOInterfaces.sol'; +import { NounsDAOV3Types, NounsDAOV3Types } from './NounsDAOInterfaces.sol'; + +contract NounsDAOProxyV3 { + /// @notice Administrator for this contract + address public admin; + + /// @notice Pending administrator for this contract + address public pendingAdmin; + + /// @notice Active brains of Governor + address public implementation; + + /// @notice Emitted when implementation is changed + event NewImplementation(address oldImplementation, address newImplementation); -contract NounsDAOProxyV3 is NounsDAOProxyStorage, NounsDAOEvents { constructor( address timelock_, address nouns_, @@ -49,8 +61,8 @@ contract NounsDAOProxyV3 is NounsDAOProxyStorage, NounsDAOEvents { address vetoer_, address admin_, address implementation_, - NounsDAOStorageV3.NounsDAOParams memory daoParams_, - NounsDAOStorageV3.DynamicQuorumParams memory dynamicQuorumParams_ + NounsDAOV3Types.NounsDAOParams memory daoParams_, + NounsDAOV3Types.DynamicQuorumParams memory dynamicQuorumParams_ ) { // Admin set to msg.sender for initialization admin = msg.sender; diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOV3Admin.sol b/packages/nouns-contracts/contracts/governance/NounsDAOV3Admin.sol index 2e12ddf834..836c4e8757 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOV3Admin.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOV3Admin.sol @@ -21,7 +21,7 @@ import './NounsDAOInterfaces.sol'; import { NounsDAOV3DynamicQuorum } from './NounsDAOV3DynamicQuorum.sol'; library NounsDAOV3Admin { - using NounsDAOV3DynamicQuorum for NounsDAOStorageV3.StorageV3; + using NounsDAOV3DynamicQuorum for NounsDAOV3Types.StorageV3; error AdminOnly(); error VetoerOnly(); @@ -337,7 +337,7 @@ library NounsDAOV3Admin { * Must be lower than or equal to maxQuorumVotesBPS */ function _setMinQuorumVotesBPS(uint16 newMinQuorumVotesBPS) external onlyAdmin { - NounsDAOStorageV3.DynamicQuorumParams memory params = ds().getDynamicQuorumParamsAt(block.number); + NounsDAOV3Types.DynamicQuorumParams memory params = ds().getDynamicQuorumParamsAt(block.number); require( newMinQuorumVotesBPS >= MIN_QUORUM_VOTES_BPS_LOWER_BOUND && @@ -364,7 +364,7 @@ library NounsDAOV3Admin { * Must be higher than or equal to minQuorumVotesBPS */ function _setMaxQuorumVotesBPS(uint16 newMaxQuorumVotesBPS) external onlyAdmin { - NounsDAOStorageV3.DynamicQuorumParams memory params = ds().getDynamicQuorumParamsAt(block.number); + NounsDAOV3Types.DynamicQuorumParams memory params = ds().getDynamicQuorumParamsAt(block.number); require( newMaxQuorumVotesBPS <= MAX_QUORUM_VOTES_BPS_UPPER_BOUND, @@ -388,7 +388,7 @@ library NounsDAOV3Admin { * @param newQuorumCoefficient the new coefficient, as a fixed point integer with 6 decimals */ function _setQuorumCoefficient(uint32 newQuorumCoefficient) external onlyAdmin { - NounsDAOStorageV3.DynamicQuorumParams memory params = ds().getDynamicQuorumParamsAt(block.number); + NounsDAOV3Types.DynamicQuorumParams memory params = ds().getDynamicQuorumParamsAt(block.number); uint32 oldQuorumCoefficient = params.quorumCoefficient; params.quorumCoefficient = newQuorumCoefficient; @@ -426,9 +426,9 @@ library NounsDAOV3Admin { revert MinQuorumBPSGreaterThanMaxQuorumBPS(); } - NounsDAOStorageV3.DynamicQuorumParams memory oldParams = ds().getDynamicQuorumParamsAt(block.number); + NounsDAOV3Types.DynamicQuorumParams memory oldParams = ds().getDynamicQuorumParamsAt(block.number); - NounsDAOStorageV3.DynamicQuorumParams memory params = NounsDAOStorageV3.DynamicQuorumParams({ + NounsDAOV3Types.DynamicQuorumParams memory params = NounsDAOV3Types.DynamicQuorumParams({ minQuorumVotesBPS: newMinQuorumVotesBPS, maxQuorumVotesBPS: newMaxQuorumVotesBPS, quorumCoefficient: newQuorumCoefficient @@ -554,11 +554,7 @@ library NounsDAOV3Admin { * @param timelockV1 the new timelockV1 contract * @param admin the new admin address */ - function _setTimelocksAndAdmin( - address timelock, - address timelockV1, - address admin - ) external onlyAdmin { + function _setTimelocksAndAdmin(address timelock, address timelockV1, address admin) external onlyAdmin { ds().timelock = INounsDAOExecutorV2(timelock); ds().timelockV1 = INounsDAOExecutor(timelockV1); ds().admin = admin; @@ -566,14 +562,14 @@ library NounsDAOV3Admin { emit TimelocksAndAdminSet(timelock, timelockV1, admin); } - function _writeQuorumParamsCheckpoint(NounsDAOStorageV3.DynamicQuorumParams memory params) internal { + function _writeQuorumParamsCheckpoint(NounsDAOV3Types.DynamicQuorumParams memory params) internal { uint32 blockNumber = safe32(block.number, 'block number exceeds 32 bits'); uint256 pos = ds().quorumParamsCheckpoints.length; if (pos > 0 && ds().quorumParamsCheckpoints[pos - 1].fromBlock == blockNumber) { ds().quorumParamsCheckpoints[pos - 1].params = params; } else { ds().quorumParamsCheckpoints.push( - NounsDAOStorageV3.DynamicQuorumParamsCheckpoint({ fromBlock: blockNumber, params: params }) + NounsDAOV3Types.DynamicQuorumParamsCheckpoint({ fromBlock: blockNumber, params: params }) ); } } @@ -599,7 +595,7 @@ library NounsDAOV3Admin { * since the DAO no longer makes explicit calls to this library. * This function assumes the storage struct starts at slot 0. */ - function ds() internal pure returns (NounsDAOStorageV3.StorageV3 storage ds_) { + function ds() internal pure returns (NounsDAOV3Types.StorageV3 storage ds_) { assembly { ds_.slot := 0 } diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOV3DynamicQuorum.sol b/packages/nouns-contracts/contracts/governance/NounsDAOV3DynamicQuorum.sol index 7c83928b9a..a6388f690e 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOV3DynamicQuorum.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOV3DynamicQuorum.sol @@ -21,7 +21,7 @@ import './NounsDAOInterfaces.sol'; import { NounsDAOV3Fork } from './fork/NounsDAOV3Fork.sol'; library NounsDAOV3DynamicQuorum { - using NounsDAOV3Fork for NounsDAOStorageV3.StorageV3; + using NounsDAOV3Fork for NounsDAOV3Types.StorageV3; error UnsafeUint16Cast(); @@ -29,8 +29,8 @@ library NounsDAOV3DynamicQuorum { * @notice Quorum votes required for a specific proposal to succeed * Differs from `GovernerBravo` which uses fixed amount */ - function quorumVotes(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) internal view returns (uint256) { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + function quorumVotes(NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId) internal view returns (uint256) { + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; if (proposal.totalSupply == 0) { return proposal.quorumVotes; } @@ -58,7 +58,7 @@ library NounsDAOV3DynamicQuorum { function dynamicQuorumVotes( uint256 againstVotes, uint256 totalSupply, - NounsDAOStorageV3.DynamicQuorumParams memory params + NounsDAOV3Types.DynamicQuorumParams memory params ) public pure returns (uint256) { uint256 againstVotesBPS = (10000 * againstVotes) / totalSupply; uint256 quorumAdjustmentBPS = (params.quorumCoefficient * againstVotesBPS) / 1e6; @@ -74,17 +74,16 @@ library NounsDAOV3DynamicQuorum { * @param blockNumber_ the block number to get the params at * @return The dynamic quorum parameters that were set at the given block number */ - function getDynamicQuorumParamsAt(NounsDAOStorageV3.StorageV3 storage ds, uint256 blockNumber_) - internal - view - returns (NounsDAOStorageV3.DynamicQuorumParams memory) - { + function getDynamicQuorumParamsAt( + NounsDAOV3Types.StorageV3 storage ds, + uint256 blockNumber_ + ) internal view returns (NounsDAOV3Types.DynamicQuorumParams memory) { uint32 blockNumber = safe32(blockNumber_, 'NounsDAO::getDynamicQuorumParamsAt: block number exceeds 32 bits'); uint256 len = ds.quorumParamsCheckpoints.length; if (len == 0) { return - NounsDAOStorageV3.DynamicQuorumParams({ + NounsDAOV3Types.DynamicQuorumParams({ minQuorumVotesBPS: safe16(ds.quorumVotesBPS), maxQuorumVotesBPS: safe16(ds.quorumVotesBPS), quorumCoefficient: 0 @@ -97,7 +96,7 @@ library NounsDAOV3DynamicQuorum { if (ds.quorumParamsCheckpoints[0].fromBlock > blockNumber) { return - NounsDAOStorageV3.DynamicQuorumParams({ + NounsDAOV3Types.DynamicQuorumParams({ minQuorumVotesBPS: safe16(ds.quorumVotesBPS), maxQuorumVotesBPS: safe16(ds.quorumVotesBPS), quorumCoefficient: 0 @@ -108,7 +107,7 @@ library NounsDAOV3DynamicQuorum { uint256 upper = len - 1; while (upper > lower) { uint256 center = upper - (upper - lower) / 2; - NounsDAOStorageV3.DynamicQuorumParamsCheckpoint memory cp = ds.quorumParamsCheckpoints[center]; + NounsDAOV3Types.DynamicQuorumParamsCheckpoint memory cp = ds.quorumParamsCheckpoints[center]; if (cp.fromBlock == blockNumber) { return cp.params; } else if (cp.fromBlock < blockNumber) { @@ -123,22 +122,20 @@ library NounsDAOV3DynamicQuorum { /** * @notice Current min quorum votes using Nouns adjusted total supply */ - function minQuorumVotes(NounsDAOStorageV3.StorageV3 storage ds, uint256 adjustedTotalSupply) - internal - view - returns (uint256) - { + function minQuorumVotes( + NounsDAOV3Types.StorageV3 storage ds, + uint256 adjustedTotalSupply + ) internal view returns (uint256) { return bps2Uint(getDynamicQuorumParamsAt(ds, block.number).minQuorumVotesBPS, adjustedTotalSupply); } /** * @notice Current max quorum votes using Nouns adjusted total supply */ - function maxQuorumVotes(NounsDAOStorageV3.StorageV3 storage ds, uint256 adjustedTotalSupply) - internal - view - returns (uint256) - { + function maxQuorumVotes( + NounsDAOV3Types.StorageV3 storage ds, + uint256 adjustedTotalSupply + ) internal view returns (uint256) { return bps2Uint(getDynamicQuorumParamsAt(ds, block.number).maxQuorumVotesBPS, adjustedTotalSupply); } diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol b/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol index 0e80a674ce..0a210585a8 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol @@ -25,8 +25,8 @@ import { ECDSA } from '../external/openzeppelin/ECDSA.sol'; import { SafeCast } from '@openzeppelin/contracts/utils/math/SafeCast.sol'; library NounsDAOV3Proposals { - using NounsDAOV3DynamicQuorum for NounsDAOStorageV3.StorageV3; - using NounsDAOV3Fork for NounsDAOStorageV3.StorageV3; + using NounsDAOV3DynamicQuorum for NounsDAOV3Types.StorageV3; + using NounsDAOV3Fork for NounsDAOV3Types.StorageV3; error CantCancelProposalAtFinalState(); error ProposalInfoArityMismatch(); @@ -78,7 +78,7 @@ library NounsDAOV3Proposals { * @return Proposal id of new proposal */ function propose( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, ProposalTxs memory txs, string memory description, uint32 clientId @@ -94,7 +94,7 @@ library NounsDAOV3Proposals { ds.proposalCount = ds.proposalCount + 1; uint32 proposalId = SafeCast.toUint32(ds.proposalCount); - NounsDAOStorageV3.Proposal storage newProposal = createNewProposal( + NounsDAOV3Types.Proposal storage newProposal = createNewProposal( ds, proposalId, proposalThreshold_, @@ -104,7 +104,14 @@ library NounsDAOV3Proposals { ); ds.latestProposalIds[msg.sender] = proposalId; - emitNewPropEvents(newProposal, new address[](0), ds.minQuorumVotes(adjustedTotalSupply), txs, description, clientId); + emitNewPropEvents( + newProposal, + new address[](0), + ds.minQuorumVotes(adjustedTotalSupply), + txs, + description, + clientId + ); return proposalId; } @@ -118,14 +125,14 @@ library NounsDAOV3Proposals { * @return uint256 Proposal id of new proposal */ function proposeOnTimelockV1( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, ProposalTxs memory txs, string memory description, uint32 client ) internal returns (uint256) { uint256 newProposalId = propose(ds, txs, description, client); - NounsDAOStorageV3.Proposal storage newProposal = ds._proposals[newProposalId]; + NounsDAOV3Types.Proposal storage newProposal = ds._proposals[newProposalId]; newProposal.executeOnTimelockV1 = true; emit NounsDAOEventsV3.ProposalCreatedOnTimelockV1(newProposalId); @@ -148,8 +155,8 @@ library NounsDAOV3Proposals { * @return uint256 Proposal id of new proposal */ function proposeBySigs( - NounsDAOStorageV3.StorageV3 storage ds, - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, + NounsDAOV3Types.StorageV3 storage ds, + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures, ProposalTxs memory txs, string memory description, uint32 clientId @@ -163,7 +170,7 @@ library NounsDAOV3Proposals { temp.adjustedTotalSupply = ds.adjustedTotalSupply(); temp.propThreshold = proposalThreshold(ds, temp.adjustedTotalSupply); - NounsDAOStorageV3.Proposal storage newProposal = createNewProposal( + NounsDAOV3Types.Proposal storage newProposal = createNewProposal( ds, temp.proposalId, temp.propThreshold, @@ -186,7 +193,14 @@ library NounsDAOV3Proposals { newProposal.signers = signers; - emitNewPropEvents(newProposal, signers, ds.minQuorumVotes(temp.adjustedTotalSupply), txs, description, clientId); + emitNewPropEvents( + newProposal, + signers, + ds.minQuorumVotes(temp.adjustedTotalSupply), + txs, + description, + clientId + ); return temp.proposalId; } @@ -200,7 +214,7 @@ library NounsDAOV3Proposals { * not be invalidated. * @param sig The signature to cancel */ - function cancelSig(NounsDAOStorageV3.StorageV3 storage ds, bytes calldata sig) external { + function cancelSig(NounsDAOV3Types.StorageV3 storage ds, bytes calldata sig) external { bytes32 sigHash = keccak256(sig); ds.cancelledSigs[msg.sender][sigHash] = true; @@ -219,7 +233,7 @@ library NounsDAOV3Proposals { * @param updateMessage Short message to explain the update */ function updateProposal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, address[] memory targets, uint256[] memory values, @@ -252,7 +266,7 @@ library NounsDAOV3Proposals { * @param updateMessage Short message to explain the update */ function updateProposalTransactions( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, address[] memory targets, uint256[] memory values, @@ -274,7 +288,7 @@ library NounsDAOV3Proposals { } function updateProposalTransactionsInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, address[] memory targets, uint256[] memory values, @@ -283,7 +297,7 @@ library NounsDAOV3Proposals { ) internal { checkProposalTxs(ProposalTxs(targets, values, signatures, calldatas)); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; checkProposalUpdatable(ds, proposalId, proposal); proposal.targets = targets; @@ -299,12 +313,12 @@ library NounsDAOV3Proposals { * @param updateMessage Short message to explain the update */ function updateProposalDescription( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, string calldata description, string calldata updateMessage ) external { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; checkProposalUpdatable(ds, proposalId, proposal); emit NounsDAOEventsV3.ProposalDescriptionUpdated(proposalId, msg.sender, description, updateMessage); @@ -322,9 +336,9 @@ library NounsDAOV3Proposals { * @param updateMessage Short message to explain the update */ function updateProposalBySigs( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures, ProposalTxs memory txs, string memory description, string memory updateMessage @@ -334,8 +348,8 @@ library NounsDAOV3Proposals { // this problem doesn't exist in the propose function because we check for prop threshold there if (proposerSignatures.length == 0) revert MustProvideSignatures(); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; - if (stateInternal(ds, proposalId) != NounsDAOStorageV3.ProposalState.Updatable) + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; + if (stateInternal(ds, proposalId) != NounsDAOV3Types.ProposalState.Updatable) revert CanOnlyEditUpdatableProposals(); if (msg.sender != proposal.proposer) revert OnlyProposerCanEdit(); @@ -376,12 +390,12 @@ library NounsDAOV3Proposals { * @notice Queues a proposal of state succeeded * @param proposalId The id of the proposal to queue */ - function queue(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) external { + function queue(NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId) external { require( - stateInternal(ds, proposalId) == NounsDAOStorageV3.ProposalState.Succeeded, + stateInternal(ds, proposalId) == NounsDAOV3Types.ProposalState.Succeeded, 'NounsDAO::queue: proposal can only be queued if it is succeeded' ); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; INounsDAOExecutor timelock = getProposalTimelock(ds, proposal); uint256 eta = block.timestamp + timelock.delay(); for (uint256 i = 0; i < proposal.targets.length; i++) { @@ -395,7 +409,7 @@ library NounsDAOV3Proposals { ); } proposal.eta = eta; - emit NounsDAOEvents.ProposalQueued(proposalId, eta); + emit NounsDAOEventsV3.ProposalQueued(proposalId, eta); } function queueOrRevertInternal( @@ -417,19 +431,19 @@ library NounsDAOV3Proposals { * @notice Executes a queued proposal if eta has passed * @param proposalId The id of the proposal to execute */ - function execute(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) external { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + function execute(NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId) external { + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; INounsDAOExecutor timelock = getProposalTimelock(ds, proposal); executeInternal(ds, proposal, timelock); } function executeInternal( - NounsDAOStorageV3.StorageV3 storage ds, - NounsDAOStorageV3.Proposal storage proposal, + NounsDAOV3Types.StorageV3 storage ds, + NounsDAOV3Types.Proposal storage proposal, INounsDAOExecutor timelock ) internal { require( - stateInternal(ds, proposal.id) == NounsDAOStorageV3.ProposalState.Queued, + stateInternal(ds, proposal.id) == NounsDAOV3Types.ProposalState.Queued, 'NounsDAO::execute: proposal can only be executed if it is queued' ); if (ds.isForkPeriodActive()) revert CannotExecuteDuringForkingPeriod(); @@ -445,12 +459,12 @@ library NounsDAOV3Proposals { proposal.eta ); } - emit NounsDAOEvents.ProposalExecuted(proposal.id); + emit NounsDAOEventsV3.ProposalExecuted(proposal.id); } function getProposalTimelock( - NounsDAOStorageV3.StorageV3 storage ds, - NounsDAOStorageV3.Proposal storage proposal + NounsDAOV3Types.StorageV3 storage ds, + NounsDAOV3Types.Proposal storage proposal ) internal view returns (INounsDAOExecutor) { if (proposal.executeOnTimelockV1) { return ds.timelockV1; @@ -463,7 +477,7 @@ library NounsDAOV3Proposals { * @notice Vetoes a proposal only if sender is the vetoer and the proposal has not been executed. * @param proposalId The id of the proposal to veto */ - function veto(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) external { + function veto(NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId) external { if (ds.vetoer == address(0)) { revert VetoerBurned(); } @@ -472,11 +486,11 @@ library NounsDAOV3Proposals { revert VetoerOnly(); } - if (stateInternal(ds, proposalId) == NounsDAOStorageV3.ProposalState.Executed) { + if (stateInternal(ds, proposalId) == NounsDAOV3Types.ProposalState.Executed) { revert CantVetoExecutedProposal(); } - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; proposal.vetoed = true; INounsDAOExecutor timelock = getProposalTimelock(ds, proposal); @@ -490,7 +504,7 @@ library NounsDAOV3Proposals { ); } - emit NounsDAOEvents.ProposalVetoed(proposalId); + emit NounsDAOEventsV3.ProposalVetoed(proposalId); } /** @@ -498,19 +512,19 @@ library NounsDAOV3Proposals { * dropped below proposal threshold * @param proposalId The id of the proposal to cancel */ - function cancel(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) external { - NounsDAOStorageV3.ProposalState proposalState = stateInternal(ds, proposalId); + function cancel(NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId) external { + NounsDAOV3Types.ProposalState proposalState = stateInternal(ds, proposalId); if ( - proposalState == NounsDAOStorageV3.ProposalState.Canceled || - proposalState == NounsDAOStorageV3.ProposalState.Defeated || - proposalState == NounsDAOStorageV3.ProposalState.Expired || - proposalState == NounsDAOStorageV3.ProposalState.Executed || - proposalState == NounsDAOStorageV3.ProposalState.Vetoed + proposalState == NounsDAOV3Types.ProposalState.Canceled || + proposalState == NounsDAOV3Types.ProposalState.Defeated || + proposalState == NounsDAOV3Types.ProposalState.Expired || + proposalState == NounsDAOV3Types.ProposalState.Executed || + proposalState == NounsDAOV3Types.ProposalState.Vetoed ) { revert CantCancelProposalAtFinalState(); } - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; address proposer = proposal.proposer; NounsTokenLike nouns = ds.nouns; @@ -539,7 +553,7 @@ library NounsDAOV3Proposals { ); } - emit NounsDAOEvents.ProposalCanceled(proposalId); + emit NounsDAOEventsV3.ProposalCanceled(proposalId); } /** @@ -549,9 +563,9 @@ library NounsDAOV3Proposals { * @return Proposal state */ function state( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId - ) public view returns (NounsDAOStorageV3.ProposalState) { + ) public view returns (NounsDAOV3Types.ProposalState) { return stateInternal(ds, proposalId); } @@ -563,34 +577,34 @@ library NounsDAOV3Proposals { * @return Proposal state */ function stateInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId - ) internal view returns (NounsDAOStorageV3.ProposalState) { + ) internal view returns (NounsDAOV3Types.ProposalState) { require(ds.proposalCount >= proposalId, 'NounsDAO::state: invalid proposal id'); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; if (proposal.vetoed) { - return NounsDAOStorageV3.ProposalState.Vetoed; + return NounsDAOV3Types.ProposalState.Vetoed; } else if (proposal.canceled) { - return NounsDAOStorageV3.ProposalState.Canceled; + return NounsDAOV3Types.ProposalState.Canceled; } else if (block.number <= proposal.updatePeriodEndBlock) { - return NounsDAOStorageV3.ProposalState.Updatable; + return NounsDAOV3Types.ProposalState.Updatable; } else if (block.number <= proposal.startBlock) { - return NounsDAOStorageV3.ProposalState.Pending; + return NounsDAOV3Types.ProposalState.Pending; } else if (block.number <= proposal.endBlock) { - return NounsDAOStorageV3.ProposalState.Active; + return NounsDAOV3Types.ProposalState.Active; } else if (block.number <= proposal.objectionPeriodEndBlock) { - return NounsDAOStorageV3.ProposalState.ObjectionPeriod; + return NounsDAOV3Types.ProposalState.ObjectionPeriod; } else if (isDefeated(ds, proposal)) { - return NounsDAOStorageV3.ProposalState.Defeated; + return NounsDAOV3Types.ProposalState.Defeated; } else if (proposal.eta == 0) { - return NounsDAOStorageV3.ProposalState.Succeeded; + return NounsDAOV3Types.ProposalState.Succeeded; } else if (proposal.executed) { - return NounsDAOStorageV3.ProposalState.Executed; + return NounsDAOV3Types.ProposalState.Executed; } else if (block.timestamp >= proposal.eta + getProposalTimelock(ds, proposal).GRACE_PERIOD()) { - return NounsDAOStorageV3.ProposalState.Expired; + return NounsDAOV3Types.ProposalState.Expired; } else { - return NounsDAOStorageV3.ProposalState.Queued; + return NounsDAOV3Types.ProposalState.Queued; } } @@ -603,7 +617,7 @@ library NounsDAOV3Proposals { * @return calldatas */ function getActions( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId ) internal @@ -615,7 +629,7 @@ library NounsDAOV3Proposals { bytes[] memory calldatas ) { - NounsDAOStorageV3.Proposal storage p = ds._proposals[proposalId]; + NounsDAOV3Types.Proposal storage p = ds._proposals[proposalId]; return (p.targets, p.values, p.signatures, p.calldatas); } @@ -626,10 +640,10 @@ library NounsDAOV3Proposals { * @return The voting receipt */ function getReceipt( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, address voter - ) internal view returns (NounsDAOStorageV3.Receipt memory) { + ) internal view returns (NounsDAOV3Types.Receipt memory) { return ds._proposals[proposalId].receipts[voter]; } @@ -640,12 +654,12 @@ library NounsDAOV3Proposals { * @return A `ProposalCondensed` struct with the proposal data */ function proposals( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId - ) external view returns (NounsDAOStorageV2.ProposalCondensed memory) { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + ) external view returns (NounsDAOV3Types.ProposalCondensedV2 memory) { + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; return - NounsDAOStorageV2.ProposalCondensed({ + NounsDAOV3Types.ProposalCondensedV2({ id: proposal.id, proposer: proposal.proposer, proposalThreshold: proposal.proposalThreshold, @@ -671,12 +685,12 @@ library NounsDAOV3Proposals { * @return A `ProposalCondensed` struct with the proposal data */ function proposalsV3( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId - ) external view returns (NounsDAOStorageV3.ProposalCondensed memory) { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + ) external view returns (NounsDAOV3Types.ProposalCondensed memory) { + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; return - NounsDAOStorageV3.ProposalCondensed({ + NounsDAOV3Types.ProposalCondensed({ id: proposal.id, proposer: proposal.proposer, proposalThreshold: proposal.proposalThreshold, @@ -701,12 +715,12 @@ library NounsDAOV3Proposals { } function proposalDataForRewards( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId - ) internal view returns (NounsDAOStorageV3.ProposalForRewards memory) { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + ) internal view returns (NounsDAOV3Types.ProposalForRewards memory) { + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; return - NounsDAOStorageV3.ProposalForRewards({ + NounsDAOV3Types.ProposalForRewards({ endBlock: proposal.endBlock, objectionPeriodEndBlock: proposal.objectionPeriodEndBlock, forVotes: proposal.forVotes, @@ -724,15 +738,15 @@ library NounsDAOV3Proposals { * Differs from `GovernerBravo` which uses fixed amount */ function proposalThreshold( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 adjustedTotalSupply ) internal view returns (uint256) { return bps2Uint(ds.proposalThresholdBPS, adjustedTotalSupply); } function isDefeated( - NounsDAOStorageV3.StorageV3 storage ds, - NounsDAOStorageV3.Proposal storage proposal + NounsDAOV3Types.StorageV3 storage ds, + NounsDAOV3Types.Proposal storage proposal ) internal view returns (bool) { uint256 forVotes = proposal.forVotes; return forVotes <= proposal.againstVotes || forVotes < ds.quorumVotes(proposal.id); @@ -742,15 +756,15 @@ library NounsDAOV3Proposals { * @notice reverts if `proposer` is the proposer or signer of an active proposal. * This is a spam protection mechanism to limit the number of proposals each noun can back. */ - function checkNoActiveProp(NounsDAOStorageV3.StorageV3 storage ds, address proposer) internal view { + function checkNoActiveProp(NounsDAOV3Types.StorageV3 storage ds, address proposer) internal view { uint256 latestProposalId = ds.latestProposalIds[proposer]; if (latestProposalId != 0) { - NounsDAOStorageV3.ProposalState proposersLatestProposalState = stateInternal(ds, latestProposalId); + NounsDAOV3Types.ProposalState proposersLatestProposalState = stateInternal(ds, latestProposalId); if ( - proposersLatestProposalState == NounsDAOStorageV3.ProposalState.ObjectionPeriod || - proposersLatestProposalState == NounsDAOStorageV3.ProposalState.Active || - proposersLatestProposalState == NounsDAOStorageV3.ProposalState.Pending || - proposersLatestProposalState == NounsDAOStorageV3.ProposalState.Updatable + proposersLatestProposalState == NounsDAOV3Types.ProposalState.ObjectionPeriod || + proposersLatestProposalState == NounsDAOV3Types.ProposalState.Active || + proposersLatestProposalState == NounsDAOV3Types.ProposalState.Pending || + proposersLatestProposalState == NounsDAOV3Types.ProposalState.Updatable ) revert ProposerAlreadyHasALiveProposal(); } } @@ -759,8 +773,8 @@ library NounsDAOV3Proposals { * @dev Extracted this function to fix the `Stack too deep` error `proposeBySigs` hit. */ function verifySignersCanBackThisProposalAndCountTheirVotes( - NounsDAOStorageV3.StorageV3 storage ds, - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, + NounsDAOV3Types.StorageV3 storage ds, + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures, ProposalTxs memory txs, string memory description, uint256 proposalId @@ -825,24 +839,24 @@ library NounsDAOV3Proposals { } function checkProposalUpdatable( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, - NounsDAOStorageV3.Proposal storage proposal + NounsDAOV3Types.Proposal storage proposal ) internal view { - if (stateInternal(ds, proposalId) != NounsDAOStorageV3.ProposalState.Updatable) + if (stateInternal(ds, proposalId) != NounsDAOV3Types.ProposalState.Updatable) revert CanOnlyEditUpdatableProposals(); if (msg.sender != proposal.proposer) revert OnlyProposerCanEdit(); if (proposal.signers.length > 0) revert ProposerCannotUpdateProposalWithSigners(); } function createNewProposal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint32 proposalId, uint256 proposalThreshold_, uint256 adjustedTotalSupply, ProposalTxs memory txs, uint32 clientId - ) internal returns (NounsDAOStorageV3.Proposal storage newProposal) { + ) internal returns (NounsDAOV3Types.Proposal storage newProposal) { uint64 updatePeriodEndBlock = SafeCast.toUint64(block.number + ds.proposalUpdatablePeriodInBlocks); uint256 startBlock = updatePeriodEndBlock + ds.votingDelay; uint256 endBlock = startBlock + ds.votingPeriod; @@ -865,7 +879,7 @@ library NounsDAOV3Proposals { } function emitNewPropEvents( - NounsDAOStorageV3.Proposal storage newProposal, + NounsDAOV3Types.Proposal storage newProposal, address[] memory signers, uint256 minQuorumVotes, ProposalTxs memory txs, @@ -873,7 +887,7 @@ library NounsDAOV3Proposals { uint32 clientId ) internal { /// @notice Maintains backwards compatibility with GovernorBravo events - emit NounsDAOEvents.ProposalCreated( + emit NounsDAOEventsV3.ProposalCreated( newProposal.id, msg.sender, txs.targets, @@ -891,7 +905,7 @@ library NounsDAOV3Proposals { /// @notice V4: Removed data that's already emitted in `ProposalCreated`, added clientId emit NounsDAOEventsV3.ProposalCreatedWithRequirements( newProposal.id, - signers, + signers, newProposal.updatePeriodEndBlock, newProposal.proposalThreshold, minQuorumVotes, @@ -900,7 +914,7 @@ library NounsDAOV3Proposals { } function checkPropThreshold( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 votes, uint256 adjustedTotalSupply ) internal view returns (uint256 propThreshold) { @@ -919,9 +933,9 @@ library NounsDAOV3Proposals { } function verifyProposalSignature( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, bytes memory proposalEncodeData, - NounsDAOStorageV3.ProposerSignature memory proposerSignature, + NounsDAOV3Types.ProposerSignature memory proposerSignature, bytes32 typehash ) internal view { bytes32 sigHash = keccak256(proposerSignature.sig); diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol b/packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol index 29d3021a3e..1300073d46 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol @@ -22,7 +22,7 @@ import { NounsDAOV3Proposals } from './NounsDAOV3Proposals.sol'; import { SafeCast } from '@openzeppelin/contracts/utils/math/SafeCast.sol'; library NounsDAOV3Votes { - using NounsDAOV3Proposals for NounsDAOStorageV3.StorageV3; + using NounsDAOV3Proposals for NounsDAOV3Types.StorageV3; error CanOnlyVoteAgainstDuringObjectionPeriod(); @@ -67,7 +67,7 @@ library NounsDAOV3Votes { * @param proposalId The id of the proposal to vote on * @param support The support value for the vote. 0=against, 1=for, 2=abstain */ - function castVote(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId, uint8 support) external { + function castVote(NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, uint8 support) external { emit VoteCast(msg.sender, proposalId, support, castVoteInternal(ds, msg.sender, proposalId, support, 0), ''); } @@ -82,7 +82,7 @@ library NounsDAOV3Votes { * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVote( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, uint8 support, uint32 clientId @@ -102,7 +102,7 @@ library NounsDAOV3Votes { * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVoteWithReason( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, uint8 support, string calldata reason, @@ -119,7 +119,7 @@ library NounsDAOV3Votes { * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVoteInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, uint8 support, string memory reason, @@ -141,7 +141,7 @@ library NounsDAOV3Votes { * @param reason The reason given for the vote by the voter */ function castVoteWithReason( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, uint8 support, string calldata reason @@ -160,7 +160,7 @@ library NounsDAOV3Votes { * @dev External function that accepts EIP-712 signatures for voting on proposals. */ function castVoteBySig( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, uint8 support, uint8 v, @@ -188,25 +188,25 @@ library NounsDAOV3Votes { * @return votes The number of votes cast */ function castVoteInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, address voter, uint256 proposalId, uint8 support, uint32 clientId ) internal returns (uint96 votes) { - NounsDAOStorageV3.ProposalState proposalState = ds.stateInternal(proposalId); + NounsDAOV3Types.ProposalState proposalState = ds.stateInternal(proposalId); - if (proposalState == NounsDAOStorageV3.ProposalState.Active) { + if (proposalState == NounsDAOV3Types.ProposalState.Active) { votes = castVoteDuringVotingPeriodInternal(ds, proposalId, voter, support); - } else if (proposalState == NounsDAOStorageV3.ProposalState.ObjectionPeriod) { + } else if (proposalState == NounsDAOV3Types.ProposalState.ObjectionPeriod) { if (support != 0) revert CanOnlyVoteAgainstDuringObjectionPeriod(); votes = castObjectionInternal(ds, proposalId, voter); } else { revert('NounsDAO::castVoteInternal: voting is closed'); } - NounsDAOStorageV3.ClientVoteData memory voteData = ds._proposals[proposalId].voteClients[clientId]; - ds._proposals[proposalId].voteClients[clientId] = NounsDAOStorageV3.ClientVoteData({ + NounsDAOV3Types.ClientVoteData memory voteData = ds._proposals[proposalId].voteClients[clientId]; + ds._proposals[proposalId].voteClients[clientId] = NounsDAOV3Types.ClientVoteData({ votes: uint32(voteData.votes + votes), txs: voteData.txs + 1 }); @@ -221,14 +221,14 @@ library NounsDAOV3Votes { * @return The number of votes cast */ function castVoteDuringVotingPeriodInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, address voter, uint8 support ) internal returns (uint96) { require(support <= 2, 'NounsDAO::castVoteDuringVotingPeriodInternal: invalid vote type'); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; - NounsDAOStorageV3.Receipt storage receipt = proposal.receipts[voter]; + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOV3Types.Receipt storage receipt = proposal.receipts[voter]; require(receipt.hasVoted == false, 'NounsDAO::castVoteDuringVotingPeriodInternal: voter already voted'); /// @notice: Unlike GovernerBravo, votes are considered from the block the proposal was created in order to normalize quorumVotes and proposalThreshold metrics @@ -286,12 +286,12 @@ library NounsDAOV3Votes { * @return The number of votes cast */ function castObjectionInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, address voter ) internal returns (uint96) { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; - NounsDAOStorageV3.Receipt storage receipt = proposal.receipts[voter]; + NounsDAOV3Types.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOV3Types.Receipt storage receipt = proposal.receipts[voter]; require(receipt.hasVoted == false, 'NounsDAO::castVoteInternal: voter already voted'); uint96 votes = receipt.votes = ds.nouns.getPriorVotes( @@ -328,9 +328,9 @@ library NounsDAOV3Votes { * @param proposal The proposal storage reference, used to read `creationBlock` and `startBlock` */ function proposalVoteSnapshotBlock( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256 proposalId, - NounsDAOStorageV3.Proposal storage proposal + NounsDAOV3Types.Proposal storage proposal ) internal view returns (uint256) { // The idea is to temporarily use this code that would still use `creationBlock` until all proposals are using // `startBlock`, then we can deploy a quick DAO fix that removes this line and only uses `startBlock`. diff --git a/packages/nouns-contracts/contracts/governance/data/NounsDAOData.sol b/packages/nouns-contracts/contracts/governance/data/NounsDAOData.sol index d3c511e232..b3f3b49d68 100644 --- a/packages/nouns-contracts/contracts/governance/data/NounsDAOData.sol +++ b/packages/nouns-contracts/contracts/governance/data/NounsDAOData.sol @@ -19,13 +19,13 @@ pragma solidity ^0.8.19; import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; import { NounsDAOV3Proposals } from '../NounsDAOV3Proposals.sol'; -import { NounsTokenLike, NounsDAOStorageV3 } from '../NounsDAOInterfaces.sol'; +import { NounsTokenLike, NounsDAOV3Types } from '../NounsDAOInterfaces.sol'; import { SignatureChecker } from '../../external/openzeppelin/SignatureChecker.sol'; import { UUPSUpgradeable } from '@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol'; import { NounsDAODataEvents } from './NounsDAODataEvents.sol'; interface INounsDAO { - function proposalsV3(uint256 proposalId) external view returns (NounsDAOStorageV3.ProposalCondensed memory); + function proposalsV3(uint256 proposalId) external view returns (NounsDAOV3Types.ProposalCondensed memory); } contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents { @@ -132,7 +132,7 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents ) external payable { if (proposalIdToUpdate > 0) { INounsDAO dao = INounsDAO(nounsDao); - NounsDAOStorageV3.ProposalCondensed memory propInfo = dao.proposalsV3(proposalIdToUpdate); + NounsDAOV3Types.ProposalCondensed memory propInfo = dao.proposalsV3(proposalIdToUpdate); if (block.number > propInfo.updatePeriodEndBlock) revert ProposalToUpdateMustBeUpdatable(); if (propInfo.proposer != msg.sender) revert OnlyProposerCanCreateUpdateCandidate(); @@ -283,11 +283,7 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents * @param support msg.sender's vote-like feedback: 0 is against, 1 is for, 2 is abstain. * @param reason their free text feedback. */ - function sendFeedback( - uint256 proposalId, - uint8 support, - string memory reason - ) external { + function sendFeedback(uint256 proposalId, uint8 support, string memory reason) external { if (support > 2) revert InvalidSupportValue(); emit FeedbackSent(msg.sender, proposalId, support, reason); @@ -301,12 +297,7 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents * @param support msg.sender's vote-like feedback: 0 is against, 1 is for, 2 is abstain. * @param reason their free text feedback. */ - function sendCandidateFeedback( - address proposer, - string memory slug, - uint8 support, - string memory reason - ) external { + function sendCandidateFeedback(address proposer, string memory slug, uint8 support, string memory reason) external { if (!propCandidates[proposer][keccak256(bytes(slug))]) revert SlugDoesNotExist(); if (support > 2) revert InvalidSupportValue(); diff --git a/packages/nouns-contracts/contracts/governance/fork/ForkDAODeployer.sol b/packages/nouns-contracts/contracts/governance/fork/ForkDAODeployer.sol index d455248eef..0bf9916be8 100644 --- a/packages/nouns-contracts/contracts/governance/fork/ForkDAODeployer.sol +++ b/packages/nouns-contracts/contracts/governance/fork/ForkDAODeployer.sol @@ -18,11 +18,10 @@ pragma solidity ^0.8.19; import { ERC1967Proxy } from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import { IForkDAODeployer, INounsDAOForkEscrow, NounsDAOStorageV3 } from '../NounsDAOInterfaces.sol'; +import { IForkDAODeployer, INounsDAOForkEscrow, NounsDAOV3Types } from '../NounsDAOInterfaces.sol'; import { NounsTokenFork } from './newdao/token/NounsTokenFork.sol'; import { NounsAuctionHouseFork } from './newdao/NounsAuctionHouseFork.sol'; import { NounsDAOExecutorV2 } from '../NounsDAOExecutorV2.sol'; -import { NounsDAOProxy } from '../NounsDAOProxy.sol'; import { NounsDAOLogicV3 } from '../NounsDAOLogicV3.sol'; import { NounsDAOLogicV1Fork } from './newdao/governance/NounsDAOLogicV1Fork.sol'; import { NounsToken } from '../../NounsToken.sol'; @@ -89,10 +88,10 @@ contract ForkDAODeployer is IForkDAODeployer { * @return treasury The address of the fork DAO treasury * @return token The address of the fork DAO token */ - function deployForkDAO(uint256 forkingPeriodEndTimestamp, INounsDAOForkEscrow forkEscrow) - external - returns (address treasury, address token) - { + function deployForkDAO( + uint256 forkingPeriodEndTimestamp, + INounsDAOForkEscrow forkEscrow + ) external returns (address treasury, address token) { token = address(new ERC1967Proxy(tokenImpl, '')); address auction = address(new ERC1967Proxy(auctionImpl, '')); address governor = address(new ERC1967Proxy(governorImpl, '')); @@ -131,12 +130,7 @@ contract ForkDAODeployer is IForkDAODeployer { /** * @dev Used to prevent the 'Stack too deep' error in the main deploy function. */ - function initDAO( - address governor, - address treasury, - address token, - NounsDAOExecutorV2 originalTimelock - ) internal { + function initDAO(address governor, address treasury, address token, NounsDAOExecutorV2 originalTimelock) internal { NounsDAOLogicV3 originalDAO = NounsDAOLogicV3(payable(originalTimelock.admin())); NounsDAOLogicV1Fork(governor).initialize( treasury, diff --git a/packages/nouns-contracts/contracts/governance/fork/NounsDAOV3Fork.sol b/packages/nouns-contracts/contracts/governance/fork/NounsDAOV3Fork.sol index d87ffc701a..156bb47ca7 100644 --- a/packages/nouns-contracts/contracts/governance/fork/NounsDAOV3Fork.sol +++ b/packages/nouns-contracts/contracts/governance/fork/NounsDAOV3Fork.sol @@ -17,7 +17,7 @@ pragma solidity ^0.8.19; -import { NounsDAOStorageV3, INounsDAOForkEscrow, INounsDAOExecutorV2 } from '../NounsDAOInterfaces.sol'; +import { NounsDAOV3Types, INounsDAOForkEscrow, INounsDAOExecutorV2 } from '../NounsDAOInterfaces.sol'; import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import { NounsTokenFork } from './newdao/token/NounsTokenFork.sol'; @@ -72,7 +72,7 @@ library NounsDAOV3Fork { * @param reason the reason for want to fork. This will only be used to emit event. */ function escrowToFork( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256[] calldata tokenIds, uint256[] calldata proposalIds, string calldata reason @@ -92,7 +92,7 @@ library NounsDAOV3Fork { * Only allowed to withdraw tokens that the sender has escrowed. * @param tokenIds the tokenIds to withdraw */ - function withdrawFromForkEscrow(NounsDAOStorageV3.StorageV3 storage ds, uint256[] calldata tokenIds) external { + function withdrawFromForkEscrow(NounsDAOV3Types.StorageV3 storage ds, uint256[] calldata tokenIds) external { if (isForkPeriodActive(ds)) revert ForkPeriodActive(); INounsDAOForkEscrow forkEscrow = ds.forkEscrow; @@ -108,10 +108,9 @@ library NounsDAOV3Fork { * @return forkTreasury The address of the new DAO's treasury * @return forkToken The address of the new DAO's token */ - function executeFork(NounsDAOStorageV3.StorageV3 storage ds) - external - returns (address forkTreasury, address forkToken) - { + function executeFork( + NounsDAOV3Types.StorageV3 storage ds + ) external returns (address forkTreasury, address forkToken) { if (isForkPeriodActive(ds)) revert ForkPeriodActive(); INounsDAOForkEscrow forkEscrow = ds.forkEscrow; @@ -139,7 +138,7 @@ library NounsDAOV3Fork { * @param tokenIds the tokenIds to send to the DAO in exchange for joining the fork */ function joinFork( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256[] calldata tokenIds, uint256[] calldata proposalIds, string calldata reason @@ -164,9 +163,10 @@ library NounsDAOV3Fork { * @dev Only the DAO can call this function * @param tokenIds the tokenIds to withdraw */ - function withdrawDAONounsFromEscrowToTreasury(NounsDAOStorageV3.StorageV3 storage ds, uint256[] calldata tokenIds) - external - { + function withdrawDAONounsFromEscrowToTreasury( + NounsDAOV3Types.StorageV3 storage ds, + uint256[] calldata tokenIds + ) external { withdrawDAONounsFromEscrow(ds, tokenIds, address(ds.timelock)); } @@ -177,7 +177,7 @@ library NounsDAOV3Fork { * @param to the address to send the nouns to */ function withdrawDAONounsFromEscrowIncreasingTotalSupply( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256[] calldata tokenIds, address to ) external { @@ -189,7 +189,7 @@ library NounsDAOV3Fork { } function withdrawDAONounsFromEscrow( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, uint256[] calldata tokenIds, address to ) private { @@ -205,14 +205,14 @@ library NounsDAOV3Fork { /** * @notice Returns the required number of tokens to escrow to trigger a fork */ - function forkThreshold(NounsDAOStorageV3.StorageV3 storage ds) public view returns (uint256) { + function forkThreshold(NounsDAOV3Types.StorageV3 storage ds) public view returns (uint256) { return (adjustedTotalSupply(ds) * ds.forkThresholdBPS) / 10_000; } /** * @notice Returns the number of tokens currently in escrow, contributing to the fork threshold */ - function numTokensInForkEscrow(NounsDAOStorageV3.StorageV3 storage ds) public view returns (uint256) { + function numTokensInForkEscrow(NounsDAOV3Types.StorageV3 storage ds) public view returns (uint256) { return ds.forkEscrow.numTokensInEscrow(); } @@ -221,14 +221,14 @@ library NounsDAOV3Fork { * escrow after it has closed. * This is used when calculating proposal threshold, quorum, fork threshold & treasury split. */ - function adjustedTotalSupply(NounsDAOStorageV3.StorageV3 storage ds) internal view returns (uint256) { + function adjustedTotalSupply(NounsDAOV3Types.StorageV3 storage ds) internal view returns (uint256) { return ds.nouns.totalSupply() - ds.nouns.balanceOf(address(ds.timelock)) - ds.forkEscrow.numTokensOwnedByDAO(); } /** * @notice Returns true if noun holders can currently join a fork */ - function isForkPeriodActive(NounsDAOStorageV3.StorageV3 storage ds) internal view returns (bool) { + function isForkPeriodActive(NounsDAOV3Types.StorageV3 storage ds) internal view returns (bool) { return ds.forkEndTimestamp > block.timestamp; } @@ -238,7 +238,7 @@ library NounsDAOV3Fork { * Sends ETH and ERC20 tokens listed in `ds.erc20TokensToIncludeInFork`. */ function sendProRataTreasury( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOV3Types.StorageV3 storage ds, address newDAOTreasury, uint256 tokenCount, uint256 totalSupply diff --git a/packages/nouns-contracts/contracts/interfaces/INounsDAOLogicV3.sol b/packages/nouns-contracts/contracts/interfaces/INounsDAOLogicV3.sol index b34e655cac..1aeacecca0 100644 --- a/packages/nouns-contracts/contracts/interfaces/INounsDAOLogicV3.sol +++ b/packages/nouns-contracts/contracts/interfaces/INounsDAOLogicV3.sol @@ -71,7 +71,7 @@ interface INounsDAOLogicV3 { ) external returns (uint256); function proposeBySigs( - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures, address[] memory targets, uint256[] memory values, string[] memory signatures, @@ -93,7 +93,7 @@ interface INounsDAOLogicV3 { * @return uint256 Proposal id of new proposal */ function proposeBySigs( - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures, address[] memory targets, uint256[] memory values, string[] memory signatures, @@ -181,7 +181,7 @@ interface INounsDAOLogicV3 { */ function updateProposalBySigs( uint256 proposalId, - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures, address[] memory targets, uint256[] memory values, string[] memory signatures, @@ -214,7 +214,7 @@ interface INounsDAOLogicV3 { * @param proposalId The id of the proposal * @return Proposal state */ - function state(uint256 proposalId) external view returns (NounsDAOStorageV3.ProposalState); + function state(uint256 proposalId) external view returns (NounsDAOV3Types.ProposalState); /** * @notice Gets actions of a proposal @@ -242,7 +242,7 @@ interface INounsDAOLogicV3 { * @param voter The address of the voter * @return The voting receipt */ - function getReceipt(uint256 proposalId, address voter) external view returns (NounsDAOStorageV3.Receipt memory); + function getReceipt(uint256 proposalId, address voter) external view returns (NounsDAOV3Types.Receipt memory); /** * @notice Returns the proposal details given a proposal id. @@ -250,7 +250,7 @@ interface INounsDAOLogicV3 { * @param proposalId the proposal id to get the data for * @return A `ProposalCondensed` struct with the proposal data, backwards compatible with V1 and V2 */ - function proposals(uint256 proposalId) external view returns (NounsDAOStorageV2.ProposalCondensed memory); + function proposals(uint256 proposalId) external view returns (NounsDAOV3Types.ProposalCondensedV2 memory); /** * @notice Returns the proposal details given a proposal id. @@ -259,23 +259,23 @@ interface INounsDAOLogicV3 { * @return A `ProposalCondensed` struct with the proposal data, not backwards compatible as it contains additional values * like `objectionPeriodEndBlock` and `signers` */ - function proposalsV3(uint256 proposalId) external view returns (NounsDAOStorageV3.ProposalCondensed memory); + function proposalsV3(uint256 proposalId) external view returns (NounsDAOV3Types.ProposalCondensed memory); function proposalDataForRewards( uint256 proposalId - ) external view returns (NounsDAOStorageV3.ProposalForRewards memory); + ) external view returns (NounsDAOV3Types.ProposalForRewards memory); function proposalClientId(uint256 proposalId) external view returns (uint16); function proposalVoteClientsData( uint256 proposalId, uint32[] calldata clientIds - ) external view returns (NounsDAOStorageV3.ClientVoteData[] memory); + ) external view returns (NounsDAOV3Types.ClientVoteData[] memory); function proposalVoteClientData( uint256 proposalId, uint32 clientId - ) external view returns (NounsDAOStorageV3.ClientVoteData memory); + ) external view returns (NounsDAOV3Types.ClientVoteData memory); /** * @notice Current proposal threshold using Noun Total Supply @@ -484,7 +484,7 @@ interface INounsDAOLogicV3 { function dynamicQuorumVotes( uint256 againstVotes, uint256 adjustedTotalSupply_, - NounsDAOStorageV3.DynamicQuorumParams memory params + NounsDAOV3Types.DynamicQuorumParams memory params ) external pure returns (uint256); /** @@ -496,7 +496,7 @@ interface INounsDAOLogicV3 { */ function getDynamicQuorumParamsAt( uint256 blockNumber_ - ) external view returns (NounsDAOStorageV3.DynamicQuorumParams memory); + ) external view returns (NounsDAOV3Types.DynamicQuorumParams memory); /** * @notice Current min quorum votes using Nouns adjusted total supply @@ -511,14 +511,14 @@ interface INounsDAOLogicV3 { /** * @notice Get all quorum params checkpoints */ - function quorumParamsCheckpoints() external view returns (NounsDAOStorageV3.DynamicQuorumParamsCheckpoint[] memory); + function quorumParamsCheckpoints() external view returns (NounsDAOV3Types.DynamicQuorumParamsCheckpoint[] memory); /** * @notice Get a quorum params checkpoint by its index */ function quorumParamsCheckpoints( uint256 index - ) external view returns (NounsDAOStorageV3.DynamicQuorumParamsCheckpoint memory); + ) external view returns (NounsDAOV3Types.DynamicQuorumParamsCheckpoint memory); /** * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ @@ -663,6 +663,9 @@ interface INounsDAOLogicV3 { * STATE VARIABLE GETTERS * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ */ + + function implementation() external view returns (address); + function vetoer() external view returns (address); function pendingVetoer() external view returns (address); diff --git a/packages/nouns-contracts/contracts/test/MaliciousVoter.sol b/packages/nouns-contracts/contracts/test/MaliciousVoter.sol index 3e695b104c..0e30b66c46 100644 --- a/packages/nouns-contracts/contracts/test/MaliciousVoter.sol +++ b/packages/nouns-contracts/contracts/test/MaliciousVoter.sol @@ -2,20 +2,15 @@ pragma solidity ^0.8.19; -import { NounsDAOLogicV2 } from '../governance/NounsDAOLogicV2.sol'; +import { NounsDAOLogicV3 } from '../governance/NounsDAOLogicV3.sol'; contract MaliciousVoter { - NounsDAOLogicV2 public dao; + NounsDAOLogicV3 public dao; uint256 public proposalId; uint8 public support; bool useReason; - constructor( - NounsDAOLogicV2 dao_, - uint256 proposalId_, - uint8 support_, - bool useReason_ - ) { + constructor(NounsDAOLogicV3 dao_, uint256 proposalId_, uint8 support_, bool useReason_) { dao = dao_; proposalId = proposalId_; support = support_; diff --git a/packages/nouns-contracts/contracts/test/NounsDAOLogicV1Harness.sol b/packages/nouns-contracts/contracts/test/NounsDAOLogicV1Harness.sol deleted file mode 100644 index acc20c155f..0000000000 --- a/packages/nouns-contracts/contracts/test/NounsDAOLogicV1Harness.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import '../governance/NounsDAOLogicV1.sol'; - -contract NounsDAOLogicV1Harness is NounsDAOLogicV1 { - function initialize( - address timelock_, - address nouns_, - address vetoer_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - uint256 quorumVotesBPS_ - ) public override { - require(msg.sender == admin, 'NounsDAO::initialize: admin only'); - require(address(timelock) == address(0), 'NounsDAO::initialize: can only initialize once'); - - timelock = INounsDAOExecutor(timelock_); - nouns = NounsTokenLike(nouns_); - vetoer = vetoer_; - votingPeriod = votingPeriod_; - votingDelay = votingDelay_; - proposalThresholdBPS = proposalThresholdBPS_; - quorumVotesBPS = quorumVotesBPS_; - } -} diff --git a/packages/nouns-contracts/contracts/test/NounsDAOLogicV2Harness.sol b/packages/nouns-contracts/contracts/test/NounsDAOLogicV2Harness.sol deleted file mode 100644 index ade2b2d6e4..0000000000 --- a/packages/nouns-contracts/contracts/test/NounsDAOLogicV2Harness.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import '../governance/NounsDAOLogicV2.sol'; - -contract NounsDAOLogicV2Harness is NounsDAOLogicV2 { - function initialize( - address timelock_, - address nouns_, - address vetoer_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - DynamicQuorumParams calldata dynamicQuorumParams_ - ) public override { - require(msg.sender == admin, 'NounsDAO::initialize: admin only'); - require(address(timelock) == address(0), 'NounsDAO::initialize: can only initialize once'); - - timelock = INounsDAOExecutor(timelock_); - nouns = NounsTokenLike(nouns_); - vetoer = vetoer_; - votingPeriod = votingPeriod_; - votingDelay = votingDelay_; - proposalThresholdBPS = proposalThresholdBPS_; - _setDynamicQuorumParams( - dynamicQuorumParams_.minQuorumVotesBPS, - dynamicQuorumParams_.maxQuorumVotesBPS, - dynamicQuorumParams_.quorumCoefficient - ); - } -} diff --git a/packages/nouns-contracts/contracts/test/Voter.sol b/packages/nouns-contracts/contracts/test/Voter.sol index 991fc9c5a2..e1f2947c6d 100644 --- a/packages/nouns-contracts/contracts/test/Voter.sol +++ b/packages/nouns-contracts/contracts/test/Voter.sol @@ -2,23 +2,18 @@ pragma solidity ^0.8.19; -import { NounsDAOLogicV2 } from '../governance/NounsDAOLogicV2.sol'; +import { NounsDAOLogicV3 } from '../governance/NounsDAOLogicV3.sol'; /** * @dev this contract is used to simulate voting via a multisig */ contract Voter { - NounsDAOLogicV2 public dao; + NounsDAOLogicV3 public dao; uint256 public proposalId; uint8 public support; bool useReason; - constructor( - NounsDAOLogicV2 dao_, - uint256 proposalId_, - uint8 support_, - bool useReason_ - ) { + constructor(NounsDAOLogicV3 dao_, uint256 proposalId_, uint8 support_, bool useReason_) { dao = dao_; proposalId = proposalId_; support = support_; diff --git a/packages/nouns-contracts/src/index.ts b/packages/nouns-contracts/src/index.ts index 3b91b127a8..e1059dc1b2 100644 --- a/packages/nouns-contracts/src/index.ts +++ b/packages/nouns-contracts/src/index.ts @@ -2,8 +2,6 @@ export { default as NounsTokenABI } from '../abi/contracts/NounsToken.sol/NounsT export { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; export { default as NounsDescriptorABI } from '../abi/contracts/NounsDescriptor.sol/NounsDescriptor.json'; export { default as NounsSeederABI } from '../abi/contracts/NounsSeeder.sol/NounsSeeder.json'; -export { default as NounsDAOABI } from '../abi/contracts/governance/NounsDAOLogicV1.sol/NounsDAOLogicV1.json'; -export { default as NounsDAOV2ABI } from '../abi/contracts/governance/NounsDAOLogicV2.sol/NounsDAOLogicV2.json'; export { default as NounsDAOV3ABI } from '../abi/contracts/governance/NounsDAOLogicV3.sol/NounsDAOLogicV3.json'; export { default as NounsDAODataABI } from '../abi/contracts/governance/data/NounsDAOData.sol/NounsDAOData.json'; export { default as NounsDAOExecutorV2ABI } from '../abi/contracts/governance/NounsDAOExecutorV2.sol/NounsDAOExecutorV2.json'; @@ -11,8 +9,6 @@ export { NounsToken__factory as NounsTokenFactory } from '../typechain/factories export { NounsAuctionHouse__factory as NounsAuctionHouseFactory } from '../typechain/factories/contracts/NounsAuctionHouse__factory'; export { NounsDescriptor__factory as NounsDescriptorFactory } from '../typechain/factories/contracts/NounsDescriptor__factory'; export { NounsSeeder__factory as NounsSeederFactory } from '../typechain/factories/contracts/NounsSeeder__factory'; -export { NounsDAOLogicV1__factory as NounsDaoLogicV1Factory } from '../typechain/factories/contracts/governance/NounsDAOLogicV1__factory'; -export { NounsDAOLogicV2__factory as NounsDaoLogicV2Factory } from '../typechain/factories/contracts/governance/NounsDAOLogicV2__factory'; export { NounsDAOLogicV3__factory as NounsDaoLogicV3Factory } from '../typechain/factories/contracts/governance/NounsDAOLogicV3__factory'; export { NounsDAOData__factory as NounsDaoDataFactory } from '../typechain/factories/contracts/governance/data/NounsDAOData.sol/NounsDAOData__factory'; export { NounsDAOExecutorV2__factory as NounsDaoExecutorV2Factory } from '../typechain/factories/contracts/governance/NounsDAOExecutorV2__factory'; diff --git a/packages/nouns-contracts/tasks/create-proposal.ts b/packages/nouns-contracts/tasks/create-proposal.ts index 88239f4804..2bb1d71ce4 100644 --- a/packages/nouns-contracts/tasks/create-proposal.ts +++ b/packages/nouns-contracts/tasks/create-proposal.ts @@ -9,14 +9,14 @@ task('create-proposal', 'Create a governance proposal') types.string, ) .setAction(async ({ nounsDaoProxy }, { ethers }) => { - const nounsDaoFactory = await ethers.getContractFactory('NounsDAOLogicV1'); + const nounsDaoFactory = await ethers.getContractFactory('NounsDAOLogicV3'); const nounsDao = nounsDaoFactory.attach(nounsDaoProxy); const [deployer] = await ethers.getSigners(); const oneETH = utils.parseEther('1'); const receipt = await ( - await nounsDao.propose( + await nounsDao['propose(address[],uint256[],string[],bytes[],string)']( [deployer.address], [oneETH], [''], diff --git a/packages/nouns-contracts/tasks/deploy-and-configure-short-times-daov1.ts b/packages/nouns-contracts/tasks/deploy-and-configure-short-times-daov1.ts deleted file mode 100644 index 5c6d7154ec..0000000000 --- a/packages/nouns-contracts/tasks/deploy-and-configure-short-times-daov1.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { printContractsTable } from './utils'; - -task( - 'deploy-and-configure-short-times-daov1', - 'Deploy and configure all contracts with short gov times for testing', -) - .addFlag('startAuction', 'Start the first auction upon deployment completion') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addFlag('updateConfigs', 'Write the deployed addresses to the SDK and subgraph configs') - .addOptionalParam('weth', 'The WETH contract address') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 30 /* 30 seconds */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 2 /* 2 minutes */, - types.int, - ) - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 /* 1 min */, types.int) - .addOptionalParam( - 'votingPeriod', - 'The voting period (blocks)', - 80 /* 20 min (15s blocks) */, - types.int, - ) - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'quorumVotesBps', - 'Votes required for quorum (basis points)', - 1_000 /* 10% */, - types.int, - ) - .setAction(async (args, { run }) => { - // Deploy the Nouns DAO contracts and return deployment information - const contracts = await run('deploy-short-times-daov1', args); - - // Verify the contracts on Etherscan - await run('verify-etherscan', { - contracts, - }); - - // Populate the on-chain art - await run('populate-descriptor', { - nftDescriptor: contracts.NFTDescriptorV2.address, - nounsDescriptor: contracts.NounsDescriptorV2.address, - }); - - // Transfer ownership of all contract except for the auction house. - // We must maintain ownership of the auction house to kick off the first auction. - const executorAddress = contracts.NounsDAOExecutor.address; - await contracts.NounsDescriptorV2.instance.transferOwnership(executorAddress); - await contracts.NounsToken.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouseProxyAdmin.instance.transferOwnership(executorAddress); - console.log( - 'Transferred ownership of the descriptor, token, and proxy admin contracts to the executor.', - ); - - // Optionally kick off the first auction and transfer ownership of the auction house - // to the Nouns DAO executor. - if (args.startAuction) { - const auctionHouse = contracts.NounsAuctionHouse.instance.attach( - contracts.NounsAuctionHouseProxy.address, - ); - await auctionHouse.unpause({ - gasLimit: 1_000_000, - }); - await auctionHouse.transferOwnership(executorAddress); - console.log( - 'Started the first auction and transferred ownership of the auction house to the executor.', - ); - } - - // Optionally write the deployed addresses to the SDK and subgraph configs. - if (args.updateConfigs) { - await run('update-configs', { - contracts, - }); - } - - printContractsTable(contracts); - console.log('Deployment Complete.'); - }); diff --git a/packages/nouns-contracts/tasks/deploy-and-configure-short-times.ts b/packages/nouns-contracts/tasks/deploy-and-configure-short-times.ts deleted file mode 100644 index e731c51d9f..0000000000 --- a/packages/nouns-contracts/tasks/deploy-and-configure-short-times.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { printContractsTable } from './utils'; - -task( - 'deploy-and-configure-short-times', - 'Deploy and configure all contracts with short gov times for testing', -) - .addFlag('startAuction', 'Start the first auction upon deployment completion') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addFlag('updateConfigs', 'Write the deployed addresses to the SDK and subgraph configs') - .addOptionalParam('weth', 'The WETH contract address') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 30 /* 30 seconds */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 2 /* 2 minutes */, - types.int, - ) - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 /* 1 min */, types.int) - .addOptionalParam('votingPeriod', 'The voting period (blocks)', 25 /* 5 mins */, types.int) - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'minQuorumVotesBPS', - 'Min basis points input for dynamic quorum', - 1_000, - types.int, - ) // Default: 10% - .addOptionalParam( - 'maxQuorumVotesBPS', - 'Max basis points input for dynamic quorum', - 4_000, - types.int, - ) // Default: 40% - .addOptionalParam('quorumCoefficient', 'Dynamic quorum coefficient (float)', 1, types.float) - .setAction(async (args, { run }) => { - // Deploy the Nouns DAO contracts and return deployment information - const contracts = await run('deploy-short-times', args); - - // Verify the contracts on Etherscan - await run('verify-etherscan-daov2', { - contracts, - }); - - // Populate the on-chain art - await run('populate-descriptor', { - nftDescriptor: contracts.NFTDescriptorV2.address, - nounsDescriptor: contracts.NounsDescriptorV2.address, - }); - - // Transfer ownership of all contract except for the auction house. - // We must maintain ownership of the auction house to kick off the first auction. - const executorAddress = contracts.NounsDAOExecutor.address; - await contracts.NounsDescriptorV2.instance.transferOwnership(executorAddress); - await contracts.NounsToken.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouseProxyAdmin.instance.transferOwnership(executorAddress); - console.log( - 'Transferred ownership of the descriptor, token, and proxy admin contracts to the executor.', - ); - - // Optionally kick off the first auction and transfer ownership of the auction house - // to the Nouns DAO executor. - if (args.startAuction) { - const auctionHouse = contracts.NounsAuctionHouse.instance.attach( - contracts.NounsAuctionHouseProxy.address, - ); - await auctionHouse.unpause({ - gasLimit: 1_000_000, - }); - await auctionHouse.transferOwnership(executorAddress); - console.log( - 'Started the first auction and transferred ownership of the auction house to the executor.', - ); - } - - // Optionally write the deployed addresses to the SDK and subgraph configs. - if (args.updateConfigs) { - await run('update-configs-daov2', { - contracts, - }); - } - - printContractsTable(contracts); - console.log('Deployment Complete.'); - }); diff --git a/packages/nouns-contracts/tasks/deploy-and-configure.ts b/packages/nouns-contracts/tasks/deploy-and-configure.ts deleted file mode 100644 index a2b7f56d5f..0000000000 --- a/packages/nouns-contracts/tasks/deploy-and-configure.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { printContractsTable } from './utils'; - -task('deploy-and-configure', 'Deploy and configure all contracts') - .addFlag('startAuction', 'Start the first auction upon deployment completion') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addFlag('updateConfigs', 'Write the deployed addresses to the SDK and subgraph configs') - .addOptionalParam('weth', 'The WETH contract address') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 5 * 60 /* 5 minutes */, - types.int, - ) - .addOptionalParam('auctionReservePrice', 'The auction reserve price (wei)') - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - ) - .addOptionalParam('auctionDuration', 'The auction duration (seconds)') - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)') - .addOptionalParam('votingPeriod', 'The voting period (blocks)') - .addOptionalParam('votingDelay', 'The voting delay (blocks)') - .addOptionalParam('proposalThresholdBps', 'The proposal threshold (basis points)') - .addOptionalParam('quorumVotesBps', 'Votes required for quorum (basis points)') - .setAction(async (args, { run }) => { - // Deploy the Nouns DAO contracts and return deployment information - const contracts = await run('deploy', args); - - // Verify the contracts on Etherscan - await run('verify-etherscan', { - contracts, - }); - - // Populate the on-chain art - await run('populate-descriptor', { - nftDescriptor: contracts.NFTDescriptorV2.address, - nounsDescriptor: contracts.NounsDescriptorV2.address, - }); - - // Transfer ownership of all contract except for the auction house. - // We must maintain ownership of the auction house to kick off the first auction. - const executorAddress = contracts.NounsDAOExecutor.address; - await contracts.NounsDescriptorV2.instance.transferOwnership(executorAddress); - await contracts.NounsToken.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouseProxyAdmin.instance.transferOwnership(executorAddress); - console.log( - 'Transferred ownership of the descriptor, token, and proxy admin contracts to the executor.', - ); - - // Optionally kick off the first auction and transfer ownership of the auction house - // to the Nouns DAO executor. - if (args.startAuction) { - const auctionHouse = contracts.NounsAuctionHouse.instance.attach( - contracts.NounsAuctionHouseProxy.address, - ); - await auctionHouse.unpause({ - gasLimit: 1_000_000, - }); - await auctionHouse.transferOwnership(executorAddress); - console.log( - 'Started the first auction and transferred ownership of the auction house to the executor.', - ); - } - - // Optionally write the deployed addresses to the SDK and subgraph configs. - if (args.updateConfigs) { - await run('update-configs', { - contracts, - }); - } - - printContractsTable(contracts); - console.log('Deployment Complete.'); - }); diff --git a/packages/nouns-contracts/tasks/deploy-ci.ts b/packages/nouns-contracts/tasks/deploy-ci.ts deleted file mode 100644 index c0aeb83b7b..0000000000 --- a/packages/nouns-contracts/tasks/deploy-ci.ts +++ /dev/null @@ -1,37 +0,0 @@ -import fs from 'fs'; -import { task } from 'hardhat/config'; - -task('deploy-ci', 'Deploy contracts (automated by CI)') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam( - 'weth', - 'The WETH contract address', - '0xc778417e063141139fce010982780140aa0cd5ab', - ) - .setAction(async ({ noundersdao, weth }, { ethers, run }) => { - const [deployer] = await ethers.getSigners(); - const contracts = await run('deploy', { - weth, - noundersDAO: noundersdao || deployer.address, - }); - - if (!fs.existsSync('logs')) { - fs.mkdirSync('logs'); - } - fs.writeFileSync( - 'logs/deploy.json', - JSON.stringify({ - contractAddresses: { - NFTDescriptor: contracts.NFTDescriptor.address, - NounsDescriptor: contracts.NounsDescriptor.address, - NounsSeeder: contracts.NounsSeeder.address, - NounsToken: contracts.NounsToken.address, - }, - gitHub: { - // Get the commit sha when running in CI - sha: process.env.GITHUB_SHA, - }, - }), - { flag: 'w' }, - ); - }); diff --git a/packages/nouns-contracts/tasks/deploy-descriptor-v2.ts b/packages/nouns-contracts/tasks/deploy-descriptor-v2.ts index 953cd5d7c1..b93bfb2313 100644 --- a/packages/nouns-contracts/tasks/deploy-descriptor-v2.ts +++ b/packages/nouns-contracts/tasks/deploy-descriptor-v2.ts @@ -1,5 +1,5 @@ import { task } from 'hardhat/config'; -import { ContractName, DeployedContract } from './types'; +import { ContractNamesDAOV3, DeployedContract } from './types'; import { printContractsTable } from './utils'; async function delay(seconds: number) { @@ -12,8 +12,8 @@ task('deploy-descriptor-v2', 'Deploy NounsDescriptorV2 & populate it with art') 'The address of the NounsDAOExecutor that should be the owner of the descriptor.', ) .setAction(async ({ daoExecutor }, { ethers, run, network }) => { - const contracts: Record = {} as Record< - ContractName, + const contracts: Record = {} as Record< + ContractNamesDAOV3, DeployedContract >; const [deployer] = await ethers.getSigners(); diff --git a/packages/nouns-contracts/tasks/deploy-local-dao-v3.ts b/packages/nouns-contracts/tasks/deploy-local-dao-v3.ts index 588c8e4d67..6b2741a279 100644 --- a/packages/nouns-contracts/tasks/deploy-local-dao-v3.ts +++ b/packages/nouns-contracts/tasks/deploy-local-dao-v3.ts @@ -4,31 +4,9 @@ import { default as NounsDAOExecutorV2ABI } from '../abi/contracts/governance/No import { task, types } from 'hardhat/config'; import { Interface, parseUnits } from 'ethers/lib/utils'; import { Contract as EthersContract } from 'ethers'; -import { ContractName } from './types'; +import { ContractNamesDAOV3 } from './types'; -type LocalContractName = - | Exclude< - ContractName, - 'NounsDAOLogicV1' | 'NounsDAOProxy' | 'NounsDAOLogicV2' | 'NounsDAOExecutor' - > - | 'NounsDAOLogicV3' - | 'NounsDAOProxyV3' - | 'NounsDAOV3Admin' - | 'NounsDAOV3DynamicQuorum' - | 'NounsDAOV3Proposals' - | 'NounsDAOV3Votes' - | 'NounsDAOV3Fork' - | 'NounsDAOForkEscrow' - | 'ForkDAODeployer' - | 'NounsTokenFork' - | 'NounsAuctionHouseFork' - | 'NounsDAOLogicV1Fork' - | 'NounsDAOExecutorV2' - | 'NounsDAOExecutorProxy' - | 'WETH' - | 'Multicall2' - | 'NounsDAOData' - | 'NounsDAODataProxy'; +type LocalContractName = ContractNamesDAOV3 | 'WETH' | 'Multicall2'; interface Contract { args?: (string | number | (() => string | undefined))[]; diff --git a/packages/nouns-contracts/tasks/deploy-local.ts b/packages/nouns-contracts/tasks/deploy-local.ts deleted file mode 100644 index e5d0192d11..0000000000 --- a/packages/nouns-contracts/tasks/deploy-local.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; -import { task, types } from 'hardhat/config'; -import { Interface, parseUnits } from 'ethers/lib/utils'; -import { Contract as EthersContract } from 'ethers'; -import { ContractName } from './types'; - -type LocalContractName = - | Exclude - | 'NounsDAOLogicV2' - | 'NounsDAOProxyV2' - | 'WETH' - | 'Multicall2'; - -interface Contract { - args?: (string | number | (() => string | undefined))[]; - instance?: EthersContract; - libraries?: () => Record; - waitForConfirmation?: boolean; -} - -task('deploy-local', 'Deploy contracts to hardhat') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam('auctionTimeBuffer', 'The auction time buffer (seconds)', 30, types.int) // Default: 30 seconds - .addOptionalParam('auctionReservePrice', 'The auction reserve price (wei)', 1, types.int) // Default: 1 wei - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', // Default: 5% - 5, - types.int, - ) - .addOptionalParam('auctionDuration', 'The auction duration (seconds)', 60 * 2, types.int) // Default: 2 minutes - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 * 60 * 24 * 2, types.int) // Default: 2 days - .addOptionalParam('votingPeriod', 'The voting period (blocks)', 4 * 60 * 24 * 3, types.int) // Default: 3 days - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) // Default: 1 block - .addOptionalParam('proposalThresholdBps', 'The proposal threshold (basis points)', 500, types.int) // Default: 5% - .addOptionalParam( - 'minQuorumVotesBPS', - 'Min basis points input for dynamic quorum', - 1_000, - types.int, - ) // Default: 10% - .addOptionalParam( - 'maxQuorumVotesBPS', - 'Max basis points input for dynamic quorum', - 4_000, - types.int, - ) // Default: 40% - .addOptionalParam('quorumCoefficient', 'Dynamic quorum coefficient (float)', 1, types.float) - .setAction(async (args, { ethers }) => { - const network = await ethers.provider.getNetwork(); - if (network.chainId !== 31337) { - console.log(`Invalid chain id. Expected 31337. Got: ${network.chainId}.`); - return; - } - - const proxyRegistryAddress = '0xa5409ec958c83c3f309868babaca7c86dcb077c1'; - - const NOUNS_ART_NONCE_OFFSET = 5; - const AUCTION_HOUSE_PROXY_NONCE_OFFSET = 10; - const GOVERNOR_N_DELEGATOR_NONCE_OFFSET = 13; - - const [deployer] = await ethers.getSigners(); - const nonce = await deployer.getTransactionCount(); - const expectedNounsArtAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + NOUNS_ART_NONCE_OFFSET, - }); - const expectedNounsDAOProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + GOVERNOR_N_DELEGATOR_NONCE_OFFSET, - }); - const expectedAuctionHouseProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + AUCTION_HOUSE_PROXY_NONCE_OFFSET, - }); - const contracts: Record = { - WETH: {}, - NFTDescriptorV2: {}, - SVGRenderer: {}, - NounsDescriptorV2: { - args: [expectedNounsArtAddress, () => contracts.SVGRenderer.instance?.address], - libraries: () => ({ - NFTDescriptorV2: contracts.NFTDescriptorV2.instance?.address as string, - }), - }, - Inflator: {}, - NounsArt: { - args: [ - () => contracts.NounsDescriptorV2.instance?.address, - () => contracts.Inflator.instance?.address, - ], - }, - NounsSeeder: {}, - NounsToken: { - args: [ - args.noundersdao || deployer.address, - expectedAuctionHouseProxyAddress, - () => contracts.NounsDescriptorV2.instance?.address, - () => contracts.NounsSeeder.instance?.address, - proxyRegistryAddress, - ], - }, - NounsAuctionHouse: { - waitForConfirmation: true, - }, - NounsAuctionHouseProxyAdmin: {}, - NounsAuctionHouseProxy: { - args: [ - () => contracts.NounsAuctionHouse.instance?.address, - () => contracts.NounsAuctionHouseProxyAdmin.instance?.address, - () => - new Interface(NounsAuctionHouseABI).encodeFunctionData('initialize', [ - contracts.NounsToken.instance?.address, - contracts.WETH.instance?.address, - args.auctionTimeBuffer, - args.auctionReservePrice, - args.auctionMinIncrementBidPercentage, - args.auctionDuration, - ]), - ], - }, - NounsDAOExecutor: { - args: [expectedNounsDAOProxyAddress, args.timelockDelay], - }, - NounsDAOLogicV2: { - waitForConfirmation: true, - }, - NounsDAOProxyV2: { - args: [ - () => contracts.NounsDAOExecutor.instance?.address, - () => contracts.NounsToken.instance?.address, - args.noundersdao || deployer.address, - () => contracts.NounsDAOExecutor.instance?.address, - () => contracts.NounsDAOLogicV2.instance?.address, - args.votingPeriod, - args.votingDelay, - args.proposalThresholdBps, - { - minQuorumVotesBPS: args.minQuorumVotesBPS, - maxQuorumVotesBPS: args.maxQuorumVotesBPS, - quorumCoefficient: parseUnits(args.quorumCoefficient.toString(), 6), - }, - ], - waitForConfirmation: true, - }, - Multicall2: {}, - }; - - for (const [name, contract] of Object.entries(contracts)) { - const factory = await ethers.getContractFactory(name, { - libraries: contract?.libraries?.(), - }); - - const deployedContract = await factory.deploy( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - ); - - if (contract.waitForConfirmation) { - await deployedContract.deployed(); - } - - contracts[name as LocalContractName].instance = deployedContract; - - console.log(`${name} contract deployed to ${deployedContract.address}`); - } - - return contracts; - }); diff --git a/packages/nouns-contracts/tasks/deploy-short-times-daov1.ts b/packages/nouns-contracts/tasks/deploy-short-times-daov1.ts deleted file mode 100644 index 9bde8df632..0000000000 --- a/packages/nouns-contracts/tasks/deploy-short-times-daov1.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; -import { ChainId, ContractDeployment, ContractName, DeployedContract } from './types'; -import { Interface } from 'ethers/lib/utils'; -import { task, types } from 'hardhat/config'; -import { constants } from 'ethers'; -import promptjs from 'prompt'; - -promptjs.colors = false; -promptjs.message = '> '; -promptjs.delimiter = ''; - -const proxyRegistries: Record = { - [ChainId.Mainnet]: '0xa5409ec958c83c3f309868babaca7c86dcb077c1', -}; -const wethContracts: Record = { - [ChainId.Mainnet]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - [ChainId.Ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', - [ChainId.Kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', - [ChainId.Goerli]: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', -}; - -const NOUNS_ART_NONCE_OFFSET = 4; -const AUCTION_HOUSE_PROXY_NONCE_OFFSET = 9; -const GOVERNOR_N_DELEGATOR_NONCE_OFFSET = 12; - -task('deploy-short-times-daov1', 'Deploy all Nouns contracts with short gov times for testing') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addOptionalParam('weth', 'The WETH contract address', undefined, types.string) - .addOptionalParam('noundersdao', 'The nounders DAO contract address', undefined, types.string) - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 30 /* 30 seconds */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 2 /* 2 minutes */, - types.int, - ) - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 /* 1 min */, types.int) - .addOptionalParam( - 'votingPeriod', - 'The voting period (blocks)', - 80 /* 20 min (15s blocks) */, - types.int, - ) - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'quorumVotesBps', - 'Votes required for quorum (basis points)', - 1_000 /* 10% */, - types.int, - ) - .setAction(async (args, { ethers }) => { - const network = await ethers.provider.getNetwork(); - const [deployer] = await ethers.getSigners(); - - // prettier-ignore - const proxyRegistryAddress = proxyRegistries[network.chainId] ?? constants.AddressZero; - - if (!args.noundersdao) { - console.log( - `Nounders DAO address not provided. Setting to deployer (${deployer.address})...`, - ); - args.noundersdao = deployer.address; - } - if (!args.weth) { - const deployedWETHContract = wethContracts[network.chainId]; - if (!deployedWETHContract) { - throw new Error( - `Can not auto-detect WETH contract on chain ${network.name}. Provide it with the --weth arg.`, - ); - } - args.weth = deployedWETHContract; - } - - const nonce = await deployer.getTransactionCount(); - const expectedNounsArtAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + NOUNS_ART_NONCE_OFFSET, - }); - const expectedAuctionHouseProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + AUCTION_HOUSE_PROXY_NONCE_OFFSET, - }); - const expectedNounsDAOProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + GOVERNOR_N_DELEGATOR_NONCE_OFFSET, - }); - const deployment: Record = {} as Record< - ContractName, - DeployedContract - >; - const contracts: Record = { - NFTDescriptorV2: {}, - SVGRenderer: {}, - NounsDescriptorV2: { - args: [expectedNounsArtAddress, () => deployment.SVGRenderer.address], - libraries: () => ({ - NFTDescriptorV2: deployment.NFTDescriptorV2.address, - }), - }, - Inflator: {}, - NounsArt: { - args: [() => deployment.NounsDescriptorV2.address, () => deployment.Inflator.address], - }, - NounsSeeder: {}, - NounsToken: { - args: [ - args.noundersdao, - expectedAuctionHouseProxyAddress, - () => deployment.NounsDescriptorV2.address, - () => deployment.NounsSeeder.address, - proxyRegistryAddress, - ], - }, - NounsAuctionHouse: { - waitForConfirmation: true, - }, - NounsAuctionHouseProxyAdmin: {}, - NounsAuctionHouseProxy: { - args: [ - () => deployment.NounsAuctionHouse.address, - () => deployment.NounsAuctionHouseProxyAdmin.address, - () => - new Interface(NounsAuctionHouseABI).encodeFunctionData('initialize', [ - deployment.NounsToken.address, - args.weth, - args.auctionTimeBuffer, - args.auctionReservePrice, - args.auctionMinIncrementBidPercentage, - args.auctionDuration, - ]), - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedAuctionHouseProxyAddress.toLowerCase(); - const actual = deployment.NounsAuctionHouseProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected auction house proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - NounsDAOExecutor: { - args: [expectedNounsDAOProxyAddress, args.timelockDelay], - }, - NounsDAOLogicV1: { - waitForConfirmation: true, - }, - NounsDAOProxy: { - args: [ - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsToken.address, - args.noundersdao, - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsDAOLogicV1.address, - args.votingPeriod, - args.votingDelay, - args.proposalThresholdBps, - args.quorumVotesBps, - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedNounsDAOProxyAddress.toLowerCase(); - const actual = deployment.NounsDAOProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected Nouns DAO proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - }; - - for (const [name, contract] of Object.entries(contracts)) { - let gasPrice = await ethers.provider.getGasPrice(); - if (!args.autoDeploy) { - const gasInGwei = Math.round(Number(ethers.utils.formatUnits(gasPrice, 'gwei'))); - - promptjs.start(); - - const result = await promptjs.get([ - { - properties: { - gasPrice: { - type: 'integer', - required: true, - description: 'Enter a gas price (gwei)', - default: gasInGwei, - }, - }, - }, - ]); - gasPrice = ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); - } - - let nameForFactory: string; - switch (name) { - case 'NounsDAOExecutor': - nameForFactory = 'NounsDAOExecutorTest'; - break; - case 'NounsDAOLogicV1': - nameForFactory = 'NounsDAOLogicV1Harness'; - break; - default: - nameForFactory = name; - break; - } - - const factory = await ethers.getContractFactory(nameForFactory, { - libraries: contract?.libraries?.(), - }); - - const deploymentGas = await factory.signer.estimateGas( - factory.getDeployTransaction( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ), - ); - const deploymentCost = deploymentGas.mul(gasPrice); - - console.log( - `Estimated cost to deploy ${name}: ${ethers.utils.formatUnits( - deploymentCost, - 'ether', - )} ETH`, - ); - - if (!args.autoDeploy) { - const result = await promptjs.get([ - { - properties: { - confirm: { - pattern: /^(DEPLOY|SKIP|EXIT)$/, - description: - 'Type "DEPLOY" to confirm, "SKIP" to skip this contract, or "EXIT" to exit.', - }, - }, - }, - ]); - if (result.operation === 'SKIP') { - console.log(`Skipping ${name} deployment...`); - continue; - } - if (result.operation === 'EXIT') { - console.log('Exiting...'); - return; - } - } - console.log(`Deploying ${name}...`); - - const deployedContract = await factory.deploy( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ); - - if (contract.waitForConfirmation) { - await deployedContract.deployed(); - } - - deployment[name as ContractName] = { - name: nameForFactory, - instance: deployedContract, - address: deployedContract.address, - constructorArguments: contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? [], - libraries: contract?.libraries?.() ?? {}, - }; - - contract.validateDeployment?.(); - - console.log(`${name} contract deployed to ${deployedContract.address}`); - } - - return deployment; - }); diff --git a/packages/nouns-contracts/tasks/deploy-short-times.ts b/packages/nouns-contracts/tasks/deploy-short-times.ts deleted file mode 100644 index 610baa3ebe..0000000000 --- a/packages/nouns-contracts/tasks/deploy-short-times.ts +++ /dev/null @@ -1,315 +0,0 @@ -import { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; -import { ChainId, ContractDeployment, ContractNamesDAOV2, DeployedContract } from './types'; -import { Interface, parseUnits } from 'ethers/lib/utils'; -import { task, types } from 'hardhat/config'; -import { constants } from 'ethers'; -import promptjs from 'prompt'; - -promptjs.colors = false; -promptjs.message = '> '; -promptjs.delimiter = ''; - -const proxyRegistries: Record = { - [ChainId.Mainnet]: '0xa5409ec958c83c3f309868babaca7c86dcb077c1', - [ChainId.Goerli]: '0x5d44754DE92363d5746485F31280E4c0c54c855c', // ProxyRegistryMock - [ChainId.Sepolia]: '0x152E981d511F8c0865354A71E1cb84d0FB318470', // ProxyRegistryMock -}; -const wethContracts: Record = { - [ChainId.Mainnet]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - [ChainId.Ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', - [ChainId.Kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', - [ChainId.Goerli]: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', - [ChainId.Sepolia]: '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14', -}; - -const NOUNS_ART_NONCE_OFFSET = 4; -const AUCTION_HOUSE_PROXY_NONCE_OFFSET = 9; -const GOVERNOR_N_DELEGATOR_NONCE_OFFSET = 12; - -task('deploy-short-times', 'Deploy all Nouns contracts with short gov times for testing') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addOptionalParam('weth', 'The WETH contract address', undefined, types.string) - .addOptionalParam('noundersdao', 'The nounders DAO contract address', undefined, types.string) - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 30 /* 30 seconds */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 2 /* 2 minutes */, - types.int, - ) - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 /* 1 min */, types.int) - .addOptionalParam( - 'votingPeriod', - 'The voting period (blocks)', - 80 /* 20 min (15s blocks) */, - types.int, - ) - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'minQuorumVotesBPS', - 'Min basis points input for dynamic quorum', - 1_000, - types.int, - ) // Default: 10% - .addOptionalParam( - 'maxQuorumVotesBPS', - 'Max basis points input for dynamic quorum', - 4_000, - types.int, - ) // Default: 40% - .addOptionalParam('quorumCoefficient', 'Dynamic quorum coefficient (float)', 1, types.float) - .setAction(async (args, { ethers }) => { - const network = await ethers.provider.getNetwork(); - const [deployer] = await ethers.getSigners(); - - // prettier-ignore - const proxyRegistryAddress = proxyRegistries[network.chainId] ?? constants.AddressZero; - - if (!args.noundersdao) { - console.log( - `Nounders DAO address not provided. Setting to deployer (${deployer.address})...`, - ); - args.noundersdao = deployer.address; - } - if (!args.weth) { - const deployedWETHContract = wethContracts[network.chainId]; - if (!deployedWETHContract) { - throw new Error( - `Can not auto-detect WETH contract on chain ${network.name}. Provide it with the --weth arg.`, - ); - } - args.weth = deployedWETHContract; - } - - const nonce = await deployer.getTransactionCount(); - const expectedNounsArtAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + NOUNS_ART_NONCE_OFFSET, - }); - const expectedAuctionHouseProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + AUCTION_HOUSE_PROXY_NONCE_OFFSET, - }); - const expectedNounsDAOProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + GOVERNOR_N_DELEGATOR_NONCE_OFFSET, - }); - const deployment: Record = {} as Record< - ContractNamesDAOV2, - DeployedContract - >; - const contracts: Record = { - NFTDescriptorV2: {}, - SVGRenderer: {}, - NounsDescriptorV2: { - args: [expectedNounsArtAddress, () => deployment.SVGRenderer.address], - libraries: () => ({ - NFTDescriptorV2: deployment.NFTDescriptorV2.address, - }), - }, - Inflator: {}, - NounsArt: { - args: [() => deployment.NounsDescriptorV2.address, () => deployment.Inflator.address], - }, - NounsSeeder: {}, - NounsToken: { - args: [ - args.noundersdao, - expectedAuctionHouseProxyAddress, - () => deployment.NounsDescriptorV2.address, - () => deployment.NounsSeeder.address, - proxyRegistryAddress, - ], - }, - NounsAuctionHouse: { - waitForConfirmation: true, - }, - NounsAuctionHouseProxyAdmin: {}, - NounsAuctionHouseProxy: { - args: [ - () => deployment.NounsAuctionHouse.address, - () => deployment.NounsAuctionHouseProxyAdmin.address, - () => - new Interface(NounsAuctionHouseABI).encodeFunctionData('initialize', [ - deployment.NounsToken.address, - args.weth, - args.auctionTimeBuffer, - args.auctionReservePrice, - args.auctionMinIncrementBidPercentage, - args.auctionDuration, - ]), - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedAuctionHouseProxyAddress.toLowerCase(); - const actual = deployment.NounsAuctionHouseProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected auction house proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - NounsDAOExecutor: { - args: [expectedNounsDAOProxyAddress, args.timelockDelay], - }, - NounsDAOLogicV2: { - waitForConfirmation: true, - }, - NounsDAOProxyV2: { - args: [ - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsToken.address, - args.noundersdao, - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsDAOLogicV2.address, - args.votingPeriod, - args.votingDelay, - args.proposalThresholdBps, - { - minQuorumVotesBPS: args.minQuorumVotesBPS, - maxQuorumVotesBPS: args.maxQuorumVotesBPS, - quorumCoefficient: parseUnits(args.quorumCoefficient.toString(), 6), - }, - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedNounsDAOProxyAddress.toLowerCase(); - const actual = deployment.NounsDAOProxyV2.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected Nouns DAO proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - }; - - for (const [name, contract] of Object.entries(contracts)) { - let gasPrice = await ethers.provider.getGasPrice(); - if (!args.autoDeploy) { - const gasInGwei = Math.round(Number(ethers.utils.formatUnits(gasPrice, 'gwei'))); - - promptjs.start(); - - const result = await promptjs.get([ - { - properties: { - gasPrice: { - type: 'integer', - required: true, - description: 'Enter a gas price (gwei)', - default: gasInGwei, - }, - }, - }, - ]); - gasPrice = ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); - } - - let nameForFactory: string; - switch (name) { - case 'NounsDAOExecutor': - nameForFactory = 'NounsDAOExecutorTest'; - break; - case 'NounsDAOLogicV2': - nameForFactory = 'NounsDAOLogicV2Harness'; - break; - default: - nameForFactory = name; - break; - } - - const factory = await ethers.getContractFactory(nameForFactory, { - libraries: contract?.libraries?.(), - }); - - const deploymentGas = await factory.signer.estimateGas( - factory.getDeployTransaction( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ), - ); - const deploymentCost = deploymentGas.mul(gasPrice); - - console.log( - `Estimated cost to deploy ${name}: ${ethers.utils.formatUnits( - deploymentCost, - 'ether', - )} ETH`, - ); - - if (!args.autoDeploy) { - const result = await promptjs.get([ - { - properties: { - confirm: { - pattern: /^(DEPLOY|SKIP|EXIT)$/, - description: - 'Type "DEPLOY" to confirm, "SKIP" to skip this contract, or "EXIT" to exit.', - }, - }, - }, - ]); - if (result.operation === 'SKIP') { - console.log(`Skipping ${name} deployment...`); - continue; - } - if (result.operation === 'EXIT') { - console.log('Exiting...'); - return; - } - } - console.log(`Deploying ${name}...`); - - const deployedContract = await factory.deploy( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ); - - if (contract.waitForConfirmation) { - await deployedContract.deployed(); - } - - deployment[name as ContractNamesDAOV2] = { - name: nameForFactory, - instance: deployedContract, - address: deployedContract.address, - constructorArguments: contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? [], - libraries: contract?.libraries?.() ?? {}, - }; - - contract.validateDeployment?.(); - - console.log(`${name} contract deployed to ${deployedContract.address}`); - } - - return deployment; - }); diff --git a/packages/nouns-contracts/tasks/deploy-test-token.ts b/packages/nouns-contracts/tasks/deploy-test-token.ts index 696818d119..917f376396 100644 --- a/packages/nouns-contracts/tasks/deploy-test-token.ts +++ b/packages/nouns-contracts/tasks/deploy-test-token.ts @@ -1,5 +1,5 @@ import { task } from 'hardhat/config'; -import { ContractName, DeployedContract } from './types'; +import { DeployedContract } from './types'; async function delay(seconds: number) { return new Promise(resolve => setTimeout(resolve, 1000 * seconds)); diff --git a/packages/nouns-contracts/tasks/deploy-v2-logic.ts b/packages/nouns-contracts/tasks/deploy-v2-logic.ts deleted file mode 100644 index 1d52ac6e84..0000000000 --- a/packages/nouns-contracts/tasks/deploy-v2-logic.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { task } from 'hardhat/config'; -import promptjs from 'prompt'; -import { - getDeploymentConfirmationWithPrompt, - getGasPriceWithPrompt, - printEstimatedCost, -} from './utils'; - -promptjs.colors = false; -promptjs.message = '> '; -promptjs.delimiter = ''; - -task('deploy-v2-logic', 'Deploys NounsDAOLogicV2').setAction(async (_args, { ethers, run }) => { - const factory = await ethers.getContractFactory('NounsDAOLogicV2'); - const signer = (await ethers.getSigners())[0]; - - const gasPrice = await getGasPriceWithPrompt(ethers); - await printEstimatedCost(factory, gasPrice); - - const deployConfirmed = await getDeploymentConfirmationWithPrompt(); - if (!deployConfirmed) { - console.log('Exiting'); - return; - } - - console.log('Deploying...'); - const contract = await factory.deploy({ gasPrice }); - await contract.deployed(); - console.log(`Transaction hash: ${contract.deployTransaction.hash} \n`); - console.log(`NounsDAOLogicV2 deployed to ${contract.address}`); - - await new Promise(f => setTimeout(f, 60000)); - - console.log('Verifying on Etherscan...'); - await run('verify:verify', { - address: contract.address, - constructorArguments: [], - }); - console.log('Verified'); -}); diff --git a/packages/nouns-contracts/tasks/deploy.ts b/packages/nouns-contracts/tasks/deploy.ts deleted file mode 100644 index f76de429db..0000000000 --- a/packages/nouns-contracts/tasks/deploy.ts +++ /dev/null @@ -1,298 +0,0 @@ -import { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; -import { ChainId, ContractDeployment, ContractName, DeployedContract } from './types'; -import { Interface } from 'ethers/lib/utils'; -import { task, types } from 'hardhat/config'; -import { constants } from 'ethers'; -import promptjs from 'prompt'; - -promptjs.colors = false; -promptjs.message = '> '; -promptjs.delimiter = ''; - -const proxyRegistries: Record = { - [ChainId.Mainnet]: '0xa5409ec958c83c3f309868babaca7c86dcb077c1', -}; -const wethContracts: Record = { - [ChainId.Mainnet]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - [ChainId.Ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', - [ChainId.Kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', - [ChainId.Goerli]: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', -}; - -const NOUNS_ART_NONCE_OFFSET = 4; -const AUCTION_HOUSE_PROXY_NONCE_OFFSET = 9; -const GOVERNOR_N_DELEGATOR_NONCE_OFFSET = 12; - -task('deploy', 'Deploys NFTDescriptor, NounsDescriptor, NounsSeeder, and NounsToken') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addOptionalParam('weth', 'The WETH contract address', undefined, types.string) - .addOptionalParam('noundersdao', 'The nounders DAO contract address', undefined, types.string) - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 5 * 60 /* 5 minutes */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 60 * 24 /* 24 hours */, - types.int, - ) - .addOptionalParam( - 'timelockDelay', - 'The timelock delay (seconds)', - 60 * 60 * 24 * 2 /* 2 days */, - types.int, - ) - .addOptionalParam( - 'votingPeriod', - 'The voting period (blocks)', - Math.round(4 * 60 * 24 * (60 / 13)) /* 4 days (13s blocks) */, - types.int, - ) - .addOptionalParam( - 'votingDelay', - 'The voting delay (blocks)', - Math.round(3 * 60 * 24 * (60 / 13)) /* 3 days (13s blocks) */, - types.int, - ) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'quorumVotesBps', - 'Votes required for quorum (basis points)', - 1_000 /* 10% */, - types.int, - ) - .setAction(async (args, { ethers }) => { - const network = await ethers.provider.getNetwork(); - const [deployer] = await ethers.getSigners(); - - // prettier-ignore - const proxyRegistryAddress = proxyRegistries[network.chainId] ?? constants.AddressZero - - if (!args.noundersdao) { - console.log( - `Nounders DAO address not provided. Setting to deployer (${deployer.address})...`, - ); - args.noundersdao = deployer.address; - } - if (!args.weth) { - const deployedWETHContract = wethContracts[network.chainId]; - if (!deployedWETHContract) { - throw new Error( - `Can not auto-detect WETH contract on chain ${network.name}. Provide it with the --weth arg.`, - ); - } - args.weth = deployedWETHContract; - } - - const nonce = await deployer.getTransactionCount(); - const expectedNounsArtAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + NOUNS_ART_NONCE_OFFSET, - }); - const expectedAuctionHouseProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + AUCTION_HOUSE_PROXY_NONCE_OFFSET, - }); - const expectedNounsDAOProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + GOVERNOR_N_DELEGATOR_NONCE_OFFSET, - }); - const deployment: Record = {} as Record< - ContractName, - DeployedContract - >; - const contracts: Record = { - NFTDescriptorV2: {}, - SVGRenderer: {}, - NounsDescriptorV2: { - args: [expectedNounsArtAddress, () => deployment.SVGRenderer.address], - libraries: () => ({ - NFTDescriptorV2: deployment.NFTDescriptorV2.address, - }), - }, - Inflator: {}, - NounsArt: { - args: [() => deployment.NounsDescriptorV2.address, () => deployment.Inflator.address], - }, - NounsSeeder: {}, - NounsToken: { - args: [ - args.noundersdao, - expectedAuctionHouseProxyAddress, - () => deployment.NounsDescriptorV2.address, - () => deployment.NounsSeeder.address, - proxyRegistryAddress, - ], - }, - NounsAuctionHouse: { - waitForConfirmation: true, - }, - NounsAuctionHouseProxyAdmin: {}, - NounsAuctionHouseProxy: { - args: [ - () => deployment.NounsAuctionHouse.address, - () => deployment.NounsAuctionHouseProxyAdmin.address, - () => - new Interface(NounsAuctionHouseABI).encodeFunctionData('initialize', [ - deployment.NounsToken.address, - args.weth, - args.auctionTimeBuffer, - args.auctionReservePrice, - args.auctionMinIncrementBidPercentage, - args.auctionDuration, - ]), - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedAuctionHouseProxyAddress.toLowerCase(); - const actual = deployment.NounsAuctionHouseProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected auction house proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - NounsDAOExecutor: { - args: [expectedNounsDAOProxyAddress, args.timelockDelay], - }, - NounsDAOLogicV1: { - waitForConfirmation: true, - }, - NounsDAOProxy: { - args: [ - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsToken.address, - args.noundersdao, - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsDAOLogicV1.address, - args.votingPeriod, - args.votingDelay, - args.proposalThresholdBps, - args.quorumVotesBps, - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedNounsDAOProxyAddress.toLowerCase(); - const actual = deployment.NounsDAOProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected Nouns DAO proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - }; - - for (const [name, contract] of Object.entries(contracts)) { - let gasPrice = await ethers.provider.getGasPrice(); - if (!args.autoDeploy) { - const gasInGwei = Math.round(Number(ethers.utils.formatUnits(gasPrice, 'gwei'))); - - promptjs.start(); - - const result = await promptjs.get([ - { - properties: { - gasPrice: { - type: 'integer', - required: true, - description: 'Enter a gas price (gwei)', - default: gasInGwei, - }, - }, - }, - ]); - gasPrice = ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); - } - - const factory = await ethers.getContractFactory(name, { - libraries: contract?.libraries?.(), - }); - - const deploymentGas = await factory.signer.estimateGas( - factory.getDeployTransaction( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ), - ); - const deploymentCost = deploymentGas.mul(gasPrice); - - console.log( - `Estimated cost to deploy ${name}: ${ethers.utils.formatUnits( - deploymentCost, - 'ether', - )} ETH`, - ); - - if (!args.autoDeploy) { - const result = await promptjs.get([ - { - properties: { - confirm: { - pattern: /^(DEPLOY|SKIP|EXIT)$/, - description: - 'Type "DEPLOY" to confirm, "SKIP" to skip this contract, or "EXIT" to exit.', - }, - }, - }, - ]); - if (result.operation === 'SKIP') { - console.log(`Skipping ${name} deployment...`); - continue; - } - if (result.operation === 'EXIT') { - console.log('Exiting...'); - return; - } - } - console.log(`Deploying ${name}...`); - - const deployedContract = await factory.deploy( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ); - - if (contract.waitForConfirmation) { - await deployedContract.deployed(); - } - - deployment[name as ContractName] = { - name, - instance: deployedContract, - address: deployedContract.address, - constructorArguments: contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? [], - libraries: contract?.libraries?.() ?? {}, - }; - - contract.validateDeployment?.(); - - console.log(`${name} contract deployed to ${deployedContract.address}`); - } - - return deployment; - }); diff --git a/packages/nouns-contracts/tasks/descriptor-v1-export-abi.ts b/packages/nouns-contracts/tasks/descriptor-v1-export-abi.ts deleted file mode 100644 index cd18bf07ad..0000000000 --- a/packages/nouns-contracts/tasks/descriptor-v1-export-abi.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { writeFileSync } from 'fs'; -import { task, types } from 'hardhat/config'; -import path from 'path'; -import ImageData from '../files/image-data-v1.json'; - -task( - 'descriptor-v1-export-abi', - 'Exports the image-data to abi files to be able to load from forge tests', -) - .addOptionalParam( - 'exportPath', - 'Where to save abi encoded files to be used in forge tests', - path.join(__dirname, '../test/foundry/files/descriptor_v1/'), - ) - .setAction(async ({ exportPath }, { ethers }) => { - const { bgcolors, palette, images } = ImageData; - let { bodies, accessories, heads, glasses } = images; - - const abiEncoded = ethers.utils.defaultAbiCoder.encode( - ['string[]', 'string[]', 'bytes[]', 'bytes[]', 'bytes[]', 'bytes[]'], - [ - bgcolors, - palette, - bodies.map(({ data }) => data), - accessories.map(({ data }) => data), - heads.map(({ data }) => data), - glasses.map(({ data }) => data), - ], - ); - - const filepath = path.join(exportPath, 'image-data.abi'); - writeFileSync(filepath, abiEncoded); - console.log(`Saved image-data to ${filepath}`); - }); diff --git a/packages/nouns-contracts/tasks/index.ts b/packages/nouns-contracts/tasks/index.ts index d3b95f6f8d..9ce6237ea9 100644 --- a/packages/nouns-contracts/tasks/index.ts +++ b/packages/nouns-contracts/tasks/index.ts @@ -1,28 +1,11 @@ export * from './accounts'; export * from './create-proposal'; -export * from './deploy'; -export * from './deploy-ci'; -export * from './deploy-local'; -export * from './deploy-and-configure'; -export * from './mint-noun'; export * from './populate-descriptor'; -export * from './run-local'; -export * from './verify-etherscan'; -export * from './update-configs'; export * from './descriptor-art-to-console'; -export * from './descriptor-v1-export-abi'; export * from './deploy-descriptor-v2'; -export * from './deploy-short-times'; -export * from './deploy-and-configure-short-times'; export * from './populate-descriptor-via-proposal'; export * from './deploy-test-token'; -export * from './populate-descriptor-v1'; export * from './upgrade-descriptor-via-proposal'; -export * from './deploy-v2-logic'; -export * from './verify-etherscan-daov2'; -export * from './update-configs-daov2'; -export * from './deploy-short-times-daov1'; -export * from './deploy-and-configure-short-times-daov1'; export * from './deploy-local-dao-v3'; export * from './run-local-dao-v3'; export * from './deploy-short-times-dao-v3'; diff --git a/packages/nouns-contracts/tasks/mint-noun.ts b/packages/nouns-contracts/tasks/mint-noun.ts deleted file mode 100644 index 0a840a0692..0000000000 --- a/packages/nouns-contracts/tasks/mint-noun.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Result } from 'ethers/lib/utils'; -import { task, types } from 'hardhat/config'; - -task('mint-noun', 'Mints a Noun') - .addOptionalParam( - 'nounsToken', - 'The `NounsToken` contract address', - '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9', - types.string, - ) - .setAction(async ({ nounsToken }, { ethers }) => { - const nftFactory = await ethers.getContractFactory('NounsToken'); - const nftContract = nftFactory.attach(nounsToken); - - const receipt = await (await nftContract.mint()).wait(); - const nounCreated = receipt.events?.[1]; - const { tokenId } = nounCreated?.args as Result; - - console.log(`Noun minted with ID: ${tokenId.toString()}.`); - }); diff --git a/packages/nouns-contracts/tasks/populate-descriptor-v1.ts b/packages/nouns-contracts/tasks/populate-descriptor-v1.ts deleted file mode 100644 index 93f7415f5f..0000000000 --- a/packages/nouns-contracts/tasks/populate-descriptor-v1.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { task, types } from 'hardhat/config'; -import ImageData from '../files/image-data-v1.json'; -import { chunkArray } from '../utils'; - -task('populate-descriptor-v1', 'Populates the descriptor with color palettes and Noun parts') - .addOptionalParam( - 'nftDescriptor', - 'The `NFTDescriptor` contract address', - '0x5FbDB2315678afecb367f032d93F642f64180aa3', - types.string, - ) - .addOptionalParam( - 'nounsDescriptor', - 'The `NounsDescriptor` contract address', - '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', - types.string, - ) - .setAction(async ({ nftDescriptor, nounsDescriptor }, { ethers }) => { - const descriptorFactory = await ethers.getContractFactory('NounsDescriptor', { - libraries: { - NFTDescriptor: nftDescriptor, - }, - }); - const descriptorContract = descriptorFactory.attach(nounsDescriptor); - - const { bgcolors, palette, images } = ImageData; - const { bodies, accessories, heads, glasses } = images; - - // Chunk head and accessory population due to high gas usage - await descriptorContract.addManyBackgrounds(bgcolors); - await descriptorContract.addManyColorsToPalette(0, palette); - await descriptorContract.addManyBodies(bodies.map(({ data }) => data)); - - const accessoryChunk = chunkArray(accessories, 10); - for (const chunk of accessoryChunk) { - await descriptorContract.addManyAccessories(chunk.map(({ data }) => data)); - } - - const headChunk = chunkArray(heads, 10); - for (const chunk of headChunk) { - await descriptorContract.addManyHeads(chunk.map(({ data }) => data)); - } - - await descriptorContract.addManyGlasses(glasses.map(({ data }) => data)); - - console.log('Descriptor populated with palettes and parts.'); - }); diff --git a/packages/nouns-contracts/tasks/run-local.ts b/packages/nouns-contracts/tasks/run-local.ts deleted file mode 100644 index 9fb16c470e..0000000000 --- a/packages/nouns-contracts/tasks/run-local.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { TASK_COMPILE, TASK_NODE } from 'hardhat/builtin-tasks/task-names'; -import { task } from 'hardhat/config'; - -task( - 'run-local', - 'Start a hardhat node, deploy contracts, and execute setup transactions', -).setAction(async (_, { ethers, run }) => { - await run(TASK_COMPILE); - - await Promise.race([ - run(TASK_NODE, { hostname: '0.0.0.0' }), - new Promise(resolve => setTimeout(resolve, 2_000)), - ]); - - const contracts = await run('deploy-local'); - - await run('populate-descriptor', { - nftDescriptor: contracts.NFTDescriptorV2.instance.address, - nounsDescriptor: contracts.NounsDescriptorV2.instance.address, - }); - - await contracts.NounsAuctionHouse.instance - .attach(contracts.NounsAuctionHouseProxy.instance.address) - .unpause({ - gasLimit: 1_000_000, - }); - - // Transfer ownership - const executorAddress = contracts.NounsDAOExecutor.instance.address; - await contracts.NounsDescriptorV2.instance.transferOwnership(executorAddress); - await contracts.NounsToken.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouseProxyAdmin.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouse.instance - .attach(contracts.NounsAuctionHouseProxy.instance.address) - .transferOwnership(executorAddress); - console.log( - 'Transferred ownership of the descriptor, token, and proxy admin contracts to the executor.', - ); - - // await run('create-proposal', { - // nounsDaoProxy: contracts.NounsDAOProxyV2.instance.address, - // }); - - const { chainId } = await ethers.provider.getNetwork(); - - const accounts = { - 'Account #0': { - Address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', - 'Private Key': '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', - }, - 'Account #1': { - Address: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', - 'Private Key': '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', - }, - }; - - console.table(accounts); - console.log( - `Noun contracts deployed to local node at http://localhost:8545 (Chain ID: ${chainId})`, - ); - console.log(`Auction House Proxy address: ${contracts.NounsAuctionHouseProxy.instance.address}`); - console.log(`Nouns ERC721 address: ${contracts.NounsToken.instance.address}`); - console.log(`Nouns DAO Executor address: ${contracts.NounsDAOExecutor.instance.address}`); - console.log(`Nouns DAO Proxy address: ${contracts.NounsDAOProxyV2.instance.address}`); - - await ethers.provider.send('evm_setIntervalMining', [12_000]); - - await new Promise(() => { - /* keep node alive until this process is killed */ - }); -}); diff --git a/packages/nouns-contracts/tasks/types/index.ts b/packages/nouns-contracts/tasks/types/index.ts index c943c8a787..cd368f5afd 100644 --- a/packages/nouns-contracts/tasks/types/index.ts +++ b/packages/nouns-contracts/tasks/types/index.ts @@ -9,19 +9,17 @@ export enum ChainId { Sepolia = 11155111, } -// prettier-ignore -export type DescriptorV1ContractNames = 'NFTDescriptor' | 'NounsDescriptor'; -// prettier-ignore -export type DescriptorV2ContractNames = 'NFTDescriptorV2' | 'NounsDescriptorV2' | 'SVGRenderer' | 'NounsArt' | 'Inflator'; -// prettier-ignore -export type ContractName = DescriptorV2ContractNames | 'NounsSeeder' | 'NounsToken' | 'NounsAuctionHouse' | 'NounsAuctionHouseProxyAdmin' | 'NounsAuctionHouseProxy' | 'NounsDAOExecutor' | 'NounsDAOLogicV1' | 'NounsDAOProxy'; -// prettier-ignore -export type ContractNameDescriptorV1 = DescriptorV1ContractNames | 'NounsSeeder' | 'NounsToken' | 'NounsAuctionHouse' | 'NounsAuctionHouseProxyAdmin' | 'NounsAuctionHouseProxy' | 'NounsDAOExecutor' | 'NounsDAOLogicV1' | 'NounsDAOProxy'; -// prettier-ignore -export type ContractNamesDAOV2 = Exclude | 'NounsDAOLogicV2' | 'NounsDAOProxyV2'; - export type ContractNamesDAOV3 = - | Exclude + | 'NFTDescriptorV2' + | 'NounsDescriptorV2' + | 'SVGRenderer' + | 'NounsArt' + | 'Inflator' + | 'NounsSeeder' + | 'NounsToken' + | 'NounsAuctionHouse' + | 'NounsAuctionHouseProxyAdmin' + | 'NounsAuctionHouseProxy' | 'NounsDAOLogicV3' | 'NounsDAOProxyV3' | 'NounsDAOV3Admin' diff --git a/packages/nouns-contracts/tasks/update-configs-daov2.ts b/packages/nouns-contracts/tasks/update-configs-daov2.ts deleted file mode 100644 index 96b1fe33a9..0000000000 --- a/packages/nouns-contracts/tasks/update-configs-daov2.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { ContractNamesDAOV2, DeployedContract } from './types'; -import { readFileSync, writeFileSync } from 'fs'; -import { execSync } from 'child_process'; -import { join } from 'path'; - -task('update-configs-daov2', 'Write the deployed addresses to the SDK and subgraph configs') - .addParam('contracts', 'Contract objects from the deployment', undefined, types.json) - .setAction( - async ( - { contracts }: { contracts: Record }, - { ethers }, - ) => { - const { name: network, chainId } = await ethers.provider.getNetwork(); - - // Update SDK addresses - const sdkPath = join(__dirname, '../../nouns-sdk'); - const addressesPath = join(sdkPath, 'src/contract/addresses.json'); - const addresses = JSON.parse(readFileSync(addressesPath, 'utf8')); - addresses[chainId] = { - nounsToken: contracts.NounsToken.address, - nounsSeeder: contracts.NounsSeeder.address, - nounsDescriptor: contracts.NounsDescriptorV2.address, - nftDescriptor: contracts.NFTDescriptorV2.address, - nounsAuctionHouse: contracts.NounsAuctionHouse.address, - nounsAuctionHouseProxy: contracts.NounsAuctionHouseProxy.address, - nounsAuctionHouseProxyAdmin: contracts.NounsAuctionHouseProxyAdmin.address, - nounsDaoExecutor: contracts.NounsDAOExecutor.address, - nounsDAOProxy: contracts.NounsDAOProxyV2.address, - nounsDAOLogicV2: contracts.NounsDAOLogicV2.address, - }; - writeFileSync(addressesPath, JSON.stringify(addresses, null, 2)); - try { - execSync('yarn build', { - cwd: sdkPath, - }); - } catch { - console.log('Failed to re-build `@nouns/sdk`. Please rebuild manually.'); - } - console.log('Addresses written to the Nouns SDK.'); - - // Generate subgraph config - const configName = `${network}-fork`; - const subgraphConfigPath = join(__dirname, `../../nouns-subgraph/config/${configName}.json`); - const subgraphConfig = { - network, - nounsToken: { - address: contracts.NounsToken.address, - startBlock: contracts.NounsToken.instance.deployTransaction.blockNumber, - }, - nounsAuctionHouse: { - address: contracts.NounsAuctionHouseProxy.address, - startBlock: contracts.NounsAuctionHouseProxy.instance.deployTransaction.blockNumber, - }, - nounsDAO: { - address: contracts.NounsDAOProxyV2.address, - startBlock: contracts.NounsDAOProxyV2.instance.deployTransaction.blockNumber, - }, - }; - writeFileSync(subgraphConfigPath, JSON.stringify(subgraphConfig, null, 2)); - console.log('Subgraph config has been generated.'); - }, - ); diff --git a/packages/nouns-contracts/tasks/update-configs.ts b/packages/nouns-contracts/tasks/update-configs.ts deleted file mode 100644 index c82bb44a79..0000000000 --- a/packages/nouns-contracts/tasks/update-configs.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { ContractName, ContractNameDescriptorV1, DeployedContract } from './types'; -import { readFileSync, writeFileSync } from 'fs'; -import { execSync } from 'child_process'; -import { join } from 'path'; - -task('update-configs', 'Write the deployed addresses to the SDK and subgraph configs') - .addParam('contracts', 'Contract objects from the deployment', undefined, types.json) - .setAction( - async ( - { - contracts, - }: { contracts: Record }, - { ethers }, - ) => { - const { name: network, chainId } = await ethers.provider.getNetwork(); - - // Update SDK addresses - const sdkPath = join(__dirname, '../../nouns-sdk'); - const addressesPath = join(sdkPath, 'src/contract/addresses.json'); - const addresses = JSON.parse(readFileSync(addressesPath, 'utf8')); - addresses[chainId] = { - nounsToken: contracts.NounsToken.address, - nounsSeeder: contracts.NounsSeeder.address, - nounsDescriptor: contracts.NounsDescriptorV2 - ? contracts.NounsDescriptorV2.address - : contracts.NounsDescriptor.address, - nftDescriptor: contracts.NFTDescriptorV2 - ? contracts.NFTDescriptorV2.address - : contracts.NFTDescriptor.address, - nounsAuctionHouse: contracts.NounsAuctionHouse.address, - nounsAuctionHouseProxy: contracts.NounsAuctionHouseProxy.address, - nounsAuctionHouseProxyAdmin: contracts.NounsAuctionHouseProxyAdmin.address, - nounsDaoExecutor: contracts.NounsDAOExecutor.address, - nounsDAOProxy: contracts.NounsDAOProxy.address, - nounsDAOLogicV1: contracts.NounsDAOLogicV1.address, - }; - writeFileSync(addressesPath, JSON.stringify(addresses, null, 2)); - try { - execSync('yarn build', { - cwd: sdkPath, - }); - } catch { - console.log('Failed to re-build `@nouns/sdk`. Please rebuild manually.'); - } - console.log('Addresses written to the Nouns SDK.'); - - // Generate subgraph config - const configName = `${network}-fork`; - const subgraphConfigPath = join(__dirname, `../../nouns-subgraph/config/${configName}.json`); - const subgraphConfig = { - network, - nounsToken: { - address: contracts.NounsToken.address, - startBlock: contracts.NounsToken.instance.deployTransaction.blockNumber, - }, - nounsAuctionHouse: { - address: contracts.NounsAuctionHouseProxy.address, - startBlock: contracts.NounsAuctionHouseProxy.instance.deployTransaction.blockNumber, - }, - nounsDAO: { - address: contracts.NounsDAOProxy.address, - startBlock: contracts.NounsDAOProxy.instance.deployTransaction.blockNumber, - }, - }; - writeFileSync(subgraphConfigPath, JSON.stringify(subgraphConfig, null, 2)); - console.log('Subgraph config has been generated.'); - }, - ); diff --git a/packages/nouns-contracts/tasks/upgrade-descriptor-via-proposal.ts b/packages/nouns-contracts/tasks/upgrade-descriptor-via-proposal.ts index 86455f7710..ce8ef8d9e1 100644 --- a/packages/nouns-contracts/tasks/upgrade-descriptor-via-proposal.ts +++ b/packages/nouns-contracts/tasks/upgrade-descriptor-via-proposal.ts @@ -10,8 +10,8 @@ task('upgrade-descriptor-via-proposal', 'Upgrade NounsToken to use Descriptor V2 const signatures = ['setDescriptor(address)']; const calldatas = [ethers.utils.defaultAbiCoder.encode(['address'], [descriptor])]; - const gov = (await ethers.getContractFactory('NounsDAOLogicV1')).attach(dao); - const propTx = await gov.propose( + const gov = (await ethers.getContractFactory('NounsDAOLogicV3')).attach(dao); + const propTx = await gov['propose(address[],uint256[],string[],bytes[],string)']( targets, values, signatures, diff --git a/packages/nouns-contracts/tasks/utils/index.ts b/packages/nouns-contracts/tasks/utils/index.ts index 03a067bd73..aad57140d4 100644 --- a/packages/nouns-contracts/tasks/utils/index.ts +++ b/packages/nouns-contracts/tasks/utils/index.ts @@ -1,61 +1,12 @@ -import { HardhatEthersHelpers } from '@nomiclabs/hardhat-ethers/types'; -import type { BigNumber, ContractFactory, ethers as ethersType } from 'ethers'; -import { ethers, utils } from 'ethers'; +import { ethers } from 'ethers'; import promptjs from 'prompt'; import { deflateRawSync } from 'zlib'; -import { ContractName, ContractRow, DeployedContract } from '../types'; +import { ContractNamesDAOV3, ContractRow, DeployedContract } from '../types'; promptjs.colors = false; promptjs.message = '> '; promptjs.delimiter = ''; -export async function getGasPriceWithPrompt( - ethers: typeof ethersType & HardhatEthersHelpers, -): Promise { - const gasPrice = await ethers.provider.getGasPrice(); - const gasInGwei = Math.round(Number(ethers.utils.formatUnits(gasPrice, 'gwei'))); - - promptjs.start(); - - let result = await promptjs.get([ - { - properties: { - gasPrice: { - type: 'integer', - required: true, - description: 'Enter a gas price (gwei)', - default: gasInGwei, - }, - }, - }, - ]); - - return ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); -} - -export async function getDeploymentConfirmationWithPrompt(): Promise { - const result = await promptjs.get([ - { - properties: { - confirm: { - type: 'string', - description: 'Type "DEPLOY" to confirm:', - }, - }, - }, - ]); - - return result.confirm == 'DEPLOY'; -} - -export async function printEstimatedCost(factory: ContractFactory, gasPrice: BigNumber) { - const deploymentGas = await factory.signer.estimateGas( - factory.getDeployTransaction({ gasPrice }), - ); - const deploymentCost = deploymentGas.mul(gasPrice); - console.log(`Estimated cost to deploy: ${utils.formatUnits(deploymentCost, 'ether')} ETH`); -} - export function dataToDescriptorInput(data: string[]): { encodedCompressed: string; originalLength: number; @@ -76,7 +27,7 @@ export function dataToDescriptorInput(data: string[]): { }; } -export function printContractsTable(contracts: Record) { +export function printContractsTable(contracts: Record) { console.table( Object.values(contracts).reduce( (acc: Record, contract: DeployedContract) => { diff --git a/packages/nouns-contracts/tasks/verify-etherscan-dao-v3.ts b/packages/nouns-contracts/tasks/verify-etherscan-dao-v3.ts index 152f74e552..5dc1115479 100644 --- a/packages/nouns-contracts/tasks/verify-etherscan-dao-v3.ts +++ b/packages/nouns-contracts/tasks/verify-etherscan-dao-v3.ts @@ -1,5 +1,5 @@ import { task, types } from 'hardhat/config'; -import { ContractName, ContractNamesDAOV3, DeployedContract } from './types'; +import { ContractNamesDAOV3, DeployedContract } from './types'; // prettier-ignore // These contracts require a fully qualified name to be passed because diff --git a/packages/nouns-contracts/tasks/verify-etherscan-daov2.ts b/packages/nouns-contracts/tasks/verify-etherscan-daov2.ts deleted file mode 100644 index 2a5404cf8f..0000000000 --- a/packages/nouns-contracts/tasks/verify-etherscan-daov2.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { ContractName, ContractNamesDAOV2, DeployedContract } from './types'; - -// prettier-ignore -// These contracts require a fully qualified name to be passed because -// they share bytecode with the underlying contract. -const nameToFullyQualifiedName: Record = { - NounsAuctionHouseProxy: 'contracts/proxies/NounsAuctionHouseProxy.sol:NounsAuctionHouseProxy', - NounsAuctionHouseProxyAdmin: 'contracts/proxies/NounsAuctionHouseProxyAdmin.sol:NounsAuctionHouseProxyAdmin', - NounsDAOLogicV2Harness: 'contracts/test/NounsDAOLogicV2Harness.sol:NounsDAOLogicV2Harness' -}; - -task('verify-etherscan-daov2', 'Verify the Solidity contracts on Etherscan') - .addParam('contracts', 'Contract objects from the deployment', undefined, types.json) - .setAction( - async ({ contracts }: { contracts: Record }, hre) => { - for (const [, contract] of Object.entries(contracts)) { - console.log(`verifying ${contract.name}...`); - try { - const code = await contract.instance?.provider.getCode(contract.address); - if (code === '0x') { - console.log( - `${contract.name} contract deployment has not completed. waiting to verify...`, - ); - await contract.instance?.deployed(); - } - await hre.run('verify:verify', { - ...contract, - contract: nameToFullyQualifiedName[contract.name], - }); - } catch ({ message }) { - if ((message as string).includes('Reason: Already Verified')) { - continue; - } - console.error(message); - } - } - }, - ); diff --git a/packages/nouns-contracts/tasks/verify-etherscan.ts b/packages/nouns-contracts/tasks/verify-etherscan.ts deleted file mode 100644 index c389e80f49..0000000000 --- a/packages/nouns-contracts/tasks/verify-etherscan.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { ContractName, DeployedContract } from './types'; - -// prettier-ignore -// These contracts require a fully qualified name to be passed because -// they share bytecode with the underlying contract. -const nameToFullyQualifiedName: Record = { - NounsAuctionHouseProxy: 'contracts/proxies/NounsAuctionHouseProxy.sol:NounsAuctionHouseProxy', - NounsAuctionHouseProxyAdmin: 'contracts/proxies/NounsAuctionHouseProxyAdmin.sol:NounsAuctionHouseProxyAdmin', - NounsDAOLogicV1Harness: 'contracts/test/NounsDAOLogicV1Harness.sol:NounsDAOLogicV1Harness' -}; - -task('verify-etherscan', 'Verify the Solidity contracts on Etherscan') - .addParam('contracts', 'Contract objects from the deployment', undefined, types.json) - .setAction(async ({ contracts }: { contracts: Record }, hre) => { - for (const [, contract] of Object.entries(contracts)) { - console.log(`verifying ${contract.name}...`); - try { - const code = await contract.instance?.provider.getCode(contract.address); - if (code === '0x') { - console.log( - `${contract.name} contract deployment has not completed. waiting to verify...`, - ); - await contract.instance?.deployed(); - } - await hre.run('verify:verify', { - ...contract, - contract: nameToFullyQualifiedName[contract.name], - }); - } catch ({ message }) { - if ((message as string).includes('Reason: Already Verified')) { - continue; - } - console.error(message); - } - } - }); diff --git a/packages/nouns-contracts/test/foundry/DAOUpgradeTo3p1/UpgradeToDAOV3p1MainnetFork.t.sol b/packages/nouns-contracts/test/foundry/DAOUpgradeTo3p1/UpgradeToDAOV3p1MainnetFork.t.sol index 12818bab26..a9fe2125d5 100644 --- a/packages/nouns-contracts/test/foundry/DAOUpgradeTo3p1/UpgradeToDAOV3p1MainnetFork.t.sol +++ b/packages/nouns-contracts/test/foundry/DAOUpgradeTo3p1/UpgradeToDAOV3p1MainnetFork.t.sol @@ -6,15 +6,15 @@ import { Strings } from '@openzeppelin/contracts/utils/Strings.sol'; import { DeployDAOV3LogicMainnet } from '../../../script/DAOV3p1/DeployDAOV3LogicMainnet.s.sol'; import { ProposeDAOV3p1UpgradeMainnet } from '../../../script/DAOV3p1/ProposeDAOV3p1UpgradeMainnet.s.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; -import { INounsDAOShared } from '../helpers/INounsDAOShared.sol'; -import { NounsDAOStorageV3, NounsDAOStorageV2 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; abstract contract UpgradeToDAOV3p1MainnetForkBaseTest is Test { address public constant NOUNDERS = 0x2573C60a6D127755aA2DC85e342F7da2378a0Cc5; address public constant WHALE = 0x83fCFe8Ba2FEce9578F0BbaFeD4Ebf5E915045B9; NounsToken public nouns = NounsToken(0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03); - INounsDAOShared public constant NOUNS_DAO_PROXY_MAINNET = - INounsDAOShared(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d); + INounsDAOLogicV3 public constant NOUNS_DAO_PROXY_MAINNET = + INounsDAOLogicV3(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d); address public constant CURRENT_DAO_IMPL = 0xdD1492570beb290a2f309541e1fDdcaAA3f00B61; address proposerAddr = vm.addr(0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb); @@ -53,7 +53,7 @@ abstract contract UpgradeToDAOV3p1MainnetForkBaseTest is Test { } function voteAndExecuteProposal(uint256 proposalId) internal { - NounsDAOStorageV2.ProposalCondensed memory propInfo = NOUNS_DAO_PROXY_MAINNET.proposals(proposalId); + NounsDAOV3Types.ProposalCondensedV2 memory propInfo = NOUNS_DAO_PROXY_MAINNET.proposals(proposalId); vm.roll(propInfo.startBlock + 1); vm.prank(proposerAddr, origin); diff --git a/packages/nouns-contracts/test/foundry/NounsDAOData.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOData.t.sol index d0c0fed5af..ce4980d795 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOData.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOData.t.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.19; import 'forge-std/Test.sol'; import { DeployUtilsV3 } from './helpers/DeployUtilsV3.sol'; import { AuctionHelpers } from './helpers/AuctionHelpers.sol'; -import { INounsDAOShared } from './helpers/INounsDAOShared.sol'; -import { NounsTokenLike, NounsDAOStorageV3 } from '../../contracts/governance/NounsDAOInterfaces.sol'; +import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; +import { NounsTokenLike, NounsDAOV3Types } from '../../contracts/governance/NounsDAOInterfaces.sol'; import { INounsAuctionHouse } from '../../contracts/interfaces/INounsAuctionHouse.sol'; import { NounsDAOData } from '../../contracts/governance/data/NounsDAOData.sol'; import { NounsDAODataEvents } from '../../contracts/governance/data/NounsDAODataEvents.sol'; @@ -17,16 +17,16 @@ abstract contract NounsDAODataBaseTest is DeployUtilsV3, SigUtils, NounsDAODataE NounsDAODataProxy proxy; NounsDAOData data; address dataAdmin = makeAddr('data admin'); - INounsDAOShared nounsDao; + INounsDAOLogicV3 nounsDao; INounsAuctionHouse auction; address feeRecipient = makeAddr('fee recipient'); address otherProposer = makeAddr('other proposer'); address notNouner = makeAddr('not nouner'); function setUp() public virtual { - nounsDao = INounsDAOShared(address(_deployDAOV3())); + nounsDao = INounsDAOLogicV3(address(_deployDAOV3())); auction = INounsAuctionHouse(nounsDao.nouns().minter()); - vm.prank(nounsDao.timelock()); + vm.prank(address(nounsDao.timelock())); auction.unpause(); NounsDAOData logic = new NounsDAOData(address(nounsDao.nouns()), address(nounsDao)); @@ -1019,9 +1019,9 @@ contract NounsDAOData_CreateCandidateToUpdateProposalTest is NounsDAODataBaseTes NounsDAOV3Proposals.ProposalTxs memory txs, string memory description ) internal returns (uint256 proposalId) { - NounsDAOStorageV3.ProposerSignature[] memory sigs = new NounsDAOStorageV3.ProposerSignature[](signers.length); + NounsDAOV3Types.ProposerSignature[] memory sigs = new NounsDAOV3Types.ProposerSignature[](signers.length); for (uint256 i = 0; i < signers.length; ++i) { - sigs[i] = NounsDAOStorageV3.ProposerSignature( + sigs[i] = NounsDAOV3Types.ProposerSignature( signProposal(proposer, signerPKs[i], txs, description, expirationTimestamps[i], address(nounsDao)), signers[i], expirationTimestamps[i] diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicState.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicState.t.sol index 2fb60197f2..7abe07dd5f 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicState.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicState.t.sol @@ -2,12 +2,8 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { INounsDAOShared } from './helpers/INounsDAOShared.sol'; -import { NounsDAOLogicV2 } from '../../contracts/governance/NounsDAOLogicV2.sol'; -import { NounsDAOLogicV3 } from '../../contracts/governance/NounsDAOLogicV3.sol'; -import { NounsDAOProxy } from '../../contracts/governance/NounsDAOProxy.sol'; -import { NounsDAOProxyV2 } from '../../contracts/governance/NounsDAOProxyV2.sol'; -import { NounsDAOStorageV2, NounsDAOStorageV3 } from '../../contracts/governance/NounsDAOInterfaces.sol'; +import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; +import { NounsDAOV3Types } from '../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsDescriptorV2 } from '../../contracts/NounsDescriptorV2.sol'; import { NounsToken } from '../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../contracts/NounsSeeder.sol'; @@ -32,19 +28,19 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { function testPendingGivenProposalJustCreated() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); - uint256 state = uint256(NounsDAOLogicV3(payable(address(daoProxy))).state(proposalId)); + uint256 state = uint256(INounsDAOLogicV3(payable(address(daoProxy))).state(proposalId)); if (daoVersion() < 3) { - assertEq(state, uint256(NounsDAOStorageV3.ProposalState.Pending)); + assertEq(state, uint256(NounsDAOV3Types.ProposalState.Pending)); } else { - assertEq(state, uint256(NounsDAOStorageV3.ProposalState.Updatable)); + assertEq(state, uint256(NounsDAOV3Types.ProposalState.Updatable)); } } function testActiveGivenProposalPastVotingDelay() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.roll(block.number + daoProxy.votingDelay() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Active); } function testCanceledGivenCanceledProposal() public { @@ -52,14 +48,14 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vm.prank(proposer); daoProxy.cancel(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Canceled); } function testDefeatedByRunningOutOfTime() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.roll(block.number + daoProxy.votingDelay() + daoProxy.votingPeriod() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Defeated); } function testDefeatedByVotingAgainst() public { @@ -74,7 +70,7 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vote(againstVoter, proposalId, 0); endVotingPeriod(); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Defeated); } function testSucceeded() public { @@ -89,14 +85,14 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vote(againstVoter, proposalId, 0); endVotingPeriod(); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Succeeded); } function testQueueRevertsGivenDefeatedProposal() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.roll(block.number + daoProxy.votingDelay() + daoProxy.votingPeriod() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Defeated); vm.expectRevert('NounsDAO::queue: proposal can only be queued if it is succeeded'); daoProxy.queue(proposalId); @@ -107,7 +103,7 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vm.prank(proposer); daoProxy.cancel(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Canceled); vm.expectRevert('NounsDAO::queue: proposal can only be queued if it is succeeded'); daoProxy.queue(proposalId); @@ -128,7 +124,7 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { // anyone can queue daoProxy.queue(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Queued); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Queued); } function testExpired() public { @@ -145,7 +141,7 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { daoProxy.queue(proposalId); vm.warp(block.timestamp + timelock.delay() + timelock.GRACE_PERIOD() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Expired); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Expired); } function testExecutedOnlyAfterQueued() public { @@ -173,10 +169,10 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vm.deal(address(timelock), 100); daoProxy.execute(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Executed); vm.warp(block.timestamp + timelock.delay() + timelock.GRACE_PERIOD() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Executed); } } @@ -185,12 +181,8 @@ contract NounsDAOLogicV1ForkStateTest is NounsDAOLogicStateBaseTest { return 1; } - function deployDAOProxy( - address, - address, - address - ) internal override returns (INounsDAOShared) { - return INounsDAOShared(address(deployForkDAOProxy())); + function deployDAOProxy(address, address, address) internal override returns (INounsDAOLogicV3) { + return INounsDAOLogicV3(address(deployForkDAOProxy())); } } @@ -199,7 +191,7 @@ contract NounsDAOLogicV3StateTest is NounsDAOLogicStateBaseTest { address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogicV3) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposal.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposal.t.sol index d3bd5f8a8f..9fec5c1de1 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposal.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposal.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; abstract contract ZeroState is NounsDAOLogicV3BaseTest { @@ -21,7 +21,7 @@ abstract contract ZeroState is NounsDAOLogicV3BaseTest { emit ProposalCanceled(proposalId); vm.prank(proposer); dao.cancel(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Canceled)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Canceled)); } function verifyRandoCantCancel() internal { @@ -54,7 +54,7 @@ abstract contract ProposalUpdatableState is ZeroState { proposalId = propose(proposer, target, 0, '', '', ''); vm.roll(block.number + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Updatable)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Updatable)); } } @@ -91,7 +91,7 @@ abstract contract ProposalPendingState is ProposalUpdatableState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).updatePeriodEndBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Pending)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Pending)); } } @@ -106,7 +106,7 @@ abstract contract ProposalActiveState is ProposalPendingState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).startBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Active)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Active)); } } @@ -125,7 +125,7 @@ abstract contract ProposalObjectionPeriodState is ProposalActiveState { dao.castVote(proposalId, 1); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.ObjectionPeriod)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.ObjectionPeriod)); } } @@ -143,7 +143,7 @@ abstract contract ProposalSucceededState is ProposalActiveState { dao.castVote(proposalId, 1); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Succeeded)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Succeeded)); } } @@ -158,7 +158,7 @@ abstract contract ProposalQueuedState is ProposalSucceededState { super.setUp(); dao.queue(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Queued)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Queued)); } } @@ -174,7 +174,7 @@ abstract contract ProposalExecutedState is ProposalQueuedState { vm.warp(dao.proposalsV3(proposalId).eta + 1); dao.execute(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Executed)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Executed)); } } @@ -189,7 +189,7 @@ abstract contract ProposalDefeatedState is ProposalActiveState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Defeated)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Defeated)); } } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposalBySigs.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposalBySigs.t.sol index 6647452dd1..d758fa2088 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposalBySigs.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposalBySigs.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; abstract contract ZeroState is NounsDAOLogicV3BaseTest { @@ -32,8 +32,8 @@ abstract contract ProposalUpdatableState is ZeroState { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposer, signerWithVotePK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote, expirationTimestamp @@ -51,7 +51,7 @@ abstract contract ProposalUpdatableState is ZeroState { vm.roll(block.number + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Updatable)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Updatable)); } } @@ -61,7 +61,7 @@ abstract contract IsCancellable is ZeroState { emit ProposalCanceled(proposalId); vm.prank(proposer); dao.cancel(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Canceled)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Canceled)); } function test_randoCantCancel() public { @@ -99,7 +99,7 @@ abstract contract ProposalPendingState is ProposalUpdatableState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).updatePeriodEndBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Pending)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Pending)); } } @@ -114,7 +114,7 @@ abstract contract ProposalActiveState is ProposalPendingState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).startBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Active)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Active)); } } @@ -133,7 +133,7 @@ abstract contract ProposalObjectionPeriodState is ProposalActiveState { dao.castVote(proposalId, 1); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.ObjectionPeriod)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.ObjectionPeriod)); } } @@ -151,7 +151,7 @@ abstract contract ProposalSucceededState is ProposalActiveState { dao.castVote(proposalId, 1); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Succeeded)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Succeeded)); } } @@ -166,7 +166,7 @@ abstract contract ProposalQueuedState is ProposalSucceededState { super.setUp(); dao.queue(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Queued)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Queued)); } } @@ -182,7 +182,7 @@ abstract contract ProposalExecutedState is ProposalQueuedState { vm.warp(dao.proposalsV3(proposalId).eta + 1); dao.execute(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Executed)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Executed)); } } @@ -197,7 +197,7 @@ abstract contract ProposalDefeatedState is ProposalActiveState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Defeated)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Defeated)); } } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOLogicV3BaseTest.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOLogicV3BaseTest.sol index e54e6915a8..1eadb9e69f 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOLogicV3BaseTest.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOLogicV3BaseTest.sol @@ -8,7 +8,7 @@ import { ProxyRegistryMock } from '../helpers/ProxyRegistryMock.sol'; import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; @@ -58,8 +58,8 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { ); event ProposalCreatedWithRequirements( - uint256 id, - address[] signers, + uint256 id, + address[] signers, uint256 updatePeriodEndBlock, uint256 proposalThreshold, uint256 quorumVotes, @@ -216,9 +216,9 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { NounsDAOV3Proposals.ProposalTxs memory txs, string memory description ) internal returns (uint256 proposalId) { - NounsDAOStorageV3.ProposerSignature[] memory sigs = new NounsDAOStorageV3.ProposerSignature[](signers.length); + NounsDAOV3Types.ProposerSignature[] memory sigs = new NounsDAOV3Types.ProposerSignature[](signers.length); for (uint256 i = 0; i < signers.length; ++i) { - sigs[i] = NounsDAOStorageV3.ProposerSignature( + sigs[i] = NounsDAOV3Types.ProposerSignature( signProposal(proposer, signerPKs[i], txs, description, expirationTimestamps[i], address(dao)), signers[i], expirationTimestamps[i] @@ -238,9 +238,9 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { NounsDAOV3Proposals.ProposalTxs memory txs, string memory description ) internal { - NounsDAOStorageV3.ProposerSignature[] memory sigs = new NounsDAOStorageV3.ProposerSignature[](signers.length); + NounsDAOV3Types.ProposerSignature[] memory sigs = new NounsDAOV3Types.ProposerSignature[](signers.length); for (uint256 i = 0; i < signers.length; ++i) { - sigs[i] = NounsDAOStorageV3.ProposerSignature( + sigs[i] = NounsDAOV3Types.ProposerSignature( signProposal(proposer, signerPKs[i], txs, description, expirationTimestamps[i], address(dao)), signers[i], expirationTimestamps[i] @@ -303,8 +303,8 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { vm.expectEmit(true, true, true, true); emit ProposalCreatedWithRequirements( - expectedPropId, - expectedSigners, + expectedPropId, + expectedSigners, block.number + proposalUpdatablePeriodInBlocks, expectedPropThreshold, expectedMinQuorumVotes, diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Admin.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Admin.t.sol index cc6ca9bdf0..adce4f63ac 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Admin.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Admin.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; import { NounsDAOV3Admin } from '../../../contracts/governance/NounsDAOV3Admin.sol'; -import { NounsDAOProxy } from '../../../contracts/governance/NounsDAOProxy.sol'; +import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; contract NounsDAOLogicV3AdminTest is NounsDAOLogicV3BaseTest { @@ -132,7 +132,7 @@ contract NounsDAOLogicV3AdminTest is NounsDAOLogicV3BaseTest { assertEq(address(dao.timelock()), address(1)); assertEq(address(dao.timelockV1()), address(2)); - assertEq(NounsDAOProxy(payable(address(dao))).admin(), address(3)); + assertEq(NounsDAOProxyV3(payable(address(dao))).admin(), address(3)); } function test_setVoteSnapshotBlockSwitchProposalId_onlyAdmin() public { diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Votes.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Votes.t.sol index 58f5e8c66c..a22b3e9c00 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Votes.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Votes.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; import { NounsDAOV3Votes } from '../../../contracts/governance/NounsDAOV3Votes.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { address proposer = makeAddr('proposer'); @@ -39,7 +39,7 @@ contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { // go into objection period vm.roll(block.number + dao.lastMinuteWindowInBlocks()); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.ObjectionPeriod); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.ObjectionPeriod); vm.expectRevert(NounsDAOV3Votes.CanOnlyVoteAgainstDuringObjectionPeriod.selector); vm.prank(voter); @@ -48,7 +48,7 @@ contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { function test_givenStateUpdatable_reverts() public { vm.startPrank(voter); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Updatable); vm.expectRevert('NounsDAO::castVoteInternal: voting is closed'); dao.castVote(proposalId, 1); @@ -58,7 +58,7 @@ contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { vm.startPrank(voter); vm.roll(block.number + dao.proposalUpdatablePeriodInBlocks() + 1); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Pending); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Pending); vm.expectRevert('NounsDAO::castVoteInternal: voting is closed'); dao.castVote(proposalId, 1); @@ -68,7 +68,7 @@ contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { vm.startPrank(voter); vm.roll(block.number + dao.proposalUpdatablePeriodInBlocks() + dao.votingDelay() + dao.votingPeriod() + 1); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Defeated); vm.expectRevert('NounsDAO::castVoteInternal: voting is closed'); dao.castVote(proposalId, 1); @@ -78,12 +78,12 @@ contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { vm.startPrank(voter); vm.roll(block.number + dao.proposalUpdatablePeriodInBlocks() + dao.votingDelay() + 1); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Active); dao.castVote(proposalId, 1); vm.roll(block.number + dao.votingPeriod()); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Succeeded); vm.expectRevert('NounsDAO::castVoteInternal: voting is closed'); dao.castVote(proposalId, 1); diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ProposeBySigs.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ProposeBySigs.t.sol index 3a814cb20f..2f92dbb227 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ProposeBySigs.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ProposeBySigs.t.sol @@ -8,7 +8,7 @@ import { SigUtils, ERC1271Stub } from '../helpers/SigUtils.sol'; import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; @@ -49,7 +49,7 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenNoSigs_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](0); + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](0); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.MustProvideSignatures.selector)); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, ''); @@ -58,8 +58,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenCanceledSig_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, '', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -76,8 +76,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenExpireddSig_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp - 1; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, '', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -91,8 +91,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSigOnDifferentDescription_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal( proposerWithVote, signerWithVote1PK, @@ -120,8 +120,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSigOnDifferentTargets_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -137,8 +137,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSigOnDifferentValues_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -154,8 +154,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSigOnDifferentSignatures_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -171,8 +171,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSigOnDifferentCalldatas_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -188,8 +188,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSigOnDifferentExpiration_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -205,8 +205,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSigOnDifferentSigner_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -222,8 +222,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSigOnDifferentDomainName_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal( proposerWithVote, signerWithVote1PK, @@ -245,8 +245,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSigOnDifferentVerifyingContract_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal( proposerWithVote, signerWithVote1PK, @@ -268,8 +268,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { ERC1271Stub erc1271 = new ERC1271Stub(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), address(erc1271), expirationTimestamp @@ -286,8 +286,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -303,8 +303,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -326,8 +326,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -341,8 +341,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenProposerWithEnoughVotesAndSignerWithNoVotes_reverts() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithNoVotesPK, txs, 'description', expirationTimestamp, address(dao)), signerWithNoVotes, expirationTimestamp @@ -364,8 +364,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -391,8 +391,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithVote, proposerWithVotePK, txs, 'description', expirationTimestamp, address(dao)), proposerWithVote, expirationTimestamp @@ -406,8 +406,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenProposerWithNoVotesAndSignerWithEnoughVotes_worksAndEmitsEvents() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -424,8 +424,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenOnesOfSignersHasNoVotes_signerIsFilteredOut() public { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](2); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](2); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal( proposerWithNoVotes, signerWithNoVotesPK, @@ -437,7 +437,7 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { signerWithNoVotes, expirationTimestamp ); - proposerSignatures[1] = NounsDAOStorageV3.ProposerSignature( + proposerSignatures[1] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote2PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote2, expirationTimestamp @@ -457,7 +457,7 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { 'description' ); - NounsDAOStorageV3.ProposalCondensed memory proposal = dao.proposalsV3(proposalId); + NounsDAOV3Types.ProposalCondensed memory proposal = dao.proposalsV3(proposalId); assertEq(proposal.signers, expectedSigners); } @@ -472,13 +472,13 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](2); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](2); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp ); - proposerSignatures[1] = NounsDAOStorageV3.ProposerSignature( + proposerSignatures[1] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote2PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote2, expirationTimestamp @@ -499,7 +499,7 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { 'description' ); - NounsDAOStorageV3.ProposalCondensed memory proposal = dao.proposalsV3(proposalId); + NounsDAOV3Types.ProposalCondensed memory proposal = dao.proposalsV3(proposalId); assertEq(proposal.signers, expectedSigners); } @@ -514,13 +514,13 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](2); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](2); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp ); - proposerSignatures[1] = NounsDAOStorageV3.ProposerSignature( + proposerSignatures[1] = NounsDAOV3Types.ProposerSignature( signProposal( proposerWithNoVotes, signerWithVote1PK, @@ -546,8 +546,8 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOV3Types.ProposerSignature[] memory proposerSignatures = new NounsDAOV3Types.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOV3Types.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), address(erc1271), expirationTimestamp diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposal.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposal.t.sol index 474c5e90be..700257b57f 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposal.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposal.t.sol @@ -8,7 +8,7 @@ import { SigUtils, ERC1271Stub } from '../helpers/SigUtils.sol'; import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; @@ -91,7 +91,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { function test_givenStatesPendingActiveSucceededQueuedAndExecuted_reverts() public { // Pending vm.roll(block.number + proposalUpdatablePeriodInBlocks); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Pending); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Pending); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -104,7 +104,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { // Active vm.roll(block.number + VOTING_DELAY); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Active); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -119,7 +119,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { vm.prank(proposer); dao.castVote(proposalId, 1); vm.roll(block.number + VOTING_PERIOD); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Succeeded); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -132,7 +132,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { // Queued dao.queue(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Queued); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Queued); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -146,7 +146,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { // Executed vm.warp(block.timestamp + TIMELOCK_DELAY); dao.execute(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Executed); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -161,7 +161,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { function test_givenStateCanceled_reverts() public { vm.prank(proposer); dao.cancel(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Canceled); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -179,7 +179,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { vm.prank(proposer); dao.castVote(proposalId, 0); vm.roll(block.number + VOTING_PERIOD); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Defeated); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -199,7 +199,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { vm.roll(block.number + VOTING_PERIOD); dao.queue(proposalId); vm.warp(block.timestamp + TIMELOCK_DELAY + timelock.GRACE_PERIOD()); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Expired); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Expired); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -215,7 +215,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { function test_givenStateVetoed_reverts() public { vm.prank(vetoer); dao.veto(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -235,7 +235,7 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { vm.prank(proposer); dao.castVote(proposalId, 1); vm.roll(block.number + lastMinuteWindowInBlocks); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.ObjectionPeriod); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.ObjectionPeriod); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); @@ -307,7 +307,7 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { } function test_givenStateUpdatable_updateProposal_updatesTxsAndEmitsEvent() public { - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Updatable); ( address[] memory targetsBefore, uint256[] memory valuesBefore, @@ -360,7 +360,7 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { } function test_givenStateUpdatable_updateProposalTransactions_updatesTxsAndEmitsEvent() public { - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Updatable); ( address[] memory targetsBefore, uint256[] memory valuesBefore, @@ -413,7 +413,7 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { contract UpdateProposalDescriptionTest is UpdateProposalBaseTest { function test_givenStateUpdatable_updatesDescriptionAndEmitsEvent() public { - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Updatable); vm.expectEmit(true, true, true, true); emit ProposalDescriptionUpdated(proposalId, proposer, 'new description', 'update message'); diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposalBySigs.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposalBySigs.t.sol index 4338ce5b63..8167770b25 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposalBySigs.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposalBySigs.t.sol @@ -9,7 +9,7 @@ import { SigUtils, ERC1271Stub } from '../helpers/SigUtils.sol'; import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; @@ -81,7 +81,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -101,7 +101,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = fewerSignersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -121,7 +121,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = moreSignersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -146,7 +146,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { signerPKs[1] = _signerPKs[_signers.length - 1]; NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -167,7 +167,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -193,7 +193,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { expirationTimestamps[1] = block.timestamp - 1; NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -214,7 +214,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -241,7 +241,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { address[] memory differentTargets = new address[](1); differentTargets[0] = makeAddr('different new target'); txs.targets = differentTargets; - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -270,7 +270,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory differentValues = new uint256[](1); differentValues[0] = updateValues[0] + 1234; txs.values = differentValues; - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -299,7 +299,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { string[] memory differentSignatures = new string[](1); differentSignatures[0] = 'different signature'; txs.signatures = differentSignatures; - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -328,7 +328,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { bytes[] memory differentCalldatas = new bytes[](1); differentCalldatas[0] = 'different calldatas'; txs.calldatas = differentCalldatas; - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -351,7 +351,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -374,7 +374,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -397,7 +397,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -419,7 +419,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -441,7 +441,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -465,7 +465,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -494,7 +494,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { signatures, calldatas ); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -529,7 +529,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { signatures, calldatas ); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -559,7 +559,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { signatures, calldatas ); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -578,7 +578,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -588,13 +588,13 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { // Pending vm.roll(block.number + proposalUpdatablePeriodInBlocks); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Pending); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Pending); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); // Active vm.roll(block.number + VOTING_DELAY); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Active); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); @@ -604,20 +604,20 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.prank(_signers[0]); dao.castVote(proposalId, 1); vm.roll(block.number + VOTING_PERIOD); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Succeeded); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); // Queued dao.queue(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Queued); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Queued); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); // Executed vm.warp(block.timestamp + TIMELOCK_DELAY); dao.execute(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Executed); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -629,7 +629,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -639,7 +639,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.prank(proposer); dao.cancel(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Canceled); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); @@ -652,7 +652,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -661,7 +661,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.roll(block.number + proposalUpdatablePeriodInBlocks + VOTING_DELAY + VOTING_PERIOD); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Defeated); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); @@ -674,7 +674,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -690,7 +690,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.roll(block.number + VOTING_PERIOD); dao.queue(proposalId); vm.warp(block.timestamp + TIMELOCK_DELAY + timelock.GRACE_PERIOD()); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Expired); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Expired); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); @@ -703,7 +703,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -713,7 +713,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.prank(vetoer); dao.veto(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); @@ -726,7 +726,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -742,7 +742,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.prank(_signers[0]); dao.castVote(proposalId, 1); vm.roll(block.number + lastMinuteWindowInBlocks); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.ObjectionPeriod); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.ObjectionPeriod); vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); @@ -755,7 +755,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -793,14 +793,14 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { 'new signature', 'new calldata' ); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOV3Types.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, UpdateProposalParams(proposalId, proposer, txs, 'descriptionAfter'), address(dao) ); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOV3Types.ProposalState.Updatable); ( address[] memory targetsBefore, uint256[] memory valuesBefore, @@ -848,14 +848,12 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { assertEq(calldatasAfter[0], 'new calldata'); } - function signersPKsExpirations(uint256 len) + function signersPKsExpirations( + uint256 len + ) internal view - returns ( - address[] memory signers, - uint256[] memory signerPKs, - uint256[] memory expirationTimestamps - ) + returns (address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps) { signers = new address[](len); signerPKs = new uint256[](len); @@ -871,11 +869,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { function signersPKsExpirations() internal view - returns ( - address[] memory signers, - uint256[] memory signerPKs, - uint256[] memory expirationTimestamps - ) + returns (address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps) { return signersPKsExpirations(2); } @@ -883,11 +877,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { function fewerSignersPKsExpirations() internal view - returns ( - address[] memory signers, - uint256[] memory signerPKs, - uint256[] memory expirationTimestamps - ) + returns (address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps) { return signersPKsExpirations(1); } @@ -895,11 +885,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { function moreSignersPKsExpirations() internal view - returns ( - address[] memory signers, - uint256[] memory signerPKs, - uint256[] memory expirationTimestamps - ) + returns (address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps) { return signersPKsExpirations(3); } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Veto.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Veto.t.sol index 0161fe2e6b..0680a312c7 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Veto.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Veto.t.sol @@ -4,10 +4,10 @@ pragma solidity ^0.8.19; import 'forge-std/Test.sol'; import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsDAOLogicSharedBaseTest } from '../helpers/NounsDAOLogicSharedBase.t.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; import { NounsDAOV3Admin } from '../../../contracts/governance/NounsDAOV3Admin.sol'; -import { INounsDAOShared } from '../helpers/INounsDAOShared.sol'; +import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { event NewPendingVetoer(address oldPendingVetoer, address newPendingVetoer); @@ -63,35 +63,35 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { uint256 proposalId = propose(address(0x1234), 100, '', ''); // Need to roll one block because in V3 on the proposal creation block the state is Updatable vm.roll(block.number + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Pending); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Pending); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); } function test_veto_worksForPropStateActive() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.roll(block.number + daoProxy.votingDelay() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Active); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); } function test_veto_worksForPropStateCanceled() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.prank(proposer); daoProxy.cancel(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Canceled); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); } function test_veto_worksForPropStateDefeated() public { @@ -100,12 +100,12 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { vm.prank(proposer); daoProxy.castVote(proposalId, 0); vm.roll(block.number + daoProxy.votingPeriod() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Defeated); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); } function test_veto_worksForPropStateSucceeded() public { @@ -114,12 +114,12 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { vm.prank(proposer); daoProxy.castVote(proposalId, 1); vm.roll(block.number + daoProxy.votingPeriod() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Succeeded); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); } function test_veto_worksForPropStateQueued() public { @@ -129,12 +129,12 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { daoProxy.castVote(proposalId, 1); vm.roll(block.number + daoProxy.votingPeriod() + 1); daoProxy.queue(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Queued); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Queued); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); } function test_veto_worksForPropStateExpired() public { @@ -145,12 +145,12 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { vm.roll(block.number + daoProxy.votingPeriod() + 1); daoProxy.queue(proposalId); vm.warp(block.timestamp + timelock.delay() + timelock.GRACE_PERIOD() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Expired); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Expired); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); } function test_veto_revertsForPropStateExecuted() public { @@ -163,7 +163,7 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { daoProxy.queue(proposalId); vm.warp(block.timestamp + timelock.delay() + 1); daoProxy.execute(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Executed); vm.expectRevert(NounsDAOV3Proposals.CantVetoExecutedProposal.selector); vm.prank(vetoer); @@ -174,24 +174,24 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); } function test_veto_worksForPropStateUpdatable() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); NounsDAOLogicV3 daoAsV3 = NounsDAOLogicV3(payable(address(daoProxy))); - assertTrue(daoAsV3.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(daoAsV3.state(proposalId) == NounsDAOV3Types.ProposalState.Updatable); vm.prank(vetoer); daoAsV3.veto(proposalId); - assertTrue(daoAsV3.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoAsV3.state(proposalId) == NounsDAOV3Types.ProposalState.Vetoed); } function test_setPendingVetoer_failsIfNotCurrentVetoer() public { @@ -266,7 +266,7 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogicV3) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Withdraw.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Withdraw.t.sol index 52aa872c1d..4d28ae60cb 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Withdraw.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Withdraw.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsDAOV3Admin } from '../../../contracts/governance/NounsDAOV3Admin.sol'; contract WithdrawTest is NounsDAOLogicV3BaseTest { diff --git a/packages/nouns-contracts/test/foundry/governance/InflationHandling.t.sol b/packages/nouns-contracts/test/foundry/governance/InflationHandling.t.sol index a99e855780..06a9e8401d 100644 --- a/packages/nouns-contracts/test/foundry/governance/InflationHandling.t.sol +++ b/packages/nouns-contracts/test/foundry/governance/InflationHandling.t.sol @@ -2,12 +2,13 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { INounsDAOShared } from '../helpers/INounsDAOShared.sol'; +import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; import { NounsDAOLogicSharedBaseTest } from '../helpers/NounsDAOLogicSharedBase.t.sol'; -import { NounsDAOLogicV2 } from '../../../contracts/governance/NounsDAOLogicV2.sol'; -import { NounsDAOProxyV2 } from '../../../contracts/governance/NounsDAOProxyV2.sol'; -import { NounsDAOStorageV1, NounsDAOStorageV2 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; +import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { Utils } from '../helpers/Utils.sol'; +import { DeployUtilsV3 } from '../helpers/DeployUtilsV3.sol'; abstract contract NounsDAOLogicV2InflationHandlingTest is NounsDAOLogicSharedBaseTest, Utils { uint256 constant proposalThresholdBPS_ = 678; // 6.78% @@ -18,36 +19,15 @@ abstract contract NounsDAOLogicV2InflationHandlingTest is NounsDAOLogicSharedBas address user3; function daoVersion() internal pure override returns (uint256) { - return 2; + return 3; } function deployDAOProxy( address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { - NounsDAOLogicV2 daoLogic = new NounsDAOLogicV2(); - - return - INounsDAOShared( - address( - new NounsDAOProxyV2( - timelock, - nounsToken, - vetoer, - admin, - address(daoLogic), - votingPeriod, - votingDelay, - proposalThresholdBPS_, - NounsDAOStorageV2.DynamicQuorumParams({ - minQuorumVotesBPS: minQuorumVotesBPS, - maxQuorumVotesBPS: 2000, - quorumCoefficient: 10000 - }) - ) - ) - ); + ) internal override returns (INounsDAOLogicV3) { + return _createDAOV3Proxy(timelock, nounsToken, vetoer); } function setUp() public virtual override { @@ -82,7 +62,7 @@ contract NounsDAOLogicV2InflationHandling40TotalSupplyTest is NounsDAOLogicV2Inf function testSetsParametersCorrectly() public { assertEq(daoProxy.proposalThresholdBPS(), proposalThresholdBPS_); - assertEq(daoProxyAsV2().getDynamicQuorumParamsAt(block.number).minQuorumVotesBPS, minQuorumVotesBPS); + assertEq(daoProxy.getDynamicQuorumParamsAt(block.number).minQuorumVotesBPS, minQuorumVotesBPS); } function testProposalThresholdBasedOnTotalSupply() public { @@ -92,7 +72,7 @@ contract NounsDAOLogicV2InflationHandling40TotalSupplyTest is NounsDAOLogicV2Inf function testMinimumQuorumVotes() public { // 11% of 40 = 4.4, floored to 4 - assertEq(daoProxyAsV2().minQuorumVotes(), 4); + assertEq(daoProxy.minQuorumVotes(), 4); } function testRejectsIfProposingBelowThreshold() public { @@ -163,8 +143,8 @@ abstract contract TotalSupply40WithAProposalState is NounsDAOLogicV2InflationHan contract InflationHandlingWithAProposalTest is TotalSupply40WithAProposalState { function testSetsProposalAttrbiutesCorrectly() public { - assertEq(daoProxyAsV2().proposals(proposalId).proposalThreshold, 2); - assertEq(daoProxyAsV2().proposals(proposalId).quorumVotes, 4); + assertEq(daoProxy.proposals(proposalId).proposalThreshold, 2); + assertEq(daoProxy.proposals(proposalId).quorumVotes, 4); } } @@ -181,7 +161,7 @@ contract SupplyIncreasedStateTest is SupplyIncreasedState { assertEq(daoProxy.proposalThreshold(), 5); // 11% of 80 = 8.88, floored to 8 - assertEq(daoProxyAsV2().minQuorumVotes(), 8); + assertEq(daoProxy.minQuorumVotes(), 8); } function testRejectsProposalsPreviouslyAboveThresholdButNowBelowBecauseSupplyIncreased() public { @@ -190,8 +170,8 @@ contract SupplyIncreasedStateTest is SupplyIncreasedState { } function testDoesntChangePreviousProposalAttributes() public { - assertEq(daoProxyAsV2().proposals(proposalId).proposalThreshold, 2); - assertEq(daoProxyAsV2().proposals(proposalId).quorumVotes, 4); + assertEq(daoProxy.proposals(proposalId).proposalThreshold, 2); + assertEq(daoProxy.proposals(proposalId).quorumVotes, 4); } function testProposalPassesWhenForVotesAboveQuorumAndAgainstVotes() public { @@ -204,11 +184,11 @@ contract SupplyIncreasedStateTest is SupplyIncreasedState { vm.prank(user3); daoProxy.castVote(proposalId, 0); // 5 votes - assertEq(daoProxyAsV2().proposals(proposalId).forVotes, 6); - assertEq(daoProxyAsV2().proposals(proposalId).againstVotes, 5); + assertEq(daoProxy.proposals(proposalId).forVotes, 6); + assertEq(daoProxy.proposals(proposalId).againstVotes, 5); vm.roll(block.number + votingPeriod); - assertEq(uint256(daoProxy.state(proposalId)), uint256(NounsDAOStorageV1.ProposalState.Succeeded)); + assertEq(uint256(daoProxy.state(proposalId)), uint256(NounsDAOV3Types.ProposalState.Succeeded)); } } diff --git a/packages/nouns-contracts/test/foundry/governance/NounsDAOLogicV3GasSnapshot.t.sol b/packages/nouns-contracts/test/foundry/governance/NounsDAOLogicV3GasSnapshot.t.sol index c6cc8d0ca8..9536236fe2 100644 --- a/packages/nouns-contracts/test/foundry/governance/NounsDAOLogicV3GasSnapshot.t.sol +++ b/packages/nouns-contracts/test/foundry/governance/NounsDAOLogicV3GasSnapshot.t.sol @@ -4,13 +4,11 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { NounsDAOLogicSharedBaseTest } from '../helpers/NounsDAOLogicSharedBase.t.sol'; -import { INounsDAOShared } from '../helpers/INounsDAOShared.sol'; +import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; import { DeployUtilsV3 } from '../helpers/DeployUtilsV3.sol'; -import { NounsDAOLogicV2 } from '../../../contracts/governance/NounsDAOLogicV2.sol'; import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; -import { NounsDAOProxyV2 } from '../../../contracts/governance/NounsDAOProxyV2.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV2, NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; abstract contract NounsDAOLogic_GasSnapshot_propose is NounsDAOLogicSharedBaseTest { address immutable target = makeAddr('target'); @@ -155,27 +153,17 @@ contract NounsDAOLogic_GasSnapshot_V3_propose is DeployUtilsV3, NounsDAOLogic_Ga address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogicV3) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } } -contract NounsDAOLogic_GasSnapshot_V2_propose is DeployUtilsV3, NounsDAOLogic_GasSnapshot_propose { - function deployDAOProxy( - address timelock, - address nounsToken, - address vetoer - ) internal override returns (INounsDAOShared) { - return _createDAOV2Proxy(timelock, nounsToken, vetoer); - } -} - contract NounsDAOLogic_GasSnapshot_V3_vote is DeployUtilsV3, NounsDAOLogic_GasSnapshot_castVote { function deployDAOProxy( address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogicV3) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } @@ -184,16 +172,6 @@ contract NounsDAOLogic_GasSnapshot_V3_vote is DeployUtilsV3, NounsDAOLogic_GasSn } } -contract NounsDAOLogic_GasSnapshot_V2_vote is DeployUtilsV3, NounsDAOLogic_GasSnapshot_castVote { - function deployDAOProxy( - address timelock, - address nounsToken, - address vetoer - ) internal override returns (INounsDAOShared) { - return _createDAOV2Proxy(timelock, nounsToken, vetoer); - } -} - contract NounsDAOLogic_GasSnapshot_V3_voteDuringObjectionPeriod is DeployUtilsV3, NounsDAOLogic_GasSnapshot_castVoteDuringObjectionPeriod @@ -202,7 +180,7 @@ contract NounsDAOLogic_GasSnapshot_V3_voteDuringObjectionPeriod is address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogicV3) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } } diff --git a/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol b/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol index d4175a70bd..7771b177e8 100644 --- a/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol +++ b/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol @@ -2,20 +2,16 @@ pragma solidity ^0.8.19; import 'forge-std/Test.sol'; -import { INounsDAOShared } from './INounsDAOShared.sol'; +import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; import { DescriptorHelpers } from './DescriptorHelpers.sol'; import { NounsDescriptorV2 } from '../../../contracts/NounsDescriptorV2.sol'; import { SVGRenderer } from '../../../contracts/SVGRenderer.sol'; import { NounsArt } from '../../../contracts/NounsArt.sol'; import { NounsDAOExecutor } from '../../../contracts/governance/NounsDAOExecutor.sol'; -import { NounsDAOLogicV2 } from '../../../contracts/governance/NounsDAOLogicV2.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; import { NounsDescriptor } from '../../../contracts/NounsDescriptor.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; -import { NounsDAOProxy } from '../../../contracts/governance/NounsDAOProxy.sol'; -import { NounsDAOStorageV2 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -import { NounsDAOProxyV2 } from '../../../contracts/governance/NounsDAOProxyV2.sol'; import { Inflator } from '../../../contracts/Inflator.sol'; import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; import { NounsAuctionHouseProxyAdmin } from '../../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; @@ -94,40 +90,6 @@ abstract contract DeployUtils is Test, DescriptorHelpers { return descriptorV2; } - function _deployTokenAndDAOAndPopulateDescriptor( - address noundersDAO, - address vetoer, - address minter - ) internal returns (address, address) { - IProxyRegistry proxyRegistry = IProxyRegistry(address(3)); - - NounsDAOExecutor timelock = new NounsDAOExecutor(address(1), TIMELOCK_DELAY); - NounsDescriptor descriptor = new NounsDescriptor(); - NounsToken nounsToken = new NounsToken(noundersDAO, minter, descriptor, new NounsSeeder(), proxyRegistry); - NounsDAOProxy proxy = new NounsDAOProxy( - address(timelock), - address(nounsToken), - vetoer, - address(timelock), - address(new NounsDAOLogicV2()), - VOTING_PERIOD, - VOTING_DELAY, - PROPOSAL_THRESHOLD, - QUORUM_VOTES_BPS - ); - - vm.prank(address(timelock)); - timelock.setPendingAdmin(address(proxy)); - vm.prank(address(proxy)); - timelock.acceptAdmin(); - - nounsToken.transferOwnership(address(timelock)); - - _populateDescriptor(descriptor); - - return (address(nounsToken), address(proxy)); - } - function deployToken(address noundersDAO, address minter) internal returns (NounsToken nounsToken) { IProxyRegistry proxyRegistry = IProxyRegistry(address(3)); NounsDescriptorV2 descriptor = _deployAndPopulateV2(); @@ -135,65 +97,6 @@ abstract contract DeployUtils is Test, DescriptorHelpers { nounsToken = new NounsToken(noundersDAO, minter, descriptor, new NounsSeeder(), proxyRegistry); } - function _createDAOV2Proxy( - address timelock, - address nounsToken, - address vetoer - ) internal returns (INounsDAOShared) { - return - INounsDAOShared( - address( - new NounsDAOProxyV2( - timelock, - nounsToken, - vetoer, - timelock, - address(new NounsDAOLogicV2()), - VOTING_PERIOD, - VOTING_DELAY, - PROPOSAL_THRESHOLD, - NounsDAOStorageV2.DynamicQuorumParams({ - minQuorumVotesBPS: 200, - maxQuorumVotesBPS: 2000, - quorumCoefficient: 10000 - }) - ) - ) - ); - } - - function deployDAOV2() internal returns (NounsDAOLogicV2) { - NounsDAOExecutor timelock = new NounsDAOExecutor(address(1), TIMELOCK_DELAY); - - NounsAuctionHouse auctionLogic = new NounsAuctionHouse(); - NounsAuctionHouseProxyAdmin auctionAdmin = new NounsAuctionHouseProxyAdmin(); - NounsAuctionHouseProxy auctionProxy = new NounsAuctionHouseProxy( - address(auctionLogic), - address(auctionAdmin), - '' - ); - auctionAdmin.transferOwnership(address(timelock)); - - NounsDescriptorV2 descriptor = _deployAndPopulateV2(); - NounsToken nounsToken = new NounsToken( - makeAddr('noundersDAO'), - address(auctionProxy), - descriptor, - new NounsSeeder(), - IProxyRegistry(address(0)) - ); - INounsDAOShared daoProxy = _createDAOV2Proxy(address(timelock), address(nounsToken), makeAddr('vetoer')); - - vm.prank(address(timelock)); - timelock.setPendingAdmin(address(daoProxy)); - vm.prank(address(daoProxy)); - timelock.acceptAdmin(); - - nounsToken.transferOwnership(address(timelock)); - - return NounsDAOLogicV2(payable(address(daoProxy))); - } - function get1967Implementation(address proxy) internal view returns (address) { bytes32 slot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1); return address(uint160(uint256(vm.load(proxy, slot)))); diff --git a/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol b/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol index 1b761e52b1..4bc0ed4661 100644 --- a/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol +++ b/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import 'forge-std/Test.sol'; import { DeployUtils } from './DeployUtils.sol'; -import { INounsDAOShared } from './INounsDAOShared.sol'; +import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; import { NounsDAOForkEscrow } from '../../../contracts/governance/fork/NounsDAOForkEscrow.sol'; @@ -19,7 +19,7 @@ import { ForkDAODeployer } from '../../../contracts/governance/fork/ForkDAODeplo import { NounsTokenFork } from '../../../contracts/governance/fork/newdao/token/NounsTokenFork.sol'; import { NounsAuctionHouseFork } from '../../../contracts/governance/fork/newdao/NounsAuctionHouseFork.sol'; import { NounsDAOLogicV1Fork } from '../../../contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; abstract contract DeployUtilsV3 is DeployUtils { @@ -29,10 +29,10 @@ abstract contract DeployUtilsV3 is DeployUtils { address timelock, address nounsToken, address vetoer - ) internal returns (INounsDAOShared dao) { + ) internal returns (INounsDAOLogicV3 dao) { uint256 nonce = vm.getNonce(address(this)); address predictedForkEscrowAddress = computeCreateAddress(address(this), nonce + 2); - dao = INounsDAOShared( + dao = INounsDAOLogicV3( address( new NounsDAOProxyV3( timelock, @@ -42,7 +42,7 @@ abstract contract DeployUtilsV3 is DeployUtils { vetoer, timelock, address(new NounsDAOLogicV3()), - NounsDAOStorageV3.NounsDAOParams({ + NounsDAOV3Types.NounsDAOParams({ votingPeriod: VOTING_PERIOD, votingDelay: VOTING_DELAY, proposalThresholdBPS: PROPOSAL_THRESHOLD, @@ -50,7 +50,7 @@ abstract contract DeployUtilsV3 is DeployUtils { objectionPeriodDurationInBlocks: OBJECTION_PERIOD_BLOCKS, proposalUpdatablePeriodInBlocks: 0 }), - NounsDAOStorageV3.DynamicQuorumParams({ + NounsDAOV3Types.DynamicQuorumParams({ minQuorumVotesBPS: 200, maxQuorumVotesBPS: 2000, quorumCoefficient: 10000 @@ -114,7 +114,7 @@ abstract contract DeployUtilsV3 is DeployUtils { makeAddr('vetoer'), address(t.timelock), daoLogicImplementation, - NounsDAOStorageV3.NounsDAOParams({ + NounsDAOV3Types.NounsDAOParams({ votingPeriod: VOTING_PERIOD, votingDelay: VOTING_DELAY, proposalThresholdBPS: PROPOSAL_THRESHOLD, @@ -122,7 +122,7 @@ abstract contract DeployUtilsV3 is DeployUtils { objectionPeriodDurationInBlocks: OBJECTION_PERIOD_BLOCKS, proposalUpdatablePeriodInBlocks: UPDATABLE_PERIOD_BLOCKS }), - NounsDAOStorageV3.DynamicQuorumParams({ + NounsDAOV3Types.DynamicQuorumParams({ minQuorumVotesBPS: 200, maxQuorumVotesBPS: 2000, quorumCoefficient: 10000 diff --git a/packages/nouns-contracts/test/foundry/helpers/INounsDAOShared.sol b/packages/nouns-contracts/test/foundry/helpers/INounsDAOShared.sol deleted file mode 100644 index fae3d62de7..0000000000 --- a/packages/nouns-contracts/test/foundry/helpers/INounsDAOShared.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.19; - -import { NounsDAOStorageV3, NounsTokenLike, NounsDAOStorageV2 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; - -interface INounsDAOShared { - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) external returns (uint256); - - function queue(uint256 proposalId) external; - - function execute(uint256 proposalId) external; - - function cancel(uint256 proposalId) external; - - function castVote(uint256 proposalId, uint8 support) external; - - function castRefundableVote(uint256 proposalId, uint8 support) external; - - function castVoteWithReason( - uint256 proposalId, - uint8 support, - string memory reason - ) external; - - function veto(uint256 proposalId) external; - - function state(uint256 proposalId) external view returns (NounsDAOStorageV3.ProposalState); - - function timelock() external view returns (address); - - function votingDelay() external view returns (uint256); - - function votingPeriod() external view returns (uint256); - - function proposalThresholdBPS() external view returns (uint256); - - function proposalThreshold() external view returns (uint256); - - function vetoer() external view returns (address); - - function _setVotingPeriod(uint256 votingPeriod_) external; - - function _setVotingDelay(uint256 votingDelay_) external; - - function _setProposalThresholdBPS(uint256 proposalThresholdBPS_) external; - - function _setQuorumVotesBPS(uint256 quorumVotesBPS_) external; - - function _burnVetoPower() external; - - function _setPendingVetoer(address pendingVetoer_) external; - - function pendingVetoer() external view returns (address); - - function _acceptVetoer() external; - - function proposals(uint256 proposalId) external view returns (NounsDAOStorageV2.ProposalCondensed memory); - - function proposalsV3(uint256 proposalId) external view returns (NounsDAOStorageV3.ProposalCondensed memory); - - function implementation() external view returns (address); - - function nouns() external view returns (NounsTokenLike); - - function proposeBySigs( - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) external returns (uint256); -} diff --git a/packages/nouns-contracts/test/foundry/helpers/NounsDAOLogicSharedBase.t.sol b/packages/nouns-contracts/test/foundry/helpers/NounsDAOLogicSharedBase.t.sol index f790b4b799..1b79349c4c 100644 --- a/packages/nouns-contracts/test/foundry/helpers/NounsDAOLogicSharedBase.t.sol +++ b/packages/nouns-contracts/test/foundry/helpers/NounsDAOLogicSharedBase.t.sol @@ -2,10 +2,7 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { INounsDAOShared } from './INounsDAOShared.sol'; -import { NounsDAOLogicV2 } from '../../../contracts/governance/NounsDAOLogicV2.sol'; -import { NounsDAOProxy } from '../../../contracts/governance/NounsDAOProxy.sol'; -import { NounsDAOProxyV2 } from '../../../contracts/governance/NounsDAOProxyV2.sol'; +import { INounsDAOLogicV3 } from '../../../contracts/interfaces/INounsDAOLogicV3.sol'; import { NounsDescriptorV2 } from '../../../contracts/NounsDescriptorV2.sol'; import { DeployUtilsFork } from './DeployUtilsFork.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; @@ -15,8 +12,12 @@ import { NounsDAOExecutor } from '../../../contracts/governance/NounsDAOExecutor import { INounsTokenForkLike } from '../../../contracts/governance/fork/newdao/governance/INounsTokenForkLike.sol'; import { Utils } from './Utils.sol'; +interface DAOLogicFork { + function _setQuorumVotesBPS(uint256 newQuorumVotesBPS) external; +} + abstract contract NounsDAOLogicSharedBaseTest is Test, DeployUtilsFork { - INounsDAOShared daoProxy; + INounsDAOLogicV3 daoProxy; NounsToken nounsToken; NounsDAOExecutor timelock = new NounsDAOExecutor(address(1), TIMELOCK_DELAY); address vetoer = address(0x3); @@ -47,7 +48,7 @@ abstract contract NounsDAOLogicSharedBaseTest is Test, DeployUtilsFork { address timelock, address nounsToken, address vetoer - ) internal virtual returns (INounsDAOShared); + ) internal virtual returns (INounsDAOLogicV3); function daoVersion() internal virtual returns (uint256) { return 0; // override to specify version @@ -99,36 +100,28 @@ abstract contract NounsDAOLogicSharedBaseTest is Test, DeployUtilsFork { vm.roll(block.number + daoProxy.votingDelay() + daoProxy.votingPeriod() + 1); } - function vote( - address voter, - uint256 proposalId, - uint8 support - ) internal { + function vote(address voter, uint256 proposalId, uint8 support) internal { vm.prank(voter); daoProxy.castVote(proposalId, support); } - function daoProxyAsV2() internal view returns (NounsDAOLogicV2) { - return NounsDAOLogicV2(payable(address(daoProxy))); - } - - function deployForkDAOProxy() internal returns (INounsDAOShared) { + function deployForkDAOProxy() internal returns (INounsDAOLogicV3) { (address treasuryAddress, address tokenAddress, address daoAddress) = _deployForkDAO(); timelock = NounsDAOExecutor(payable(treasuryAddress)); nounsToken = NounsToken(tokenAddress); minter = nounsToken.minter(); - INounsDAOShared dao = INounsDAOShared(daoAddress); + INounsDAOLogicV3 dao = INounsDAOLogicV3(daoAddress); - vm.startPrank(dao.timelock()); + vm.startPrank(address(dao.timelock())); dao._setVotingPeriod(votingPeriod); dao._setVotingDelay(votingDelay); dao._setProposalThresholdBPS(proposalThresholdBPS); - dao._setQuorumVotesBPS(1000); + DAOLogicFork(address(dao))._setQuorumVotesBPS(1000); vm.stopPrank(); vm.warp(INounsTokenForkLike(tokenAddress).forkingPeriodEndTimestamp()); - return INounsDAOShared(daoAddress); + return INounsDAOLogicV3(daoAddress); } } diff --git a/packages/nouns-contracts/test/foundry/helpers/SigUtils.sol b/packages/nouns-contracts/test/foundry/helpers/SigUtils.sol index 70061244d5..30f48a0c66 100644 --- a/packages/nouns-contracts/test/foundry/helpers/SigUtils.sol +++ b/packages/nouns-contracts/test/foundry/helpers/SigUtils.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { ECDSA } from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; import { IERC1271 } from '@openzeppelin/contracts/interfaces/IERC1271.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOV3Types } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; contract SigUtils is Test { @@ -35,7 +35,7 @@ contract SigUtils is Test { uint256[] memory expirationTimestamps, UpdateProposalParams memory proposalParams, address verifyingContract - ) internal returns (NounsDAOStorageV3.ProposerSignature[] memory sigs) { + ) internal returns (NounsDAOV3Types.ProposerSignature[] memory sigs) { return makeUpdateProposalSigs( signers, @@ -54,10 +54,10 @@ contract SigUtils is Test { UpdateProposalParams memory proposalParams, address verifyingContract, string memory domainName - ) internal view returns (NounsDAOStorageV3.ProposerSignature[] memory sigs) { - sigs = new NounsDAOStorageV3.ProposerSignature[](signers.length); + ) internal view returns (NounsDAOV3Types.ProposerSignature[] memory sigs) { + sigs = new NounsDAOV3Types.ProposerSignature[](signers.length); for (uint256 i = 0; i < signers.length; ++i) { - sigs[i] = NounsDAOStorageV3.ProposerSignature( + sigs[i] = NounsDAOV3Types.ProposerSignature( signProposalUpdate( proposalParams.proposalId, proposalParams.proposer, diff --git a/packages/nouns-contracts/test/governance/quorumConfig.test.ts b/packages/nouns-contracts/test/governance/quorumConfig.test.ts index 7395a9e7de..b7f0b7b014 100644 --- a/packages/nouns-contracts/test/governance/quorumConfig.test.ts +++ b/packages/nouns-contracts/test/governance/quorumConfig.test.ts @@ -6,25 +6,20 @@ import { getSigners, TestSigners, setTotalSupply, - deployGovernorV1, blockNumber, advanceBlocks, populateDescriptorV2, - deployGovernorV3AndSetImpl, + deployGovernorV3WithV3Proxy, } from '../utils'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { NounsToken, NounsDescriptorV2__factory as NounsDescriptorV2Factory, - NounsDAOLogicV3, INounsDAOLogicV3, - NounsDAOLogicV3, - NounsDAOLogicV3, NounsDAOLogicV3__factory, } from '../../typechain'; import { parseUnits } from 'ethers/lib/utils'; import { DynamicQuorumParams } from '../types'; -import { NounsDaoLogicV3Factory } from '../../src'; chai.use(solidity); const { expect } = chai; @@ -48,13 +43,7 @@ async function setup() { await setTotalSupply(token, 100); - const { address: govProxyAddress } = await deployGovernorV1( - deployer, - token.address, - V1_QUORUM_BPS, - ); - - gov = await deployGovernorV3AndSetImpl(deployer, govProxyAddress); + gov = await deployGovernorV3WithV3Proxy(deployer, token.address); } describe('NounsDAO#_setDynamicQuorumParams', () => { @@ -75,16 +64,6 @@ describe('NounsDAO#_setDynamicQuorumParams', () => { }); describe('allowed values', () => { - it('returns default values if no config set yet', async () => { - const params = await gov.getDynamicQuorumParamsAt(await blockNumber()); - - expectEqualParams(params, { - minQuorumVotesBPS: V1_QUORUM_BPS, - maxQuorumVotesBPS: V1_QUORUM_BPS, - quorumCoefficient: 0, - }); - }); - it('reverts when sender is not admin [ @skip-on-coverage ]', async () => { await expect(gov.connect(account0)._setDynamicQuorumParams(0, 0, 0)).to.be.revertedWith( 'AdminOnly()', @@ -138,22 +117,6 @@ describe('NounsDAO#_setDynamicQuorumParams', () => { .withArgs(parseUnits('1', 6), quorumCoefficient); }); - it('given no prior config, sets value and emits event', async () => { - const quorumCoefficient = parseUnits('1', 6); - const tx = await gov._setDynamicQuorumParams(200, 4000, quorumCoefficient); - - const actualParams = await gov.getDynamicQuorumParamsAt(await blockNumber()); - expect(actualParams.minQuorumVotesBPS).to.equal(200); - expect(actualParams.maxQuorumVotesBPS).to.equal(4000); - expect(actualParams.quorumCoefficient).to.equal(quorumCoefficient); - - let govWithEvents = NounsDAOLogicV3__factory.connect(gov.address, gov.signer); - - await expect(tx).to.emit(govWithEvents, 'MinQuorumVotesBPSSet').withArgs(V1_QUORUM_BPS, 200); - await expect(tx).to.emit(govWithEvents, 'MaxQuorumVotesBPSSet').withArgs(V1_QUORUM_BPS, 4000); - await expect(tx).to.emit(govWithEvents, 'QuorumCoefficientSet').withArgs(0, quorumCoefficient); - }); - describe('quorum params checkpointing', () => { let blockNum1: number; let blockNum2: number; @@ -207,16 +170,6 @@ describe('NounsDAO#_setDynamicQuorumParams', () => { expectEqualParams(await gov.getDynamicQuorumParamsAt(blockNum3), params3); }); - it('returns default values if block number too low', async () => { - const params = await gov.getDynamicQuorumParamsAt(blockNum1 - 2); - - expectEqualParams(params, { - minQuorumVotesBPS: V1_QUORUM_BPS, - maxQuorumVotesBPS: V1_QUORUM_BPS, - quorumCoefficient: 0, - }); - }); - it('reads correct values in between block numbers', async () => { expectEqualParams(await gov.getDynamicQuorumParamsAt(blockNum1 + 5), params1); expectEqualParams(await gov.getDynamicQuorumParamsAt(blockNum2 + 5), params2);