diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/design-your-plugin.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/design-your-plugin.adoc index e69de29bb..2bb4ad80c 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/design-your-plugin.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/design-your-plugin.adoc @@ -0,0 +1,304 @@ += Designing your plugin + +== Governance Plugins + +### How to Build a Governance Plugin + +One of the most common use cases for plugins are governance plugins. Governance plugins are plugins DAOs install to help them make decisions. + +#### What are Governance Plugins + +Governance plugins are characterized by the **ability to execute actions in the DAO** they have been installed to. Accordingly, the `EXECUTE_PERMISSION_ID` is granted on installation on the installing DAO to the governance plugin contract. + +```solidity +grant({ + where: installingDao, + who: governancePlugin, + permissionId: EXECUTE_PERMISSION_ID +}); +``` + +Beyond this fundamental ability, governance plugins usually implement two interfaces: + +- xref:guide-develop-plugin/design-your-plugin#proposals[The `IProposal` interface] introducing the **notion of proposals** and how they are created and executed. +- xref:guide-develop-plugin/design-your-plugin#membership[The `IMembership` interface] introducing the **notion of membership** to the DAO. + +#### Examples of Governance Plugins + +Some examples of governance plugins are: + +- link:https://github.com/aragon/osx/tree/main/packages/contracts/src/plugins/governance/majority-voting/token[A token-voting plugin]: Results are based on what the majority votes and the vote's weight is determined by how many tokens an account holds. Ex: Alice has 10 tokens, Bob 2, and Alice votes yes, the yes wins. +- link:https://github.com/aragon/osx/tree/main/packages/contracts/src/plugins/governance/multisig[Multisig plugin]: A determined set of addresses is able to approve. Once `x` amount of addresses approve (as determined by the plugin settings), then the proposal automatically succeeds. +- link:https://github.com/aragon/osx/tree/main/packages/contracts/src/plugins/governance/admin[Admin plugin]: One address can create and immediately execute proposals on the DAO (full control). +- link:https://github.com/aragon/osx/tree/main/packages/contracts/src/plugins/governance/majority-voting/addresslist[Addresslist plugin]: Majority-based voting, where list of addresses are able to vote in decision-making for the organization. Unlike a multisig, everybody here is expected to vote yes/no/abstain within a certain time frame. + +// + +// + + + +### Proposals + +#### The `IProposal` Interface + +The `IProposal` interface is used to create and execute proposals containing actions and a description. + +The interface is defined as follows: + +```solidity +interface IProposal { + /// @notice Emitted when a proposal is created. + /// @param proposalId The ID of the proposal. + /// @param creator The creator of the proposal. + /// @param startDate The start date of the proposal in seconds. + /// @param endDate The end date of the proposal in seconds. + /// @param metadata The metadata of the proposal. + /// @param actions The actions that will be executed if 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. + event ProposalCreated( + uint256 indexed proposalId, + address indexed creator, + uint64 startDate, + uint64 endDate, + bytes metadata, + IDAO.Action[] actions, + uint256 allowFailureMap + ); + + /// @notice Emitted when a proposal is executed. + /// @param proposalId The ID of the proposal. + event ProposalExecuted(uint256 indexed proposalId); + + /// @notice Returns the proposal count determining the next proposal ID. + /// @return The proposal count. + function proposalCount() external view returns (uint256); +} +``` + +This interface contains two events and one function + +##### `ProposalCreated` event + +This event should be emitted when a proposal is created. It contains the following parameters: + +- `proposalId`: The ID of the proposal. +- `creator`: The creator of the proposal. +- `startDate`: The start block number of the proposal. +- `endDate`: The end block number of the proposal. +- `metadata`: This should contain a metadata ipfs hash or any other type of link to the metadata of the proposal. +- `actions`: The actions that will be executed if the proposal passes. +- `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. + +##### `ProposalExecuted` event + +This event should be emitted when a proposal is executed. It contains the proposal ID as a parameter. + +##### `proposalCount` function + +This function should return the proposal count determining the next proposal ID. + +#### Usage + +```solidity +contract MyPlugin is IProposal { + uint256 public proposalCount; + + function createProposal( + uint64 _startDate, + uint64 _endDate, + bytes calldata _metadata, + IDAO.Action[] calldata _actions, + uint256 _allowFailureMap + ) external { + proposalCount++; + emit ProposalCreated( + proposalCount, + msg.sender, + _startDate, + _endDate, + _metadata, + _actions, + _allowFailureMap + ); + } + + function proposalCount() external view returns (uint256) { + return proposalCount; + } + + function executeProposal(uint256 _proposalId) external { + // Execute the proposal + emit ProposalExecuted(_proposalId); + } +} +``` + +### Membership + +#### The `IMembership` Interface + +The `IMembership` interface defines common functions and events for for plugins that keep track of membership in a DAO. This plugins can be used to define who can vote on proposals, who can create proposals, etc. The list of members can be defined in the plugin itself or by a contract that defines the membership like an ERC20 or ERC721 token. + +The interface is defined as follows: + +```solidity title= +/// @notice An interface to be implemented by DAO plugins that define membership. +interface IMembership { + /// @notice Emitted when members are added to the DAO plugin. + /// @param members The list of new members being added. + event MembersAdded(address[] members); + + /// @notice Emitted when members are removed from the DAO plugin. + /// @param members The list of existing members being removed. + event MembersRemoved(address[] members); + + /// @notice Emitted to announce the membership being defined by a contract. + /// @param definingContract The contract defining the membership. + event MembershipContractAnnounced(address indexed definingContract); + + /// @notice Checks if an account is a member of the DAO. + /// @param _account The address of the account to be checked. + /// @return Whether the account is a member or not. + /// @dev This function must be implemented in the plugin contract that introduces the members to the DAO. + function isMember(address _account) external view returns (bool); +} +``` + +The interface contains three events and one function. + +##### `MembersAdded` event + +The members added event should be emitted when members are added to the DAO plugin. It only contains one `address[] members` parameter that references the list of new members being added. + +- `members`: The list of new members being added. + +##### `MembersRemoved` event + +The members added event should be emitted when members are removed from the DAO plugin. It only contains one `address[] members` parameter that references the list of members being removed. + +##### `MembershipContractAnnounced` event + +This event should be emitted during the initialization of the membership plugin to announce the membership being defined by a contract. It contains the defining contract as a parameter. + +##### `isMember` function + +This is a simple function that should be implemented in the plugin contract that introduces the members to the DAO. It checks if an account is a member of the DAO and returns a boolean value. + +#### Usage + +```solidity + +contract MyPlugin is IMembership { + address public membershipContract; + + constructor(address tokenAddress) { + // Initialize the membership contract + // ... + membershipContract = tokenAddress; + emit MembershipContractAnnounced(tokenAddress); + } + + function isMember(address _account) external view returns (bool) { + // Check if the account is a member of the DAO + // ... + } + + // Other plugin functions + function addMembers(address[] memory _members) external { + // Add members to the DAO + // ... + emit MembersAdded(_members); + } + + function removeMembers(address[] memory _members) external { + // Remove members from the DAO + // ... + emit MembersRemoved(_members); + } +} + +``` + +== Choosing the Plugin Upgradeability + +### How to Choose the Base Contract for Your Plugin + +Although it is not mandatory to choose one of our interfaces as the base contracts for your plugins, we do offer some options for you to inherit from and speed up development. + +The needs of your plugin determine the type of plugin you may want to choose. This is based on: + +- the need for a plugin's upgradeability +- whether you need it deployed by a specific deployment method +- whether you need it to be compatible with meta transactions + +In this regard, we provide 3 options for base contracts you can choose from: + +- `Plugin` for instantiation via `new` +- `PluginClones` for [minimal proxy pattern link:https://eips.ethereum.org/EIPS/eip-1167[ERC-1167]] deployment +- `PluginUUPSUpgradeable` for [UUPS pattern link:https://eips.ethereum.org/EIPS/eip-1822[ERC-1822]] deployment + +Let's take a look at what this means for you. + +### Upgradeability & Deployment + +Upgradeability and the deployment method of a plugin contract go hand in hand. The motivation behind upgrading smart contracts is nicely summarized by OpenZeppelin: + +> Smart contracts in Ethereum are immutable by default. Once you create them there is no way to alter them, effectively acting as an unbreakable contract among participants. +> +> However, for some scenarios, it is desirable to be able to modify them [...] +> +> - to fix a bug [...], +> - to add additional features, or simply to +> - change the rules enforced by it. +> +> Here’s what you’d need to do to fix a bug in a contract you cannot upgrade: +> +> 1. Deploy a new version of the contract +> 2. Manually migrate all state from the old one contract to the new one (which can be very expensive in terms of gas fees!) +> 3. Update all contracts that interacted with the old contract to use the address of the new one +> 4. Reach out to all your users and convince them to start using the new deployment (and handle both contracts being used simultaneously, as users are slow to migrate +> +> _source: link:https://docs.openzeppelin.com/learn/upgrading-smart-contracts#whats-in-an-upgrade[OpenZeppelin: What's in an upgrade]_ + +Some key things to keep in mind: + +- With upgradeable smart contracts, you can modify their code while keep using or even extending the storage (see the guide link:https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable[Writing Upgradeable Contracts] by OpenZeppelin). +- To enable upgradeable smart contracts (as well as cheap contract clones), the proxy pattern is used. +- Depending on your upgradeability requirements and the deployment method you choose, you can also greatly reduce the gas costs to distribute your plugin. However, the upgradeability and deployment method can introduce caveats during [the plugin setup](../../01-how-it-works/02-framework/02-plugin-management/02-plugin-setup/index.md), especially when updating from an older version to a new one. + +// TODO:CLAUDIA add table cells style +|=== +| |`new` Instantiation | Minimal Proxy (Clones)| Transparent Proxy| UUPS Proxy + +| upgradeability +|no +| no +| yes +| yes +| gas costs +| high +| very low +| moderate +| low +| difficulty +| low +| low +| high +| high +|=== + +Accordingly, we recommend to use link:https://eips.ethereum.org/EIPS/eip-1167[minimal proxies (ERC-1167)] for non-upgradeable and link:https://eips.ethereum.org/EIPS/eip-1822[UUPS proxies (ERC-1822)] for upgradeable plugins. +To help you with developing and deploying your plugin within the Aragon infrastructure, we provide the following implementation that you can inherit from: + +- `Plugin` for instantiation via `new` +- `PluginClones` for [minimal proxy pattern link:https://eips.ethereum.org/EIPS/eip-1167[ERC-1167]] deployment +- `PluginUUPSUpgradeable` for [UUPS pattern link:https://eips.ethereum.org/EIPS/eip-1822[ERC-1822]] deployment + +#### Caveats of Non-upgradeable Plugins + +Aragon plugins using the non-upgradeable smart contracts bases (`Plugin`, `PluginCloneable`) can be cheap to deploy (i.e., using clones) but **cannot be updated**. + +Updating, in distinction from upgrading, will call Aragon OSx' internal process for switching from an older plugin version to a newer one. + +WARNING: To switch from an older version of a non-upgradeable contract to a newer one, the underlying contract has to be replaced. In consequence, the state of the older version is not available in the new version anymore, unless it is migrated or has been made publicly accessible in the old version through getter functions. \ No newline at end of file diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/manage-dao-plugins.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/manage-dao-plugins.adoc index e69de29bb..de4d539c0 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/manage-dao-plugins.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/manage-dao-plugins.adoc @@ -0,0 +1,47 @@ += Manage your DAO's Plugins + +== How to manage the Plugins within your DAO + +// + +You can install, uninstall or update any plugin into your DAO. If you want to dive deeper into plugins, check out xref:core/plugins.adoc[how plugins work here]. + +Before diving deeper into this guide, make sure that you understand xref:core/permissions.adoc[permissions] and know about the xref:core/dao.adoc[DAO executor]. + +### How to create a DAO with Plugins + +When you create your DAO, you must **install at least one functioning governance plugin** (meaning one plugin having the `EXECUTION_PERMISSION`) so your have a mechanism of executing actions on behalf of your DAO. +This is crucial because otherwise nobody can operate the DAO and it would become incapacitated right after it was created. You would have spent gas for nothing. + +:::info +If you create your DAO through the link:https://app.aragon.org[Aragon App] or the link:https://devs.aragon.org/docs/sdk[Aragon SDK], this will be checked and you will be warned in case you have not selected a suitable Aragon plugin. +::: + +Although the easiest (and recommended) way to create your DAO is through the link:https://app.aragon.org[Aragon App] or the link:https://devs.aragon.org/docs/sdk[Aragon SDK], you can also do it directly from the protocol through calling on the link:https://github.com/aragon/osx/blob/develop/packages/contracts/src/framework/dao/DAOFactory.sol#L63[`createDAO` function] from the `DAOFactory` contract and passing it the calldata `DAOSettings` for your DAO as well as the `PluginSettings` array referencing the plugins and the settings to be installed upon DAO creation. + +// + +#### How to change a DAO's Governance Setup after a DAO has been created + +After a DAO is created with at least one plugin installed with `EXECUTE_PERMISSION` on the DAO, it's likely you may want to change change your governance setup later on by xref:framework/plugin-setup-processor.adoc[installing, updating, or uninstalling plugins]. + +Here, it is very important that you **maintain at least one functioning governance plugin** (a contract with `EXECUTE_PERMISSION` on the DAO) so that your assets are not locked in the future. In that regard, you want to be careful to not accidentally: + +- uninstall every plugin within your DAO, or +- update or upgrade the plugin or otherwise change the internal plugin settings. + +If you do that, nobody would be able to create proposals and execute actions on the DAO anymore. Accordingly, DAOs must review proposals requesting to change the governance setup with utmost care before voting for them. In the next section, we explain how to review a proposal properly and what to pay attention too. + + + +### How to maintain Execution Permission on the DAO + +A very important thing to consider when operating your DAO is to make sure that you do not lock it - meaning, you allow it into a state where the DAO cannot execute actions anymore. + +The accidental loss of the permission to execute actions on your DAO (xref:core/permissions.adoc#permissions_native_to_the_dao_contract[the `EXECUTION_PERMISSION_ID` permission]) incapacitates your DAO. If this happens, you are not able to withdraw funds or act through the DAO, unless you have the `ROOT_PERMISSION_ID` on the DAO. + + +WARNING: Do not interact directly with the smart contracts unless you know exactly what you are doing, **especially if this involves granting or revoking permissions**. Instead, use the Aragon App or Aragon SDK for creating and managing your DAO and interacting with the smart contracts. + +If you interact with the Aragon OSx protocol through the Aragon App frontend or the Aragon SDK and use only audited and verified plugins, this will not happen. +However, diligence and care is required in some situations. \ No newline at end of file diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/upgrade-dao.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/upgrade-dao.adoc index e69de29bb..ea6ce5055 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/upgrade-dao.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/upgrade-dao.adoc @@ -0,0 +1,11 @@ += Upgrade your DAO + +== Upgrading to Future Aragon OSx Protocol Versions + +At Aragon, we are constantly working on improving the Aragon OSx framework. + +To make it easy for your DAO to switch to future Aragon OSx protocol versions, we added the possibility to upgrade our protocol in the future. + +Whenever we provide a new Aragon OSx protocol version, it will be possible to upgrade your DAO and associated plugins through your DAO dashboard. + +link:https://aragondevelopers.substack.com/[Add your email here] if you'd like to receive updates when this happens! \ No newline at end of file