Skip to content

Commit

Permalink
src: update contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
jordipainan committed Dec 15, 2023
1 parent 39461d0 commit 7d9d7eb
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 193 deletions.
119 changes: 119 additions & 0 deletions packages/contracts/src/ExecutionMultisig.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.17;

import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {SafeCastUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

import {IDAO} from "@aragon/osx/core/dao/IDAO.sol";
import {PluginUUPSUpgradeable} from "@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol";
import {Addresslist} from "@aragon/osx/plugins/utils/Addresslist.sol";

import {IExecutionMultisig} from "./IExecutionMultisig.sol";

abstract contract ExecutionMultisig is
IExecutionMultisig,
Initializable,
ERC165Upgradeable,
PluginUUPSUpgradeable,
Addresslist
{
using SafeCastUpgradeable for uint256;

/// @notice The ID of the permission required to add/remove executionMultisig members.
bytes32 public constant UPDATE_PLUGIN_EXECUTION_MULTISIG_PERMISSION_ID =
keccak256("UPDATE_PLUGIN_EXECUTION_MULTISIG_PERMISSION");

/// @notice Keeps track at which block number the executionMultisig has been changed the last time.
uint64 internal lastExecutionMultisigChange;

/// @notice Initializes the component to be used by inheriting contracts.
/// @dev This method is required to support [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822).
/// @param _dao The IDAO interface of the associated DAO.
function __ExecutionMultisig_init(IDAO _dao) internal onlyInitializing {
__PluginUUPSUpgradeable_init(_dao);
}

/// @notice Checks if this or the parent contract supports an interface by its ID.
/// @param _interfaceId The ID of the interface.
/// @return Returns `true` if the interface is supported.
function supportsInterface(
bytes4 _interfaceId
) public view virtual override(ERC165Upgradeable, PluginUUPSUpgradeable) returns (bool) {
return
_interfaceId == type(IExecutionMultisig).interfaceId ||
_interfaceId == type(Addresslist).interfaceId ||
super.supportsInterface(_interfaceId);
}

/// @inheritdoc IExecutionMultisig
function addExecutionMultisigMembers(
address[] calldata _members
) external override auth(UPDATE_PLUGIN_EXECUTION_MULTISIG_PERMISSION_ID) {
_addExecutionMultisigMembers(_members);
}

/// @notice Private function for adding execution multisig members.
/// @param _members The addresses to add.
function _addExecutionMultisigMembers(address[] calldata _members) internal {
_guardExecutionMultisig();
if (_members.length == 0) {
revert InvalidListLength({length: _members.length});
}

uint256 newAddresslistLength = addresslistLength() + _members.length;

// Check if the new address list length would be greater than `type(uint16).max`, the maximal number of approvals.
if (newAddresslistLength > type(uint16).max) {
revert AddresslistLengthOutOfBounds({
limit: type(uint16).max,
actual: newAddresslistLength
});
}

_addAddresses(_members);
lastExecutionMultisigChange = uint64(block.number);

emit ExecutionMultisigMembersAdded({newMembers: _members});
}

/// @inheritdoc IExecutionMultisig
function removeExecutionMultisigMembers(address[] calldata _members) external virtual {}

/// @inheritdoc IExecutionMultisig
function isExecutionMultisigMember(address _member) public view override returns (bool) {
return _isExecutionMultisigMember(_member);
}

/// @notice Internal function for checking whether an address is a executionMultisig member.
/// @param _member The address to check.
/// @return Whether the address is a executionMultisig member.
function _isExecutionMultisigMember(address _member) internal view returns (bool) {
return isListed(_member);
}

/// @notice Returns true if msg.sender has approved the given proposal tally
/// @param _proposalId The ID of the proposal.
/// @return Whether the msg.sender has approved the proposal tally.
function hasApprovedTally(
uint256 _proposalId,
address _member
) external view virtual returns (bool);

/// @notice Returns the block number of the last executionMultisig change.
/// @return The block number of the last executionMultisig change.
function getLastExecutionMultisigChange() external view returns (uint64) {
return lastExecutionMultisigChange;
}

/// @notice Guard checks that processes key updates are not executed in the same block
/// where the executionMultisig changed.
function _guardExecutionMultisig() internal view {
if (lastExecutionMultisigChange == uint64(block.number)) {
revert ExecutionMultisigUpdatedTooRecently({lastUpdate: lastExecutionMultisigChange});
}
}

/// @notice This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain (see [OpenZeppelin's guide about storage gaps](https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps)).
uint256[49] private __gap;
}
52 changes: 52 additions & 0 deletions packages/contracts/src/IExecutionMultisig.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.17;

interface IExecutionMultisig {
/// @notice Emitted when one or more execution multisig members are added.
/// @param newMembers The addresses of the new execution multisig members.
event ExecutionMultisigMembersAdded(address[] indexed newMembers);

/// @notice Emitted when one or more execution multisig member are removed.
/// @param removedMembers The addresses of the removed execution multisig members.
event ExecutionMultisigMembersRemoved(address[] indexed removedMembers);

/// @notice Thrown if the address list length is out of bounds.
/// @param limit The limit value.
/// @param actual The actual value.
error AddresslistLengthOutOfBounds(uint16 limit, uint256 actual);

/// @notice Thrown if invalid list length
/// @param length The actual length
error InvalidListLength(uint256 length);

/// @notice Thrown if the minimal approvals value is out of bounds (less than 1 or greater than the number of members in the address list).
/// @param limit The maximal value.
/// @param actual The actual value.
error MinApprovalsOutOfBounds(uint16 limit, uint16 actual);

/// @notice Thrown if the execution multisig is updated too recently.
/// @param lastUpdate The block number of the last update.
error ExecutionMultisigUpdatedTooRecently(uint64 lastUpdate);

/// @notice Adds members to the execution multisig.
/// @param _members The addresses to add.
function addExecutionMultisigMembers(address[] calldata _members) external;

/// @notice Removes members from the execution multisig.
/// @param _members The addresses to remove.
function removeExecutionMultisigMembers(address[] calldata _members) external;

/// @notice Checks if an address is a member of the execution multisig.
/// @param _member The address to check.
/// @return Whether the address is a member of the execution multisig.
function isExecutionMultisigMember(address _member) external view returns (bool);

/// @notice Returns true if msg.sender has approved the given proposal tally
/// @param _proposalId The ID of the proposal.
/// @return Whether the msg.sender has approved the proposal tally.
function hasApprovedTally(uint256 _proposalId, address _member) external view returns (bool);

/// @notice Returns the block number of the last executionMultisig change.
/// @return The block number of the last executionMultisig change.
function getLastExecutionMultisigChange() external view returns (uint64);
}
2 changes: 1 addition & 1 deletion packages/contracts/src/IVocdoniProposal.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.17;
pragma solidity 0.8.17;

import {IDAO} from "@aragon/osx/core/dao/IDAO.sol";

Expand Down
41 changes: 1 addition & 40 deletions packages/contracts/src/IVocdoniVoting.sol
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.17;
pragma solidity 0.8.17;

/// @title IVocdoniVoting
/// @author Vocdoni
/// @notice The Vocdoni gasless voting contract interface for the OSX plugin.
/// @notice The voting Proposal is managed gasless on the Vocdoni blockchain.
interface IVocdoniVoting {
/// @notice Emitted when one or more execution multisig members are added.
/// @param newMembers The addresses of the new execution multisig members.
event ExecutionMultisigMembersAdded(address[] newMembers);

/// @notice Emitted when one or more execution multisig member are removed.
/// @param removedMembers The addresses of the removed execution multisig members.
event ExecutionMultisigMembersRemoved(address[] removedMembers);

/// @notice Emitted when the tally of a proposal is set.
/// @param proposalId The ID of the proposal.
/// @param tally The tally.
Expand All @@ -23,16 +15,6 @@ interface IVocdoniVoting {
/// @param proposalId The ID of the proposal.
event TallyApproval(uint256 indexed proposalId, address indexed approver);

/// @notice Thrown if the address list length is out of bounds.
/// @param limit The limit value.
/// @param actual The actual value.
error AddresslistLengthOutOfBounds(uint16 limit, uint256 actual);

/// @notice Thrown if the minimal approvals value is out of bounds (less than 1 or greater than the number of members in the address list).
/// @param limit The maximal value.
/// @param actual The actual value.
error MinApprovalsOutOfBounds(uint16 limit, uint16 actual);

/// @notice Thrown if the vote phase duration is out of bounds (more than 1 year or less than 1 hour).
/// @param limit The limit value.
/// @param actual The actual value.
Expand Down Expand Up @@ -62,10 +44,6 @@ interface IVocdoniVoting {
/// @param lastUpdate The block number of the last update.
error PluginSettingsUpdatedTooRecently(uint64 lastUpdate);

/// @notice Thrown if the execution multisig is updated too recently.
/// @param lastUpdate The block number of the last update.
error ExecutionMultisigUpdatedTooRecently(uint64 lastUpdate);

/// @notice Thrown if the proposal is already executed.
/// @param proposalId The ID of the proposal.
error ProposalAlreadyExecuted(uint256 proposalId);
Expand Down Expand Up @@ -124,23 +102,6 @@ interface IVocdoniVoting {
/// @param totalVotingPower The total voting power
error InvalidTotalVotingPower(uint256 totalVotingPower);

/// @notice Thrown if invalid list length
/// @param length The actual length
error InvalidListLength(uint256 length);

/// @notice Adds new execution multisig members.
/// @param _members The addresses of the new execution multisig members.
function addExecutionMultisigMembers(address[] calldata _members) external;

/// @notice Removes execution multisig members.
/// @param _members The addresses of the execution multisig members to remove.
function removeExecutionMultisigMembers(address[] calldata _members) external;

/// @notice Returns whether an address is a execution ultisig member.
/// @param _member The address to check.
/// @return Whether the address is a execution multisig member.
function isExecutionMultisigMember(address _member) external view returns (bool);

/// @notice Sets the tally of a given proposal.
/// @param _proposalId The ID of the proposal to set the tally of.
/// @param _tally The tally to set.
Expand Down
40 changes: 39 additions & 1 deletion packages/contracts/src/VocdoniProposalUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.17;
pragma solidity 0.8.17;

import {CountersUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";
import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
Expand All @@ -13,6 +13,44 @@ import {IDAO} from "@aragon/osx/core/dao/IDAO.sol";
abstract contract VocdoniProposalUpgradeable is IVocdoniProposal, ERC165Upgradeable {
using CountersUpgradeable for CountersUpgradeable.Counter;

/// @notice A container for the proposal parameters.
/// @param securityBlock Block number used for limiting contract usage when plugin settings are updated
/// @param startDate The timestamp when the proposal starts.
/// @param voteEndDate The timestamp when the proposal ends. At this point the tally can be set.
/// @param tallyEndDate The timestamp when the proposal expires. Proposal can't be executed after.
/// @param totalVotingPower The total voting power of the proposal.
/// @param censusURI The URI of the census.
/// @param censusRoot The root of the census.
struct ProposalParameters {
uint64 securityBlock;
uint64 startDate;
uint64 voteEndDate;
uint64 tallyEndDate;
uint256 totalVotingPower;
string censusURI;
bytes32 censusRoot;
}

/// @notice A container for proposal-related information.
/// @param executed Whether the proposal is executed or not.
/// @param vochainProposalId The ID of the proposal in the Vochain.
/// @param allowFailureMap A bitmap allowing the proposal to succeed, even if individual actions might revert. If the bit at index `i` is 1,
// the proposal succeeds even if the nth action reverts. A failure map value of 0 requires every action to not revert.
/// @param parameters The parameters of the proposal.
/// @param tally The tally of the proposal.
/// @dev tally only supports [[Yes, No, Abstain]] schema in this order. i.e [[10, 5, 2]] means 10 Yes, 5 No, 2 Abstain.
/// @param approvers The approvers of the tally.
/// @param actions The actions to be executed when the proposal passes.
struct Proposal {
bool executed;
bytes32 vochainProposalId;
uint256 allowFailureMap;
ProposalParameters parameters;
uint256[][] tally;
address[] approvers;
IDAO.Action[] actions;
}

/// @notice The incremental ID for proposals and executions.
CountersUpgradeable.Counter private proposalCounter;

Expand Down
Loading

0 comments on commit 7d9d7eb

Please sign in to comment.