This is the last of a three-part series of articles written to showcase the outcomes from the last year of work in the Commons Swarm.
You can read up on the previous articles here:
- Part 1: The Augmented Bonding Curve: A plug-and-play bonding curve
- Part 2: The Hatch: A fundraising module for DAOs
- Part 3: EVM-Crispr: A tool to mutate a DAO’s DNA
And without further ado,
EVMcrispr, a new tool to handle Aragon DAO actions
During the last few months, the 1hive Commons Swarm has been working on EVMcrispr, a library that can be used to wrap many actions within just one vote in AragonOS and Gardens DAOs.
There are many actions that can be done within this new tool including:
- Installing new Aragon apps,
- Granting or revoking permissions,
- Calling internal apps or external contracts methods such as minting tokens, withdrawing funds, etc.
And we’re just getting started. EVMcrispr works with both AragonOS v4 and v5, supporting a plethora of DAO configurations.
It has already been used in production by many organizations to do different operations in their Aragon DAOs:
- CurveDAO used it to upgrade it’s voting app implementation contract.
- 1Hive used it to claim it’s ENS airdrop and transfer the funds of it’s mainnet DAO.
- Giveth used it to replace the Unipool contract for another one in their gardens DAO.
- TECommons used it for minting and burning tokens, and will use it for migrating to a gardens DAO and installing a bonding curve.
- BrightId is using it to change the parameters on their garden’s conviction voting app, and will use it to install the BrightId gatekeeper as an ACL oracle.
- Agave used it to remove the vesting of some of their seeds and transfer funds from their agent to many contributors.
How complex votes were bundled before EVMcrispr
1hive has built many tools over the years to deal with multi-action complex votes:
- The 1hive node installer was written in JavaScript and executed from the console. It had been used to install Aragon applications with complex configurations, and offered some parsing helpers, but the developer experience of installing a new app or doing any other operation was poorly done.
- The 1hive app installer was an end-user tool with an UI interface that works pretty well, although it could only install pre-configured applications, which are still difficult to configure.
- The 1hive transactions app could create votes with multiple actions for minting, burning or transferring tokens. It worked well for those specific purposes, but it wasn’t able to create any kind of vote.
We should mention as well that, Aragon Client has a built-in console which is the most similar work to EVMcrispr. However development has been discontinued and the console is quite limited on creating multi-action votes neither does it have helpers to parse parameters, making it difficult for complex operations.
How does EVMcrispr work?
The easier way to bundle many actions using EVMcrispr is by using the EVMcrispr terminal. We can define one command after the other and forward them through a defined path.
The first line of the script has the following syntax:
connect <daoAddressOrName> [...path] [@context:<context>]
The path is composed of the app names through which the EVM script will be sent:
- For a regular Aragon DAO this is
token-manager voting
because thetoken-manager
app has theCREATE_VOTES_ROLE
needed to forward actions tovoting
. - For a garden DAO this is only
disputable-voting
becauseANY_ADDRESS
usually has permission to create votes. Worth noting however is that the disputable voting forwarder requires an extra parameter calledcontext
, where we can add a link to a forum post containing more information in case of a dispute.
Examples:
- Forwarding actions to Gardens Swarm voting would be encoded as
connect gardensswarm token-manager voting
(only token holders can vote so we have to include the token manager in the path). - Forwarding actions to 1hive Garden’s disputable voting would be encoded as
connect 0x8ccbeab14b5ac4a431fffc39f4bec4089020a155 disputable-voting.open @context:https://forum.1hive.org/t/999
.
Once the correct path is defined, the subsequent lines define the actions of the script. We’ll continue to explore in this article some of these actions in more detail.
Installing apps
Syntax:
install <repo>:<label> [...initParams]
This command installs a new instance of the specified app with its initialization parameters.
There are many apps we can choose from, such as token-manager
, voting
, vault
, agent
, finance
, redemptions.open
, augmented-bonding-curve.open
, and the list goes on! initParams
are used to call the initialize
function of the app.
In the parameters we can use app identifiers such as voting
, agent:0
and token-manager:1
to specify the address of those apps (when no index is specified, we consider it as 0
).
When specifying numbers we can use the scientific notation to input big numbers, such as 100e18 to represent 100,000,000,000,000,000,000 (usually used to define token balances and percentages).
We can also append the letters s
, m
, h
, d
, w
, and y
at the end of the number for defining them as seconds, minutes, hours, days, weeks, and years respectively. For example 2d
would get converted to 172,800 seconds, which is usually the format solidity smart contracts expect time periods to be passed in as.
Examples:
- Installing a new agent would be encoded as
install agent:new
since it does not have initialization parameters (see the agent’s contract initialize function). - Installing a new voting with 50% support required, 15% min acceptance quorum, and 1 day voting period would be encoded as
install voting:new 50e16 15e16 1d
(see voting’s contract initialize function). - Installing a new redemptions app with the vault address, token manager address, and ETH as the redeemable token be encoded as
install redemptions.open:new vault token-manager [ETH]
(see the redemptions’ contract initialize function).
Upgrading apps
This command can potentially break the app we are upgrading, so be especially careful to check that the new implementation contract is compatible with the previous one.
Syntax:
upgrade <repo> [contract]
This command upgrades the kernel’s base contracts of the defined apps, so those app proxies will point to a new implementation contract.
Examples:
- Upgrading all voting instances to the latest implementation contract can be encoded as
upgrade voting
. - Upgrading all conviction voting instances to a specific implementation contract (that should be previously registered as a repo version in APM):
upgrade disputable-conviction-voting.open 0x123456789abcdef123456789abcdef0123456789
.
Granting permissions
This command can potentially burn a permission manager if it is set to the wrong address, making the permission unable to be changed in the future. We usually want to set the main voting app as the permission manager of all permissions.
The most critical permissions are argumentably the ones on the Kernel (DAO main contract) and the ACL (permission management contract), so be careful who we grant them to.
Syntax:
grant <entity> <app> <roleName> [defaultPermissionManager]
This command grants an entity (app or external address) the ability of calling methods protected by a specific role.
This is needed because many app methods are protected by Aragon’s auth
and authP
solidity modifiers, ensuring only a set of addresses can call them. In order to add permission to an address to call the methods protected by a specific role, we need to add the permission to the DAO access control list (ACL).
Examples:
- Granting any entity permissions to create new votes on the new instance of voting and setting it as the permission manager would be encoded as
grant ANY_ENTITY voting:new CREATE_VOTES_ROLE voting:new
(see voting contract roles). - Granting the second voting app to be able to transfer funds from the third vault in the case the role already has a permission manager can be encoded as
grant voting:1 vault:2 TRANSFER_ROLE
(see agent contract roles, notice app indexes start at 0, and the permission manager is not mandatory if it’s already set).
Revoking permissions
This command can potentially remove a permission that is needed for the DAO to work. Be careful not removing the permissions to create votes in voting, create permissions in ACL, or manage apps in the kernel.
Synax:
revoke <entity> <app> <roleName> [shouldRemoveManager?]
This command removes the specified permission, optionally removing the permission manager as well.
Examples:
- Revoking the previously defined permission that Finance app had on transferring funds from the Agent app would be encoded as
revoke finance agent TRANSFER_ROLE false
. - Revoking the previously defined permission
revoke voting finance CREATE_PAYMENTS_ROLE true
.
Executing app methods
exec <app> <methodName> [...params]
This command executes an app method (defined in the smart contract code). We can use the same parameter helpers that are explained in the install section (we can use app identifiers, scientific notation and time units).
Examples:
- Minting 1,000 DAO tokens to the vault would be encoded as
exec token-manager mint vault 1000e18
(see token manager’s mint function). Be aware the executor needs to have theMINT_ROLE
permission to execute this action. - Transfering 1 ETH from the first vault to the second vault would be encoded as
exec vault transfer ETH vault:1 1e18
(see vault’s transfer function). Be aware that the executor needs to have theTRANSFER_ROLE
permission to execute this action.
Executing external methods using the Agent
act <agent> <target> <methodSignature> [...params]
This command executes an action on an external contract using the specified agent as the caller.
Examples:
- Approving the transfer of 500 wxDAI from the first agent to a contract would be encoded as
act agent 0xe91d153e0b41518a2ce8dd3d7944fa863463a97d approve(address,uint256) 0x123456789abcdef123456789abcdef0123456789 500e18
. - Swapping 500 wxDAI from the first agent to HNY assuming an ABI similar to uniswap would be encoded as
act agent 0x123456789abcdef123456789abcdef0123456789 swap(uint,uint,address,bytes) 0 500e18 agent 0x0
.
Bringing it all together
Imagine ExampleDAO has 100 wxDAI into the vault and wants to transform them back into xDAI. We have already learned what the steps are to do that:
- Connect to the
exampledao.aragonid.eth
DAO using sending the actions to the voting app through the token manager. - Install a new agent.
- Grant to voting permission to transfer funds from the vault.
- Grant to voting permission to transfer funds from the new agent.
- Transfer 100 wxDAI from the vault to the new installed agent.
- Call the wxDAI token external function withdraw to free the xDAI.
- Transfer the resulting 100 xDAI from the new agent to the vault.
connect exampledao token-manager voting
install agent:new
grant voting vault TRANSFER_ROLE voting
grant voting agent:new TRANSFER_ROLE voting
exec vault transfer @token(WXDAI) agent:new 100e18
act agent:new @token(WXDAI) withdraw(uint256) 100e18
exec agent:new transfer XDAI vault 100e18
Note: in the example we use the
@token()
feature not available in current v0.3.x. We can use the wxDAI token address instead.
As we can see with this example, the true power of the EVMcrispr is when we combine different commands to perform increasingly complex tasks. We hope this documentation serves to help many more people to write their own scripts and configure DAOs in really unique ways. The limit to this powerful new tool is our own imagination!
I would like to thank @divine_comedian for his corrections on this article, he really improved its quality.