-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
911 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
= Actions & Execution | ||
|
||
== A Deep Dive into Actions and Execution | ||
|
||
The DAO's `execute` function is part of the `DAO.sol` contract and has the following function header: | ||
|
||
```solidity | ||
function execute( | ||
bytes32 _callId, | ||
Action[] calldata _actions, | ||
uint256 _allowFailureMap | ||
) | ||
external | ||
override | ||
auth(address(this), EXECUTE_PERMISSION_ID) | ||
returns (bytes[] memory execResults, uint256 failureMap) | ||
``` | ||
|
||
It offers two features that we will dive into in this article: | ||
|
||
1. Execution of an array of arbitrary `Action` items. | ||
2. Allowing failure of individual actions without reverting the entire transaction. | ||
|
||
### Actions | ||
|
||
In our framework, actions are represented by a solidity struct: | ||
|
||
```solidity title="@aragon/osx/core/dao/IDAO.sol" | ||
/// @notice The action struct to be consumed by the DAO's `execute` function resulting in an external call. | ||
/// @param to The address to call. | ||
/// @param value The native token value to be sent with the call. | ||
/// @param data The bytes-encoded function selector and calldata for the call. | ||
struct Action { | ||
address to; | ||
uint256 value; | ||
bytes data; | ||
} | ||
``` | ||
|
||
Actions can be | ||
|
||
- function calls to the DAO itself (e.g., to upgrade the DAO contract to a newer version of Aragon OSx) | ||
- function calls to other contracts, such as | ||
|
||
- external services (e.g. Uniswap, Compound, etc.) | ||
- Aragon OSx plugins (e.g., the DAO can be a member of a multisig installed in another DAO), | ||
- Aragon OSx protocol infrastructure (e.g., to xref:how-it-works/framework/plugin-management/plugin-setup/index.adoc[setup a plugin]). | ||
|
||
- transfers of native tokens | ||
|
||
#### Example: Calling the wETH Contract | ||
|
||
We have an Aragon DAO deployed on the Goerli testnet. Now, we want to wrap `0.1 ETH` from the DAO treasury into `wETH` by depositing it into the link:https://goerli.etherscan.io/token/0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6#writeContract[Goerli WETH contract] deployed on the address `0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6`. The corresponding `Action` and `execute` function call look as follows: | ||
|
||
```solidity | ||
|
||
IDAO.Action[] memory actions = new IDAO.Action[](1); | ||
|
||
actions[0] = IDAO.Action({ | ||
to: address(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6), // The address of the WETH contract on Goerli | ||
value: 0.1 ether, // The Goerli ETH value to be sent with the function call | ||
data: abi.encodeCall(IDAO.deposit, ()) // The calldata | ||
}); | ||
|
||
dao().execute({_callId: '', _actions: actions, _allowFailureMap: 0}); | ||
|
||
``` | ||
|
||
For the `execute` call to work, the caller must have the required xref:how-it-works/core/permissions/index.adoc[`EXECUTE_PERMISSION_ID` permission] on the DAO contract. | ||
|
||
### The Action Array | ||
|
||
The `Action[] calldata _actions` input argument allows you to execute an array of up to 256 `Action` items in a single transaction within the gas limitations of the Ethereum virtual machine (EVM). | ||
This is important so that several calls can be executed in a strict order within a single transaction. | ||
|
||
Imagine a DAO is currently governed by a multisig (it has the `Multisig` plugin installed) and wants to transition the DAO governance to token voting. | ||
To achieve this, one of the Multisig members creates a proposal in the plugin proposing to | ||
|
||
1. install the `TokenVoting` plugin | ||
2. uninstall the `Multisig` plugin | ||
|
||
If enough multisig signers approve and the proposals passes, the action array can be executed and the transition happens. | ||
|
||
Here, it is important that the two actions happen in the specified order and both are required to succeed. | ||
Otherwise, if the first action would fail or the second one would happen beforehand, the DAO could end up in a state without having a governance plugin enabled. | ||
|
||
Accordingly and by default, none of the atomic actions in the action array is allowed to revert. Otherwise, the entire action array is reverted. | ||
|
||
### Allowing For Failure | ||
|
||
In some scenarios, it makes sense to relax this requirement and allow specific actions in the array to revert. | ||
Imagine a DAO wants to buy two NFTs A and B with DAI tokens. A proposal is scheduled in a governance plugin to | ||
|
||
1. set the DAI allowance to `125` | ||
2. try to buy NFT A for `100` DAI | ||
3. try to buy NFT B for `125` DAI | ||
4. set the DAI allowance to `0` | ||
|
||
Once the proposal has passed, it might be that the NFT A or B was already bought by someone else so that action 2 or 3 would revert. | ||
However, if the other NFT is still available, the DAO might still want to make at least the second trade. | ||
Either way, the DAO needs to first approve `125` DAO tokens before the trade and wants to set it back to `0` after the potential trades have happened for security reasons. | ||
|
||
#### The `allowFailureMap` Input Argument | ||
|
||
This optionality can be achieved with the allow-failure feature available in the DAO's `execute` function. | ||
To specify that failure is allowed for the actions 2 and 3, we provide the following `_allowFailureMap`: | ||
|
||
```solidity | ||
uint256 _allowFailureMap = 6; | ||
``` | ||
|
||
and explain why in the following: | ||
|
||
In binary representation a `uint256` value is a number with 256 digits that can be 0 or 1. In this representation, the value of `uint256(6)` translates into | ||
|
||
```solidity | ||
... 0 0 0 1 1 0 // the value 6 in binary representation | ||
... 5 4 3 2 1 0 // the indices of the action array items that are allowed to fail. | ||
``` | ||
|
||
where we omitted 250 more leading zeros. This binary value encodes a map to be read from right to left encoding the indices of the action array that are allowed to revert. | ||
Accordingly, the second and third array item (with the indices 1 and 2) are allowed to fail. | ||
If we want that every atomic succeeds, we specify a `allowFailureMap` value of `0`. | ||
|
||
#### The `failureMap` Output Argument | ||
|
||
In analogy and after an action array with a provided allow-failure map was executed successfully in the DAO, the `execute` function returns a corresponding `uint256 failureMap` containing the actual failures that have happened. | ||
If all actions succeeded, the value `uint256(0)` will be returned. | ||
If the third action failed, for example, because the NFT was already sold or the DAO had not enough DAI, a failure map value `uint256(4)` is returned | ||
|
||
```solidity | ||
... 0 0 0 1 0 0 // the value 4 in binary representation | ||
... 5 4 3 2 1 0 // the indices of the action array items that are allowed to fail. | ||
``` | ||
|
||
On the frontend, these conversions will be handled automatically. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
= DAO | ||
|
||
== The DAO Contract: The Identity and Basis of Your Organization | ||
|
||
In this section, you will learn about the core functionality of every Aragon OSx DAO. | ||
|
||
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 | ||
|
||
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:how-it-works/core/plugins/index.adoc[plugin installed to your DAO] | ||
|
||
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:how-it-works/core/dao/actions.adoc[A Deep Dive Into Actions]. | ||
|
||
### 2. Asset Management | ||
|
||
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)] | ||
|
||
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:how-it-works/core/plugins/index.adoc[plugins]. | ||
|
||
### 3. Upgradeability | ||
|
||
Your DAO contract has the ability to be upgraded to a newer version (see xref:how-to-guides/dao/protocol-upgrades.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 | ||
|
||
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 | ||
|
||
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 | ||
|
||
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:how-it-works/core/plugins/index.adoc[plugins] that you can install on your DAO. | ||
|
||
To learn more, visit the xref:how-it-works/core/permissions/index.adoc[permission manager] section. |
Oops, something went wrong.