From 43876a2840cdd075e2b4054761346b761829ac18 Mon Sep 17 00:00:00 2001 From: Claudia Barcelo Date: Wed, 11 Dec 2024 14:01:19 +0100 Subject: [PATCH] feat: docs improve heading and content on pages (#626) * change sidebar * new docs * add docs images * feat: add missing pages in framework * feat: add missing pages in guide set up dao and develop plugin * change image urls * add reference links * ci: remove how-it-works/core from docs since all pages have been moved to core * fix: update the reference to point to the corresponding core or framework page * feat: add initial core index page * ci: remove how-it-works/framework files since all pages were moved to framework * fix: update reference link to use the correct one * fix: update ref links to point to right pages * feat: move develop plugin pages to the correct folder * feat: move information to correct folder page, fix link references * fix broken links * feat: improve and fix overview page * fix: heading * feat: improve formatting and structure in core index page * feat: ifx heading and improve wording in dao page * fixL plugins page heading * fix: permissions page heading * feat: update framework init page heading * feat: rephrase the dao factory and registry page and fix heading * feat: enhance the plugin repo page * feat: enhance and update heading in repo factory and registry page * feat: enhance the plugin setup processor and ens registrar page and heading * feat: order dao guide init page * feat: enhance page and fix heading * feat: custom condition page fix heading and listed items format * feat: enhance keep dao safe dao and upgrade dao pages, fix heading * feat: improve content and heading in the guide develop a plugin pages --------- Co-authored-by: Giorgi Lagidze --- packages/contracts/docs/antora.yml | 2 +- packages/contracts/docs/config.js | 2 +- .../docs/modules/ROOT/pages/core/dao.adoc | 34 +- .../docs/modules/ROOT/pages/core/index.adoc | 33 +- .../modules/ROOT/pages/core/permissions.adoc | 22 +- .../docs/modules/ROOT/pages/core/plugins.adoc | 8 +- .../pages/framework/dao-factory-registry.adoc | 51 ++- .../ROOT/pages/framework/ens-registrar.adoc | 17 +- .../modules/ROOT/pages/framework/index.adoc | 18 +- .../ROOT/pages/framework/plugin-repos.adoc | 29 +- .../framework/plugin-setup-processor.adoc | 23 +- .../framework/repo-factory-registry.adoc | 17 +- .../design-your-plugin.adoc | 50 ++- .../follow-best-practices.adoc | 4 +- .../pages/guide-develop-plugin/index.adoc | 8 +- .../publishing-plugin.adoc | 26 +- .../guide-develop-plugin/upgrade-plugin.adoc | 363 +++++++++--------- .../write-plugin-contract.adoc | 19 +- .../write-plugin-setup-contract.adoc | 17 +- .../write-upgradeable-plugin.adoc | 55 +-- .../custom-permission-condition.adoc | 54 ++- .../guide-set-up-dao/execute-actions.adoc | 22 +- .../ROOT/pages/guide-set-up-dao/index.adoc | 13 +- .../pages/guide-set-up-dao/keep-dao-safe.adoc | 87 ++--- .../guide-set-up-dao/manage-dao-plugins.adoc | 10 +- .../pages/guide-set-up-dao/upgrade-dao.adoc | 2 +- .../plugin-development/index.adoc | 3 +- .../docs/modules/ROOT/pages/index.adoc | 31 +- .../docs/modules/api/pages/core.adoc | 175 +++------ .../docs/modules/api/pages/framework.adoc | 170 ++------ packages/contracts/src/framework/README.adoc | 6 +- 31 files changed, 580 insertions(+), 791 deletions(-) diff --git a/packages/contracts/docs/antora.yml b/packages/contracts/docs/antora.yml index fd484391e..4428eadc8 100644 --- a/packages/contracts/docs/antora.yml +++ b/packages/contracts/docs/antora.yml @@ -1,5 +1,5 @@ name: osx-contracts -title: Core +title: OSX Contracts version: 1.x prerelease: false nav: diff --git a/packages/contracts/docs/config.js b/packages/contracts/docs/config.js index 4afb34bc1..bdced2c53 100644 --- a/packages/contracts/docs/config.js +++ b/packages/contracts/docs/config.js @@ -8,7 +8,7 @@ const helpers = require(path.resolve(__dirname, './templates/helpers')); // overwrite the functions. helpers.version = () => version; helpers.githubURI = () => repository.url; -helpers.readmePath = (opts) => { +helpers['readme-path'] = opts => { return 'src/' + opts.data.root.id.replace(/\.adoc$/, '') + '/README.adoc'; }; diff --git a/packages/contracts/docs/modules/ROOT/pages/core/dao.adoc b/packages/contracts/docs/modules/ROOT/pages/core/dao.adoc index efff0fc38..d31898a35 100644 --- a/packages/contracts/docs/modules/ROOT/pages/core/dao.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/core/dao.adoc @@ -6,48 +6,50 @@ In this section, you will learn about the core functionality of every Aragon OSx The `DAO` contract is the identity and basis of your organization. It is the address carrying the DAO’s ENS name, metadata, and holding the funds. Furthermore, it has **six base functionalities** being commonly found in other DAO frameworks in the ecosystem. -### 1. Execution of Arbitrary Actions +=== 1. Execution of Arbitrary Actions The most important and basic functionality of your DAO is the **execution of arbitrary actions**, which allows you to execute the DAO's own functions as well as interacting with the rest of the world, i.e., calling methods in other contracts and sending assets to other addresses. -NOTE: Typically, actions are scheduled in a proposal in a governance - xref:core/plugins.adoc[plugin installed to your DAO] +NOTE: Actions are typically executed through governance proposals. These proposals can implement various decision-making mechanisms, such as token-weighted voting or multisig requirements, and may include execution delays to ensure proper governance oversight before actions are executed. Multiple `Action` structs can be put into one `Action[]` array and executed in a single transaction via the `execute` function. To learn more about actions and advanced features of the DAO executor, visit the xref:core/actions.adoc[A Deep Dive Into Actions]. -### 2. Asset Management +=== 2. Asset Management -The DAO provides basic **asset management** functionality to deposit, withdraw, and keep track of +The DAO provides basic **asset management** functionality to deposit, withdraw, and keep track of: -- native -- link:https://eips.ethereum.org/EIPS/eip-20[ERC-20 (Token Standard)] -- link:https://eips.ethereum.org/EIPS/eip-721[ERC-721 (NFT Standard)], and -- link:https://eips.ethereum.org/EIPS/eip-1155[ERC-1155 (Multi Token Standard)] +* native ETH +* link:https://eips.ethereum.org/EIPS/eip-20[ERC-20 (Token Standard)] +* link:https://eips.ethereum.org/EIPS/eip-721[ERC-721 (NFT Standard)] +* link:https://eips.ethereum.org/EIPS/eip-1155[ERC-1155 (Multi Token Standard)] tokens in the treasury. -In the future, more advanced asset management and finance functionality can be added to your DAO in the form of xref:core/plugins.adoc[plugins]. +In the future, more advanced asset management and finance functionality can be added to your DAO by installing additional plugins. -### 3. Upgradeability +NOTE: Don't worry if you're not familiar with plugins yet - they will be explained in detail in a later section. For now, you can think of them just like plugins in other software: modular pieces that provide new features and can be plugged in or removed as needed. + +=== 3. Upgradeability Your DAO contract has the ability to be upgraded to a newer version (see xref:guide-develop-plugin/upgrade-plugin.adoc[Upgrade your DAO]) if a new version of Aragon OSx is released in the future. These upgrades allow your DAO to smoothly transition to a new protocol version unlocking new features. -### 4. Callback Handling +=== 4. Callback Handling To interact with the DAO, external contracts might require certain callback functions to be present. Examples are the `onERC721Received` and `onERC1155Received` / `onERC1155BatchReceived` functions required by the link:https://eips.ethereum.org/EIPS/eip-721[ERC-721 (NFT Standard)] and link:https://eips.ethereum.org/EIPS/eip-1155[ERC-1155 (Multi Token Standard)] tokens. Our `CallbackHandler` allows to register the required callback responses dynamically so that the DAO contract does not need to be upgraded. -### 5. Signature Validation +=== 5. Signature Validation -Currently, externally owned accounts (EOAs) can sign messages with their associated private keys, but contracts cannot. +Currently, Externally Owned Accounts (EOAs) can sign messages with their associated private keys, but contracts cannot. An exemplary use case is a decentralized exchange with an off-chain order book, where buy/sell orders are signed messages. To accept such a request, both, the external service provider and caller need to follow a standard with which the signed message of the caller can be validated. By supporting the link:https://eips.ethereum.org/EIPS/eip-721[ERC-721 (NFT Standard)], your DAO can validate signatures via its `isValidSignature` function that forwards the call to a signature validator contract. -### 6. Permission Management +=== 6. Permission Management -Lastly, it is essential that only the right entities (e.g., the DAO itself or trusted addresses) have permission to use the above-mentioned functionalities. This is why Aragon OSx DAOs contain a flexible and battle-tested **permission manager** being able to assign permissions for the above functionalities to specific addresses. +Lastly, it is essential that only the right entities (e.g., the DAO itself or trusted addresses) have permission to use the above-mentioned functionalities. This is why Aragon OSx DAOs contain a flexible and battle-tested **Permission Manager** being able to assign permissions for the above functionalities to specific addresses. Although possible, the permissions to execute arbitrary actions or upgrade the DAO should not be given to EOAs as this poses a security risk to the organization if the account is compromised or acts adversarial. Instead, the permissions for the above-mentioned functionalities are better restricted to the `DAO` contract itself and triggered through governance xref:core/plugins.adoc[plugins] that you can install on your DAO. -To learn more, visit the xref:core/permissions.adoc[permission manager] section. \ No newline at end of file +To learn more about permissions and how they work in detail, check out the xref:core/permissions.adoc[Permission Manager] section. \ No newline at end of file diff --git a/packages/contracts/docs/modules/ROOT/pages/core/index.adoc b/packages/contracts/docs/modules/ROOT/pages/core/index.adoc index 93435f810..34af513f7 100644 --- a/packages/contracts/docs/modules/ROOT/pages/core/index.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/core/index.adoc @@ -1,22 +1,27 @@ -= The Smart Contracts behind DAOs += The Contracts behind DAOs -== The Contracts Constituting Your DAO +In a nutshell, your Aragon OSx DAO consists of three pieces **DAO**, **Permission Manager**, and **Plugins**. -In a nutshell, your Aragon OSx DAO consists of three pieces: -1. **The DAO contract:** The DAO contract is where the **core functionality** of the protocol lies. It is in charge of: +== The DAO contract - - Representing the identity of the DAO (ENS name, logo, description, other metadata) - - Keeping the treasury - - Executing arbitrary actions to - - Transfer assets - - Call its own functions - - Call functions in external contracts - - Providing general technical utilities (signature validation, callback handling) +The DAO contract is where the **core functionality** of the protocol lies. +It is in charge of: + * Representing the identity of the DAO (ENS name, logo, description, other metadata) + * Keeping the treasury + * Executing arbitrary actions to + ** Transfer assets + ** Call its own functions + ** Call functions in external contracts + * Providing general technical utilities (signature validation, callback handling) -2. **The Permission Manager:** The permission manager is part of the DAO contract and the center of our protocol architecture. It **manages permissions for your DAO** by specifying which addresses have permission to call distinct functions on contracts associated with your DAO. +== The Permission Manager -3. **Plugins:** Any custom functionality can be added or removed through plugins, allowing you to **fully customize your DAO**. These plugins can be related to +The permission manager is part of the DAO contract and the center of our protocol architecture. It **manages permissions for your DAO** by specifying which addresses have permission to call distinct functions on contracts associated with your DAO. + +== Plugins + +Any custom functionality can be added or removed through plugins, allowing you to **fully customize your DAO**. These plugins can be related to - Governance (e.g., token voting, one-person one-vote) - Asset management (e.g., ERC-20 or NFT minting, token streaming, DeFi) @@ -29,6 +34,8 @@ image::dao-plugin.drawio.svg[align="center"] An exemplary DAO setup showing interactions between the three core contract pieces triggered by different user groups: The `DAO` contract in blue containing the `PermissionManager` in red, respectively, as well as two `Plugin` contracts in green. Function calls are visualized as black arrows and require permission checks (red, dashed arrow). In this example, the permission manager determines whether the token voting plugin can execute actions on the DAO, a member can change its settings, or if a DeFi-related plugin is allowed to invest in a certain, external contract. + +== Walkthrough In the upcoming sections, you will learn about each of them in more depth. // reorder if the nav bar is updated diff --git a/packages/contracts/docs/modules/ROOT/pages/core/permissions.adoc b/packages/contracts/docs/modules/ROOT/pages/core/permissions.adoc index dffef9f15..e8a350502 100644 --- a/packages/contracts/docs/modules/ROOT/pages/core/permissions.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/core/permissions.adoc @@ -7,7 +7,7 @@ Permissions between contracts and wallets allow a DAO to manage and govern its a Here, you will learn how the permissions in Aragon OSx work, how they can be granted and revoked from wallets and contracts, and how they are managed through the DAO. -As we mentioned earlier, it is essential that only the right person or contract can execute a certain action. As a developer, you might have seen or used link:https://docs.openzeppelin.com/contracts/2.x/api/ownership#Ownable[modifiers such as onlyOwner] in contracts. This `onlyOwner` modifier provides basic access control to your DAO: only the `owner` address is permitted to execute the function to which the modifier is attached. +As we mentioned earlier, it is essential that only the right person or contract can execute a certain action. As a developer, you might have seen or used link:https://docs.openzeppelin.com/contracts/2.x/api/ownership#Ownable[modifiers such as `onlyOwner`] in contracts. This `onlyOwner` modifier provides basic access control to your DAO: only the `owner` address is permitted to execute the function to which the modifier is attached. In Aragon OSx, we follow the same approach but provide more advanced functionality: Each `DAO` contracts includes a `PermissionManager` contract allowing to flexibly, securely, and collectively manage permissions through the DAO and, thus, govern its actions. @@ -15,7 +15,7 @@ This `PermissionManager`, called `ACL` in previous Aragon OS versions, was one b The code and configuration of a DAO specifies which wallets or contracts (`who`) are allowed to call which authorized functions on a target contract (`where`). Identifiers, permissions, and modifiers link everything together. -### Permission Identifiers +=== Permission Identifiers To differentiate between different permissions, permission **identifiers** are used that you will frequently find at the top of Aragon OSx contracts. They look something like this: @@ -23,7 +23,7 @@ To differentiate between different permissions, permission **identifiers** are u bytes32 public constant EXECUTE_PERMISSION_ID = keccak256("EXECUTE_PERMISSION"); ``` -### Permissions +=== Permissions A permission specifies an address `who` being allowed to call certain functions on a contract address `where`. In the `PermissionManager` contract, permissions are defined as the concatenation of the word `"PERMISSION"` with the `who` and `where` address, as well as the `bytes32` permission identifier `permissionId`. @@ -45,7 +45,7 @@ mapping(bytes32 => address) internal permissionsHashed; Here, the `bytes32` keys are the permission hashes and the `address` values are either zero-address flags, such as `ALLOW_FLAG = address(2)` and `UNSET_FLAG = address(0)` indicating if the permission is set, or an actual address pointing to a `PermissionCondition` contract, which is discussed in the next section of this guide. -### Authorization Modifiers +=== Authorization Modifiers Using **authorization modifiers** is how we make functions permissioned. Permissions are associated with functions by adding the `auth` modifier, which includes the permission identifier in the function’s definition header. @@ -63,11 +63,11 @@ function execute( returns (bytes[] memory execResults, uint256 failureMap); ``` -### Managing Permissions +=== Managing Permissions To manage permissions, the DAO contract has the `grant`, `revoke` and `grantWithCondition` functions in its public interface. -#### Granting and Revoking Permissions +==== Granting and Revoking Permissions The `grant` and `revoke` functions are the main functions we use to manage permissions. Both receive the `_permissionId` identifier of the permission and the `_where` and `_who` addresses as arguments. @@ -93,7 +93,7 @@ This means, that these functions can only be called through the DAO’s `execute NOTE: Typically, the `EXECUTE_PERMISSION_ID` permission is granted to governance contracts (such as a majority voting plugin owned by the DAO or a multi-sig). Accordingly, a proposal is often required to change permissions. Exceptions are, again, the xref:framework/dao-factory-registry.adoc[DAO creation] and xref:framework/plugin-setup-processor.adoc[plugin setup] processes. -#### Granting Permission with Conditions +==== Granting Permission with Conditions Aragon OSx supports relaying the authorization of a function call to another contract inheriting from the `IPermissionCondition` interface. This works by granting the permission with the `grantWithCondition` function @@ -106,13 +106,11 @@ function grantWithCondition( ) external auth(_where, ROOT_PERMISSION_ID) {} ``` -and specifying the `_condition` contract address. This provides full flexibility to customize the conditions under which the function call is allowed. - -Typically, conditions are written specifically for and installed together with xref:core/plugins.adoc[plugins] +and specifying the `_condition` contract address. This provides full flexibility to customize the conditions under which the function call is allowed. Typically, conditions are written specifically for and installed together with xref:core/plugins.adoc[plugins]. To learn more about this advanced topic and possible applications, visit the xref:guide-set-up-dao/custom-permission-condition.adoc[permission conditions]. -#### Granting Permission to `ANY_ADDR` +==== Granting Permission to `ANY_ADDR` In combination with conditions, the arguments `_where` and `_who` can be set to `ANY_ADDR = address(type(uint160).max)`. Granting a permission with `_who: ANY_ADDR` has the effect that any address can now call the function so that it behaves as if the `auth` modifier is not present. @@ -137,7 +135,7 @@ Moreover, if a condition is set, we return its `isGranted` result and do not fal 2. Condition with generic `_who: ANY_ADDR` and specific `_where`. 3. Condition with specific `_where` and generic `_who: ANY_ADDR`. -### Permissions Native to the `DAO` Contract +=== Permissions Native to the DAO Contract The following functions in the DAO are permissioned: diff --git a/packages/contracts/docs/modules/ROOT/pages/core/plugins.adoc b/packages/contracts/docs/modules/ROOT/pages/core/plugins.adoc index 7c3711a95..e5ab3dea6 100644 --- a/packages/contracts/docs/modules/ROOT/pages/core/plugins.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/core/plugins.adoc @@ -15,7 +15,7 @@ Plugins can be related to: - And **anything** else that comes to mind! -## Understanding Plugins +== Understanding Plugins Whenever a DAO installs a plugin, an instance of that plugin's base template is deployed using the configuration parameters defined by the DAO. For example, you may want to use a specific token for your DAO's voting process, which means you have to determine this within your plugin's configuration parameters. @@ -25,7 +25,7 @@ TIP: Learn more about the different xref:guide-develop-plugin/design-your-plugin This raises questions on how the DAO manages plugins and who actually owns plugins. -### How Does the DAO Manage a Plugin? +=== How Does the DAO Manage a Plugin? A DAO manages plugins and interactions between them. In more detail, its permission manager: @@ -39,6 +39,6 @@ image::dao-plugin.drawio.svg[align="center"] An exemplary DAO setup showing interactions between the three core contract pieces triggered by different user groups: The `DAO` contract in blue containing the `PermissionManager` in red, respectively, as well as two `Plugin` contracts in green. Function calls are visualized as black arrows and require permission checks (red, dashed arrow). In this example, the permission manager determines whether the token voting plugin can execute actions on the DAO, a member can change its settings, or if a DeFi-related plugin is allowed to invest in a certain, external contract. -Whereas deployed plugin instances belong to the DAO, the developer of the original plugin implementation owns the implementation -and setup contract of the plugin. The plugin developer is the maintainer of an Aragon OSx xref:framework/plugin-repos.adoc[plugin repo]. +Whereas deployed plugin instances belong to the DAO, the developer of the original plugin implementation owns the implementation and setup contract of the plugin. The plugin developer is the maintainer of an Aragon OSx xref:framework/plugin-repos.adoc[plugin repo]. + Finally, the Aragon OSx protocol manages the registry in which the plugin repositories are listed, which is required to install a plugin using the Aragon OSx framework infrastructure to your DAO. diff --git a/packages/contracts/docs/modules/ROOT/pages/framework/dao-factory-registry.adoc b/packages/contracts/docs/modules/ROOT/pages/framework/dao-factory-registry.adoc index cd4015c78..c3c19bb6f 100644 --- a/packages/contracts/docs/modules/ROOT/pages/framework/dao-factory-registry.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/framework/dao-factory-registry.adoc @@ -1,36 +1,51 @@ -= Creating a DAO += DAO Factory and Registry -== The DAO Creation Process +Two framework contracts manage the `DAO` contract creation process, the `DAOFactory` and the `DAORegistry`. -Two framework contracts manage the `DAO` contract creation process: +NOTE: Find detailed contract documentation at xref:api:framework.adoc#DAOFactory[DAOFactory API] and xref:api:framework.adoc#DAORegistry[DAORegistry API] -- The xref:api:framework.adoc#DAOFactory[DAOFactory] -- The xref:api:framework.adoc#DAORegistry[DAORegistry] +== DAO Factory -### `DAOFactory` +The `DAOFactory` creates and sets up a `DAO` for you with the `createDao` function. -The `DAOFactory` creates and sets up a `DAO` for you in four steps with the `createDao` function. The function requires the `DAOSettings` including +```solidity +function createDao( + DAOSettings calldata _daoSettings, + PluginSettings[] calldata _pluginSettings +) external returns (DAO createdDao, InstalledPlugin[] memory installedPlugins); +``` + +This function requires the `DAOSettings` including: + + * The trusted forwarder address for future link:https://eips.ethereum.org/EIPS/eip-2771[ERC-2771 (Meta Transaction)] compatibility that is set to `address(0)` for now + * The ENS name to be registered under the `dao.eth` domain + * The link:https://eips.ethereum.org/EIPS/eip-4824[ERC-4824 (Common Interfaces for DAOs)] `daoURI` + * Optional metadata -- The trusted forwarder address for future link:https://eips.ethereum.org/EIPS/eip-2771[ERC-2771 (Meta Transaction)] compatibility that is set to `address(0)` for now -- The ENS name (to be registered under the `dao.eth` domain) -- The link:https://eips.ethereum.org/EIPS/eip-4824[ERC-4824 (Common Interfaces for DAOs)] `daoURI` -- Optional metadata +as well as an array of `PluginSettings` containing: -as well as an array of `PluginSettings` containing `PluginSetup` contract references and respective setup data for the initial set of plugins to be installed on the DAO. + * The `PluginSetup` contract reference + ** The version tag of the plugin setup + ** The plugin setup repository address + * The bytes-encoded data needed for the plugin installation. The `DAOFactory` create the `DAO` in four steps and interacts with the `DAORegistry` and being also part of the Aragon OSx framework: 1. Creates a new DAO by deploying an link:https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] proxy pointing to the latest Aragon OSx `DAO` implementation and becomes the initial owner. -2. Registers the new contract in the [`DAORegistry`](#daoregistry). TODO:GIORGI +2. Registers the new contract in the xref:#dao_registry[`DAORegistry`]. 3. Installs the plugins using the `PluginSetupProcessor` (see also the section about xref:framework/plugin-setup-processor.adoc[the plugin setup process]). 4. Sets the xref:core/permissions.adoc#permissions_native_to_the_dao_contract[native permissions] of the `DAO` and revokes its own ownership. -For more details visit the xref:api:framework.adoc#DAOFactory[`DAOFactory` reference guide entry]. +This function returns the `DAO` address and an array of `InstalledPlugin` structs each containing: -### `DAORegistry` +* The new created plugin address +* The list of plugin helpers +* The list of the permissions applied during the plugin installation + +== DAO Registry The `DAORegistry` is used by the `DAOFactory` and contains the `register` function @@ -44,8 +59,6 @@ function register( requiring the `REGISTER_DAO_PERMISSION_ID` permission currently held only by the `DAOFactory`. -If the requested ENS `subdomain` name xref:framework/ens-registrar.adoc[is valid] and not taken, the `DAORegistry` registers the subdomain and adds the `DAO` contract address to the `DAORegistry`. +If the requested ENS `subdomain` name xref:framework/ens-registrar.adoc#allowed_character_set[is valid] and not taken, the `DAORegistry` registers the subdomain and adds the `DAO` contract address to the `DAORegistry`. If the `subdomain` parameter is non-empty (not `""`) and still available, the ENS name will be registered. -If the registration was successful, the DAO name, contract and creator addresses are emitted in an event. - -For more details visit the xref:api:framework.adoc#DAORegistry[`DAORegistry` reference guide entry]. +If the registration was successful, the DAO name, contract and creator addresses are emitted in an event. \ No newline at end of file diff --git a/packages/contracts/docs/modules/ROOT/pages/framework/ens-registrar.adoc b/packages/contracts/docs/modules/ROOT/pages/framework/ens-registrar.adoc index 2054a15dd..106306e57 100644 --- a/packages/contracts/docs/modules/ROOT/pages/framework/ens-registrar.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/framework/ens-registrar.adoc @@ -1,13 +1,18 @@ -= ENS Names - -== Unique DAO and Plugin Repo Names += ENS Registrar To make DAOs and plugin repositories easily identifiable in the Aragon OSx ecosystem, we assign unique ENS names to them upon -registration during the xref:framework/dao-factory-registry.adoc[DAO creation] and xref:framework/repo-factory-registry.adoc[plugin publishing] processes. +registration during the xref:framework/dao-factory-registry.adoc[DAO creation] and xref:framework/repo-factory-registry.adoc[Plugin publishing] processes. + +== Aragon's Domain + +Aragon owns the `dao.eth` domain, which is used to register DAO ENS names. New DAOs can be registered under this domain (ex: `patito.dao.eth`), and new plugins can be registered under the `plugin.dao.eth` domain (ex: `admin.plugin.dao.eth`). + + +TIP: You can skip registering an ENS for your DAO by leaving the xref:api:framework.adoc#DAOFactory[`DAOSettings.subdomain` field] empty when calling the xref:api:framework.adoc#DAOFactory[`createDao`] function. -TIP: You can skip registering an ENS name for your DAO under the `dao.eth` by leaving the xref:api:framework.adoc#DAOFactory[`DAOSettings.subdomain` field] empty when calling the xref:api:framework.adoc#DAOFactory[`createDao`] function. +WARNING: Plugins cannot be registered without an ENS, we will re-consider this in the future. -### Allowed Character Set +== Allowed Character Set We allow the following characters for the subdomain names: diff --git a/packages/contracts/docs/modules/ROOT/pages/framework/index.adoc b/packages/contracts/docs/modules/ROOT/pages/framework/index.adoc index e12aa1d05..459d6e2c5 100644 --- a/packages/contracts/docs/modules/ROOT/pages/framework/index.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/framework/index.adoc @@ -2,15 +2,19 @@ = Framework == The Infrastructure Running the Aragon OSx Protocol -The Aragon OSx protocol is composed of **framework-related contracts** creating and managing the **core contracts**. This includes the - -- xref:framework/dao-factory-registry.adoc[Creation of DAOs]and initial plugin configuration. -- xref:framework/repo-factory-registry.adoc[Creation of plugins] and the versioning of different implementations and respective setup contracts. -- xref:framework/plugin-setup-processor.adoc[Installation of plugins] and setting it up on the DAO. -- xref:framework/ens-registrar.adoc[Assignment of ENS Names] to `Plugin` and `DAO` contracts created through the framework. +The Aragon OSx protocol is composed of **framework-related contracts** creating and managing the **core contracts**. An overview of the framework and core contracts of the Aragon OSx protocol and their interactions is shown below: image::../../../../_/images/optimized-svg/framework/aragon-os-infrastructure-core-overview.drawio.svg[ align="center"] -In the following sections, you will learn more about the framework-related contracts of the Aragon OSx protocol. \ No newline at end of file +In the following sections, you will learn more about the framework-related contracts of the Aragon OSx protocol. + +== Walkthrough + +In the upcoming sections, you will learn about each framework contract and their interactions. + +- xref:framework/dao-factory-registry.adoc[Creation of DAOs] and initial plugin configuration. +- xref:framework/repo-factory-registry.adoc[Creation of plugins] and the versioning of different implementations and respective setup contracts. +- xref:framework/plugin-setup-processor.adoc[Installation of plugins] and setting it up on the DAO. +- xref:framework/ens-registrar.adoc[Assignment of ENS Names] to `Plugin` and `DAO` contracts created through the framework. diff --git a/packages/contracts/docs/modules/ROOT/pages/framework/plugin-repos.adoc b/packages/contracts/docs/modules/ROOT/pages/framework/plugin-repos.adoc index fe38176f0..5cea9bec7 100644 --- a/packages/contracts/docs/modules/ROOT/pages/framework/plugin-repos.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/framework/plugin-repos.adoc @@ -1,21 +1,12 @@ = Plugin Repositories -== Plugins - As mentioned earlier, plugins built by Aragon and third-party developers can be added and removed from your DAO to adapt it to your needs. -The management of these plugins is handled for you by the Aragon OSx protocol so that the process of - -- Releasing new plugins as well as -- Installing, updating, and uninstalling them to your DAO - -becomes as streamlined as possible. - -In the following, we learn what a plugin consists of. +The management of these plugins is handled for you by the Aragon OSx protocol so that the process of *releasing* new plugins as well as *installing*, *updating*, and *uninstalling* them to your DAO becomes as streamlined as possible. // -### What Does a Plugin Consist Of? +== What Does a Plugin Consist Of? An Aragon OSx Plugin consists of: @@ -37,17 +28,12 @@ A detailed explanation of the xref:guide-develop-plugin/publishing-plugin.adoc#h image::../../../../_/images/optimized-svg/plugins/plugin-version.drawio.svg[align="center"] -The `PluginSetup` is written by you, the plugin developer. The processing of the setup is managed by the `PluginSetupProcessor`, the central component of the setup process in the Aragon OSx framework, which is explained in the section xref:framework/repo-factory-registry.adoc[The Plugin Setup Process]. - -Each plugin with its different builds and releases is versioned inside its own plugin repositories in a `PluginRepo` contract, which is explained in the next section. +The `PluginSetup` is written by you, the plugin developer. The processing of the setup is managed by the `PluginSetupProcessor`, the central component of the setup process in the Aragon OSx framework, which is explained in the section xref:framework/plugin-setup-processor.adoc[The Plugin Setup Process]. +Each plugin with its different builds and releases is versioned inside its own plugin repositories in a `PluginRepo` contract. == Plugin Repositories - -### What are Plugin Repositories? - - Each plugin has its own Plugin Repository, unique ENS name, and on-chain repository contract, the `PluginRepo`, in which different versions of the plugin are stored for reference using version tags constituted by a **release** and **build** number. Different versions might contain: @@ -65,7 +51,7 @@ image::../../../../_/images/optimized-svg/plugins/plugin-repo-overview.drawio.sv Overview of the plugin versioning and registry in the Aragon OSx protocol. The `PluginRepoRegistry` contract, which is a curated list of ENS named `PluginRepo` contracts, is shown on the left. Each `PluginRepo` contract maintains a list of versions of the `PluginSetup` contract (internally referencing the `Plugin` implementation contract) and the associated UI building blocks as a URI, exemplarily shown on the right. -#### The `PluginRepo` Contract +=== The `PluginRepo` Contract The `PluginRepo` contract versions the releases of a `Plugin`. The first version of a plugin is always published as release 1 and build 1 (version tag `1.1`). When you publish the first plugin version, a new plugin repository is automatically created for you by the Aragon OSx protocol in which you @@ -95,5 +81,6 @@ If it is a new release number, the build number is `1` (e.g., `2.1`). 3. The `_buildMetadata` URI pointing to a JSON file containing the UI data, setup data, and change description for this specific version. 4. The `_releaseMetadata` URI pointing to a JSON file containing the plugin name, description, as well as optional data such as images to be shown in the aragonApp frontend. -Other functions present in the contract allow you to query previous versions and to update the release metadata. For more details visit the xref:api:framework.adoc#PluginRepo[`PluginRepo` reference guide entry]. -The `PluginRepo` is created for you when you publish the `PluginSetup` contract of your first version to the Aragon OSx protocol, which is explained in the next section: xref:framework/repo-factory-registry.adoc[The Plugin Repo Creation Process]. \ No newline at end of file +Other functions present in the contract allow you to query previous versions and to update the release metadata. The `PluginRepo` is created for you when you publish the `PluginSetup` contract of your first version to the Aragon OSx protocol, which is explained in the next section: xref:framework/repo-factory-registry.adoc[The Plugin Repo Creation Process]. + +NOTE: For more details visit the xref:api:framework.adoc#PluginRepo[`PluginRepo` reference guide entry]. diff --git a/packages/contracts/docs/modules/ROOT/pages/framework/plugin-setup-processor.adoc b/packages/contracts/docs/modules/ROOT/pages/framework/plugin-setup-processor.adoc index a38e0208d..4d552aa01 100644 --- a/packages/contracts/docs/modules/ROOT/pages/framework/plugin-setup-processor.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/framework/plugin-setup-processor.adoc @@ -1,10 +1,6 @@ = Plugin Setup Processor -== Installing Plugins - -### The Smart Contracts Behind Plugins - -A DAO can be set up and customized by the **installation, update, and uninstallation** of plugins. Plugins are composed of two key contracts: +A DAO can be set up and customized by the *installation* , *update*, and *uninstallation* of plugins, this process in OSX is handled by the `PluginSetupProcessor` contract. Plugins are composed of two key contracts: - **Plugin contract:** contains the plugin's implementation logic; everything needed to extend the functionality for DAOs. - **Plugin Setup contract:** contains the instructions needed to install, update, and uninstall the plugin into the DAO. This is done through granting or revoking permissions, enabling plugins to perform actions within the scope of the DAO. @@ -19,7 +15,7 @@ How this works: - Publishing a Plugin into the Aragon OSx protocol is done through creating the first version of the plugin's `PluginRepo`. The plugin's `PluginRepo` instance stores all plugin versions. You can read more about that xref:guide-develop-plugin/publishing-plugin.adoc[here]. - Except for the gas costs required, plugins are completely free to install, unless decided otherwise by the developer. -#### How are Plugins installed in DAOs? +== How are Plugins installed in DAOs? The `PluginSetup` processing is **security critical** because the permissions it handles are granted to third-party contracts. @@ -32,7 +28,9 @@ This is why we see the installation process in two phases: The `PluginSetupProcessor` is the Aragon contract in charge of invoking the `prepareInstallation()` function from your plugin's `PluginSetup` contract and use it to prepare the installation and (eventually) apply it once it has been approved by the DAO. -##### What happens during the Plugin Preparation? +WARNING: Installation can be done manually by the DAO members or through a proposal, however, we recommend using the `PluginSetupProcessor` to handle this complex process. + +=== What happens during the Plugin Preparation? The preparation of a `PluginSetup` contract proceeds as follows: @@ -40,7 +38,9 @@ The preparation of a `PluginSetup` contract proceeds as follows: 2. The DAO builder defines the parameters and settings that he/she wants for their DAO. Depending on the case, the `prepareInstallation`, `prepareUpdate`, or `prepareUninstallation` method in the `PluginSetup` contract is called through the `PluginSetupProcessor` (and creates a unique setup ID). -3. The link:https://github.com/aragon/osx/blob/e24d9fa3bd6d5a4c9f5936c14ccda1fe9886c2b0/packages/contracts/src/framework/plugin/setup/PluginSetup.sol[`PluginSetup`] contract deploys all the contracts and gathers addresses and other input arguments required for the installation/uninstallation/upgrade instructions. This can include: +3. The link:https://github.com/aragon/osx/blob/e24d9fa3bd6d5a4c9f5936c14ccda1fe9886c2b0/packages/contracts/src/framework/plugin/setup/PluginSetup.sol[`PluginSetup`] contract deploys all the contracts and gathers addresses and other input arguments required for the installation/uninstallation/upgrade instructions. ++ +This can include: * deployment of new contracts * initialization of new storage variables @@ -48,9 +48,10 @@ The preparation of a `PluginSetup` contract proceeds as follows: * governance settings or other attributes * ... - Because the addresses of all associated contracts are now known, a static permission list can be emitted, hashed, and stored on-chain. ++ +Because the addresses of all associated contracts are now known, a static permission list can be emitted, hashed, and stored on-chain. -4. Once the Plugin installation has been prepared, we use it as the parameter of the `applyInstallation()` action. Once encoded, this action is what must be added to the `Action[]` array of the installation proposal. That way, when the proposal passes, the action becomes executable and the plugin can be installed in the DAO using the parameters defined in the prepare installation process. For a plugin to be installed, it needs to be approved by the governance mechanism (plugin) of the organization, passed as the encoded action of a proposal, and executed by a signer. +4. Once the Plugin installation has been prepared, we use it as the parameter of the `applyInstallation()` action. Once encoded, this action is what must be added to the `Action[]` array of the installation proposal. That way, when the proposal passes, the action becomes executable and the plugin can be installed in the DAO using the parameters defined in the prepare installation process. For a plugin to be installed, it needs to be approved by the governance mechanism of the organization, passed as the encoded action of a proposal, and executed by a signer. TIP: The governance plugin can be a simple majority vote, an optimistic process or an admin governance plugin that does not involve a waiting period. It can be any governance mechanism existing within the DAO which has access to the DAO's `execute` permission. @@ -63,7 +64,7 @@ To learn more visit the xref:guide-set-up-dao/keep-dao-safe.adoc#risks_and_their // Optionally, the proposer can also request refunds for the gas spent for the preparation of the plugin in the proposal. // --> -##### What happens during the Preparation Application? +=== What happens during the Preparation Application? After this initial preparation transaction, the addresses and permissions related to the plugin become apparent. The members of a governance plugin with permissions can decide if the installation proposal should be accepted or denied. diff --git a/packages/contracts/docs/modules/ROOT/pages/framework/repo-factory-registry.adoc b/packages/contracts/docs/modules/ROOT/pages/framework/repo-factory-registry.adoc index e71418a5a..518df8390 100644 --- a/packages/contracts/docs/modules/ROOT/pages/framework/repo-factory-registry.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/framework/repo-factory-registry.adoc @@ -1,14 +1,9 @@ -= Publishing a Plugin += Plugin Repo Factory and Registry -== Start publishing your Plugin by creating a PluginRepo +To be available for installation in the Aragon OSx framework, a `PluginRepo` must be created for each plugin. The `PluginRepo` creation process is handled by the `PluginRepoFactory` contract who creates the `PluginRepo` instance for each plugin to hold all plugin versions and the `PluginRepoRegistry` contract who registers the Plugin in the framework for DAOs to install. -To be available for installation in the Aragon OSx framework, a `PluginRepo` must be created for each plugin. The `PluginRepo` creation process is handled by: -- The xref:api:framework.adoc#PluginRepoFactory[PluginRepoFactory]: who creates the `PluginRepo` instance for each plugin to hold all plugin versions. -- The xref:api:framework.adoc#PluginRepoRegistry[PluginRepoRegistry]: who registers the Plugin into the Protocol for DAOs to install. - - -### The `PluginRepoFactory` Contract +== Plugin Repo Factory The `PluginRepoFactory` is the contract in charge of creating the first version of a plugin. It does this through the `createPluginRepoWithFirstVersion` function which creates a `PluginRepo` instance for the plugin with the first release @@ -38,9 +33,9 @@ Additional to the information required by the xref:framework/plugin-repos.adoc#t - A valid ENS `_subdomain` unique name composed of letters from a-z, all in lower caps, separated by a `-`. For ex: `token-voting-plugin`. - The address of the plugin repo maintainer who ends up having the `ROOT_PERMISSION_ID`, `MAINTAINER_PERMISSION_ID`, and `UPGRADE_REPO_PERMISSION_ID` permissions. These permissions enable the maintainer to call the internal `PermissionManager`, the `createVersion` and `updateReleaseMetadata` functions as well as upgrading the plugin contract. -For more details visit the xref:api:framework.adoc#PluginRepoFactory[`PluginRepoFactory` Reference Guide entry]. +NOTE: Find detailed contract documentation at xref:api:framework.adoc#PluginRepoFactory[`PluginRepoFactory` API]. -### The `PluginRepoRegistry` Contract +== Plugin Repo Registry The `PluginRepoRegistry` contract is the central contract listing all the plugins managed through the Aragon OSx protocol. The `PluginRepoFactory` calls on the `PluginRepoRegistry` to register the plugin in the Aragon OSx protocol. @@ -56,4 +51,4 @@ address pluginRepo } ``` -For more details visit the xref:api:framework.adoc#PluginRepoRegistry[`PluginRepoRegistry` reference guide entry]. +NOTE: Find detailed contract documentation at xref:api:framework.adoc#PluginRepoRegistry[`PluginRepoRegistry` API]. 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 e4cd1e033..fd34cce7d 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 @@ -1,12 +1,12 @@ = Designing your plugin -== Governance Plugins +This guide explains how to design plugins for Aragon OSx, covering governance plugins, membership management, and upgradeability patterns. You'll learn about the core interfaces, implementation patterns, and how to choose the right base contract for your specific use case. -### How to Build a Governance Plugin +== Governance Plugins 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 +=== 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. @@ -23,7 +23,7 @@ Beyond this fundamental ability, governance plugins usually implement two interf - 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 +=== Examples of Governance Plugins Some examples of governance plugins are: @@ -36,11 +36,7 @@ Some examples of governance plugins are: // - - -### Proposals - -#### The `IProposal` Interface +=== The `IProposal` Interface The `IProposal` interface is used to create and execute proposals containing actions and a description. @@ -78,7 +74,7 @@ interface IProposal { This interface contains two events and one function -##### `ProposalCreated` event +==== `ProposalCreated` event This event should be emitted when a proposal is created. It contains the following parameters: @@ -90,15 +86,15 @@ This event should be emitted when a proposal is created. It contains the followi - `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 +==== `ProposalExecuted` event This event should be emitted when a proposal is executed. It contains the proposal ID as a parameter. -##### `proposalCount` function +==== `proposalCount` function This function should return the proposal count determining the next proposal ID. -#### Usage +==== Usage ```solidity contract MyPlugin is IProposal { @@ -134,9 +130,9 @@ contract MyPlugin is IProposal { } ``` -### Membership -#### The `IMembership` Interface + +=== 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. @@ -167,25 +163,25 @@ interface IMembership { The interface contains three events and one function. -##### `MembersAdded` event +==== `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 +==== `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 +==== `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 +==== `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 +==== Usage ```solidity @@ -222,7 +218,7 @@ contract MyPlugin is IMembership { == Choosing the Plugin Upgradeability -### How to Choose the Base Contract for Your Plugin +=== How to Choose your Plugin Upgradeability 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. @@ -240,7 +236,7 @@ In this regard, we provide 3 options for base contracts you can choose from: Let's take a look at what this means for you. -### Upgradeability & Deployment +=== 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: @@ -272,10 +268,10 @@ Some key things to keep in mind: | |`new` Instantiation | Minimal Proxy (Clones)| Transparent Proxy| UUPS Proxy | upgradeability -|no +| [.no-cell]#no# | no -| yes | yes +| yes | gas costs | high | very low @@ -292,10 +288,10 @@ Accordingly, we recommend to use link:https://eips.ethereum.org/EIPS/eip-1167[mi 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 +- `PluginClones` for link:https://eips.ethereum.org/EIPS/eip-1167[minimal proxy pattern ERC-1167] deployment +- `PluginUUPSUpgradeable` for link:https://eips.ethereum.org/EIPS/eip-1822[UUPS pattern ERC-1822] deployment -#### Caveats of Non-upgradeable Plugins +=== 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**. diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/follow-best-practices.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/follow-best-practices.adoc index 50e22f821..4288f537e 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/follow-best-practices.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/follow-best-practices.adoc @@ -2,7 +2,7 @@ == Advice for Developing a Plugin -### DOs πŸ‘Œ +=== DOs πŸ‘Œ - Document your contracts using link:https://docs.soliditylang.org/en/v0.8.17/natspec-format.html[NatSpec]. - Test your contracts, e.g., using toolkits such as link:https://hardhat.org/hardhat-runner/docs/guides/test-contracts[hardhat (JS)] or link:https://book.getfoundry.sh/forge/tests[Foundry (Rust)]. @@ -12,7 +12,7 @@ - Plan the lifecycle of your plugin (need for upgrades). - Follow our xref:guide-develop-plugin/publishing-plugin.adoc#how_to_add_a_new_version_of_your_plugin[versioning guidelines]. -### DON'Ts βœ‹ +=== DON'Ts βœ‹ - Leave any contract uninitialized. - Grant the `ROOT_PERMISSION_ID` permission to anything or anyone. diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/index.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/index.adoc index 640013fd8..64f7af6a8 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/index.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/index.adoc @@ -1,12 +1,10 @@ = How to build a DAO Plugin -== Plugin Development Quickstart Guide - Plugins are how we extend the functionality for DAOs. In Aragon OSx, everything a DAO can do is based on Plugin functionality enabled through permissions. In this Quickstart guide, we will use the Aragon Hardhat template to set up a plugin. -## Setting up your environment +== Setting up your environment We recommend using our link:https://github.com/aragon/osx-plugin-template-hardhat[hardhat template] to get started. If you don't have it installed, you can do so by running: @@ -61,10 +59,10 @@ For more information on how to develop a plugin, you can check our plugin develo - xref:guide-develop-plugin/write-plugin-setup-contract.adoc[Writing your plugin setup contract] - xref:guide-develop-plugin/write-upgradeable-plugin.adoc[Writing upgradeable plugin] - xref:guide-develop-plugin/upgrade-plugin.adoc[Upgrading your plugin] -- xref:guide-develop-plugin/follow-best-practices.adoc[Best practices and patterns] +- xref:guide-develop-plugin/follow-best-practices.adoc[Following best practices] - xref:guide-develop-plugin/publishing-plugin.adoc[Publishing your plugin] -IMPORTANT: This plugin template uses version TODO:GIORGI `1.4.0-alpha.5` of the Aragon OSx protocol. This version is still in development and +IMPORTANT: This plugin template uses version `1.4.0-alpha.5` of the Aragon OSx protocol. This version is still in development and is not audited yet. diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/publishing-plugin.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/publishing-plugin.adoc index 9c3fb815b..4d76edc0a 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/publishing-plugin.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/publishing-plugin.adoc @@ -1,16 +1,18 @@ = Publication of your Plugin into Aragon OSx -== How to publish a plugin into Aragon's plugin registry - Once you've deployed your Plugin Setup contract, you will be able to publish your plugin into Aragon's plugin registry so any Aragon DAO can install it. -### 1. Make sure your plugin is deployed in the right network +== How to publish new plugin + +Publishing a plugin to Aragon OSx involves a few key steps to ensure your plugin is properly registered and accessible to DAOs. + +=== Make sure your plugin is deployed in a supported network Make sure your Plugin Setup contract is deployed in your network of choice (you can find all of the networks we support link:https://github.com/aragon/osx-commons/tree/develop/configs/src/deployments/json[here]). You will need the address of your Plugin Setup contract to be able to publish the plugin into the protocol. -### 2. Publishing your plugin +=== Publishing your plugin Every plugin in Aragon can have future versions, so when publishing a plugin to the Aragon protocol, we're really creating a link:https://github.com/aragon/osx/blob/develop/packages/contracts/src/framework/plugin/repo/PluginRepo.sol[PluginRepo] instance for each plugin, which will contain all of the plugin's versions. @@ -24,14 +26,13 @@ You can find all of the addresses of `PluginRepoFactory` contracts by network li To create more versions of your plugin in the future, you'll call on the link:https://github.com/aragon/osx/blob/develop/packages/contracts/src/framework/plugin/repo/PluginRepo.sol#L128[createVersion function] from the `PluginRepo` instance of your plugin. When you publish your plugin, you'll be able to find the address of your plugin's `PluginRepo` instance within the transaction data. -### 3. Publishing subsequent builds +=== Publishing subsequent builds When publishing subsequent builds, you want to use the `createVersion` function in the `PluginRepo` contract (link:https://github.com/aragon/osx/blob/develop/packages/contracts/src/framework/plugin/repo/PluginRepo.sol#L132[check out the function's source code here]). To deploy your plugin, follow the steps in the link:https://github.com/aragon/osx-plugin-template-hardhat/blob/main/README.md#deployment[osx-plugin-template-hardhat README.md]. - == How to add a new version of your plugin The Aragon OSx protocol has an on-chain versioning system built-in, which distinguishes between releases and builds. @@ -94,7 +95,7 @@ Currently, two kinds of metadata exist: 1. Release metadata 2. Build metadata -### Release Metadata +=== Release Metadata The release metadata is a `.json` file stored on IPFS with its IPFS CID published for each release in the xref:framework/plugin-repos.adoc[PluginRepo](see also the section about xref:#how_to_add_a_new_version_of_your_plugin[versioning]). @@ -123,7 +124,7 @@ The `release-metadata.json` file consists of the following entries: |=== -#### Example +==== Example ```json { @@ -133,7 +134,7 @@ The `release-metadata.json` file consists of the following entries: } ``` -### Build Metadata +=== Build Metadata The build metadata is a `.json` file stored on IPFS with its IPFS CID published for each build **only once** in the xref:framework/plugin-repos.adoc[PluginRepo] (see also the section about xref:#how_to_add_a_new_version_of_your_plugin[versioning]). @@ -184,7 +185,7 @@ Each `"prepare..."` object contains: By following the Solidity JSON ABI format for the inputs, we followed an established standard, have support for complex types (tuples, arrays, nested versions of the prior) and allow for future extensibility (such as the human readable description texts that we have added). -#### Example +==== Example ```json { @@ -234,7 +235,4 @@ By following the Solidity JSON ABI format for the inputs, we followed an establi } } } -``` - - -// TODO merge this sections and clean up redundancy, consider also framework and core sections. \ No newline at end of file +``` \ No newline at end of file diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/upgrade-plugin.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/upgrade-plugin.adoc index 055814855..b3bfe2052 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/upgrade-plugin.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/upgrade-plugin.adoc @@ -1,23 +1,184 @@ -= Subsequent Builds - - -== How to upgrade an Upgradeable Plugin += Upgrading your plugin Updating an Upgradeable plugin means we want to direct the implementation of our functionality to a new build, rather than the existing one. In this tutorial, we will go through how to update the version of an Upgradeable plugin and each component needed. -### 1. Create the new build implementation contract +NOTE: You can skip this section if you are working on a non-upgradeable plugin. + +== How to create new builds to an Upgradeable Plugin + +A build is a new implementation of your Upgradeable Plugin. Upgradeable contracts offer advantages because you can cheaply change +or fix the logic of your contract without losing the storage of your contract. + +The Aragon OSx protocol has an on-chain versioning system built-in, which distinguishes between releases and builds. + +- **Releases** contain breaking changes, which are incompatible with preexisting installations. Updates to a different release are +not possible. Instead, you must install the new plugin release and uninstall the old one. +- **Builds** are minor/patch versions within a release, and they are meant for compatible upgrades +only (adding a feature or fixing a bug without changing anything else). + +In this section, we'll go through how we can create these builds for our plugins. Specifically, we'll showcase two specific +types of builds - one that modifies the storage of the plugins, another one which modifies its bytecode. Both are possible and +can be implemented within the same build implementation as well. + +Before moving on, make sure you have at least one build already deployed and published into the Aragon protocol, you can check out our xref:guide-develop-plugin/publishing-plugin.adoc[publishing guide] to ensure this step is done. + +=== Create a new build implementation modifying storage + +In this second build implementation we want to update the functionality of our plugin - in this case, we want to update +the storage of our plugin with new values. Specifically, we will add a second storage variable `address public account`. +Additional to the `initializeFromBuild2` function, we also want to add a second setter function `storeAccount` that uses +the same permission as `storeNumber`. -Firstly, you want to create the new build implementation contract the plugin should use. You can read more about how to do -this in the xref:guide-develop-plugin/upgrade-plugin.adoc[How to create a subsequent build implementation to an Upgradeable Plugin] guide. +As you can see, we're still inheriting from the `PluginUUPSUpgradeable` contract and simply overriding some implementation +from the previous build. The idea is that when someone upgrades the plugin and calls on these functions, they'll use this +new upgraded implementation, rather than the older one. ```solidity -// SPDX-License-Identifier: AGPL-3.0-or-later -pragma solidity 0.8.21; +import {PluginUUPSUpgradeable, IDAO} '@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol'; -import {IDAO, PluginUUPSUpgradeable} from '@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol'; +/// @title SimpleStorage build 2 +contract SimpleStorageBuild2 is PluginUUPSUpgradeable { + bytes32 public constant STORE_PERMISSION_ID = keccak256('STORE_PERMISSION'); + + uint256 public number; // added in build 1 + address public account; // added in build 2 + + /// @notice Initializes the plugin when build 2 is installed. + function initializeBuild2( + IDAO _dao, + uint256 _number, + address _account + ) external reinitializer(2) { + __PluginUUPSUpgradeable_init(_dao); + number = _number; + account = _account; + } + + /// @notice Initializes the plugin when the update from build 1 to build 2 is applied. + /// @dev The initialization of `SimpleStorageBuild1` has already happened. + function initializeFromBuild1(address _account) external reinitializer(2) { + account = _account; + } + + function storeNumber(uint256 _number) external auth(STORE_PERMISSION_ID) { + number = _number; + } + + function storeAccount(address _account) external auth(STORE_PERMISSION_ID) { + account = _account; + } +} +``` + +Builds that you publish don't necessarily need to introduce new storage variables of your contracts and don't necessarily need to +change the storage. To read more about Upgradeability, check out link:https://docs.openzeppelin.com/contracts/4.x/api/proxy#UUPSUpgradeable[OpenZeppelin's UUPSUpgradeability implementation here]. + +NOTE: Note that because these contracts are Upgradeable, keeping storage gaps `uint256 [50] __gap;` in dependencies is a must in +order to avoid storage corruption. To learn more about storage gaps, review OpenZeppelin's documentation link:https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#storage-gaps[here]. + +=== Create a build implementation modifying bytecode + +Updates for your contracts don't necessarily need to affect the storage, they can also modify the plugin's bytecode. +Modifying the contract's bytecode, means making changes to: + +- functions +- constants +- immutables +- events +- errors + +For this third build, then, we want to change the bytecode of our implementation as an example, so we 've introduced two +separate permissions for the `storeNumber` and `storeAccount` functions and named them `STORE_NUMBER_PERMISSION_ID` and `STORE_ACCOUNT_PERMISSION_ID` permission, respectively. +Additionally, we decided to add the `NumberStored` and `AccountStored` events as well as an error preventing users from setting the +same value twice. All these changes only affect the contract bytecode and not the storage. + +Here, it is important to remember how Solidity stores `constant`s (and `immutable`s). In contrast to normal variables, they are directly +written into the bytecode on contract creation so that we don't need to worry that the second `bytes32` constant that we added +shifts down the storage so that the value in `uint256 public number` gets lost. It is also important to note that, the `initializeFromBuild2` +could be left empty. Here, we just emit the events with the currently stored values. + +```solidity +import {PluginUUPSUpgradeable, IDAO} '@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol'; + +/// @title SimpleStorage build 3 +contract SimpleStorageBuild3 is PluginUUPSUpgradeable { + bytes32 public constant STORE_NUMBER_PERMISSION_ID = keccak256('STORE_NUMBER_PERMISSION'); // changed in build 3 + bytes32 public constant STORE_ACCOUNT_PERMISSION_ID = keccak256('STORE_ACCOUNT_PERMISSION'); // added in build 3 + + uint256 public number; // added in build 1 + address public account; // added in build 2 + + // added in build 3 + event NumberStored(uint256 number); + event AccountStored(address number); + error AlreadyStored(); + + /// @notice Initializes the plugin when build 3 is installed. + function initializeBuild3( + IDAO _dao, + uint256 _number, + address _account + ) external reinitializer(3) { + __PluginUUPSUpgradeable_init(_dao); + number = _number; + account = _account; + + emit NumberStored({number: _number}); + emit AccountStored({account: _account}); + } + + /// @notice Initializes the plugin when the update from build 2 to build 3 is applied. + /// @dev The initialization of `SimpleStorageBuild2` has already happened. + function initializeFromBuild2() external reinitializer(3) { + emit NumberStored({number: number}); + emit AccountStored({account: account}); + } + + /// @notice Initializes the plugin when the update from build 1 to build 3 is applied. + /// @dev The initialization of `SimpleStorageBuild1` has already happened. + function initializeFromBuild1(address _account) external reinitializer(3) { + account = _account; + + emit NumberStored({number: number}); + emit AccountStored({account: _account}); + } + + function storeNumber(uint256 _number) external auth(STORE_NUMBER_PERMISSION_ID) { + if (_number == number) revert AlreadyStored(); + + number = _number; + + emit NumberStored({number: _number}); + } + + function storeAccount(address _account) external auth(STORE_ACCOUNT_PERMISSION_ID) { + if (_account == account) revert AlreadyStored(); + + account = _account; + + emit AccountStored({account: _account}); + } +} +``` + +NOTE: Despite no storage-related changes happening in build 3, we must apply the `reinitializer(3)` modifier to all `initialize` functions so that +none of them can be called twice or in the wrong order. + + +== How to upgrade your plugin + +Now that we understand how to create new builds, let's walk through the process of upgrading your plugin to use them, while maintaining your plugin's functionality and data integrity. + + +=== Create the new build implementation contract + +In the previous section, we created a new build implementation contract, we will use this as the new implementation for our plugin. + +```solidity +import {PluginUUPSUpgradeable, IDAO} '@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol'; /// @title SimpleStorage build 2 contract SimpleStorageBuild2 is PluginUUPSUpgradeable { @@ -53,15 +214,14 @@ contract SimpleStorageBuild2 is PluginUUPSUpgradeable { } ``` -### 2. Write a new Plugin Setup contract +=== Write a new Plugin Setup contract In order to do update a plugin, we need a `prepareUpdate()` function in our Plugin Setup contract which points the functionality to a -new build, as we described in the xref:guide-develop-plugin/upgrade-plugin.adoc[How to create a subsequent build implementation to an Upgradeable Plugin] guide. +new build, as we described before. The `prepareUpdate()` function must transition the plugin from the old build state into the new one so that it ends up having the same permissions (and helpers) as if it had been freshly installed. -In contrast to the original build 1, build 2 requires two input arguments: `uint256 _number` and `address _account` that we decode -from the bytes-encoded input `_data`. +In contrast to the original build 1, build 2 requires two input arguments: `uint256 _number` and `address _account` that we decode from the bytes-encoded input `_data`. ```solidity // SPDX-License-Identifier: AGPL-3.0-or-later @@ -151,12 +311,9 @@ contract SimpleStorageBuild2Setup is PluginSetup { } ``` -The key thing to review in this new Plugin Setup contract is its `prepareUpdate()` function. The function only contains a -condition checking from which build number the update is transitioning to build `2`. Here, it is the build number `1` as this is the -only update path we support. Inside, we decode the `address _account` input argument provided with `bytes _data` and pass -it to the `initializeFromBuild1` function taking care of initializing the storage that was added in this build. +The key thing to review in this new Plugin Setup contract is its `prepareUpdate()` function. The function only contains a condition checking from which build number the update is transitioning to build `2`. Here, it is the build number `1` as this is the only update path we support. Inside, we decode the `address _account` input argument provided with `bytes _data` and pass it to the `initializeFromBuild1` function taking care of initializing the storage that was added in this build. -### 3. Future builds +=== Future builds For each build we add, we will need to add a `prepareUpdate()` function with any parameters needed to update to that implementation. @@ -367,170 +524,4 @@ In the second case, `initializeFromBuild2` is called taking care of initializing Lastly, the `prepareUpdate()` function takes care of modifying the permissions by revoking the `STORE_PERMISSION_ID` and granting the more specific `STORE_NUMBER_PERMISSION_ID` and `STORE_ACCOUNT_PERMISSION_ID` permissions, that are also granted if build 2 is -freshly installed. This must happen for both update paths so this code is outside the `if` statements. - -== How to create a subsequent build to an Upgradeable Plugin - -A build is a new implementation of your Upgradeable Plugin. Upgradeable contracts offer advantages because you can cheaply change -or fix the logic of your contract without losing the storage of your contract. - -The Aragon OSx protocol has an on-chain versioning system built-in, which distinguishes between releases and builds. - -- **Releases** contain breaking changes, which are incompatible with preexisting installations. Updates to a different release are -not possible. Instead, you must install the new plugin release and uninstall the old one. -- **Builds** are minor/patch versions within a release, and they are meant for compatible upgrades -only (adding a feature or fixing a bug without changing anything else). - -In this how to guide, we'll go through how we can create these builds for our plugins. Specifically, we'll showcase two specific -types of builds - one that modifies the storage of the plugins, another one which modifies its bytecode. Both are possible and -can be implemented within the same build implementation as well. - -### 1. Make sure your previous build is deployed and published - -Make sure you have at least one build already deployed and published into the Aragon protocol. Make sure to check out our -xref:guide-develop-plugin/publishing-plugin.adoc[publishing guide] to ensure this step is done. - -### 2. Create a new build implementation - -In this second build implementation we want to update the functionality of our plugin - in this case, we want to update -the storage of our plugin with new values. Specifically, we will add a second storage variable `address public account;`. -Additional to the `initializeFromBuild2` function, we also want to add a second setter function `storeAccount` that uses -the same permission as `storeNumber`. - -As you can see, we're still inheriting from the `PluginUUPSUpgradeable` contract and simply overriding some implementation -from the previous build. The idea is that when someone upgrades the plugin and calls on these functions, they'll use this -new upgraded implementation, rather than the older one. - -```solidity -import {PluginUUPSUpgradeable, IDAO} '@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol'; - -/// @title SimpleStorage build 2 -contract SimpleStorageBuild2 is PluginUUPSUpgradeable { - bytes32 public constant STORE_PERMISSION_ID = keccak256('STORE_PERMISSION'); - - uint256 public number; // added in build 1 - address public account; // added in build 2 - - /// @notice Initializes the plugin when build 2 is installed. - function initializeBuild2( - IDAO _dao, - uint256 _number, - address _account - ) external reinitializer(2) { - __PluginUUPSUpgradeable_init(_dao); - number = _number; - account = _account; - } - - /// @notice Initializes the plugin when the update from build 1 to build 2 is applied. - /// @dev The initialization of `SimpleStorageBuild1` has already happened. - function initializeFromBuild1(address _account) external reinitializer(2) { - account = _account; - } - - function storeNumber(uint256 _number) external auth(STORE_PERMISSION_ID) { - number = _number; - } - - function storeAccount(address _account) external auth(STORE_PERMISSION_ID) { - account = _account; - } -} -``` - -Builds that you publish don't necessarily need to introduce new storage variables of your contracts and don't necessarily need to -change the storage. To read more about Upgradeability, check out link:https://docs.openzeppelin.com/contracts/4.x/api/proxy#UUPSUpgradeable[OpenZeppelin's UUPSUpgradeability implementation here]. - -NOTE: Note that because these contracts are Upgradeable, keeping storage gaps `uint256 [50] __gap;` in dependencies is a must in -order to avoid storage corruption. To learn more about storage gaps, review OpenZeppelin's documentation link:https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#storage-gaps[here]. - -### 3. Alternatively, a build implementation modifying bytecode - -Updates for your contracts don't necessarily need to affect the storage, they can also modify the plugin's bytecode. -Modifying the contract's bytecode, means making changes to: - -- functions -- constants -- immutables -- events -- errors - -For this third build, then, we want to change the bytecode of our implementation as an example, so we 've introduced two -separate permissions for the `storeNumber` and `storeAccount` functions and named them `STORE_NUMBER_PERMISSION_ID` and `STORE_ACCOUNT_PERMISSION_ID` permission, respectively. -Additionally, we decided to add the `NumberStored` and `AccountStored` events as well as an error preventing users from setting the -same value twice. All these changes only affect the contract bytecode and not the storage. - -Here, it is important to remember how Solidity stores `constant`s (and `immutable`s). In contrast to normal variables, they are directly -written into the bytecode on contract creation so that we don't need to worry that the second `bytes32` constant that we added -shifts down the storage so that the value in `uint256 public number` gets lost. It is also important to note that, the `initializeFromBuild2` -could be left empty. Here, we just emit the events with the currently stored values. - -```solidity -import {PluginUUPSUpgradeable, IDAO} '@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol'; - -/// @title SimpleStorage build 3 -contract SimpleStorageBuild3 is PluginUUPSUpgradeable { - bytes32 public constant STORE_NUMBER_PERMISSION_ID = keccak256('STORE_NUMBER_PERMISSION'); // changed in build 3 - bytes32 public constant STORE_ACCOUNT_PERMISSION_ID = keccak256('STORE_ACCOUNT_PERMISSION'); // added in build 3 - - uint256 public number; // added in build 1 - address public account; // added in build 2 - - // added in build 3 - event NumberStored(uint256 number); - event AccountStored(address number); - error AlreadyStored(); - - /// @notice Initializes the plugin when build 3 is installed. - function initializeBuild3( - IDAO _dao, - uint256 _number, - address _account - ) external reinitializer(3) { - __PluginUUPSUpgradeable_init(_dao); - number = _number; - account = _account; - - emit NumberStored({number: _number}); - emit AccountStored({account: _account}); - } - - /// @notice Initializes the plugin when the update from build 2 to build 3 is applied. - /// @dev The initialization of `SimpleStorageBuild2` has already happened. - function initializeFromBuild2() external reinitializer(3) { - emit NumberStored({number: number}); - emit AccountStored({account: account}); - } - - /// @notice Initializes the plugin when the update from build 1 to build 3 is applied. - /// @dev The initialization of `SimpleStorageBuild1` has already happened. - function initializeFromBuild1(address _account) external reinitializer(3) { - account = _account; - - emit NumberStored({number: number}); - emit AccountStored({account: _account}); - } - - function storeNumber(uint256 _number) external auth(STORE_NUMBER_PERMISSION_ID) { - if (_number == number) revert AlreadyStored(); - - number = _number; - - emit NumberStored({number: _number}); - } - - function storeAccount(address _account) external auth(STORE_ACCOUNT_PERMISSION_ID) { - if (_account == account) revert AlreadyStored(); - - account = _account; - - emit AccountStored({account: _account}); - } -} -``` - -NOTE: Despite no storage-related changes happening in build 3, we must apply the `reinitializer(3)` modifier to all `initialize` functions so that -none of them can be called twice or in the wrong order. - - -// TODO merge this sections and clean up redundancy \ No newline at end of file +freshly installed. This must happen for both update paths so this code is outside the `if` statements. \ No newline at end of file diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-plugin-contract.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-plugin-contract.adoc index 4d0f4c834..1e057fb68 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-plugin-contract.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-plugin-contract.adoc @@ -1,7 +1,5 @@ = Plugin Contract -// == How to develop Plugin - This section will be focuses on non-upgradeable plugins development, for upgradeable plugins please check out our xref:guide-develop-plugin/write-upgradeable-plugin.adoc[guide here]. Before continuing make sure you've read our documentation on xref:guide-develop-plugin/design-your-plugin.adoc#choosing_the_plugin_upgradeability[Choosing the Best Type for Your Plugin] to make sure you're selecting the right type of contract for your Plugin. @@ -21,16 +19,13 @@ contract SimpleAdmin is Plugin { } ``` -The way we set up the plugin's `initialize()` function depends on the plugin type selected. To review plugin types in depth, check out -our xref:guide-develop-plugin/design-your-plugin.adoc#choosing_the_plugin_upgradeability[guide here]. - -Additionally, the way we deploy our contracts is directly correlated with how they're initialized. For Non-Upgradeable Plugins, +The way we set up the plugin's `initialize()` function depends on the plugin type selected. Additionally, the way we deploy our contracts is directly correlated with how they're initialized. For Non-Upgradeable Plugins, there's two ways in which we can deploy our plugin: -- Deployment via Solidity's `new` keyword, OR +- Deployment via Solidity's `new` keyword, or - Deployment via the Minimal Proxy Pattern -### Option A: Deployment via Solidity's `new` Keyword +=== Option A: Deployment via Solidity's `new` Keyword To instantiate the contract via Solidity's `new` keyword, you should inherit from the `Plugin` Base Template Aragon created. You can find it link:https://github.com/aragon/osx-commons/blob/develop/contracts/src/plugin/Plugin.sol[here]. @@ -62,7 +57,7 @@ the constructor. This type of constructor implementation stores the `IDAO _dao` reference in the right place. If your plugin is deployed often, which we could expect, we can link:https://blog.openzeppelin.com/workshop-recap-cheap-contract-deployment-through-clones/[save significant amounts of gas by deployment through using the minimal proxy pattern]. -### Option B: Deployment via the Minimal Proxy Pattern +=== Option B: Deployment via the Minimal Proxy Pattern To deploy our plugin via the link:https://eips.ethereum.org/EIPS/eip-1167(minimal clones pattern (ERC-1167)), you inherit from the `PluginCloneable` contract introducing the same features as `Plugin`. The only difference is that you now have to remember to write an `initialize` function. @@ -101,7 +96,7 @@ with a DAO and cannot use the DAO's `PermissionManager`. Once we've initialized our plugin (take a look at our guide on xref:how_to_initialize_the_plugin[how to initialize the plugin here]), we can start using the Non-Upgradeable Base Template to perform actions on the DAO. -### 1. Set the Permission Identifier +=== 1. Set the Permission Identifier Firstly, we want to define a xref:core/permissions.adoc#permission_identifiers[permission identifier] `bytes32` constant at the top of the contract and establish a `keccak256` hash of the permission name we want to choose. @@ -135,7 +130,7 @@ However, it is important that the permission names are descriptive and cannot be Setting this permission is key because it ensures only signers who have been granted that permission are able to execute functions. -### 2. Add the logic implementation +=== 2. Add the logic implementation Now that we have created the permission, we will use it to protect the implementation. We want to make sure only the authorized callers holding the `ADMIN_EXECUTE_PERMISSION`, can use the function. @@ -178,7 +173,7 @@ For now, we used default values for the `callId` and `allowFailureMap` parameter With this, the plugin implementation could be used and deployed already. Feel free to add any additional logic to your plugin's capabilities here. -### 3. Plugin done, Setup contract next! +=== 3. Plugin done, Setup contract next! Now that we have the logic for the plugin implemented, we'll need to define how this plugin should be installed/uninstalled from a DAO. In the next step, we'll write the `PluginSetup` contract - the one containing the installation, uninstallation, and diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-plugin-setup-contract.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-plugin-setup-contract.adoc index ea9f4dae2..b18423c88 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-plugin-setup-contract.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-plugin-setup-contract.adoc @@ -1,12 +1,15 @@ = Plugin Setup Contract + +NOTE: This section is a continuation of the xref:guide-develop-plugin/write-plugin-contract.adoc[Writing your plugin contract], and is also focused on non-upgradeable plugins, for upgradeable plugins, see xref:guide-develop-plugin/write-upgradeable-plugin.adoc[Writing your upgradeable plugin]. + == What is the Plugin Setup contract? The Plugin Setup contract is the contract defining the instructions for installing, uninstalling, or upgrading plugins into DAOs. This contract prepares the permission granting or revoking that needs to happen in order for plugins to be able to perform actions on behalf of the DAO. You need it for the plugin to be installed into the DAO. -### 1. Finish the Plugin contract +=== 1. Finish the Plugin contract Before building your Plugin Setup contract, make sure you have the logic for your plugin implemented. In this case, we're building a simple admin plugin which grants one address permission to execute actions on behalf of the DAO. @@ -33,7 +36,7 @@ contract SimpleAdmin is PluginCloneable { } ``` -### 2. How to initialize the Plugin Setup contract +=== 2. How to initialize the Plugin Setup contract Each `PluginSetup` contract is deployed only once and we will publish a separate `PluginSetup` instance for each version. Accordingly, we instantiate the `implementation` contract via Solidity's `new` keyword as deployment with the minimal proxy pattern would be more expensive in this case. @@ -60,7 +63,7 @@ contract SimpleAdminSetup is PluginSetup { } ``` -### 3. Build the Skeleton +=== 3. Build the Skeleton In order for the Plugin to be easily installed into the DAO, we need to define the permissions the plugin will need. @@ -107,7 +110,7 @@ As you can see, we have a constructor storing the implementation contract instan Next, we will add the implementation for the `prepareInstallation` and `prepareUninstallation` functions. -### 4. Implementing the `prepareInstallation()` function +=== 4. Implementing the `prepareInstallation()` function The `prepareInstallation()` function should take in two parameters: @@ -183,7 +186,7 @@ Finally, we construct and return an array with the permissions that we need for - First, we request granting the `ADMIN_EXECUTE_PERMISSION_ID` to the `admin` address received. This is what gives the address access to use `plugin`'s functionality - in this case, call on the plugin's `execute` function so it can execute actions on behalf of the DAO. - Second, we request that our newly deployed plugin can use the `EXECUTE_PERMISSION_ID` permission on the `_dao`. We don't add conditions to the permissions in this case, so we use the `NO_CONDITION` constant provided by `PermissionLib`. -### 5. Implementing the `prepareUninstallation()` function +=== 5. Implementing the `prepareUninstallation()` function For the uninstallation, we have to make sure to revoke the two permissions that have been granted during the installation process. First, we revoke the `ADMIN_EXECUTE_PERMISSION_ID` from the `admin` address that we have stored in the implementation contract. @@ -219,7 +222,7 @@ function prepareUninstallation( } ``` -#### 6. Putting Everything Together +=== 6. Putting Everything Together Now, it's time to wrap up everything together. You should have a contract that looks like this: @@ -330,7 +333,7 @@ contract SimpleAdminSetup is PluginSetup { Once done, our plugin is ready to be published on the Aragon plugin registry. With the address of the `SimpleAdminSetup` contract, we are ready for creating our `PluginRepo`, the plugin's repository where all plugin versions will live. Check out our how to guides on xref:guide-develop-plugin/publishing-plugin.adoc[publishing your plugin here]. -### In the future: Subsequent Builds +=== In the future: Subsequent Builds For subsequent builds or releases of your plugin, you'll simply write a new implementation and associated Plugin Setup contract providing a new `prepareInstallation` and `prepareUninstallation` function. diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-upgradeable-plugin.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-upgradeable-plugin.adoc index e4b64afca..dad60788b 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-upgradeable-plugin.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-develop-plugin/write-upgradeable-plugin.adoc @@ -45,7 +45,7 @@ contract SimpleStorageBuild1 is PluginUUPSUpgradeable { NOTE: Keep in mind that in order to discriminate between the different initialize functions of your different builds, we name the initialize function `initializeBuild1`. This becomes more demanding for subsequent builds of your plugin. -### Initializing Subsequent Builds +=== Initializing Subsequent Builds Since you have chosen to build an upgradeable plugin, you can publish subsequent builds of plugin and **allow the users to update from an earlier build without losing the storage**. @@ -98,17 +98,17 @@ for build 4 `reinitializer(4)` and so on. == How to build an Upgradeable Plugin implementation contract -In this guide, we'll build a `SimpleStorage` Upgradeable plugin which all it does is storing a number. +For teaching purposes, we'll build a `SimpleStorage` Upgradeable plugin which all it does is storing a number. The Plugin contract is the one containing all the logic we'd like to implement on the DAO. -### 1. Set up the initialize function +=== 1. Set up the initialize function Make sure you have the initializer of your plugin well set up. Please review xref:#how_to_initialize_upgradeable_plugins[our guide on how to do that here] if you haven't already. Once you this is done, let's dive into several implementations and builds, as can be expected for Upgradeable plugins. -### 2. Adding your plugin implementation logic +=== 2. Adding your plugin implementation logic In our first build, we want to add an authorized `storeNumber` function to the contract - allowing a caller holding the `STORE_PERMISSION_ID` permission to change the stored value similar to what we did for xref:guide-develop-plugin/write-plugin-contract.adoc[the non-upgradeable `SimpleAdmin` Plugin]. @@ -133,50 +133,17 @@ contract SimpleStorageBuild1 is PluginUUPSUpgradeable { } ``` -### 3. Plugin done, PluginSetup contract next! +=== 3. Plugin done, PluginSetup contract next! Now that we have the logic for the plugin implemented, we'll need to define how this plugin should be installed/uninstalled from a DAO. In the next step, we'll write the `PluginSetup` contract - the one containing the installation, uninstallation, and upgrading instructions for the plugin. +== Building the Plugin Setup contract -// TODO set up contract should be very similar to non-upgradeable plugin setup contract check this section and minimize redundancy -// todo consider sorting this differently if after cleaning/merging/phrasing this file is still too long +As explained in previous sections, the Plugin Setup contract is the contract defining the instructions for installing, uninstalling, or upgrading plugins into DAOs. This contract prepares the permission granting or revoking that needs to happen in order for plugins to be able to perform actions on behalf of the DAO. -== How to build the Plugin Setup Contract for Upgradeable Plugins +NOTE: Before building the Plugin Setup contract, make sure you have the logic for your plugin implemented. -The Plugin Setup contract is the contract defining the instructions for installing, uninstalling, or upgrading plugins into DAOs. -This contract prepares the permission granting or revoking that needs to happen in order for plugins to be able to perform -actions on behalf of the DAO. - -### 1. Finish the Plugin contract's first build - -Before building the Plugin Setup contract, make sure you have the logic for your plugin implemented. In this case, - we're building a simple storage plugin which stores a number. - -```solidity -// SPDX-License-Identifier: AGPL-3.0-or-later -pragma solidity 0.8.21; - -import {IDAO, PluginUUPSUpgradeable} from '@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol'; - -/// @title SimpleStorage build 1 -contract SimpleStorageBuild1 is PluginUUPSUpgradeable { - bytes32 public constant STORE_PERMISSION_ID = keccak256('STORE_PERMISSION'); - - uint256 public number; // added in build 1 - - /// @notice Initializes the plugin when build 1 is installed. - function initializeBuild1(IDAO _dao, uint256 _number) external initializer { - __PluginUUPSUpgradeable_init(_dao); - number = _number; - } - - function storeNumber(uint256 _number) external auth(STORE_PERMISSION_ID) { - number = _number; - } -} -``` - -### 2. Add the `prepareInstallation()` and `prepareUninstallation()` functions +=== 1. Add the `prepareInstallation()` and `prepareUninstallation()` functions Each `PluginSetup` contract is deployed only once and each plugin version will have its own `PluginSetup` contract deployed. Accordingly, we instantiate the `implementation` contract via Solidity's `new` keyword as deployment with the minimal proxy @@ -269,7 +236,7 @@ variable `implementation` to save gas and an `implementation` function to return NOTE: Specifically important for this type of plugin is the `prepareUpdate()` function. Since we don't know the parameters we will require when updating the plugin to the next version, we can't add the `prepareUpdate()` function just yet. However, keep in mind that we will need to deploy new Plugin Setup contracts in subsequent builds to add in the `prepareUpdate()` function with each build requirements. We see this in depth in the xref:guide-develop-plugin/upgrade-plugin.adoc[How to update an Upgradeable Plugin] section. -### 3. Deployment +=== 2. Deployment Once you're done with your Plugin Setup contract, we'll need to deploy it so we can publish it into the Aragon OSx protocol. You can deploy your contract with a basic deployment script. @@ -349,7 +316,7 @@ Finally, run this in your terminal to execute the command: npx hardhat run scripts/deploy.ts ``` -### 4. Publishing the Plugin to the Aragon OSx Protocol +=== 3. Publishing the Plugin to the Aragon OSx Protocol Once done, our plugin is ready to be published on the Aragon plugin registry. With the address of the `SimpleAdminSetup` contract deployed, we're almost ready for creating our `PluginRepo`, the plugin's repository where all plugin versions will live. diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/custom-permission-condition.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/custom-permission-condition.adoc index 4078aec0e..3b50b40c3 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/custom-permission-condition.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/custom-permission-condition.adoc @@ -1,9 +1,6 @@ = Permission Conditions -== Permission Conditions - -Permission conditions relay the decision if an authorized call is permitted to another contract. -This contract must inherit from `PermissionCondition` and implement the `IPermissionCondition` interface. +Permission conditions relay the decision if an authorized call is permitted to another contract. This contract must inherit from `PermissionCondition` and implement the `IPermissionCondition` interface. ```solidity interface IPermissionCondition { @@ -25,32 +22,32 @@ interface IPermissionCondition { By implementing the `isGranted` function, any number of custom conditions can be added to the permission. These conditions can be based on -- The specific properties of +* The specific properties of - - The caller `who` - - The target `where` + ** The caller `who` + ** The target `where` -- The calldata `_data` of the function such as +* The calldata `_data` of the function such as - - Function signature - - Parameter values + ** Function signature + ** Parameter values -- General on-chain data such as +* General on-chain data such as - - Timestamps - - Token ownership - - Entries in curated registries + ** Timestamps + ** Token ownership + ** Entries in curated registries -- off-chain data being made available through oracle services (e.g., [chain.link](https://chain.link/), [witnet.io](https://witnet.io/)) such as + * Off-chain data being made available through oracle services (e.g., [chain.link](https://chain.link/), [witnet.io](https://witnet.io/)) such as - - Market data - - Weather data - - Scientific data - - Sports data + ** Market data + ** Weather data + ** Scientific data + ** Sports data -The following examples illustrate +The following examples illustrate. -## Examples +== Examples CAUTION: The following code examples serve educational purposes and are not intended to be used in production. @@ -73,7 +70,7 @@ If this is the case, the function call will succeed, otherwise it will revert. We can now add additional constraints to it by using the `grantWithCondition` function. Below, we show four exemplary conditions for different 4 different use cases that we could attach to the permission. -### Condition 1: Adding Parameter Constraints +=== Condition 1: Adding Parameter Constraints Let’s imagine that we want to make sure that `_amount` is not more than `1 ETH` without changing the code of `Example` contract. @@ -105,7 +102,7 @@ contract ParameterConstraintCondition is PermissionCondition { Now, after granting the `SEND_COINS_PERMISSION_ID` permission to `_where` and `_who` via the `grantWithCondition` function and pointing to the `ParameterConstraintCondition` condition contract, the `_who` address can only call the `sendCoins` of the `Example` contract deployed at address `_where` successfully if `_amount` is not larger than `_maxValue` stored in the condition contract. -### Condition 2: Delaying a Call With a Timestamp +=== Condition 2: Delaying a Call With a Timestamp In another use-case, we might want to make sure that the `sendCoins` can only be called after a certain date. This would look as following: @@ -132,7 +129,7 @@ contract TimeCondition is PermissionCondition { Here, the permission condition will only allow the call the `_date` specified in the constructor has passed. -### Condition 3: Using Curated Registries +=== Condition 3: Using Curated Registries In another use-case, we might want to make sure that the `sendCoins` function can only be called by real humans to prevent sybil attacks. For this, let's say we use the link:https://www.proofofhumanity.id/[Proof of Humanity (PoH)] registry providing a curated list of humans: @@ -163,11 +160,10 @@ contract ProofOfHumanityCondition is PermissionCondition { Here, the permission condition will only allow the call if the PoH registry confirms that the `_who` address is registered and belongs to a real human. -#### Condition 4: Using a Price Oracle +=== Condition 4: Using a Price Oracle In another use-case, we might want to make sure that the `sendCoins` function can only be called if the ETH price in USD is above a certain threshold: - ```solidity import '@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol'; @@ -203,6 +199,6 @@ contract PriceOracleCondition is PermissionCondition { } } -Here, we use https://docs.chain.link/docs/data-feeds/ providing us with the latest ETH/USD price on the Goerli testnet and require that the call is only allowed if the ETH price is over $9000. - -```` +/* Here, we use https://docs.chain.link/docs/data-feeds/ providing us with the latest ETH/USD price on +the Goerli testnet and require that the call is only allowed if the ETH price is over $9000. */ +``` diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/execute-actions.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/execute-actions.adoc index 0750f09e9..6fd3bb53f 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/execute-actions.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/execute-actions.adoc @@ -1,16 +1,14 @@ -= Executing actions on behalf of the DAO - -## Using the DAO Executor += Executing actions on the DAO Executing actions on behalf of the DAO is done through the `execute` function from the `DAO.sol` contract. This function allows us to link:https://github.com/aragon/osx/blob/develop/packages/contracts/src/core/dao/DAO.sol[pass an array of actions] to be executed by the DAO contract itself. However, for the `execute` call to work, the address calling the function (the `msg.sender`) needs to have the xref:core/permissions.adoc#permissions_native_to_the_dao_contract[`EXECUTE_PERMISSION`]. This is to prevent anyone from being able to execute actions on behalf of the DAO and keep your assets safe from malicious actors. -## How to grant the Execute Permission +== How to grant the Execute Permission Usually, the `EXECUTE_PERMISSION` is granted to a governance plugin of the DAO so that only the approved proposals can be executed. For example, we'd grant the `EXECUTE_PERMISSION` to the address of the Multisig Plugin. That way, when a proposal is approved by the required members of the multisig, the plugin is able to call the `execute` function on the DAO in order to get the actions executed. -To grant the `EXECUTE_PERMISSION` to an address, you'll want to call on the `PermissionManager`'s link:https://github.com/aragon/osx/blob/develop/packages/contracts/src/core/permission/PermissionManager.sol#L105[grant function] and pass it 4 parameters: +To grant the `EXECUTE_PERMISSION` to an address, you'll want to call on the `PermissionManager` 's link:https://github.com/aragon/osx/blob/develop/packages/contracts/src/core/permission/PermissionManager.sol#L105[grant function] and pass it 4 parameters: - `where`: the address of the contract containing the function `who` wants access to - `who`: the address (EOA or contract) receiving the permission @@ -19,9 +17,9 @@ To grant the `EXECUTE_PERMISSION` to an address, you'll want to call on the `Per CAUTION: You probably don't want to grant `EXECUTE_PERMISSION` to any random address, since this gives the address access to execute any action on behalf of the DAO. We recommend you only grant `EXECUTE_PERMISSION` to governance plugins to ensure the safety of your assets. Granting `EXECUTE_PERMISSION` to an externally owned account is considered an anti-pattern. -## Examples +== Examples -### Calling a DAO Function +=== Calling a DAO Function Imagine you want to call an internal function inside the `DAO` contract, for example, to manually xref:core/permissions.adoc[grant or revoke a permission]. The corresponding `Action` and `execute` function call look as follows: @@ -55,15 +53,15 @@ To revoke the permission, the selector of the xref:api:core.adoc#PermissionManag If the caller possesses the xref:core/permissions.adoc#permissions_native_to_the_dao_contract[`ROOT_PERMISSION_ID` permission] on the DAO contract, the call becomes simpler and cheaper: -CAUTION: Granting the `ROOT_PERMISSION_ID` permission to other contracts other than the `DAO` contract is dangerous and considered as an anti-pattern. - ```solidity function exampleGrantFunction(DAO dao, address _where, address _who, bytes32 _permissionId) { dao.grant(_where, _who, _permissionId); // For this to work, the `msg.sender` needs the `ROOT_PERMISSION_ID` } ``` -### Sending Native Tokens +CAUTION: Granting the `ROOT_PERMISSION_ID` permission to other contracts other than the `DAO` contract is dangerous and considered as an anti-pattern. + +=== Sending Native Tokens Send `0.1 ETH` from the DAO treasury to Alice. The corresponding `Action` and `execute` function call would look as follows: @@ -80,7 +78,7 @@ function exampleNativeTokenTransfer(IDAO dao, bytes32 _callId, address _receiver } ``` -### Calling a Function from an External Contract +=== Calling a Function from an External Contract Imagine that you want to call an external function, let's say in a `Calculator` contract that adds two numbers for you. The corresponding `Action` and `execute` function call look as follows: @@ -116,7 +114,7 @@ function exampleFunctionCall( } ``` -### Calling a Payable Function +=== Calling a Payable Function Wrap `0.1 ETH` from the DAO treasury into `wETH` by depositing it into the link:https://goerli.etherscan.io/token/0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6#writeContract[Goerli WETH9 contract]. The corresponding `Action` and `execute` function call look as follows: diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/index.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/index.adoc index bd10b753c..90009df3f 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/index.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/index.adoc @@ -2,7 +2,7 @@ DAOs are decentralized autonomous organizations. They are a group of people managing on-chain assets through a set of smart contracts. -## What do you need to know in order to operate your DAO? +== What do you need to know in order to operate your DAO? DAOs manage assets through collective decision-making mechanisms. Although a lot can be said of the social, behavioral aspects of operating a DAO, in this guide we will focus on the technical aspects. @@ -12,9 +12,12 @@ NOTE: Plugins are smart contracts which extend the functionality of what the DAO Decision-making mechanisms are one example of Plugins. Treasury management, action bundles, or connections to other smart contracts are others. +== Walkthrough + In this section, we'll go through how to operate and maintain your DAO: -- xref:how-to-guides/dao/best-practices.adoc[A Summary of Best Practices] -- xref:how-to-guides/dao/action-execution.adoc[How to execute actions on behalf of the DAO] -- xref:how-to-guides/dao/managing-plugins.adoc[How to manage a DAO's plugins] -- xref:how-to-guides/dao/protocol-upgrades.adoc[How to upgrade your DAO to a future Aragon OSx Releases] +- xref:guide-set-up-dao/execute-actions.adoc[Executing actions on the DAO] +- xref:guide-set-up-dao/manage-dao-plugins.adoc[Managing a DAO's plugins] +- xref:guide-set-up-dao/custom-permission-condition.adoc[Writing custom permission conditions] +- xref:guide-set-up-dao/upgrade-dao.adoc[Upgrading your DAO] +- xref:guide-set-up-dao/keep-dao-safe.adoc[Keeping your DAO safe] diff --git a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/keep-dao-safe.adoc b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/keep-dao-safe.adoc index 9ee9f914f..80910842d 100644 --- a/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/keep-dao-safe.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/guide-set-up-dao/keep-dao-safe.adoc @@ -1,79 +1,74 @@ = Best Practices -=== Some Advice When Operating your DAO +== Some Advice When Operating your DAO -### DOs πŸ‘Œ +=== DOs πŸ‘Œ -- Make sure that at least one address (typically a governance plugin) has `EXECUTE_PERMISSION_ID` permission so that something can be executed on behalf of the DAO. -- Check every proposal asking to install, update, or uninstall a plugin with utmost care and review. Installation means granting an external contract permissions to do things on behalf of your DAO, so you want to be extra careful about: - - the implementation contract - - the setup contract - - the helper contracts - - the permissions being granted/revoked +* Make sure that at least one address (typically a governance plugin) has `EXECUTE_PERMISSION_ID` permission so that something can be executed on behalf of the DAO. +* Check every proposal asking to install, update, or uninstall a plugin with utmost care and review. Installation means granting an external contract permissions to do things on behalf of your DAO, so you want to be extra careful about: + ** the implementation contract + ** the setup contract + ** the helper contracts + ** the permissions being granted/revoked -### DON'Ts βœ‹ +=== DON'Ts βœ‹ -- Incapacitate your DAO by revoking all `EXECUTE_PERMISSION`. This means your DAO will be blocked and any assets you hold may be locked in forever. This can happen through: - - uninstalling your last governance plugin. - - applying an update to your last governance plugin. -- Don't give permissions to directly call functions from the DAO. Better and safer to use a plugin instead. -- If you're using the Token Voting plugin in your DAO, make sure you don't mint additional tokens without careful consideration. If you mint too many at once, this may lock your DAO, since you will not be able to reach the minimum participation threshold. This happens if there are not enough tokens already on the marketΒ to meet the minimum participation percentage and the DAO owns most of the governance tokens. +* Incapacitate your DAO by revoking all `EXECUTE_PERMISSION`. This means your DAO will be blocked and any assets you hold may be locked in forever. This can happen through: + ** uninstalling your last governance plugin. + ** applying an update to your last governance plugin. +* Don't give permissions to directly call functions from the DAO. Better and safer to use a plugin instead. +* If you're using the Token Voting plugin in your DAO, make sure you don't mint additional tokens without careful consideration. If you mint too many at once, this may lock your DAO, since you will not be able to reach the minimum participation threshold. This happens if there are not enough tokens already on the marketΒ to meet the minimum participation percentage and the DAO owns most of the governance tokens. -## Risks and Their Mitigation +== Risks and Their Mitigation Extending the functionality of your DAO in the form of plugins can introduce risks, particularly, if this code comes from unaudited and untrusted sources. -### Risks +=== Risks If a plugin has a bug or vulnerability that can be exploited, this can result in loss of funds or compromise the DAO. Besides, standard vulnerabilities such as -- Re-entrancy -- Default function visibility -- Leaving contracts uninitialized -- Time or oracle manipulation attacks -- Integer overflow & underflow +* Re-entrancy +* Default function visibility +* Leaving contracts uninitialized +* Time or oracle manipulation attacks +* Integer overflow & underflow that might be carelessly or intentionally caused, a malicious plugin can hide **backdoors** in its code or request **elevated permissions** in the installation, upgrade, or uninstallation process to the attacker. -#### Backdoors +==== Backdoors -- link:https://a16zcrypto.com/metamorphic-smart-contract-detector-tool[metamorphic contracts] (contracts, that can be redeployed with new code to the same address) -- malicious repurposing of storage in an update of an upgradeable plugin contract +* link:https://a16zcrypto.com/metamorphic-smart-contract-detector-tool[metamorphic contracts] (contracts, that can be redeployed with new code to the same address) +* malicious repurposing of storage in an update of an upgradeable plugin contract -#### Permissions +==== Permissions -Examples for elevated permissions, are the [permissions native to the DAO contract](../../../01-core/02-permissions/index.md#permissions_native_to_the_dao_contract) such as +Examples for elevated permissions, are the xref:core/permissions.adoc#permissions_native_to_the_dao_contract[permissions native to the DAO contract] such as -- `ROOT_PERMISSION_ID` -- `EXECUTE_PERMISSION_ID` -- `UPGRADE_DAO_PERMISSION_ID` +* `ROOT_PERMISSION_ID` +* `EXECUTE_PERMISSION_ID` +* `UPGRADE_DAO_PERMISSION_ID` That should never be granted to untrusted addresses as they can be used to take control over your DAO. Likewise, one must be careful to not lock your DAO accidentally by -- uninstalling the last governance plugin with `EXECUTE_PERMISSION_ID` permission -- revoking the `ROOT_PERMISSION_ID` permission from itself or -- choosing governance settings and execution criteria that most likely can never be met (e.g., requiring 100% participation for a token vote to pass) +* uninstalling the last governance plugin with `EXECUTE_PERMISSION_ID` permission +* revoking the `ROOT_PERMISSION_ID` permission from itself or +* choosing governance settings and execution criteria that most likely can never be met (e.g., requiring 100% participation for a token vote to pass) -### Mitigation +=== Mitigation To mitigate the risks mentioned above, proposals requesting the setup of one or multiple plugins must be carefully examined and reviewed by inspecting -- The implementation contract -- The setup contract, i.e., - - The installation and deployment logic - - The requested permission - - The helper contracts accompanying the plugin -- The UI components, i.e., - - Misleading (re-)naming of input fields, buttons, or other elements +* The implementation contract +* The setup contract, i.e., + ** The installation and deployment logic + ** The requested permission + ** The helper contracts accompanying the plugin +* The UI components, i.e., + ** Misleading (re-)naming of input fields, buttons, or other elements -Generally, we recommend only installing plugins from trusted, verified sources such as those verified by Aragon. - -More information can be found in the How-to guides - -- [Operating your DAO](../../../../02-how-to-guides/01-dao/index.md) -- [Developing a Plugin](../../../../02-how-to-guides/02-plugin-development/index.md) +Generally, we recommend only installing plugins from trusted, verified sources such as those verified by Aragon. \ 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 299875cd0..4b440e493 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 @@ -1,14 +1,12 @@ = 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 +== 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. @@ -19,7 +17,7 @@ Although the easiest (and recommended) way to create your DAO is through the lin // -#### How to change a DAO's Governance Setup after a DAO has been created +=== 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]. @@ -30,9 +28,9 @@ Here, it is very important that you **maintain at least one functioning governan 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 +== 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. 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 ea6ce5055..146efc880 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 @@ -8,4 +8,4 @@ To make it easy for your DAO to switch to future Aragon OSx protocol versions, w 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 +NOTE: 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 diff --git a/packages/contracts/docs/modules/ROOT/pages/how-to-guides/plugin-development/index.adoc b/packages/contracts/docs/modules/ROOT/pages/how-to-guides/plugin-development/index.adoc index 9ffac00d5..c7a96f764 100644 --- a/packages/contracts/docs/modules/ROOT/pages/how-to-guides/plugin-development/index.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/how-to-guides/plugin-development/index.adoc @@ -62,5 +62,4 @@ For more information on how to develop a plugin, you can check our plugin develo - xref:how-to-guides/plugin-development/upgradeable-plugin/index.adoc[Upgradeable plugin] - xref:how-to-guides/plugin-development/governance-plugins/index.adoc[Governance plugin] -IMPORTANT: This plugin template uses version TODO:GIORGI `1.4.0-alpha.5` of the Aragon OSx protocol. This version is still in development and -is not audited yet. +IMPORTANT: This plugin template uses version TODO:GIORGI `1.4.0-alpha.5` of the Aragon OSx protocol. This version is still in development and is not audited yet. diff --git a/packages/contracts/docs/modules/ROOT/pages/index.adoc b/packages/contracts/docs/modules/ROOT/pages/index.adoc index 1e4bee018..ec92b3d7a 100644 --- a/packages/contracts/docs/modules/ROOT/pages/index.adoc +++ b/packages/contracts/docs/modules/ROOT/pages/index.adoc @@ -1,6 +1,6 @@ = Aragon OSx -## The Contracts Behind the Protocol +== The Contracts Behind the Protocol The Aragon OSx protocol is the foundation layer of the new Aragon stack. It allows users to create, manage, and customize DAOs in a way that is lean, adaptable, and secure. @@ -20,7 +20,7 @@ To facilitate this, Aragon OSx runs a set of **framework contracts**: - **Plugin repo factory and registry contract:** create and version plugin repositories. - **Plugin Setup Processor contract:** sets up plugins from a plugin repository in a DAO (installation, update, uninstallation). -## The Aragon OSx DAO Framework +== The Aragon OSx DAO Framework The Aragon OSx protocol is a DAO framework structured as follows: @@ -28,23 +28,23 @@ image::aragon-os-framework-overview.drawio.svg[align="center"] Overview of the Aragon OSx protocol with its structural components and their responsibilities: the governance layer constituted by the framework DAO, the code layer including the framework and core contracts, which depends on external libraries and services -### Code Layer +=== Code Layer -The foundation of the Aragon OSx protocol is the **code layer** constituted by the core and framework related contracts. -The xref:how-it-works/core/index.adoc[core contracts] provide the core primitives intended to be used by users and implemented by developers of the DAO framework. -The xref:how-it-works/framework/index.adoc[framework contracts] provide the infrastructure to easily create and manage your DAOs and plugins easy. +The foundation of the Aragon OSx protocol is the **code layer** constituted by the *_framework_* and *_core_* related contracts. +The xref:core/index.adoc[Core contracts] provide the core primitives intended to be used by users and implemented by developers of the DAO framework. +The xref:framework/index.adoc[Framework contracts] provide the infrastructure to easily create and manage your DAOs and plugins easy. Both are built on top of external dependencies, most notably the link:https://www.openzeppelin.com/contracts[OpenZeppelin] and the link:https://docs.ens.domains/[Ethereum Name Service (ENS)] contracts. The core and framework contracts are free to use, and no additional fees are charged. -### Governance Layer +=== Governance Layer -To govern the framework infrastructure, an Aragon OSx [Framework DAO](./03-framwork-dao.md) is deployed constituting the **governance layer** of the Aragon OSx protocol. +To govern the framework infrastructure, an Aragon OSx xref:framework/index.adoc[Framework DAO] is deployed constituting the **governance layer** of the Aragon OSx protocol. In the next sections, you will learn more about the individual components of the framework. -## Getting Started +== Getting Started Users interact with the Aragon OSx protocol through the link:https://app.aragon.org[Aragon App], link:https://devs.aragon.org/docs/sdk[Aragon SDK] or directly calling on the link:https://github.com/aragon/osx[protocol contracts] - as well as through any third-party projects built using our stack. @@ -88,17 +88,16 @@ contract Box { } ``` -## Customize your DAO +== Customize your DAO DAO Plugins are the best way to customize your DAO. These are modular extendable pieces of software which you can install or uninstall from your DAO as it evolves and grows. +In the following sections, we'll dive deeper into this topic. You can take a quick look in the xref:guide-develop-plugin/index.adoc[Guide: Developing a Plugin]. -To learn more about plugins, check out our guide xref:how-to-guides/plugin-development/index.adoc[here]. -### Walkthrough +== Walkthrough This documentation is divided into conceptual and practical sections as well as the reference guide. -- Conceptual xref:how-it-works/index.adoc[How It Works articles] explain the architecture behind our protocol. -- Practical xref:how-to-guides/index.adoc[How-to Guides] explain how to use and leverage our protocol. -- The xref:api:core.adoc[Core] and xref:api:framework.adoc[Framework], generated from the NatSpec comments of the latest `@aragon/osx` release documents each individual Solidity contract, function, and variable. - +- Conceptual xref:core/index.adoc[Core contracts] and xref:framework/index.adoc[Framework contracts] explain the architecture behind our protocol. +- Practical xref:guide-set-up-dao/index.adoc[Guide: Setting up a DAO] and xref:guide-develop-plugin/index.adoc[Guide: Developing a Plugin] explain how to use and leverage our protocol. +- The xref:api:core.adoc[API Core] and xref:api:framework.adoc[API Framework], generated from the NatSpec comments of the latest `@aragon/osx` release documents each individual Solidity contract, function, and variable. \ No newline at end of file diff --git a/packages/contracts/docs/modules/api/pages/core.adoc b/packages/contracts/docs/modules/api/pages/core.adoc index 2ff6238d8..d746320a0 100644 --- a/packages/contracts/docs/modules/api/pages/core.adoc +++ b/packages/contracts/docs/modules/api/pages/core.adoc @@ -49,30 +49,6 @@ :xref-CallbackHandler-CallbackReceived-address-bytes4-bytes-: xref:core.adoc#CallbackHandler-CallbackReceived-address-bytes4-bytes- :xref-PermissionManager-Granted-bytes32-address-address-address-address-: xref:core.adoc#PermissionManager-Granted-bytes32-address-address-address-address- :xref-PermissionManager-Revoked-bytes32-address-address-address-: xref:core.adoc#PermissionManager-Revoked-bytes32-address-address-address- -:xref-DAO-ReentrantCall--: xref:core.adoc#DAO-ReentrantCall-- -:xref-DAO-TooManyActions--: xref:core.adoc#DAO-TooManyActions-- -:xref-DAO-ActionFailed-uint256-: xref:core.adoc#DAO-ActionFailed-uint256- -:xref-DAO-InsufficientGas--: xref:core.adoc#DAO-InsufficientGas-- -:xref-DAO-ZeroAmount--: xref:core.adoc#DAO-ZeroAmount-- -:xref-DAO-NativeTokenDepositAmountMismatch-uint256-uint256-: xref:core.adoc#DAO-NativeTokenDepositAmountMismatch-uint256-uint256- -:xref-DAO-ProtocolVersionUpgradeNotSupported-uint8-3--: xref:core.adoc#DAO-ProtocolVersionUpgradeNotSupported-uint8-3-- -:xref-DAO-FunctionRemoved--: xref:core.adoc#DAO-FunctionRemoved-- -:xref-DAO-AlreadyInitialized--: xref:core.adoc#DAO-AlreadyInitialized-- -:xref-CallbackHandler-UnknownCallback-bytes4-bytes4-: xref:core.adoc#CallbackHandler-UnknownCallback-bytes4-bytes4- -:xref-PermissionManager-Unauthorized-address-address-bytes32-: xref:core.adoc#PermissionManager-Unauthorized-address-address-bytes32- -:xref-PermissionManager-PermissionAlreadyGrantedForDifferentCondition-address-address-bytes32-address-address-: xref:core.adoc#PermissionManager-PermissionAlreadyGrantedForDifferentCondition-address-address-bytes32-address-address- -:xref-PermissionManager-ConditionNotAContract-contract-IPermissionCondition-: xref:core.adoc#PermissionManager-ConditionNotAContract-contract-IPermissionCondition- -:xref-PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition-: xref:core.adoc#PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition- -:xref-PermissionManager-PermissionsForAnyAddressDisallowed--: xref:core.adoc#PermissionManager-PermissionsForAnyAddressDisallowed-- -:xref-PermissionManager-AnyAddressDisallowedForWhoAndWhere--: xref:core.adoc#PermissionManager-AnyAddressDisallowedForWhoAndWhere-- -:xref-PermissionManager-GrantWithConditionNotSupported--: xref:core.adoc#PermissionManager-GrantWithConditionNotSupported-- -:xref-DAO-MAX_ACTIONS-uint256: xref:core.adoc#DAO-MAX_ACTIONS-uint256 -:xref-CallbackHandler-callbackMagicNumbers-mapping-bytes4----bytes4-: xref:core.adoc#CallbackHandler-callbackMagicNumbers-mapping-bytes4----bytes4- -:xref-CallbackHandler-UNREGISTERED_CALLBACK-bytes4: xref:core.adoc#CallbackHandler-UNREGISTERED_CALLBACK-bytes4 -:xref-PermissionManager-ANY_ADDR-address: xref:core.adoc#PermissionManager-ANY_ADDR-address -:xref-PermissionManager-UNSET_FLAG-address: xref:core.adoc#PermissionManager-UNSET_FLAG-address -:xref-PermissionManager-ALLOW_FLAG-address: xref:core.adoc#PermissionManager-ALLOW_FLAG-address -:xref-PermissionManager-permissionsHashed-mapping-bytes32----address-: xref:core.adoc#PermissionManager-permissionsHashed-mapping-bytes32----address- :xref-PermissionManager-auth-bytes32-: xref:core.adoc#PermissionManager-auth-bytes32- :xref-PermissionManager-__PermissionManager_init-address-: xref:core.adoc#PermissionManager-__PermissionManager_init-address- :xref-PermissionManager-grant-address-address-bytes32-: xref:core.adoc#PermissionManager-grant-address-address-bytes32- @@ -92,17 +68,6 @@ :xref-PermissionManager-ROOT_PERMISSION_ID-bytes32: xref:core.adoc#PermissionManager-ROOT_PERMISSION_ID-bytes32 :xref-PermissionManager-Granted-bytes32-address-address-address-address-: xref:core.adoc#PermissionManager-Granted-bytes32-address-address-address-address- :xref-PermissionManager-Revoked-bytes32-address-address-address-: xref:core.adoc#PermissionManager-Revoked-bytes32-address-address-address- -:xref-PermissionManager-Unauthorized-address-address-bytes32-: xref:core.adoc#PermissionManager-Unauthorized-address-address-bytes32- -:xref-PermissionManager-PermissionAlreadyGrantedForDifferentCondition-address-address-bytes32-address-address-: xref:core.adoc#PermissionManager-PermissionAlreadyGrantedForDifferentCondition-address-address-bytes32-address-address- -:xref-PermissionManager-ConditionNotAContract-contract-IPermissionCondition-: xref:core.adoc#PermissionManager-ConditionNotAContract-contract-IPermissionCondition- -:xref-PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition-: xref:core.adoc#PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition- -:xref-PermissionManager-PermissionsForAnyAddressDisallowed--: xref:core.adoc#PermissionManager-PermissionsForAnyAddressDisallowed-- -:xref-PermissionManager-AnyAddressDisallowedForWhoAndWhere--: xref:core.adoc#PermissionManager-AnyAddressDisallowedForWhoAndWhere-- -:xref-PermissionManager-GrantWithConditionNotSupported--: xref:core.adoc#PermissionManager-GrantWithConditionNotSupported-- -:xref-PermissionManager-ANY_ADDR-address: xref:core.adoc#PermissionManager-ANY_ADDR-address -:xref-PermissionManager-UNSET_FLAG-address: xref:core.adoc#PermissionManager-UNSET_FLAG-address -:xref-PermissionManager-ALLOW_FLAG-address: xref:core.adoc#PermissionManager-ALLOW_FLAG-address -:xref-PermissionManager-permissionsHashed-mapping-bytes32----address-: xref:core.adoc#PermissionManager-permissionsHashed-mapping-bytes32----address- :xref-CallbackHandler-_handleCallback-bytes4-bytes-: xref:core.adoc#CallbackHandler-_handleCallback-bytes4-bytes- :xref-CallbackHandler-_registerCallback-bytes4-bytes4-: xref:core.adoc#CallbackHandler-_registerCallback-bytes4-bytes4- :xref-CallbackHandler-CallbackReceived-address-bytes4-bytes-: xref:core.adoc#CallbackHandler-CallbackReceived-address-bytes4-bytes- @@ -336,29 +301,12 @@ Public API of the Aragon DAO framework. [.contract-index] .Errors -- -* {xref-DAO-ReentrantCall--}[`++ReentrantCall()++`] -* {xref-DAO-TooManyActions--}[`++TooManyActions()++`] -* {xref-DAO-ActionFailed-uint256-}[`++ActionFailed(index)++`] -* {xref-DAO-InsufficientGas--}[`++InsufficientGas()++`] -* {xref-DAO-ZeroAmount--}[`++ZeroAmount()++`] -* {xref-DAO-NativeTokenDepositAmountMismatch-uint256-uint256-}[`++NativeTokenDepositAmountMismatch(expected, actual)++`] -* {xref-DAO-ProtocolVersionUpgradeNotSupported-uint8-3--}[`++ProtocolVersionUpgradeNotSupported(protocolVersion)++`] -* {xref-DAO-FunctionRemoved--}[`++FunctionRemoved()++`] -* {xref-DAO-AlreadyInitialized--}[`++AlreadyInitialized()++`] [.contract-subindex-inherited] .CallbackHandler -* {xref-CallbackHandler-UnknownCallback-bytes4-bytes4-}[`++UnknownCallback(callbackSelector, magicNumber)++`] [.contract-subindex-inherited] .PermissionManager -* {xref-PermissionManager-Unauthorized-address-address-bytes32-}[`++Unauthorized(where, who, permissionId)++`] -* {xref-PermissionManager-PermissionAlreadyGrantedForDifferentCondition-address-address-bytes32-address-address-}[`++PermissionAlreadyGrantedForDifferentCondition(where, who, permissionId, currentCondition, newCondition)++`] -* {xref-PermissionManager-ConditionNotAContract-contract-IPermissionCondition-}[`++ConditionNotAContract(condition)++`] -* {xref-PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition-}[`++ConditionInterfaceNotSupported(condition)++`] -* {xref-PermissionManager-PermissionsForAnyAddressDisallowed--}[`++PermissionsForAnyAddressDisallowed()++`] -* {xref-PermissionManager-AnyAddressDisallowedForWhoAndWhere--}[`++AnyAddressDisallowedForWhoAndWhere()++`] -* {xref-PermissionManager-GrantWithConditionNotSupported--}[`++GrantWithConditionNotSupported()++`] [.contract-subindex-inherited] .ProtocolVersion @@ -407,19 +355,12 @@ Public API of the Aragon DAO framework. [.contract-index] .Internal Variables -- -* {xref-DAO-MAX_ACTIONS-uint256}[`++uint256 constant MAX_ACTIONS++`] [.contract-subindex-inherited] .CallbackHandler -* {xref-CallbackHandler-callbackMagicNumbers-mapping-bytes4----bytes4-}[`++mapping(bytes4 => bytes4) callbackMagicNumbers++`] -* {xref-CallbackHandler-UNREGISTERED_CALLBACK-bytes4}[`++bytes4 constant UNREGISTERED_CALLBACK++`] [.contract-subindex-inherited] .PermissionManager -* {xref-PermissionManager-ANY_ADDR-address}[`++address constant ANY_ADDR++`] -* {xref-PermissionManager-UNSET_FLAG-address}[`++address constant UNSET_FLAG++`] -* {xref-PermissionManager-ALLOW_FLAG-address}[`++address constant ALLOW_FLAG++`] -* {xref-PermissionManager-permissionsHashed-mapping-bytes32----address-}[`++mapping(bytes32 => address) permissionsHashed++`] [.contract-subindex-inherited] .ProtocolVersion @@ -471,7 +412,7 @@ Public API of the Aragon DAO framework. A modifier to protect a function from calling itself, directly or indirectly (reentrancy). -Currently, this modifier is only applied to the `execute()` function. If this is used multiple times, private `_beforeNonReentrant()` and `_afterNonReentrant()` functions should be created to prevent code duplication. +Currently, this modifier is only applied to the `execute()` function. If this is used multiple times, private `_beforeNonReentrant()` and `_afterNonReentrant()` functions should be created to prevent code duplication. [.contract-item] [[DAO-onlyCallAtInitialization--]] @@ -490,10 +431,10 @@ Disables the initializers on the implementation contract to prevent it from bein ==== `[.contract-item-name]#++initialize++#++(bytes _metadata, address _initialOwner, address _trustedForwarder, string daoURI_)++` [.item-kind]#external# Initializes the DAO by -- setting the reentrancy status variable to `_NOT_ENTERED` +- setting the reentrancy status variable to `_NOT_ENTERED` - registering the [ERC-165](https://eips.ethereum.org/EIPS/eip-165) interface ID - setting the trusted forwarder for meta transactions -- giving the `ROOT_PERMISSION_ID` permission to the initial owner (that should be revoked and transferred to the DAO after setup). +- giving the `ROOT_PERMISSION_ID` permission to the initial owner (that should be revoked and transferred to the DAO after setup). This method is required to support [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822). @@ -507,9 +448,9 @@ Initializes the DAO after an upgrade from a previous protocol version. [[DAO-isPermissionRestrictedForAnyAddr-bytes32-]] ==== `[.contract-item-name]#++isPermissionRestrictedForAnyAddr++#++(bytes32 _permissionId) β†’ bool++` [.item-kind]#internal# -Decides if the granting permissionId is restricted when `_who == ANY_ADDR` or `_where == ANY_ADDR`. +Decides if the granting permissionId is restricted when `_who == ANY_ADDR` or `_where == ANY_ADDR`. -By default, every permission is unrestricted and it is the derived contract's responsibility to override it. Note, that the `ROOT_PERMISSION_ID` is included and not required to be set it again. +By default, every permission is unrestricted and it is the derived contract's responsibility to override it. Note, that the `ROOT_PERMISSION_ID` is included and not required to be set it again. [.contract-item] [[DAO-_authorizeUpgrade-address-]] @@ -517,7 +458,7 @@ By default, every permission is unrestricted and it is the derived contract's re Internal method authorizing the upgrade of the contract via the [upgradeability mechanism for UUPS proxies](https://docs.openzeppelin.com/contracts/4.x/api/proxy#UUPSUpgradeable) (see [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822)). -The caller must have the `UPGRADE_DAO_PERMISSION_ID` permission. +The caller must have the `UPGRADE_DAO_PERMISSION_ID` permission. [.contract-item] [[DAO-setTrustedForwarder-address-]] @@ -535,7 +476,7 @@ Getter for the trusted forwarder verifying the meta transaction. [[DAO-hasPermission-address-address-bytes32-bytes-]] ==== `[.contract-item-name]#++hasPermission++#++(address _where, address _who, bytes32 _permissionId, bytes _data) β†’ bool++` [.item-kind]#external# -Checks if an address has permission on a contract via a permission identifier and considers if `ANY_ADDRESS` was used in the granting process. +Checks if an address has permission on a contract via a permission identifier and considers if `ANY_ADDRESS` was used in the granting process. [.contract-item] [[DAO-setMetadata-bytes-]] @@ -570,17 +511,17 @@ Introduced in v1.0.0. Removed in v1.4.0. Checks whether a signature is valid for a provided hash according to [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271). Relays the validation logic determining who is allowed to sign on behalf of the DAO to its permission manager. -Caller specific bypassing can be set direct granting (i.e., `grant({_where: dao, _who: specificErc1271Caller, _permissionId: VALIDATE_SIGNATURE_PERMISSION_ID})`). -Caller specific signature validation logic can be set by granting with a `PermissionCondition` (i.e., `grantWithCondition({_where: dao, _who: specificErc1271Caller, _permissionId: VALIDATE_SIGNATURE_PERMISSION_ID, _condition: yourConditionImplementation})`) -Generic signature validation logic can be set for all calling contracts by granting with a `PermissionCondition` to `PermissionManager.ANY_ADDR()` (i.e., `grantWithCondition({_where: dao, _who: PermissionManager.ANY_ADDR(), _permissionId: VALIDATE_SIGNATURE_PERMISSION_ID, _condition: yourConditionImplementation})`). +Caller specific bypassing can be set direct granting (i.e., `grant({_where: dao, _who: specificErc1271Caller, _permissionId: VALIDATE_SIGNATURE_PERMISSION_ID})`). +Caller specific signature validation logic can be set by granting with a `PermissionCondition` (i.e., `grantWithCondition({_where: dao, _who: specificErc1271Caller, _permissionId: VALIDATE_SIGNATURE_PERMISSION_ID, _condition: yourConditionImplementation})`) +Generic signature validation logic can be set for all calling contracts by granting with a `PermissionCondition` to `PermissionManager.ANY_ADDR()` (i.e., `grantWithCondition({_where: dao, _who: PermissionManager.ANY_ADDR(), _permissionId: VALIDATE_SIGNATURE_PERMISSION_ID, _condition: yourConditionImplementation})`). [.contract-item] [[DAO-receive--]] ==== `[.contract-item-name]#++receive++#++()++` [.item-kind]#external# -Emits the `NativeTokenDeposited` event to track native token deposits that weren't made via the deposit method. +Emits the `NativeTokenDeposited` event to track native token deposits that weren't made via the deposit method. -This call is bound by the gas limitations for `send`/`transfer` calls introduced by [ERC-2929](https://eips.ethereum.org/EIPS/eip-2929). +This call is bound by the gas limitations for `send`/`transfer` calls introduced by [ERC-2929](https://eips.ethereum.org/EIPS/eip-2929). Gas cost increases in future hard forks might break this function. As an alternative, [ERC-2930](https://eips.ethereum.org/EIPS/eip-2930)-type transactions using access lists can be employed. [.contract-item] @@ -611,7 +552,7 @@ Registers an ERC standard having a callback by registering its [ERC-165](https:/ [[DAO-daoURI--]] ==== `[.contract-item-name]#++daoURI++#++() β†’ string++` [.item-kind]#external# -A distinct Uniform Resource Identifier (URI) pointing to a JSON object following the "EIP-4824 DAO JSON-LD Schema". This JSON file splits into four URIs: membersURI, proposalsURI, activityLogURI, and governanceURI. The membersURI should point to a JSON file that conforms to the "EIP-4824 Members JSON-LD Schema". The proposalsURI should point to a JSON file that conforms to the "EIP-4824 Proposals JSON-LD Schema". The activityLogURI should point to a JSON file that conforms to the "EIP-4824 Activity Log JSON-LD Schema". The governanceURI should point to a flatfile, normatively a .md file. Each of the JSON files named above can be statically hosted or dynamically-generated. +A distinct Uniform Resource Identifier (URI) pointing to a JSON object following the "EIP-4824 DAO JSON-LD Schema". This JSON file splits into four URIs: membersURI, proposalsURI, activityLogURI, and governanceURI. The membersURI should point to a JSON file that conforms to the "EIP-4824 Members JSON-LD Schema". The proposalsURI should point to a JSON file that conforms to the "EIP-4824 Proposals JSON-LD Schema". The activityLogURI should point to a JSON file that conforms to the "EIP-4824 Activity Log JSON-LD Schema". The governanceURI should point to a flatfile, normatively a .md file. Each of the JSON files named above can be statically hosted or dynamically-generated. [.contract-item] [[DAO-setDaoURI-string-]] @@ -629,31 +570,31 @@ Sets the new [ERC-4824](https://eips.ethereum.org/EIPS/eip-4824) DAO URI and emi [[DAO-EXECUTE_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++EXECUTE_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `execute` function. +The ID of the permission required to call the `execute` function. [.contract-item] [[DAO-UPGRADE_DAO_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++UPGRADE_DAO_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `_authorizeUpgrade` function. +The ID of the permission required to call the `_authorizeUpgrade` function. [.contract-item] [[DAO-SET_METADATA_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++SET_METADATA_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `setMetadata` function. +The ID of the permission required to call the `setMetadata` function. [.contract-item] [[DAO-SET_TRUSTED_FORWARDER_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++SET_TRUSTED_FORWARDER_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `setTrustedForwarder` function. +The ID of the permission required to call the `setTrustedForwarder` function. [.contract-item] [[DAO-REGISTER_STANDARD_CALLBACK_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++REGISTER_STANDARD_CALLBACK_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `registerStandardCallback` function. +The ID of the permission required to call the `registerStandardCallback` function. [.contract-item] [[DAO-VALIDATE_SIGNATURE_PERMISSION_ID-bytes32]] @@ -677,7 +618,7 @@ Thrown if a call is reentrant. [[DAO-TooManyActions--]] ==== `[.contract-item-name]#++TooManyActions++#++()++` [.item-kind]#error# -Thrown if the action array length is larger than `MAX_ACTIONS`. +Thrown if the action array length is larger than `MAX_ACTIONS`. [.contract-item] [[DAO-ActionFailed-uint256-]] @@ -808,13 +749,6 @@ The internal constant storing the maximal action array length. [.contract-index] .Errors -- -* {xref-PermissionManager-Unauthorized-address-address-bytes32-}[`++Unauthorized(where, who, permissionId)++`] -* {xref-PermissionManager-PermissionAlreadyGrantedForDifferentCondition-address-address-bytes32-address-address-}[`++PermissionAlreadyGrantedForDifferentCondition(where, who, permissionId, currentCondition, newCondition)++`] -* {xref-PermissionManager-ConditionNotAContract-contract-IPermissionCondition-}[`++ConditionNotAContract(condition)++`] -* {xref-PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition-}[`++ConditionInterfaceNotSupported(condition)++`] -* {xref-PermissionManager-PermissionsForAnyAddressDisallowed--}[`++PermissionsForAnyAddressDisallowed()++`] -* {xref-PermissionManager-AnyAddressDisallowedForWhoAndWhere--}[`++AnyAddressDisallowedForWhoAndWhere()++`] -* {xref-PermissionManager-GrantWithConditionNotSupported--}[`++GrantWithConditionNotSupported()++`] [.contract-subindex-inherited] .Initializable @@ -824,10 +758,6 @@ The internal constant storing the maximal action array length. [.contract-index] .Internal Variables -- -* {xref-PermissionManager-ANY_ADDR-address}[`++address constant ANY_ADDR++`] -* {xref-PermissionManager-UNSET_FLAG-address}[`++address constant UNSET_FLAG++`] -* {xref-PermissionManager-ALLOW_FLAG-address}[`++address constant ALLOW_FLAG++`] -* {xref-PermissionManager-permissionsHashed-mapping-bytes32----address-}[`++mapping(bytes32 => address) permissionsHashed++`] [.contract-subindex-inherited] .Initializable @@ -846,7 +776,7 @@ A modifier to make functions on inheriting contracts authorized. Permissions to Initialization method to set the initial owner of the permission manager. -The initial owner is granted the `ROOT_PERMISSION_ID` permission. +The initial owner is granted the `ROOT_PERMISSION_ID` permission. [.contract-item] [[PermissionManager-grant-address-address-bytes32-]] @@ -854,8 +784,8 @@ The initial owner is granted the `ROOT_PERMISSION_ID` permission. Grants permission to an address to call methods in a contract guarded by an auth modifier with the specified permission identifier. -Requires the `ROOT_PERMISSION_ID` permission. -Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel. +Requires the `ROOT_PERMISSION_ID` permission. +Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel. [.contract-item] [[PermissionManager-grantWithCondition-address-address-bytes32-contract-IPermissionCondition-]] @@ -863,8 +793,8 @@ Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does Grants permission to an address to call methods in a target contract guarded by an auth modifier with the specified permission identifier if the referenced condition permits it. -Requires the `ROOT_PERMISSION_ID` permission -Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel. +Requires the `ROOT_PERMISSION_ID` permission +Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel. [.contract-item] [[PermissionManager-revoke-address-address-bytes32-]] @@ -872,20 +802,20 @@ Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does Revokes permission from an address to call methods in a target contract guarded by an auth modifier with the specified permission identifier. -Requires the `ROOT_PERMISSION_ID` permission. -Note, that revoking permissions with `_who` or `_where` equal to `ANY_ADDR` does not revoke other permissions with specific `_who` and `_where` addresses that exist in parallel. +Requires the `ROOT_PERMISSION_ID` permission. +Note, that revoking permissions with `_who` or `_where` equal to `ANY_ADDR` does not revoke other permissions with specific `_who` and `_where` addresses that exist in parallel. [.contract-item] [[PermissionManager-applySingleTargetPermissions-address-struct-PermissionLib-SingleTargetPermission---]] ==== `[.contract-item-name]#++applySingleTargetPermissions++#++(address _where, struct PermissionLib.SingleTargetPermission[] items)++` [.item-kind]#external# -Applies an array of permission operations on a single target contracts `_where`. +Applies an array of permission operations on a single target contracts `_where`. [.contract-item] [[PermissionManager-applyMultiTargetPermissions-struct-PermissionLib-MultiTargetPermission---]] ==== `[.contract-item-name]#++applyMultiTargetPermissions++#++(struct PermissionLib.MultiTargetPermission[] _items)++` [.item-kind]#external# -Applies an array of permission operations on multiple target contracts `items[i].where`. +Applies an array of permission operations on multiple target contracts `items[i].where`. [.contract-item] [[PermissionManager-isGranted-address-address-bytes32-bytes-]] @@ -900,75 +830,75 @@ Checks if the caller address has permission on the target contract via a permiss Relays the question if caller address has permission on target contract via a permission identifier to a condition contract. Checks a condition contract by doing an external call via try/catch. -If the external call fails, we return `false`. +If the external call fails, we return `false`. [.contract-item] [[PermissionManager-_initializePermissionManager-address-]] ==== `[.contract-item-name]#++_initializePermissionManager++#++(address _initialOwner)++` [.item-kind]#internal# -Grants the `ROOT_PERMISSION_ID` permission to the initial owner during initialization of the permission manager. +Grants the `ROOT_PERMISSION_ID` permission to the initial owner during initialization of the permission manager. [.contract-item] [[PermissionManager-_grant-address-address-bytes32-]] ==== `[.contract-item-name]#++_grant++#++(address _where, address _who, bytes32 _permissionId)++` [.item-kind]#internal# -This method is used in the external `grant` method of the permission manager. +This method is used in the external `grant` method of the permission manager. -Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel. +Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel. [.contract-item] [[PermissionManager-_grantWithCondition-address-address-bytes32-contract-IPermissionCondition-]] ==== `[.contract-item-name]#++_grantWithCondition++#++(address _where, address _who, bytes32 _permissionId, contract IPermissionCondition _condition)++` [.item-kind]#internal# -This method is used in the external `grantWithCondition` method of the permission manager. +This method is used in the external `grantWithCondition` method of the permission manager. -Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel. +Note, that granting permissions with `_who` or `_where` equal to `ANY_ADDR` does not replace other permissions with specific `_who` and `_where` addresses that exist in parallel. [.contract-item] [[PermissionManager-_revoke-address-address-bytes32-]] ==== `[.contract-item-name]#++_revoke++#++(address _where, address _who, bytes32 _permissionId)++` [.item-kind]#internal# -This method is used in the public `revoke` method of the permission manager. +This method is used in the public `revoke` method of the permission manager. -Note, that revoking permissions with `_who` or `_where` equal to `ANY_ADDR` does not revoke other permissions with specific `_who` and `_where` addresses that might have been granted in parallel. +Note, that revoking permissions with `_who` or `_where` equal to `ANY_ADDR` does not revoke other permissions with specific `_who` and `_where` addresses that might have been granted in parallel. [.contract-item] [[PermissionManager-_auth-bytes32-]] ==== `[.contract-item-name]#++_auth++#++(bytes32 _permissionId)++` [.item-kind]#internal# -A private function to be used to check permissions on the permission manager contract (`address(this)`) itself. +A private function to be used to check permissions on the permission manager contract (`address(this)`) itself. [.contract-item] [[PermissionManager-permissionHash-address-address-bytes32-]] ==== `[.contract-item-name]#++permissionHash++#++(address _where, address _who, bytes32 _permissionId) β†’ bytes32++` [.item-kind]#internal# -Generates the hash for the `permissionsHashed` mapping obtained from the word "PERMISSION", the contract address, the address owning the permission, and the permission identifier. +Generates the hash for the `permissionsHashed` mapping obtained from the word "PERMISSION", the contract address, the address owning the permission, and the permission identifier. [.contract-item] [[PermissionManager-isPermissionRestrictedForAnyAddr-bytes32-]] ==== `[.contract-item-name]#++isPermissionRestrictedForAnyAddr++#++(bytes32 _permissionId) β†’ bool++` [.item-kind]#internal# -Decides if the granting permissionId is restricted when `_who == ANY_ADDR` or `_where == ANY_ADDR`. +Decides if the granting permissionId is restricted when `_who == ANY_ADDR` or `_where == ANY_ADDR`. -By default, every permission is unrestricted and it is the derived contract's responsibility to override it. Note, that the `ROOT_PERMISSION_ID` is included and not required to be set it again. +By default, every permission is unrestricted and it is the derived contract's responsibility to override it. Note, that the `ROOT_PERMISSION_ID` is included and not required to be set it again. [.contract-item] [[PermissionManager-ROOT_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++ROOT_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `grant`, `grantWithCondition`, `revoke`, and `bulk` function. +The ID of the permission required to call the `grant`, `grantWithCondition`, `revoke`, and `bulk` function. [.contract-item] [[PermissionManager-Granted-bytes32-address-address-address-address-]] ==== `[.contract-item-name]#++Granted++#++(bytes32 indexed permissionId, address indexed here, address where, address indexed who, address condition)++` [.item-kind]#event# -Emitted when a permission `permission` is granted in the context `here` to the address `_who` for the contract `_where`. +Emitted when a permission `permission` is granted in the context `here` to the address `_who` for the contract `_where`. [.contract-item] [[PermissionManager-Revoked-bytes32-address-address-address-]] ==== `[.contract-item-name]#++Revoked++#++(bytes32 indexed permissionId, address indexed here, address where, address indexed who)++` [.item-kind]#event# -Emitted when a permission `permission` is revoked in the context `here` from the address `_who` for the contract `_where`. +Emitted when a permission `permission` is revoked in the context `here` from the address `_who` for the contract `_where`. [.contract-item] [[PermissionManager-Unauthorized-address-address-bytes32-]] @@ -994,31 +924,31 @@ Thrown if a condition address is not a contract. [[PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition-]] ==== `[.contract-item-name]#++ConditionInterfaceNotSupported++#++(contract IPermissionCondition condition)++` [.item-kind]#error# -Thrown if a condition contract does not support the `IPermissionCondition` interface. +Thrown if a condition contract does not support the `IPermissionCondition` interface. [.contract-item] [[PermissionManager-PermissionsForAnyAddressDisallowed--]] ==== `[.contract-item-name]#++PermissionsForAnyAddressDisallowed++#++()++` [.item-kind]#error# -Thrown for `ROOT_PERMISSION_ID` or `EXECUTE_PERMISSION_ID` permission grants where `who` or `where` is `ANY_ADDR`. +Thrown for `ROOT_PERMISSION_ID` or `EXECUTE_PERMISSION_ID` permission grants where `who` or `where` is `ANY_ADDR`. [.contract-item] [[PermissionManager-AnyAddressDisallowedForWhoAndWhere--]] ==== `[.contract-item-name]#++AnyAddressDisallowedForWhoAndWhere++#++()++` [.item-kind]#error# -Thrown for permission grants where `who` and `where` are both `ANY_ADDR`. +Thrown for permission grants where `who` and `where` are both `ANY_ADDR`. [.contract-item] [[PermissionManager-GrantWithConditionNotSupported--]] ==== `[.contract-item-name]#++GrantWithConditionNotSupported++#++()++` [.item-kind]#error# -Thrown if `Operation.GrantWithCondition` is requested as an operation but the method does not support it. +Thrown if `Operation.GrantWithCondition` is requested as an operation but the method does not support it. [.contract-item] [[PermissionManager-ANY_ADDR-address]] ==== `address [.contract-item-name]#++ANY_ADDR++#` [.item-kind]#internal constant# -A special address encoding permissions that are valid for any address `who` or `where`. +A special address encoding permissions that are valid for any address `who` or `where`. [.contract-item] [[PermissionManager-UNSET_FLAG-address]] @@ -1036,7 +966,7 @@ A special address encoding if a permission is allowed. [[PermissionManager-permissionsHashed-mapping-bytes32----address-]] ==== `mapping(bytes32 => address) [.contract-item-name]#++permissionsHashed++#` [.item-kind]#internal# -A mapping storing permissions as hashes (i.e., `permissionHash(where, who, permissionId)`) and their status encoded by an address (unset, allowed, or redirecting to a `PermissionCondition`). +A mapping storing permissions as hashes (i.e., `permissionHash(where, who, permissionId)`) and their status encoded by an address (unset, allowed, or redirecting to a `PermissionCondition`). :callbackMagicNumbers: pass:normal[xref:#CallbackHandler-callbackMagicNumbers-mapping-bytes4----bytes4-[`++callbackMagicNumbers++`]] :UNREGISTERED_CALLBACK: pass:normal[xref:#CallbackHandler-UNREGISTERED_CALLBACK-bytes4[`++UNREGISTERED_CALLBACK++`]] @@ -1069,15 +999,12 @@ This callback handling functionality is intended to be used by executor contract [.contract-index] .Errors -- -* {xref-CallbackHandler-UnknownCallback-bytes4-bytes4-}[`++UnknownCallback(callbackSelector, magicNumber)++`] -- [.contract-index] .Internal Variables -- -* {xref-CallbackHandler-callbackMagicNumbers-mapping-bytes4----bytes4-}[`++mapping(bytes4 => bytes4) callbackMagicNumbers++`] -* {xref-CallbackHandler-UNREGISTERED_CALLBACK-bytes4}[`++bytes4 constant UNREGISTERED_CALLBACK++`] -- @@ -1087,7 +1014,7 @@ This callback handling functionality is intended to be used by executor contract Handles callbacks to adaptively support ERC standards. -This function is supposed to be called via `_handleCallback(msg.sig, msg.data)` in the `fallback()` function of the inheriting contract. +This function is supposed to be called via `_handleCallback(msg.sig, msg.data)` in the `fallback()` function of the inheriting contract. [.contract-item] [[CallbackHandler-_registerCallback-bytes4-bytes4-]] @@ -1099,7 +1026,7 @@ Registers a magic number for a callback function selector. [[CallbackHandler-CallbackReceived-address-bytes4-bytes-]] ==== `[.contract-item-name]#++CallbackReceived++#++(address sender, bytes4 indexed sig, bytes data)++` [.item-kind]#event# -Emitted when `_handleCallback` is called. +Emitted when `_handleCallback` is called. [.contract-item] [[CallbackHandler-UnknownCallback-bytes4-bytes4-]] diff --git a/packages/contracts/docs/modules/api/pages/framework.adoc b/packages/contracts/docs/modules/api/pages/framework.adoc index 1487cde22..32e67d367 100644 --- a/packages/contracts/docs/modules/api/pages/framework.adoc +++ b/packages/contracts/docs/modules/api/pages/framework.adoc @@ -7,14 +7,6 @@ :xref-DAOFactory-daoBase-address: xref:framework.adoc#DAOFactory-daoBase-address :xref-DAOFactory-daoRegistry-contract-DAORegistry: xref:framework.adoc#DAOFactory-daoRegistry-contract-DAORegistry :xref-DAOFactory-pluginSetupProcessor-contract-PluginSetupProcessor: xref:framework.adoc#DAOFactory-pluginSetupProcessor-contract-PluginSetupProcessor -:xref-DAOFactory-NoPluginProvided--: xref:framework.adoc#DAOFactory-NoPluginProvided-- -:xref-DAOFactory-ROOT_PERMISSION_ID-bytes32: xref:framework.adoc#DAOFactory-ROOT_PERMISSION_ID-bytes32 -:xref-DAOFactory-UPGRADE_DAO_PERMISSION_ID-bytes32: xref:framework.adoc#DAOFactory-UPGRADE_DAO_PERMISSION_ID-bytes32 -:xref-DAOFactory-SET_TRUSTED_FORWARDER_PERMISSION_ID-bytes32: xref:framework.adoc#DAOFactory-SET_TRUSTED_FORWARDER_PERMISSION_ID-bytes32 -:xref-DAOFactory-SET_METADATA_PERMISSION_ID-bytes32: xref:framework.adoc#DAOFactory-SET_METADATA_PERMISSION_ID-bytes32 -:xref-DAOFactory-REGISTER_STANDARD_CALLBACK_PERMISSION_ID-bytes32: xref:framework.adoc#DAOFactory-REGISTER_STANDARD_CALLBACK_PERMISSION_ID-bytes32 -:xref-DAOFactory-EXECUTE_PERMISSION_ID-bytes32: xref:framework.adoc#DAOFactory-EXECUTE_PERMISSION_ID-bytes32 -:xref-DAOFactory-APPLY_INSTALLATION_PERMISSION_ID-bytes32: xref:framework.adoc#DAOFactory-APPLY_INSTALLATION_PERMISSION_ID-bytes32 :xref-PluginRepoFactory-constructor-contract-PluginRepoRegistry-: xref:framework.adoc#PluginRepoFactory-constructor-contract-PluginRepoRegistry- :xref-PluginRepoFactory-supportsInterface-bytes4-: xref:framework.adoc#PluginRepoFactory-supportsInterface-bytes4- :xref-PluginRepoFactory-createPluginRepo-string-address-: xref:framework.adoc#PluginRepoFactory-createPluginRepo-string-address- @@ -35,10 +27,6 @@ :xref-InterfaceBasedRegistry-targetInterfaceId-bytes4: xref:framework.adoc#InterfaceBasedRegistry-targetInterfaceId-bytes4 :xref-InterfaceBasedRegistry-entries-mapping-address----bool-: xref:framework.adoc#InterfaceBasedRegistry-entries-mapping-address----bool- :xref-DAORegistry-DAORegistered-address-address-string-: xref:framework.adoc#DAORegistry-DAORegistered-address-address-string- -:xref-DAORegistry-InvalidDaoSubdomain-string-: xref:framework.adoc#DAORegistry-InvalidDaoSubdomain-string- -:xref-InterfaceBasedRegistry-ContractAlreadyRegistered-address-: xref:framework.adoc#InterfaceBasedRegistry-ContractAlreadyRegistered-address- -:xref-InterfaceBasedRegistry-ContractInterfaceInvalid-address-: xref:framework.adoc#InterfaceBasedRegistry-ContractInterfaceInvalid-address- -:xref-InterfaceBasedRegistry-ContractERC165SupportInvalid-address-: xref:framework.adoc#InterfaceBasedRegistry-ContractERC165SupportInvalid-address- :xref-PluginRepoRegistry-constructor--: xref:framework.adoc#PluginRepoRegistry-constructor-- :xref-PluginRepoRegistry-initialize-contract-IDAO-contract-ENSSubdomainRegistrar-: xref:framework.adoc#PluginRepoRegistry-initialize-contract-IDAO-contract-ENSSubdomainRegistrar- :xref-PluginRepoRegistry-registerPluginRepo-string-address-: xref:framework.adoc#PluginRepoRegistry-registerPluginRepo-string-address- @@ -51,11 +39,6 @@ :xref-InterfaceBasedRegistry-targetInterfaceId-bytes4: xref:framework.adoc#InterfaceBasedRegistry-targetInterfaceId-bytes4 :xref-InterfaceBasedRegistry-entries-mapping-address----bool-: xref:framework.adoc#InterfaceBasedRegistry-entries-mapping-address----bool- :xref-PluginRepoRegistry-PluginRepoRegistered-string-address-: xref:framework.adoc#PluginRepoRegistry-PluginRepoRegistered-string-address- -:xref-PluginRepoRegistry-InvalidPluginSubdomain-string-: xref:framework.adoc#PluginRepoRegistry-InvalidPluginSubdomain-string- -:xref-PluginRepoRegistry-EmptyPluginRepoSubdomain--: xref:framework.adoc#PluginRepoRegistry-EmptyPluginRepoSubdomain-- -:xref-InterfaceBasedRegistry-ContractAlreadyRegistered-address-: xref:framework.adoc#InterfaceBasedRegistry-ContractAlreadyRegistered-address- -:xref-InterfaceBasedRegistry-ContractInterfaceInvalid-address-: xref:framework.adoc#InterfaceBasedRegistry-ContractInterfaceInvalid-address- -:xref-InterfaceBasedRegistry-ContractERC165SupportInvalid-address-: xref:framework.adoc#InterfaceBasedRegistry-ContractERC165SupportInvalid-address- :xref-PluginRepo-constructor--: xref:framework.adoc#PluginRepo-constructor-- :xref-PluginRepo-initialize-address-: xref:framework.adoc#PluginRepo-initialize-address- :xref-PluginRepo-initializeFrom-uint8-3--bytes-: xref:framework.adoc#PluginRepo-initializeFrom-uint8-3--bytes- @@ -92,27 +75,6 @@ :xref-PermissionManager-Revoked-bytes32-address-address-address-: xref:core.adoc#PermissionManager-Revoked-bytes32-address-address-address- :xref-IPluginRepo-VersionCreated-uint8-uint16-address-bytes-: xref:framework.adoc#IPluginRepo-VersionCreated-uint8-uint16-address-bytes- :xref-IPluginRepo-ReleaseMetadataUpdated-uint8-bytes-: xref:framework.adoc#IPluginRepo-ReleaseMetadataUpdated-uint8-bytes- -:xref-PluginRepo-VersionHashDoesNotExist-bytes32-: xref:framework.adoc#PluginRepo-VersionHashDoesNotExist-bytes32- -:xref-PluginRepo-InvalidPluginSetupInterface--: xref:framework.adoc#PluginRepo-InvalidPluginSetupInterface-- -:xref-PluginRepo-ReleaseZeroNotAllowed--: xref:framework.adoc#PluginRepo-ReleaseZeroNotAllowed-- -:xref-PluginRepo-InvalidReleaseIncrement-uint8-uint8-: xref:framework.adoc#PluginRepo-InvalidReleaseIncrement-uint8-uint8- -:xref-PluginRepo-PluginSetupAlreadyInPreviousRelease-uint8-uint16-address-: xref:framework.adoc#PluginRepo-PluginSetupAlreadyInPreviousRelease-uint8-uint16-address- -:xref-PluginRepo-EmptyReleaseMetadata--: xref:framework.adoc#PluginRepo-EmptyReleaseMetadata-- -:xref-PluginRepo-ReleaseDoesNotExist--: xref:framework.adoc#PluginRepo-ReleaseDoesNotExist-- -:xref-PermissionManager-Unauthorized-address-address-bytes32-: xref:core.adoc#PermissionManager-Unauthorized-address-address-bytes32- -:xref-PermissionManager-PermissionAlreadyGrantedForDifferentCondition-address-address-bytes32-address-address-: xref:core.adoc#PermissionManager-PermissionAlreadyGrantedForDifferentCondition-address-address-bytes32-address-address- -:xref-PermissionManager-ConditionNotAContract-contract-IPermissionCondition-: xref:core.adoc#PermissionManager-ConditionNotAContract-contract-IPermissionCondition- -:xref-PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition-: xref:core.adoc#PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition- -:xref-PermissionManager-PermissionsForAnyAddressDisallowed--: xref:core.adoc#PermissionManager-PermissionsForAnyAddressDisallowed-- -:xref-PermissionManager-AnyAddressDisallowedForWhoAndWhere--: xref:core.adoc#PermissionManager-AnyAddressDisallowedForWhoAndWhere-- -:xref-PermissionManager-GrantWithConditionNotSupported--: xref:core.adoc#PermissionManager-GrantWithConditionNotSupported-- -:xref-PluginRepo-buildsPerRelease-mapping-uint8----uint16-: xref:framework.adoc#PluginRepo-buildsPerRelease-mapping-uint8----uint16- -:xref-PluginRepo-versions-mapping-bytes32----struct-PluginRepo-Version-: xref:framework.adoc#PluginRepo-versions-mapping-bytes32----struct-PluginRepo-Version- -:xref-PluginRepo-latestTagHashForPluginSetup-mapping-address----bytes32-: xref:framework.adoc#PluginRepo-latestTagHashForPluginSetup-mapping-address----bytes32- -:xref-PermissionManager-ANY_ADDR-address: xref:core.adoc#PermissionManager-ANY_ADDR-address -:xref-PermissionManager-UNSET_FLAG-address: xref:core.adoc#PermissionManager-UNSET_FLAG-address -:xref-PermissionManager-ALLOW_FLAG-address: xref:core.adoc#PermissionManager-ALLOW_FLAG-address -:xref-PermissionManager-permissionsHashed-mapping-bytes32----address-: xref:core.adoc#PermissionManager-permissionsHashed-mapping-bytes32----address- :xref-PluginSetupProcessor-canApply-address-bytes32-: xref:framework.adoc#PluginSetupProcessor-canApply-address-bytes32- :xref-PluginSetupProcessor-constructor-contract-PluginRepoRegistry-: xref:framework.adoc#PluginSetupProcessor-constructor-contract-PluginRepoRegistry- :xref-PluginSetupProcessor-prepareInstallation-address-struct-PluginSetupProcessor-PrepareInstallationParams-: xref:framework.adoc#PluginSetupProcessor-prepareInstallation-address-struct-PluginSetupProcessor-PrepareInstallationParams- @@ -147,7 +109,7 @@ The natspec generated API for the framework contracts. You can also find the contracts on the following link:https://github.com/aragon/osx[repository]. -=== Factories +== Factories :daoBase: pass:normal[xref:#DAOFactory-daoBase-address[`++daoBase++`]] :daoRegistry: pass:normal[xref:#DAOFactory-daoRegistry-contract-DAORegistry[`++daoRegistry++`]] @@ -203,7 +165,6 @@ The natspec generated API for the framework contracts. You can also find the con [.contract-index] .Errors -- -* {xref-DAOFactory-NoPluginProvided--}[`++NoPluginProvided()++`] [.contract-subindex-inherited] .ProtocolVersion @@ -222,13 +183,6 @@ The natspec generated API for the framework contracts. You can also find the con [.contract-index] .Internal Variables -- -* {xref-DAOFactory-ROOT_PERMISSION_ID-bytes32}[`++bytes32 ROOT_PERMISSION_ID++`] -* {xref-DAOFactory-UPGRADE_DAO_PERMISSION_ID-bytes32}[`++bytes32 UPGRADE_DAO_PERMISSION_ID++`] -* {xref-DAOFactory-SET_TRUSTED_FORWARDER_PERMISSION_ID-bytes32}[`++bytes32 SET_TRUSTED_FORWARDER_PERMISSION_ID++`] -* {xref-DAOFactory-SET_METADATA_PERMISSION_ID-bytes32}[`++bytes32 SET_METADATA_PERMISSION_ID++`] -* {xref-DAOFactory-REGISTER_STANDARD_CALLBACK_PERMISSION_ID-bytes32}[`++bytes32 REGISTER_STANDARD_CALLBACK_PERMISSION_ID++`] -* {xref-DAOFactory-EXECUTE_PERMISSION_ID-bytes32}[`++bytes32 EXECUTE_PERMISSION_ID++`] -* {xref-DAOFactory-APPLY_INSTALLATION_PERMISSION_ID-bytes32}[`++bytes32 APPLY_INSTALLATION_PERMISSION_ID++`] [.contract-subindex-inherited] .ProtocolVersion @@ -262,13 +216,13 @@ Checks if this or the parent contract supports an interface by its ID. Creates a new DAO, registers it in the DAO registry, and optionally installs plugins via the plugin setup processor. -If `_pluginSettings` is empty, the caller is granted `EXECUTE_PERMISSION` on the DAO. +If `_pluginSettings` is empty, the caller is granted `EXECUTE_PERMISSION` on the DAO. [.contract-item] [[DAOFactory-_createDAO-struct-DAOFactory-DAOSettings-]] ==== `[.contract-item-name]#++_createDAO++#++(struct DAOFactory.DAOSettings _daoSettings) β†’ contract DAO dao++` [.item-kind]#internal# -Deploys a new DAO `ERC1967` proxy, and initialize it with this contract as the initial owner. +Deploys a new DAO `ERC1967` proxy, and initialize it with this contract as the initial owner. [.contract-item] [[DAOFactory-_setDAOPermissions-address-]] @@ -280,25 +234,25 @@ Sets the required permissions for the new DAO. [[DAOFactory-daoBase-address]] ==== `[.contract-item-name]#++daoBase++#++() β†’ address++` [.item-kind]#public# -The DAO base contract, to be used for creating new `DAO`s via `createERC1967Proxy` function. +The DAO base contract, to be used for creating new `DAO`s via `createERC1967Proxy` function. [.contract-item] [[DAOFactory-daoRegistry-contract-DAORegistry]] ==== `[.contract-item-name]#++daoRegistry++#++() β†’ contract DAORegistry++` [.item-kind]#public# -The DAO registry listing the `DAO` contracts created via this contract. +The DAO registry listing the `DAO` contracts created via this contract. [.contract-item] [[DAOFactory-pluginSetupProcessor-contract-PluginSetupProcessor]] ==== `[.contract-item-name]#++pluginSetupProcessor++#++() β†’ contract PluginSetupProcessor++` [.item-kind]#public# -The plugin setup processor for installing plugins on the newly created `DAO`s. +The plugin setup processor for installing plugins on the newly created `DAO`s. [.contract-item] [[DAOFactory-NoPluginProvided--]] ==== `[.contract-item-name]#++NoPluginProvided++#++()++` [.item-kind]#error# -Thrown if `PluginSettings` array is empty, and no plugin is provided. +Thrown if `PluginSettings` array is empty, and no plugin is provided. [.contract-item] [[DAOFactory-ROOT_PERMISSION_ID-bytes32]] @@ -372,7 +326,7 @@ Thrown if `PluginSettings` array is empty, and no plugin is provided. [[PluginRepoFactory-constructor-contract-PluginRepoRegistry-]] ==== `[.contract-item-name]#++constructor++#++(contract PluginRepoRegistry _pluginRepoRegistry)++` [.item-kind]#public# -Initializes the addresses of the Aragon plugin registry and `PluginRepo` base contract to proxy to. +Initializes the addresses of the Aragon plugin registry and `PluginRepo` base contract to proxy to. [.contract-item] [[PluginRepoFactory-supportsInterface-bytes4-]] @@ -384,15 +338,15 @@ Checks if this or the parent contract supports an interface by its ID. [[PluginRepoFactory-createPluginRepo-string-address-]] ==== `[.contract-item-name]#++createPluginRepo++#++(string _subdomain, address _initialOwner) β†’ contract PluginRepo++` [.item-kind]#external# -Creates a plugin repository proxy pointing to the `pluginRepoBase` implementation and registers it in the Aragon plugin registry. +Creates a plugin repository proxy pointing to the `pluginRepoBase` implementation and registers it in the Aragon plugin registry. [.contract-item] [[PluginRepoFactory-createPluginRepoWithFirstVersion-string-address-address-bytes-bytes-]] ==== `[.contract-item-name]#++createPluginRepoWithFirstVersion++#++(string _subdomain, address _pluginSetup, address _maintainer, bytes _releaseMetadata, bytes _buildMetadata) β†’ contract PluginRepo pluginRepo++` [.item-kind]#external# -Creates and registers a `PluginRepo` with an ENS subdomain and publishes an initial version `1.1`. +Creates and registers a `PluginRepo` with an ENS subdomain and publishes an initial version `1.1`. -After the creation of the `PluginRepo` and release of the first version by the factory, ownership is transferred to the `_maintainer` address. +After the creation of the `PluginRepo` and release of the first version by the factory, ownership is transferred to the `_maintainer` address. [.contract-item] [[PluginRepoFactory-_setPluginRepoPermissions-contract-PluginRepo-address-]] @@ -400,15 +354,15 @@ After the creation of the `PluginRepo` and release of the first version by the f Set the final permissions for the published plugin repository maintainer. All permissions are revoked from the plugin factory and granted to the specified plugin maintainer. -The plugin maintainer is granted the `MAINTAINER_PERMISSION_ID`, `UPGRADE_REPO_PERMISSION_ID`, and `ROOT_PERMISSION_ID`. +The plugin maintainer is granted the `MAINTAINER_PERMISSION_ID`, `UPGRADE_REPO_PERMISSION_ID`, and `ROOT_PERMISSION_ID`. [.contract-item] [[PluginRepoFactory-_createPluginRepo-string-address-]] ==== `[.contract-item-name]#++_createPluginRepo++#++(string _subdomain, address _initialOwner) β†’ contract PluginRepo pluginRepo++` [.item-kind]#internal# -Internal method creating a `PluginRepo` via the [ERC-1967](https://eips.ethereum.org/EIPS/eip-1967) proxy pattern from the provided base contract and registering it in the Aragon plugin registry. +Internal method creating a `PluginRepo` via the [ERC-1967](https://eips.ethereum.org/EIPS/eip-1967) proxy pattern from the provided base contract and registering it in the Aragon plugin registry. -Passing an empty `_subdomain` will cause the transaction to revert. +Passing an empty `_subdomain` will cause the transaction to revert. [.contract-item] [[PluginRepoFactory-pluginRepoRegistry-contract-PluginRepoRegistry]] @@ -420,9 +374,9 @@ The Aragon plugin registry contract. [[PluginRepoFactory-pluginRepoBase-address]] ==== `[.contract-item-name]#++pluginRepoBase++#++() β†’ address++` [.item-kind]#public# -The address of the `PluginRepo` base contract to proxy to.. +The address of the `PluginRepo` base contract to proxy to.. -=== Registries +== Registries :REGISTER_DAO_PERMISSION_ID: pass:normal[xref:#DAORegistry-REGISTER_DAO_PERMISSION_ID-bytes32[`++REGISTER_DAO_PERMISSION_ID++`]] :subdomainRegistrar: pass:normal[xref:#DAORegistry-subdomainRegistrar-contract-ENSSubdomainRegistrar[`++subdomainRegistrar++`]] @@ -526,7 +480,6 @@ The address of the `PluginRepo` base contract to proxy to.. [.contract-index] .Errors -- -* {xref-DAORegistry-InvalidDaoSubdomain-string-}[`++InvalidDaoSubdomain(subdomain)++`] [.contract-subindex-inherited] .ProtocolVersion @@ -536,9 +489,6 @@ The address of the `PluginRepo` base contract to proxy to.. [.contract-subindex-inherited] .InterfaceBasedRegistry -* {xref-InterfaceBasedRegistry-ContractAlreadyRegistered-address-}[`++ContractAlreadyRegistered(registrant)++`] -* {xref-InterfaceBasedRegistry-ContractInterfaceInvalid-address-}[`++ContractInterfaceInvalid(registrant)++`] -* {xref-InterfaceBasedRegistry-ContractERC165SupportInvalid-address-}[`++ContractERC165SupportInvalid(registrant)++`] [.contract-subindex-inherited] .DaoAuthorizableUpgradeable @@ -587,7 +537,7 @@ A subdomain is unique within the Aragon DAO framework and can get stored here. [[DAORegistry-REGISTER_DAO_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++REGISTER_DAO_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `register` function. +The ID of the permission required to call the `register` function. [.contract-item] [[DAORegistry-subdomainRegistrar-contract-ENSSubdomainRegistrar]] @@ -605,7 +555,7 @@ Emitted when a new DAO is registered. [[DAORegistry-InvalidDaoSubdomain-string-]] ==== `[.contract-item-name]#++InvalidDaoSubdomain++#++(string subdomain)++` [.item-kind]#error# -Thrown if the DAO subdomain doesn't match the regex `[0-9a-z\-]` +Thrown if the DAO subdomain doesn't match the regex `[0-9a-z\-]` :REGISTER_PLUGIN_REPO_PERMISSION_ID: pass:normal[xref:#PluginRepoRegistry-REGISTER_PLUGIN_REPO_PERMISSION_ID-bytes32[`++REGISTER_PLUGIN_REPO_PERMISSION_ID++`]] :subdomainRegistrar: pass:normal[xref:#PluginRepoRegistry-subdomainRegistrar-contract-ENSSubdomainRegistrar[`++subdomainRegistrar++`]] @@ -710,8 +660,6 @@ Thrown if the DAO subdomain doesn't match the regex `[0-9a-z\-]` [.contract-index] .Errors -- -* {xref-PluginRepoRegistry-InvalidPluginSubdomain-string-}[`++InvalidPluginSubdomain(subdomain)++`] -* {xref-PluginRepoRegistry-EmptyPluginRepoSubdomain--}[`++EmptyPluginRepoSubdomain()++`] [.contract-subindex-inherited] .ProtocolVersion @@ -721,9 +669,6 @@ Thrown if the DAO subdomain doesn't match the regex `[0-9a-z\-]` [.contract-subindex-inherited] .InterfaceBasedRegistry -* {xref-InterfaceBasedRegistry-ContractAlreadyRegistered-address-}[`++ContractAlreadyRegistered(registrant)++`] -* {xref-InterfaceBasedRegistry-ContractInterfaceInvalid-address-}[`++ContractInterfaceInvalid(registrant)++`] -* {xref-InterfaceBasedRegistry-ContractERC165SupportInvalid-address-}[`++ContractERC165SupportInvalid(registrant)++`] [.contract-subindex-inherited] .DaoAuthorizableUpgradeable @@ -758,7 +703,7 @@ Used to disallow initializing the implementation contract by an attacker for ext [[PluginRepoRegistry-initialize-contract-IDAO-contract-ENSSubdomainRegistrar-]] ==== `[.contract-item-name]#++initialize++#++(contract IDAO _dao, contract ENSSubdomainRegistrar _subdomainRegistrar)++` [.item-kind]#external# -Initializes the contract by setting calling the `InterfaceBasedRegistry` base class initialize method. +Initializes the contract by setting calling the `InterfaceBasedRegistry` base class initialize method. [.contract-item] [[PluginRepoRegistry-registerPluginRepo-string-address-]] @@ -770,7 +715,7 @@ Registers a plugin repository with a subdomain and address. [[PluginRepoRegistry-REGISTER_PLUGIN_REPO_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++REGISTER_PLUGIN_REPO_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `register` function. +The ID of the permission required to call the `register` function. [.contract-item] [[PluginRepoRegistry-subdomainRegistrar-contract-ENSSubdomainRegistrar]] @@ -788,7 +733,7 @@ Emitted if a new plugin repository is registered. [[PluginRepoRegistry-InvalidPluginSubdomain-string-]] ==== `[.contract-item-name]#++InvalidPluginSubdomain++#++(string subdomain)++` [.item-kind]#error# -Thrown if the plugin subdomain doesn't match the regex `[0-9a-z\-]` +Thrown if the plugin subdomain doesn't match the regex `[0-9a-z\-]` [.contract-item] [[PluginRepoRegistry-EmptyPluginRepoSubdomain--]] @@ -796,7 +741,7 @@ Thrown if the plugin subdomain doesn't match the regex `[0-9a-z\-]` Thrown if the plugin repository subdomain is empty. -=== Framework +== Framework :Tag: pass:normal[xref:#PluginRepo-Tag[`++Tag++`]] :Version: pass:normal[xref:#PluginRepo-Version[`++Version++`]] @@ -949,23 +894,9 @@ Thrown if the plugin repository subdomain is empty. [.contract-index] .Errors -- -* {xref-PluginRepo-VersionHashDoesNotExist-bytes32-}[`++VersionHashDoesNotExist(versionHash)++`] -* {xref-PluginRepo-InvalidPluginSetupInterface--}[`++InvalidPluginSetupInterface()++`] -* {xref-PluginRepo-ReleaseZeroNotAllowed--}[`++ReleaseZeroNotAllowed()++`] -* {xref-PluginRepo-InvalidReleaseIncrement-uint8-uint8-}[`++InvalidReleaseIncrement(latestRelease, newRelease)++`] -* {xref-PluginRepo-PluginSetupAlreadyInPreviousRelease-uint8-uint16-address-}[`++PluginSetupAlreadyInPreviousRelease(release, build, pluginSetup)++`] -* {xref-PluginRepo-EmptyReleaseMetadata--}[`++EmptyReleaseMetadata()++`] -* {xref-PluginRepo-ReleaseDoesNotExist--}[`++ReleaseDoesNotExist()++`] [.contract-subindex-inherited] .PermissionManager -* {xref-PermissionManager-Unauthorized-address-address-bytes32-}[`++Unauthorized(where, who, permissionId)++`] -* {xref-PermissionManager-PermissionAlreadyGrantedForDifferentCondition-address-address-bytes32-address-address-}[`++PermissionAlreadyGrantedForDifferentCondition(where, who, permissionId, currentCondition, newCondition)++`] -* {xref-PermissionManager-ConditionNotAContract-contract-IPermissionCondition-}[`++ConditionNotAContract(condition)++`] -* {xref-PermissionManager-ConditionInterfaceNotSupported-contract-IPermissionCondition-}[`++ConditionInterfaceNotSupported(condition)++`] -* {xref-PermissionManager-PermissionsForAnyAddressDisallowed--}[`++PermissionsForAnyAddressDisallowed()++`] -* {xref-PermissionManager-AnyAddressDisallowedForWhoAndWhere--}[`++AnyAddressDisallowedForWhoAndWhere()++`] -* {xref-PermissionManager-GrantWithConditionNotSupported--}[`++GrantWithConditionNotSupported()++`] [.contract-subindex-inherited] .ProtocolVersion @@ -1002,16 +933,9 @@ Thrown if the plugin repository subdomain is empty. [.contract-index] .Internal Variables -- -* {xref-PluginRepo-buildsPerRelease-mapping-uint8----uint16-}[`++mapping(uint8 => uint16) buildsPerRelease++`] -* {xref-PluginRepo-versions-mapping-bytes32----struct-PluginRepo-Version-}[`++mapping(bytes32 => struct PluginRepo.Version) versions++`] -* {xref-PluginRepo-latestTagHashForPluginSetup-mapping-address----bytes32-}[`++mapping(address => bytes32) latestTagHashForPluginSetup++`] [.contract-subindex-inherited] .PermissionManager -* {xref-PermissionManager-ANY_ADDR-address}[`++address constant ANY_ADDR++`] -* {xref-PermissionManager-UNSET_FLAG-address}[`++address constant UNSET_FLAG++`] -* {xref-PermissionManager-ALLOW_FLAG-address}[`++address constant ALLOW_FLAG++`] -* {xref-PermissionManager-permissionsHashed-mapping-bytes32----address-}[`++mapping(bytes32 => address) permissionsHashed++`] [.contract-subindex-inherited] .ProtocolVersion @@ -1057,7 +981,7 @@ Used to disallow initializing the implementation contract by an attacker for ext Initializes the contract by - initializing the permission manager -- granting the `MAINTAINER_PERMISSION_ID` permission to the initial owner. +- granting the `MAINTAINER_PERMISSION_ID` permission to the initial owner. This method is required to support [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822). @@ -1073,13 +997,13 @@ This function is a placeholder until we require reinitialization. [[PluginRepo-createVersion-uint8-address-bytes-bytes-]] ==== `[.contract-item-name]#++createVersion++#++(uint8 _release, address _pluginSetup, bytes _buildMetadata, bytes _releaseMetadata)++` [.item-kind]#external# -Creates a new plugin version as the latest build for an existing release number or the first build for a new release number for the provided `PluginSetup` contract address and metadata. +Creates a new plugin version as the latest build for an existing release number or the first build for a new release number for the provided `PluginSetup` contract address and metadata. [.contract-item] [[PluginRepo-updateReleaseMetadata-uint8-bytes-]] ==== `[.contract-item-name]#++updateReleaseMetadata++#++(uint8 _release, bytes _releaseMetadata)++` [.item-kind]#external# -Updates the metadata for release with content `@fromHex(_releaseMetadata)`. +Updates the metadata for release with content `@fromHex(_releaseMetadata)`. [.contract-item] [[PluginRepo-getLatestVersion-uint8-]] @@ -1123,7 +1047,7 @@ The hash of the version tag obtained from the packed, bytes-encoded release and Internal method authorizing the upgrade of the contract via the [upgradeability mechanism for UUPS proxies](https://docs.openzeppelin.com/contracts/4.x/api/proxy#UUPSUpgradeable) (see [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822)). -The caller must have the `UPGRADE_REPO_PERMISSION_ID` permission. +The caller must have the `UPGRADE_REPO_PERMISSION_ID` permission. [.contract-item] [[PluginRepo-supportsInterface-bytes4-]] @@ -1135,13 +1059,13 @@ Checks if this or the parent contract supports an interface by its ID. [[PluginRepo-MAINTAINER_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++MAINTAINER_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `createVersion` function. +The ID of the permission required to call the `createVersion` function. [.contract-item] [[PluginRepo-UPGRADE_REPO_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++UPGRADE_REPO_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `createVersion` function. +The ID of the permission required to call the `createVersion` function. [.contract-item] [[PluginRepo-latestRelease-uint8]] @@ -1161,7 +1085,7 @@ Thrown if a version does not exist. [[PluginRepo-InvalidPluginSetupInterface--]] ==== `[.contract-item-name]#++InvalidPluginSetupInterface++#++()++` [.item-kind]#error# -Thrown if a plugin setup contract does not inherit from `PluginSetup`. +Thrown if a plugin setup contract does not inherit from `PluginSetup`. [.contract-item] [[PluginRepo-ReleaseZeroNotAllowed--]] @@ -1309,16 +1233,6 @@ This contract is temporarily granted the `ROOT_PERMISSION_ID` permission on the [.contract-index] .Errors -- -* {xref-PluginSetupProcessor-SetupApplicationUnauthorized-address-address-bytes32-}[`++SetupApplicationUnauthorized(dao, caller, permissionId)++`] -* {xref-PluginSetupProcessor-PluginNonupgradeable-address-}[`++PluginNonupgradeable(plugin)++`] -* {xref-PluginSetupProcessor-PluginProxyUpgradeFailed-address-address-bytes-}[`++PluginProxyUpgradeFailed(proxy, implementation, initData)++`] -* {xref-PluginSetupProcessor-IPluginNotSupported-address-}[`++IPluginNotSupported(plugin)++`] -* {xref-PluginSetupProcessor-PluginRepoNonexistent--}[`++PluginRepoNonexistent()++`] -* {xref-PluginSetupProcessor-SetupAlreadyPrepared-bytes32-}[`++SetupAlreadyPrepared(preparedSetupId)++`] -* {xref-PluginSetupProcessor-SetupNotApplicable-bytes32-}[`++SetupNotApplicable(preparedSetupId)++`] -* {xref-PluginSetupProcessor-InvalidUpdateVersion-struct-PluginRepo-Tag-struct-PluginRepo-Tag-}[`++InvalidUpdateVersion(currentVersionTag, newVersionTag)++`] -* {xref-PluginSetupProcessor-PluginAlreadyInstalled--}[`++PluginAlreadyInstalled()++`] -* {xref-PluginSetupProcessor-InvalidAppliedSetupId-bytes32-bytes32-}[`++InvalidAppliedSetupId(currentAppliedSetupId, appliedSetupId)++`] [.contract-subindex-inherited] .ProtocolVersion @@ -1358,7 +1272,7 @@ Applies the permissions of a prepared installation to a DAO. Prepares the update of an UUPS upgradeable plugin. -The list of `_params.setupPayload.currentHelpers` has to be specified in the same order as they were returned from previous setups preparation steps (the latest `prepareInstallation` or `prepareUpdate` step that has happened) on which the update is prepared for. +The list of `_params.setupPayload.currentHelpers` has to be specified in the same order as they were returned from previous setups preparation steps (the latest `prepareInstallation` or `prepareUpdate` step that has happened) on which the update is prepared for. [.contract-item] [[PluginSetupProcessor-applyUpdate-address-struct-PluginSetupProcessor-ApplyUpdateParams-]] @@ -1372,7 +1286,7 @@ Applies the permissions of a prepared update of an UUPS upgradeable proxy contra Prepares the uninstallation of a plugin. -The list of `_params.setupPayload.currentHelpers` has to be specified in the same order as they were returned from previous setups preparation steps (the latest `prepareInstallation` or `prepareUpdate` step that has happened) on which the uninstallation was prepared for. +The list of `_params.setupPayload.currentHelpers` has to be specified in the same order as they were returned from previous setups preparation steps (the latest `prepareInstallation` or `prepareUpdate` step that has happened) on which the uninstallation was prepared for. [.contract-item] [[PluginSetupProcessor-applyUninstallation-address-struct-PluginSetupProcessor-ApplyUninstallationParams-]] @@ -1380,33 +1294,33 @@ The list of `_params.setupPayload.currentHelpers` has to be specified in the sam Applies the permissions of a prepared uninstallation to a DAO. -The list of `_params.setupPayload.currentHelpers` has to be specified in the same order as they were returned from previous setups preparation steps (the latest `prepareInstallation` or `prepareUpdate` step that has happened) on which the uninstallation was prepared for. +The list of `_params.setupPayload.currentHelpers` has to be specified in the same order as they were returned from previous setups preparation steps (the latest `prepareInstallation` or `prepareUpdate` step that has happened) on which the uninstallation was prepared for. [.contract-item] [[PluginSetupProcessor-validatePreparedSetupId-bytes32-bytes32-]] ==== `[.contract-item-name]#++validatePreparedSetupId++#++(bytes32 pluginInstallationId, bytes32 preparedSetupId)++` [.item-kind]#public# -Validates that a setup ID can be applied for `applyInstallation`, `applyUpdate`, or `applyUninstallation`. +Validates that a setup ID can be applied for `applyInstallation`, `applyUpdate`, or `applyUninstallation`. -If the block number stored in `states[pluginInstallationId].blockNumber` exceeds the one stored in `pluginState.preparedSetupIdToBlockNumber[preparedSetupId]`, the prepared setup with `preparedSetupId` is outdated and not applicable anymore. +If the block number stored in `states[pluginInstallationId].blockNumber` exceeds the one stored in `pluginState.preparedSetupIdToBlockNumber[preparedSetupId]`, the prepared setup with `preparedSetupId` is outdated and not applicable anymore. [.contract-item] [[PluginSetupProcessor-APPLY_INSTALLATION_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++APPLY_INSTALLATION_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `applyInstallation` function. +The ID of the permission required to call the `applyInstallation` function. [.contract-item] [[PluginSetupProcessor-APPLY_UPDATE_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++APPLY_UPDATE_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `applyUpdate` function. +The ID of the permission required to call the `applyUpdate` function. [.contract-item] [[PluginSetupProcessor-APPLY_UNINSTALLATION_PERMISSION_ID-bytes32]] ==== `[.contract-item-name]#++APPLY_UNINSTALLATION_PERMISSION_ID++#++() β†’ bytes32++` [.item-kind]#public# -The ID of the permission required to call the `applyUninstallation` function. +The ID of the permission required to call the `applyUninstallation` function. [.contract-item] [[PluginSetupProcessor-states-mapping-bytes32----struct-PluginSetupProcessor-PluginState-]] @@ -1420,7 +1334,7 @@ This variable is public on purpose to allow future versions to access and migrat [[PluginSetupProcessor-repoRegistry-contract-PluginRepoRegistry]] ==== `[.contract-item-name]#++repoRegistry++#++() β†’ contract PluginRepoRegistry++` [.item-kind]#public# -The plugin repo registry listing the `PluginRepo` contracts versioning the `PluginSetup` contracts. +The plugin repo registry listing the `PluginRepo` contracts versioning the `PluginSetup` contracts. [.contract-item] [[PluginSetupProcessor-InstallationPrepared-address-address-bytes32-contract-PluginRepo-struct-PluginRepo-Tag-bytes-address-struct-IPluginSetup-PreparedSetupData-]] @@ -1464,7 +1378,7 @@ Emitted after a plugin installation was applied. Thrown if a setup is unauthorized and cannot be applied because of a missing permission of the associated DAO. -This is thrown if the `APPLY_INSTALLATION_PERMISSION_ID`, `APPLY_UPDATE_PERMISSION_ID`, or APPLY_UNINSTALLATION_PERMISSION_ID is missing. +This is thrown if the `APPLY_INSTALLATION_PERMISSION_ID`, `APPLY_UPDATE_PERMISSION_ID`, or APPLY_UNINSTALLATION_PERMISSION_ID is missing. [.contract-item] [[PluginSetupProcessor-PluginNonupgradeable-address-]] @@ -1476,13 +1390,13 @@ Thrown if a plugin is not upgradeable. [[PluginSetupProcessor-PluginProxyUpgradeFailed-address-address-bytes-]] ==== `[.contract-item-name]#++PluginProxyUpgradeFailed++#++(address proxy, address implementation, bytes initData)++` [.item-kind]#error# -Thrown if the upgrade of an `UUPSUpgradeable` proxy contract (see [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822)) failed. +Thrown if the upgrade of an `UUPSUpgradeable` proxy contract (see [ERC-1822](https://eips.ethereum.org/EIPS/eip-1822)) failed. [.contract-item] [[PluginSetupProcessor-IPluginNotSupported-address-]] ==== `[.contract-item-name]#++IPluginNotSupported++#++(address plugin)++` [.item-kind]#error# -Thrown if a contract does not support the `IPlugin` interface. +Thrown if a contract does not support the `IPlugin` interface. [.contract-item] [[PluginSetupProcessor-PluginRepoNonexistent--]] @@ -1500,7 +1414,7 @@ Thrown if a plugin setup was already prepared indicated by the prepared setup ID [[PluginSetupProcessor-SetupNotApplicable-bytes32-]] ==== `[.contract-item-name]#++SetupNotApplicable++#++(bytes32 preparedSetupId)++` [.item-kind]#error# -Thrown if a prepared setup ID is not eligible to be applied. This can happen if another setup has been already applied or if the setup wasn't prepared in the first place. +Thrown if a prepared setup ID is not eligible to be applied. This can happen if another setup has been already applied or if the setup wasn't prepared in the first place. [.contract-item] [[PluginSetupProcessor-InvalidUpdateVersion-struct-PluginRepo-Tag-struct-PluginRepo-Tag-]] diff --git a/packages/contracts/src/framework/README.adoc b/packages/contracts/src/framework/README.adoc index f3773489c..3d3d7d84b 100644 --- a/packages/contracts/src/framework/README.adoc +++ b/packages/contracts/src/framework/README.adoc @@ -2,19 +2,19 @@ The natspec generated API for the framework contracts. You can also find the contracts on the following link:https://github.com/aragon/osx[repository]. -=== Factories +== Factories {{DAOFactory}} {{PluginRepoFactory}} -=== Registries +== Registries {{DAORegistry}} {{PluginRepoRegistry}} -=== Framework +== Framework {{PluginRepo}}