Skip to content

Commit

Permalink
feat: add new params to token voting
Browse files Browse the repository at this point in the history
  • Loading branch information
clauBv23 committed Aug 30, 2024
1 parent cb368a3 commit 6173c49
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 25 deletions.
25 changes: 20 additions & 5 deletions packages/contracts/src/MajorityVotingBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ abstract contract MajorityVotingBase is
IDAO.Action[] actions;
uint256 allowFailureMap;
uint256 minApprovalPower;
TargetConfig targetConfig; // added in v1.3
}

/// @notice A container for the proposal parameters at the time of proposal creation.
Expand Down Expand Up @@ -220,6 +221,9 @@ abstract contract MajorityVotingBase is
bytes32 public constant UPDATE_VOTING_SETTINGS_PERMISSION_ID =
keccak256("UPDATE_VOTING_SETTINGS_PERMISSION");

/// @notice The ID of the permission required to call the `addAddresses` and `removeAddresses` functions.
bytes32 public constant CREATE_PROPOSAL_PERMISSION_ID = keccak256("CREATE_PROPOSAL_PERMISSION");

/// @notice A mapping between proposal IDs and proposal information.
// solhint-disable-next-line named-parameters-mapping
mapping(uint256 => Proposal) internal proposals;
Expand Down Expand Up @@ -259,6 +263,10 @@ abstract contract MajorityVotingBase is
/// @param proposalId The ID of the proposal.
error ProposalExecutionForbidden(uint256 proposalId);

/// @notice Thrown if the proposal with same actions and metadata already exists.
/// @param proposalId The id of the proposal.
error ProposalAlreadyExists(uint256 proposalId);

/// @notice Emitted when the voting settings are updated.
/// @param votingMode A parameter to select the vote mode.
/// @param supportThreshold The support threshold value.
Expand All @@ -285,11 +293,14 @@ abstract contract MajorityVotingBase is
function __MajorityVotingBase_init(
IDAO _dao,
VotingSettings calldata _votingSettings,
uint256 _minApprovals
uint256 _minApprovals,
TargetConfig calldata _targetConfig

Check warning on line 297 in packages/contracts/src/MajorityVotingBase.sol

View workflow job for this annotation

GitHub Actions / checks

Variable "_targetConfig" is unused

Check warning on line 297 in packages/contracts/src/MajorityVotingBase.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Variable "_targetConfig" is unused

Check warning on line 297 in packages/contracts/src/MajorityVotingBase.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Variable "_targetConfig" is unused
) internal onlyInitializing {
__PluginUUPSUpgradeable_init(_dao);
_updateVotingSettings(_votingSettings);
_updateMinApprovals(_minApprovals);

// todo set target config
}

/// @notice Checks if this or the parent contract supports an interface by its ID.
Expand Down Expand Up @@ -362,7 +373,7 @@ abstract contract MajorityVotingBase is
}

