diff --git a/src/lib/PeriodPctCheckpoints.sol b/src/lib/PeriodPctCheckpoints.sol index 25bbd9e..66a4434 100644 --- a/src/lib/PeriodPctCheckpoints.sol +++ b/src/lib/PeriodPctCheckpoints.sol @@ -65,7 +65,7 @@ library PeriodPctCheckpoints { * `timestamp`. */ function push(History storage self, uint16 delayPeriodPct, uint16 castingPeriodPct, uint16 submissionPeriodPct) internal { - return _insert(self._checkpoints, LlamaUtils.toUint48(block.timestamp), LlamaUtils.toUint16(delayPeriodPct), LlamaUtils.toUint16(castingPeriodPct), LlamaUtils.toUint16(submissionPeriodPct)); + _insert(self._checkpoints, LlamaUtils.toUint48(block.timestamp), LlamaUtils.toUint16(delayPeriodPct), LlamaUtils.toUint16(castingPeriodPct), LlamaUtils.toUint16(submissionPeriodPct)); } /** diff --git a/src/lib/QuorumCheckpoints.sol b/src/lib/QuorumCheckpoints.sol index 8b096fd..8d001ce 100644 --- a/src/lib/QuorumCheckpoints.sol +++ b/src/lib/QuorumCheckpoints.sol @@ -71,7 +71,7 @@ library QuorumCheckpoints { * accidentally introducing a bug or breaking change. */ function push(History storage self, uint256 vetoQuorumPct, uint256 voteQuorumPct) internal { - return _insert(self._checkpoints, LlamaUtils.toUint48(block.timestamp), LlamaUtils.toUint16(voteQuorumPct), LlamaUtils.toUint16(vetoQuorumPct)); + _insert(self._checkpoints, LlamaUtils.toUint48(block.timestamp), LlamaUtils.toUint16(voteQuorumPct), LlamaUtils.toUint16(vetoQuorumPct)); } /** diff --git a/src/lib/Structs.sol b/src/lib/Structs.sol index 8f0b9e4..1b30696 100644 --- a/src/lib/Structs.sol +++ b/src/lib/Structs.sol @@ -34,6 +34,15 @@ struct Action { uint96 totalDisapprovals; // The total quantity of policyholder disapprovals. } +/// @dev Quorum and period data for token voting caster contracts. +struct CasterConfig { + uint16 voteQuorumPct; + uint16 vetoQuorumPct; + uint16 delayPeriodPct; + uint16 castingPeriodPct; + uint16 submissionPeriodPct; +} + /// @dev Data that represents a permission. struct PermissionData { address target; // Contract being called by an action. diff --git a/src/token-voting/LlamaTokenCaster.sol b/src/token-voting/LlamaTokenCaster.sol index 4da6b06..9b2690a 100644 --- a/src/token-voting/LlamaTokenCaster.sol +++ b/src/token-voting/LlamaTokenCaster.sol @@ -7,6 +7,7 @@ import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol"; import {ILlamaCore} from "src/interfaces/ILlamaCore.sol"; import {ILlamaTokenAdapter} from "src/token-voting/interfaces/ILlamaTokenAdapter.sol"; import {ActionState, VoteType} from "src/lib/Enums.sol"; +import {CasterConfig} from "src/lib/Structs.sol"; import {LlamaUtils} from "src/lib/LlamaUtils.sol"; import {PeriodPctCheckpoints} from "src/lib/PeriodPctCheckpoints.sol"; import {QuorumCheckpoints} from "src/lib/QuorumCheckpoints.sol"; @@ -202,15 +203,12 @@ contract LlamaTokenCaster is Initializable { /// The `initializer` modifier ensures that this function can be invoked at most once. /// @param _llamaCore The `LlamaCore` contract for this Llama instance. /// @param _role The role used by this contract to cast approvals and disapprovals. - /// @param _voteQuorumPct The minimum % of votes required to submit an approval to `LlamaCore`. - /// @param _vetoQuorumPct The minimum % of vetoes required to submit a disapproval to `LlamaCore`. - + /// @param casterConfig Contains the quorum and period pct values to initialize the contract with. function initialize( ILlamaCore _llamaCore, ILlamaTokenAdapter _tokenAdapter, uint8 _role, - uint16 _voteQuorumPct, - uint16 _vetoQuorumPct + CasterConfig memory casterConfig ) external initializer { if (_llamaCore.actionsCount() < 0) revert InvalidLlamaCoreAddress(); if (_role > _llamaCore.policy().numRoles()) revert RoleNotInitialized(_role); @@ -218,8 +216,8 @@ contract LlamaTokenCaster is Initializable { llamaCore = _llamaCore; tokenAdapter = _tokenAdapter; role = _role; - _setQuorumPct(_voteQuorumPct, _vetoQuorumPct); - _setPeriodPcts(2500, 5000, 2500); // default to 25% delay, 50% casting, 25% submission periods + _setQuorumPct(casterConfig.voteQuorumPct, casterConfig.vetoQuorumPct); + _setPeriodPcts(casterConfig.delayPeriodPct, casterConfig.castingPeriodPct, casterConfig.submissionPeriodPct); } // =========================================== diff --git a/src/token-voting/LlamaTokenVotingFactory.sol b/src/token-voting/LlamaTokenVotingFactory.sol index c6111f4..a01328a 100644 --- a/src/token-voting/LlamaTokenVotingFactory.sol +++ b/src/token-voting/LlamaTokenVotingFactory.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.23; import {Clones} from "@openzeppelin/proxy/Clones.sol"; import {ILlamaCore} from "src/interfaces/ILlamaCore.sol"; +import {CasterConfig} from "src/lib/Structs.sol"; import {ILlamaTokenAdapter} from "src/token-voting/interfaces/ILlamaTokenAdapter.sol"; import {LlamaTokenActionCreator} from "src/token-voting/LlamaTokenActionCreator.sol"; import {LlamaTokenCaster} from "src/token-voting/LlamaTokenCaster.sol"; @@ -25,8 +26,7 @@ contract LlamaTokenVotingFactory { uint8 actionCreatorRole; // The role required by the `LlamaTokenActionCreator` to create an action. uint8 casterRole; // The role required by the `LlamaTokenCaster` to cast approvals and disapprovals. uint256 creationThreshold; // The number of tokens required to create an action. - uint16 voteQuorumPct; // The minimum percentage of tokens required to approve an action. - uint16 vetoQuorumPct; // The minimum percentage of tokens required to disapprove an action. + CasterConfig casterConfig; // The quorum and period data for the `LlamaTokenCaster`. } // ======================== @@ -112,11 +112,7 @@ contract LlamaTokenVotingFactory { caster = LlamaTokenCaster(Clones.cloneDeterministic(address(LLAMA_TOKEN_CASTER_LOGIC), salt)); caster.initialize( - tokenVotingConfig.llamaCore, - tokenAdapter, - tokenVotingConfig.casterRole, - tokenVotingConfig.voteQuorumPct, - tokenVotingConfig.vetoQuorumPct + tokenVotingConfig.llamaCore, tokenAdapter, tokenVotingConfig.casterRole, tokenVotingConfig.casterConfig ); emit LlamaTokenVotingInstanceCreated( diff --git a/test/token-voting/LlamaERC20TokenCaster.t.sol b/test/token-voting/LlamaERC20TokenCaster.t.sol index abe8caf..0889767 100644 --- a/test/token-voting/LlamaERC20TokenCaster.t.sol +++ b/test/token-voting/LlamaERC20TokenCaster.t.sol @@ -127,7 +127,7 @@ contract CastVote is LlamaERC20TokenCasterTest { ) ); ILlamaTokenAdapter tokenAdapter = createTimestampTokenAdapter(address(erc20VotesToken), 0); - casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, ERC20_VOTE_QUORUM_PCT, ERC20_VETO_QUORUM_PCT); + casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, defaultCasterConfig); vm.expectRevert(abi.encodeWithSelector(ILlamaRelativeStrategyBase.InvalidRole.selector, tokenVotingCasterRole)); casterWithWrongRole.castVote(actionInfo, uint8(VoteType.For), ""); @@ -341,7 +341,7 @@ contract CastVeto is LlamaERC20TokenCasterTest { ) ); ILlamaTokenAdapter tokenAdapter = createTimestampTokenAdapter(address(erc20VotesToken), 0); - casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, ERC20_VOTE_QUORUM_PCT, ERC20_VETO_QUORUM_PCT); + casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, defaultCasterConfig); vm.expectRevert(abi.encodeWithSelector(ILlamaRelativeStrategyBase.InvalidRole.selector, tokenVotingCasterRole)); casterWithWrongRole.castVeto(actionInfo, uint8(VoteType.For), ""); @@ -602,7 +602,7 @@ contract SubmitApprovals is LlamaERC20TokenCasterTest { ) ); ILlamaTokenAdapter tokenAdapter = createTimestampTokenAdapter(address(erc20VotesToken), 0); - casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, ERC20_VOTE_QUORUM_PCT, ERC20_VETO_QUORUM_PCT); + casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, defaultCasterConfig); vm.expectRevert(abi.encodeWithSelector(ILlamaRelativeStrategyBase.InvalidRole.selector, tokenVotingCasterRole)); casterWithWrongRole.submitApproval(actionInfo); } @@ -686,7 +686,7 @@ contract SubmitDisapprovals is LlamaERC20TokenCasterTest { ) ); ILlamaTokenAdapter tokenAdapter = createTimestampTokenAdapter(address(erc20VotesToken), 0); - casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, ERC20_VOTE_QUORUM_PCT, ERC20_VETO_QUORUM_PCT); + casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, defaultCasterConfig); vm.expectRevert(abi.encodeWithSelector(ILlamaRelativeStrategyBase.InvalidRole.selector, tokenVotingCasterRole)); casterWithWrongRole.submitDisapproval(actionInfo); } diff --git a/test/token-voting/LlamaERC721TokenCaster.t.sol b/test/token-voting/LlamaERC721TokenCaster.t.sol index 1927502..2e2d2a8 100644 --- a/test/token-voting/LlamaERC721TokenCaster.t.sol +++ b/test/token-voting/LlamaERC721TokenCaster.t.sol @@ -129,7 +129,7 @@ contract CastVote is LlamaERC721TokenCasterTest { ) ); - casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, ERC721_VOTE_QUORUM_PCT, ERC721_VETO_QUORUM_PCT); + casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, defaultCasterConfig); vm.expectRevert(abi.encodeWithSelector(ILlamaRelativeStrategyBase.InvalidRole.selector, tokenVotingCasterRole)); casterWithWrongRole.castVote(actionInfo, uint8(VoteType.For), ""); @@ -344,7 +344,7 @@ contract CastVeto is LlamaERC721TokenCasterTest { address(llamaTokenCasterLogic), keccak256(abi.encodePacked(address(erc721VotesToken), msg.sender)) ) ); - casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, ERC721_VOTE_QUORUM_PCT, ERC721_VETO_QUORUM_PCT); + casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, defaultCasterConfig); vm.expectRevert(abi.encodeWithSelector(ILlamaRelativeStrategyBase.InvalidRole.selector, tokenVotingCasterRole)); casterWithWrongRole.castVeto(actionInfo, uint8(VoteType.For), ""); @@ -604,7 +604,7 @@ contract SubmitApprovals is LlamaERC721TokenCasterTest { address(llamaTokenCasterLogic), keccak256(abi.encodePacked(address(erc721VotesToken), msg.sender)) ) ); - casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, ERC721_VOTE_QUORUM_PCT, ERC721_VETO_QUORUM_PCT); + casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, defaultCasterConfig); vm.expectRevert(abi.encodeWithSelector(ILlamaRelativeStrategyBase.InvalidRole.selector, tokenVotingCasterRole)); casterWithWrongRole.submitApproval(actionInfo); } @@ -688,7 +688,7 @@ contract SubmitDisapprovals is LlamaERC721TokenCasterTest { ) ); ILlamaTokenAdapter tokenAdapter = createTimestampTokenAdapter(address(erc721VotesToken), 0); - casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, ERC721_VOTE_QUORUM_PCT, ERC721_VETO_QUORUM_PCT); + casterWithWrongRole.initialize(CORE, tokenAdapter, madeUpRole, defaultCasterConfig); vm.expectRevert(abi.encodeWithSelector(ILlamaRelativeStrategyBase.InvalidRole.selector, tokenVotingCasterRole)); casterWithWrongRole.submitDisapproval(actionInfo); } diff --git a/test/token-voting/LlamaTokenVotingFactory.t.sol b/test/token-voting/LlamaTokenVotingFactory.t.sol index f61b44d..65999bd 100644 --- a/test/token-voting/LlamaTokenVotingFactory.t.sol +++ b/test/token-voting/LlamaTokenVotingFactory.t.sol @@ -7,7 +7,7 @@ import {Clones} from "@openzeppelin/proxy/Clones.sol"; import {LlamaTokenVotingTestSetup} from "test/token-voting/LlamaTokenVotingTestSetup.sol"; -import {ActionInfo} from "src/lib/Structs.sol"; +import {ActionInfo, CasterConfig} from "src/lib/Structs.sol"; import {ILlamaCore} from "src/interfaces/ILlamaCore.sol"; import {ILlamaPolicy} from "src/interfaces/ILlamaPolicy.sol"; import {ILlamaTokenAdapter} from "src/token-voting/interfaces/ILlamaTokenAdapter.sol"; @@ -89,8 +89,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest { tokenVotingActionCreatorRole, tokenVotingCasterRole, ERC20_CREATION_THRESHOLD, - ERC20_VOTE_QUORUM_PCT, - ERC20_VETO_QUORUM_PCT + defaultCasterConfig ); // Set up action to call `deploy` with the ERC20 token. @@ -165,8 +164,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest { tokenVotingActionCreatorRole, tokenVotingCasterRole, ERC721_CREATION_THRESHOLD, - ERC721_VOTE_QUORUM_PCT, - ERC721_VETO_QUORUM_PCT + defaultCasterConfig ); // Set up action to call `deploy` with the ERC721 token. @@ -288,8 +286,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest { tokenVotingActionCreatorRole, tokenVotingCasterRole, ERC20_CREATION_THRESHOLD, - ERC20_VOTE_QUORUM_PCT, - ERC20_VETO_QUORUM_PCT + defaultCasterConfig ); vm.prank(randomCaller); @@ -321,8 +318,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest { tokenVotingActionCreatorRole, tokenVotingCasterRole, ERC20_CREATION_THRESHOLD, - ERC20_VOTE_QUORUM_PCT, - ERC20_VETO_QUORUM_PCT + defaultCasterConfig ); // Set up action to call `deploy` with the ERC20 token. @@ -385,8 +381,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest { tokenVotingActionCreatorRole, tokenVotingCasterRole, ERC20_CREATION_THRESHOLD, - ERC20_VOTE_QUORUM_PCT, - ERC20_VETO_QUORUM_PCT + defaultCasterConfig ); // Set up action to call `deploy` with the ERC20 token. diff --git a/test/token-voting/LlamaTokenVotingTestSetup.sol b/test/token-voting/LlamaTokenVotingTestSetup.sol index 0afb7f5..8979f39 100644 --- a/test/token-voting/LlamaTokenVotingTestSetup.sol +++ b/test/token-voting/LlamaTokenVotingTestSetup.sol @@ -10,7 +10,7 @@ import {LlamaPeripheryTestSetup} from "test/LlamaPeripheryTestSetup.sol"; import {DeployLlamaTokenVotingFactory} from "script/DeployLlamaTokenVotingFactory.s.sol"; -import {ActionInfo} from "src/lib/Structs.sol"; +import {ActionInfo, CasterConfig} from "src/lib/Structs.sol"; import {ILlamaPolicy} from "src/interfaces/ILlamaPolicy.sol"; import {ILlamaRelativeStrategyBase} from "src/interfaces/ILlamaRelativeStrategyBase.sol"; import {ILlamaStrategy} from "src/interfaces/ILlamaStrategy.sol"; @@ -41,6 +41,8 @@ contract LlamaTokenVotingTestSetup is LlamaPeripheryTestSetup, DeployLlamaTokenV MockERC20Votes public erc20VotesToken; MockERC721Votes public erc721VotesToken; + CasterConfig public defaultCasterConfig; + // Token Voting Roles uint8 tokenVotingActionCreatorRole; uint8 tokenVotingCasterRole; @@ -68,6 +70,14 @@ contract LlamaTokenVotingTestSetup is LlamaPeripheryTestSetup, DeployLlamaTokenV erc20VotesToken = new MockERC20Votes(); erc721VotesToken = new MockERC721Votes(); + defaultCasterConfig = CasterConfig({ + voteQuorumPct: ERC20_VOTE_QUORUM_PCT, + vetoQuorumPct: ERC20_VETO_QUORUM_PCT, + delayPeriodPct: uint16(ONE_QUARTER_IN_BPS), + castingPeriodPct: uint16(TWO_QUARTERS_IN_BPS), + submissionPeriodPct: uint16(ONE_QUARTER_IN_BPS) + }); + //Deploy // Setting up tokenholder addresses and private keys. @@ -102,8 +112,7 @@ contract LlamaTokenVotingTestSetup is LlamaPeripheryTestSetup, DeployLlamaTokenV tokenVotingActionCreatorRole, tokenVotingCasterRole, ERC20_CREATION_THRESHOLD, - ERC20_VOTE_QUORUM_PCT, - ERC20_VETO_QUORUM_PCT + defaultCasterConfig ); vm.startPrank(address(EXECUTOR)); @@ -132,8 +141,7 @@ contract LlamaTokenVotingTestSetup is LlamaPeripheryTestSetup, DeployLlamaTokenV tokenVotingActionCreatorRole, tokenVotingCasterRole, ERC721_CREATION_THRESHOLD, - ERC721_VOTE_QUORUM_PCT, - ERC721_VETO_QUORUM_PCT + defaultCasterConfig ); vm.startPrank(address(EXECUTOR));