Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: move contracts #1

Merged
merged 19 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 2 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,13 @@
# Aragon OSX Plugin Template [![Hardhat][hardhat-badge]][hardhat] [![License: AGPL v3][license-badge]][license]
# Multisig Plugin [![Hardhat][hardhat-badge]][hardhat] [![License: AGPL v3][license-badge]][license]

[hardhat]: https://hardhat.org/
[hardhat-badge]: https://img.shields.io/badge/Built%20with-Hardhat-FFDB1C.svg
[license]: https://opensource.org/licenses/AGPL-v3
[license-badge]: https://img.shields.io/badge/License-AGPL_v3-blue.svg

## Quickstart

After [creating a new repository from this template](https://github.com/new?template_name=osx-plugin-template-hardhat&template_owner=aragon), cloning, and opening it in your IDE, run

```sh
yarn install && cd packages/contracts && yarn install && yarn build && yarn typechain
```

Meanwhile, create an `.env` file from the `.env.example` file and put in the API keys for the services that you want to use.
You can now develop a plugin by changing the `src/MyPlugin.sol` and `src/MyPluginSetup.sol` files. You can directly import contracts from [Aragon OSx](https://github.com/aragon/osx) as well as OpenZeppelin's [openzeppelin-contracts](https://github.com/OpenZeppelin/openzeppelin-contracts) and [openzeppelin-contracts-upgradeable](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable) that are already set up for you.

```sol
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.17;

import {IDAO, PluginUUPSUpgradeable} from "@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol";
import {SafeCastUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol';

contract MyPlugin is PluginUUPSUpgradeable {
//...
};
```

The initial `MyPlugin` and `MyPluginSetup` example comes with unit test, integration test, and test helpers in the `package/contracts/test` folder that you can reuse.

To build and test your contracts, run

```sh
yarn clean && yarn build && yarn test
```

## Project

The root folder of the repo includes three subfolders:
The root folder of the repo includes two subfolders:

```markdown
.
Expand Down
17 changes: 17 additions & 0 deletions packages/contracts/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Multisig Plugin

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to the [Aragon OSx Plugin Versioning Convention](https://devs.aragon.org/docs/osx/how-to-guides/plugin-development/publication/versioning).

## v1.3

### Added

- Copied files from [aragon/osx commit 1130df](https://github.com/aragon/osx/commit/1130dfce94fd294c4341e91a8f3faccc54cf43b7)

### Changed

- Used `ProxyLib` from `osx-commons-contracts` for the minimal proxy deployment in `MultisigSetup`.
- Hard-coded the `bytes32 internal constant EXECUTE_PERMISSION_ID` constant in `MultisigSetup` until it is available in `PermissionLib`.
9 changes: 6 additions & 3 deletions packages/contracts/deploy/20_new_version/22_setup_conclude.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {PLUGIN_SETUP_CONTRACT_NAME} from '../../plugin-settings';
import {AdminSetup__factory, Admin__factory} from '../../typechain';
import {MultisigSetup__factory, Multisig__factory} from '../../typechain';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import path from 'path';
Expand All @@ -17,9 +17,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {

// Get the plugin setup address
const setupDeployment = await deployments.get(PLUGIN_SETUP_CONTRACT_NAME);
const setup = AdminSetup__factory.connect(setupDeployment.address, deployer);
const setup = MultisigSetup__factory.connect(
setupDeployment.address,
deployer
);
// Get the plugin implementation address
const implementation = Admin__factory.connect(
const implementation = Multisig__factory.connect(
await setup.implementation(),
deployer
);
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const config: HardhatUserConfig = {
hardhat: {
throwOnTransactionFailures: true,
throwOnCallFailures: true,
blockGasLimit: BigNumber.from(10).pow(6).mul(30).toNumber(), // 30 million, really high to test some things that are only possible with a higher block gas limit
blockGasLimit: BigNumber.from(10).pow(6).mul(300).toNumber(), // 300 million, really high to test some things that are only possible with a higher block gas limit
gasPrice: BigNumber.from(10).pow(9).mul(150).toNumber(), // 150 gwei
accounts: getHardhatNetworkAccountsConfig(
Object.keys(namedAccounts).length
Expand Down
3 changes: 2 additions & 1 deletion packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"@aragon/osx-commons-configs": "0.1.0",
"@aragon/osx-ethers": "1.4.0-alpha.0",
"@aragon/osx-commons-sdk": "0.0.1-alpha.5",
"@aragon/osx-artifacts": "1.3.1",
"@aragon/osx-v1.0.0": "npm:@aragon/[email protected]",
"@aragon/osx-v1.3.0": "npm:@aragon/[email protected]",
"@ethersproject/abi": "^5.7.0",
"@ethersproject/abstract-signer": "^5.7.0",
"@ethersproject/bignumber": "^5.7.0",
Expand Down
9 changes: 4 additions & 5 deletions packages/contracts/plugin-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import buildMetadata from './src/build-metadata.json';
import releaseMetadata from './src/release-metadata.json';
import {VersionTag} from '@aragon/osx-commons-sdk';

export const PLUGIN_CONTRACT_NAME = 'MyPlugin'; // This must match the filename `packages/contracts/src/MyPlugin.sol` and the contract name `MyPlugin` within.
export const PLUGIN_SETUP_CONTRACT_NAME = 'MyPluginSetup'; // This must match the filename `packages/contracts/src/MyPluginSetup.sol` and the contract name `MyPluginSetup` within.
export const PLUGIN_REPO_ENS_SUBDOMAIN_NAME = 'my'; // This will result in the ENS domain name 'my.plugin.dao.eth'
export const PLUGIN_CONTRACT_NAME = 'Multisig';
export const PLUGIN_SETUP_CONTRACT_NAME = 'MultisigSetup';
export const PLUGIN_REPO_ENS_SUBDOMAIN_NAME = 'multisig'; // 'multisig.plugin.dao.eth'

export const VERSION: VersionTag = {
release: 1, // Increment this number ONLY if breaking/incompatible changes were made. Updates between releases are NOT possible.
build: 1, // Increment this number if non-breaking/compatible changes were made. Updates to newer builds are possible.
build: 3, // Increment this number if non-breaking/compatible changes were made. Updates to newer builds are possible.
};

/* DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING */
export const METADATA = {
build: buildMetadata,
release: releaseMetadata,
Expand Down
18 changes: 11 additions & 7 deletions packages/contracts/src/IMultisig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,27 @@

pragma solidity ^0.8.8;

import {IDAO} from "@aragon/osx-commons-contracts/src/dao/IDAO.sol";

/// @title IMultisig
/// @author Aragon Association - 2023
/// @notice An interface for an on-chain multisig governance plugin in which a proposal passes if X out of Y approvals are met.
/// @notice An interface for an on-chain multisig governance plugin in which a proposal passes
/// if X out of Y approvals are met.
/// @custom:security-contact [email protected]
interface IMultisig {
/// @notice Adds new members to the address list. Previously, it checks if the new address list length would be greater than `type(uint16).max`, the maximal number of approvals.
/// @notice Adds new members to the address list. Previously, it checks if the new address
/// list length would be greater than `type(uint16).max`, the maximal number of approvals.
/// @param _members The addresses of the members to be added.
function addAddresses(address[] calldata _members) external;

/// @notice Removes existing members from the address list. Previously, it checks if the new address list length is at least as long as the minimum approvals parameter requires. Note that `minApprovals` is must be at least 1 so the address list cannot become empty.
/// @notice Removes existing members from the address list. Previously, it checks if the
/// new address list length is at least as long as the minimum approvals parameter requires.
/// Note that `minApprovals` is must be at least 1 so the address list cannot become empty.
/// @param _members The addresses of the members to be removed.
function removeAddresses(address[] calldata _members) external;

/// @notice Approves and, optionally, executes the proposal.
/// @param _proposalId The ID of the proposal.
/// @param _tryExecution If `true`, execution is tried after the approval cast. The call does not revert if execution is not possible.
/// @param _tryExecution If `true`, execution is tried after the approval cast.
/// The call does not revert if execution is not possible.
function approve(uint256 _proposalId, bool _tryExecution) external;

/// @notice Checks if an account can participate on a proposal vote. This can be because the vote
Expand All @@ -36,7 +39,8 @@ interface IMultisig {
/// @return True if the proposal can be executed, false otherwise.
function canExecute(uint256 _proposalId) external view returns (bool);

/// @notice Returns whether the account has approved the proposal. Note, that this does not check if the account is listed.
/// @notice Returns whether the account has approved the proposal. Note, that this does not check
// if the account is listed.
/// @param _proposalId The ID of the proposal.
/// @param _account The account address to be checked.
/// @return The vote option cast by a voter for a certain proposal.
Expand Down
35 changes: 26 additions & 9 deletions packages/contracts/src/Multisig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

pragma solidity ^0.8.8;

/* solhint-disable max-line-length */
import {SafeCastUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

import {IMembership} from "@aragon/osx-commons-contracts/src/plugin/extensions/membership/IMembership.sol";
Expand All @@ -12,10 +13,12 @@ import {IDAO} from "@aragon/osx-commons-contracts/src/dao/IDAO.sol";

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

/* solhint-enable max-line-length */

/// @title Multisig
/// @author Aragon Association - 2022-2023
/// @notice The on-chain multisig governance plugin in which a proposal passes if X out of Y approvals are met.
/// @dev v1.2 (Release 1, Build 2)
/// @dev v1.3 (Release 1, Build 3)
/// @custom:security-contact [email protected]
contract Multisig is
IMultisig,
Expand All @@ -32,7 +35,9 @@ contract Multisig is
/// @param parameters The proposal-specific approve settings at the time of the proposal creation.
/// @param approvers The approves casted by the approvers.
/// @param actions The actions to be executed when the proposal passes.
/// @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 `i`th action reverts. A failure map value of 0 requires every action to not revert.
/// @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 `i`th action reverts.
/// A failure map value of 0 requires every action to not revert.
struct Proposal {
bool executed;
uint16 approvals;
Expand Down Expand Up @@ -74,13 +79,15 @@ contract Multisig is
keccak256("UPDATE_MULTISIG_SETTINGS_PERMISSION");

/// @notice A mapping between proposal IDs and proposal information.
// solhint-disable-next-line named-parameters-mapping
mapping(uint256 => Proposal) internal proposals;

/// @notice The current plugin settings.
MultisigSettings public multisigSettings;

/// @notice Keeps track at which block number the multisig settings have been changed the last time.
/// @dev This variable prevents a proposal from being created in the same block in which the multisig settings change.
/// @dev This variable prevents a proposal from being created in the same block in which the multisig
/// settings change.
uint64 public lastMultisigSettingsChange;

/// @notice Thrown when a sender is not allowed to create a proposal.
Expand All @@ -99,7 +106,8 @@ contract Multisig is
/// @param proposalId The ID of the proposal.
error ProposalExecutionForbidden(uint256 proposalId);

/// @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).
/// @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);
Expand Down Expand Up @@ -166,7 +174,8 @@ contract Multisig is
) external auth(UPDATE_MULTISIG_SETTINGS_PERMISSION_ID) {
uint256 newAddresslistLength = addresslistLength() + _members.length;

// Check if the new address list length would be greater than `type(uint16).max`, the maximal number of approvals.
// 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,
Expand Down Expand Up @@ -209,12 +218,16 @@ contract Multisig is
/// @notice Creates a new multisig proposal.
/// @param _metadata The metadata of the proposal.
/// @param _actions The actions that will be executed after the proposal passes.
/// @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 `i`th action reverts. A failure map value of 0 requires every action to not revert.
/// @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 `i`th action reverts.
/// A failure map value of 0 requires every action to not revert.
/// @param _approveProposal If `true`, the sender will approve the proposal.
/// @param _tryExecution If `true`, execution is tried after the vote cast. The call does not revert if early execution is not possible.
/// @param _tryExecution If `true`, execution is tried after the vote cast. The call does not revert if early
/// execution is not possible.
/// @param _startDate The start date of the proposal.
/// @param _endDate The end date of the proposal.
/// @return proposalId The ID of the proposal.
// solhint-disable-next-line code-complexity
function createProposal(
bytes calldata _metadata,
IDAO.Action[] calldata _actions,
Expand All @@ -230,7 +243,9 @@ contract Multisig is

uint64 snapshotBlock;
unchecked {
snapshotBlock = block.number.toUint64() - 1; // The snapshot block must be mined already to protect the transaction against backrunning transactions causing census changes.
// The snapshot block must be mined already to protect the transaction against backrunning transactions
// causing census changes.
snapshotBlock = block.number.toUint64() - 1;
}

// Revert if the settings have been changed in the same block as this proposal should be created in.
Expand Down Expand Up @@ -323,7 +338,9 @@ contract Multisig is
/// @return approvals The number of approvals casted.
/// @return parameters The parameters of the proposal vote.
/// @return actions The actions to be executed in the associated DAO after the proposal has passed.
/// @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 `i`th action reverts. A failure map value of 0 requires every action to not revert.
/// @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 `i`th action reverts.
/// A failure map value of 0 requires every action to not revert.
function getProposal(
uint256 _proposalId
)
Expand Down
Loading
Loading