/// @inheritdoc IMajorityVoting
function canExecute(uint256 _proposalId) public view virtual returns (bool) {
function canExecute(uint256 _proposalId) public view virtual override returns (bool) {
return _canExecute(_proposalId);
}

Expand Down Expand Up @@ -540,14 +551,18 @@ abstract contract MajorityVotingBase is
/// @notice Internal function to execute a vote. It assumes the queried proposal exists.
/// @param _proposalId The ID of the proposal.
function _execute(uint256 _proposalId) internal virtual {
proposals[_proposalId].executed = true;
Proposal storage proposal_ = proposals[_proposalId];

proposal_.executed = true;

_executeProposal(
dao(),
_execute(
proposal_.target,
_proposalId,
proposals[_proposalId].actions,
proposals[_proposalId].allowFailureMap
);

emit ProposalExecuted(_proposalId);
}

/// @notice Internal function to check if a voter can vote. It assumes the queried proposal exists.
Expand Down
71 changes: 51 additions & 20 deletions packages/contracts/src/TokenVoting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ contract TokenVoting is IMembership, MajorityVotingBase {
IDAO _dao,
VotingSettings calldata _votingSettings,
IVotesUpgradeable _token,
uint256 _minApprovals
uint256 _minApprovals,
TargetConfig calldata _targetConfig

Check warning on line 64 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / checks

Variable "_targetConfig" is unused

Check warning on line 64 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Variable "_targetConfig" is unused

Check warning on line 64 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Variable "_targetConfig" is unused
) external initializer {
__MajorityVotingBase_init(_dao, _votingSettings, _minApprovals);

Expand All @@ -69,10 +70,15 @@ contract TokenVoting is IMembership, MajorityVotingBase {
emit MembershipContractAnnounced({definingContract: address(_token)});
}

// todo double check the reinitializer version must be 2
/// @notice Initializes the plugin after an upgrade from a previous version.
/// @param _minApprovals The minimal amount of approvals the proposal needs to succeed.
function initializeFrom(uint256 _minApprovals) external reinitializer(2) {
function initializeFrom(
uint256 _minApprovals,
TargetConfig calldata _targetConfig

Check warning on line 78 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / checks

Variable "_targetConfig" is unused

Check warning on line 78 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Variable "_targetConfig" is unused

Check warning on line 78 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Variable "_targetConfig" is unused
) external reinitializer(2) {
_updateMinApprovals(_minApprovals);
// todo set target
}

/// @notice Checks if this or the parent contract supports an interface by its ID.
Expand Down Expand Up @@ -108,24 +114,7 @@ contract TokenVoting is IMembership, MajorityVotingBase {
uint64 _endDate,
VoteOption _voteOption,
bool _tryEarlyExecution
) external override returns (uint256 proposalId) {
// Check that either `_msgSender` owns enough tokens or has enough voting power from being a delegatee.
{
uint256 minProposerVotingPower_ = minProposerVotingPower();

if (minProposerVotingPower_ != 0) {
// Because of the checks in `TokenVotingSetup`, we can assume that `votingToken`
// is an [ERC-20](https://eips.ethereum.org/EIPS/eip-20) token.
if (
votingToken.getVotes(_msgSender()) < minProposerVotingPower_ &&
IERC20Upgradeable(address(votingToken)).balanceOf(_msgSender()) <
minProposerVotingPower_
) {
revert ProposalCreationForbidden(_msgSender());
}
}
}

) external override auth(CREATE_PROPOSAL_PERMISSION_ID) returns (uint256 proposalId) {
uint256 snapshotBlock;
unchecked {
// The snapshot block must be mined already to
Expand All @@ -141,6 +130,7 @@ contract TokenVoting is IMembership, MajorityVotingBase {

(_startDate, _endDate) = _validateProposalDates(_startDate, _endDate);

// todo think this should be changed since create Proposal is no longe in commons contract
proposalId = _createProposal({
_creator: _msgSender(),
_metadata: _metadata,
Expand All @@ -165,6 +155,16 @@ contract TokenVoting is IMembership, MajorityVotingBase {

proposal_.minApprovalPower = _applyRatioCeiled(totalVotingPower_, minApproval());

TargetConfig memory currentTarget = getTargetConfig();

if (currentTarget.target == address(0)) {
proposal_.target = address(dao());
proposal_.operation = Operation.Call;
} else {
proposal_.target = currentTarget.target;
proposal_.operation = currentTarget.operation;
}

// Reduce costs
if (_allowFailureMap != 0) {
proposal_.allowFailureMap = _allowFailureMap;
Expand All @@ -180,6 +180,18 @@ contract TokenVoting is IMembership, MajorityVotingBase {
if (_voteOption != VoteOption.None) {
vote(proposalId, _voteOption, _tryEarlyExecution);
}

// todo will need to emit event
}

function createProposal(
bytes calldata _metadata,
IDAO.Action[] calldata _actions,
uint64 _startDate,
uint64 _endDate
) external override returns (uint256 proposalId) {
// Calls public function for permission check.
proposalId = createProposal(_metadata, _actions, 0, false, false, _startDate, _endDate);
}

/// @inheritdoc IMembership
Expand All @@ -190,6 +202,25 @@ contract TokenVoting is IMembership, MajorityVotingBase {
IERC20Upgradeable(address(votingToken)).balanceOf(_account) > 0;
}

/// @notice Hashing function used to (re)build the proposal id from the proposal details..
/// @dev The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array

Check failure on line 206 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / checks

Line length must be no more than 120 but current length is 126

Check failure on line 206 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Line length must be no more than 120 but current length is 126

Check failure on line 206 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Line length must be no more than 120 but current length is 126
/// and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id
/// can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in
/// advance, before the proposal is submitted.
/// The chainId and the governor address are not part of the proposal id computation. Consequently, the
/// same proposal (with same operation and same description) will have the same id if submitted on multiple governors

Check failure on line 211 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / checks

Line length must be no more than 120 but current length is 121

Check failure on line 211 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Line length must be no more than 120 but current length is 121

Check failure on line 211 in packages/contracts/src/TokenVoting.sol

View workflow job for this annotation

GitHub Actions / formatting-linting / checks

Line length must be no more than 120 but current length is 121
/// across multiple networks. This also means that in order to execute the same operation twice (on the same
/// governor) the proposer will have to change the description in order to avoid proposal id conflicts.
/// @param _actions The actions that will be executed after the proposal passes.
/// @param _metadata The metadata of the proposal.
/// @return proposalId The ID of the proposal.
function createProposalId(
IDAO.Action[] calldata _actions,
bytes memory _metadata
) public pure override returns (uint256) {
return uint256(keccak256(abi.encode(_actions, _metadata)));
}

/// @inheritdoc MajorityVotingBase
function _vote(
uint256 _proposalId,
Expand Down

0 comments on commit 6173c49

Please sign in to comment.