Commons Swarm Outcomes (3/3): A tool to mutate a DAO's DNA

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:

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:

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 the token-manager app has the CREATE_VOTES_ROLE needed to forward actions to voting.
  • For a garden DAO this is only disputable-voting because ANY_ADDRESS usually has permission to create votes. Worth noting however is that the disputable voting forwarder requires an extra parameter called context, 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

:warning: 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

:warning: 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.

:warning: 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

:warning: 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 the MINT_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 the TRANSFER_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:

  1. Connect to the exampledao.aragonid.eth DAO using sending the actions to the voting app through the token manager.
  2. Install a new agent.
  3. Grant to voting permission to transfer funds from the vault.
  4. Grant to voting permission to transfer funds from the new agent.
  5. Transfer 100 wxDAI from the vault to the new installed agent.
  6. Call the wxDAI token external function withdraw to free the xDAI.
  7. 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

:information_source: 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.

4 Likes