Skip to content

aragonOS 4: Updates to aragonOS and aragon apps

Brett Sun edited this page Feb 15, 2019 · 7 revisions

Updates to aragonOS and aragon-apps

Numerous improvements to both the underlying framework, aragonOS, as well as the "first-party" applications built on top of it, aragon-apps, have been completed over summer 2018.

At a future point in time, the information provided in this document will be available to developers under our documentation website.

Auditing checkpoints:

aragonOS 4

Efforts around aragonOS 4 have focused on new concepts and interfaces that aim to make it easier for application developers to create and deploy safe contracts.

These introductions fall under two main categories:

  • Contract lifecycle guarantees; and
  • Application capabilities

Lifecycle guarantees govern the stages of "life" a deployed contract may fall under, as well as their expected functionality at any given stage. Primarily, these guarantees should help avoid confusion over whether a certain contract can be used directly, or only as a base logic contract behind another proxy contract.

Application capabilities are feature extensions available through AragonApp that may extend functionality in a given way. These include:

  • ETH and token recoverability (new; enabled by default)
  • Natively depositable proxies for ETH (new; disabled by default)
  • EVMScript (included by default)
  • Forwarding interface (not included by default)

Lifecycle Guarantees

Lifecycle guarantees were partly available in aragonOS 3 through the Initializable contract, which was included with AragonApp.

aragonOS 4 introduces Petrifiable, as well as AutoPetrified, (see changeset) to ensure that deployed base contracts are never utilizable. Petrifiable is built as an extension to Initializable, with the behaviour that contracts who are "petrified" can be assumed to be never initialized. AutoPetrified petrifies a contract on deployment, through the constructor.

The main use case for Petrifiable is to mark base contracts as unusable, to allow developers to control whether they want their application contracts to be usable directly through the deployed contract or only via a proxy contract.

By default, AragonApp now inherits from AutoPetrified, so all application contracts building from AragonApp will be petrified by default. It is important to note that making sure this is the case is still the responsibility of the application developer, as he has to protect any publicly-accessible functionality from being accessible in a petrified state himself.

Some additional hasInitialized() checks are included in AragonApp and Kernel to make this responsibility less bothersome (e.g. including it in the auth modifier and canPerform()).

The contract lifecycle of an AragonApp now looks like this:

Not deployed ---> Base deployed (immediately petrified and assumed unusable)
                       |
                       |---> Proxy deployed ---> Proxy initialized (now usable)

With Petrifiable, applications now must be initialized before they can be used, even if they had no use for initialization before.

Any attempt at initializing or using AragonApp base contracts should fail if the application developer has successfully secured their contract. By making base contracts unusable we can provide additional assurance that they will always be available and they cannot be self-destructed.

Additionally, aragonOS provides a "backdoor" to AragonApp through UnsafeAragonApp, which disables this default protection to allow application developers to create contracts which can be directly used without a proxy.

In the case of UnsafeAragonApp, the lifecycle looks like:

Not deployed ---> Base deployed --> Base initialized (now usable)
                       |
                       |---> Proxy deployed ---> Proxy initialized (now usable)

Application Capabilities

Only the depositable proxies and escape hatch recoverability are new since 01-04-2018.

Depositable Proxies

@aragon/[email protected] introduced the concept of depositable proxies (see original changeset and additional changeset to disable it by default).

Depositable proxies were designed to enhance application proxies to allow them to receive ETH on native, gas-limited, .send()s and .transfer()s due to the gas calculations of DelegateProxys. This functionality relied on the gas limit for a call.

Afterwards, in @aragon/[email protected], we added the ability to enable and disable ETH depositability inside apps, and disable it by default so that most application contracts would not behave differently based on the amount of gas sent to a call.

Right now, both AragonApps and Kernels should not able to receive ETH whether in their base contracts, or in a proxy. Most tokens, of course, we can't control.

Escape Hatch for ETH and Tokens

@aragon/[email protected] also introduced the concept of ETH and token recoverability (see changeset).

The transferToVault() escape hatch included in AragonApps and Kernels is intended for users to be able to recover any mistakenly sent ETH or tokens to a defined "default" vault for the organization. Note that, again, AragonApps and Kernels (and their proxies) are not able to receive ETH by default.

An allowRecoverability() hook is included for application contracts to define their own behaviour regarding recoverability.

This capability can be nuanced for application contracts that are meant to hold or receive ETH or tokens. For example, the Token Manager is meant to hold and control minted organization tokens, and so should prevent recoverability for those tokens. Another example is the Vault, which should prevent recoverability altogether when initialized. A further point of complexity is changing an app's default recoverability capabilities based on its lifecycle–Finance is recoverable only when not initialized, to avoid ETH or tokens being locked in an ususable contract.

Misc.

Apps must be connected to a Kernel instance for them to be usable, if they use the authorization checks properly (part of changeset for Petrifiable).

Apps instantiated through Kernel.newAppInstance() or Kernel.newPinnedAppInstance() can now be directly initialized by providing the calldata for the initialization call, which is executed right after the proxy is created (changeset).

The Kernel now uses an explicit two-level mapping for app namespacing rather than using a hash of concatenated bytes (changeset).

All contracts have been upgraded to [email protected] (changeset).

Proxies are now implemented via unstructured storage (changeset). This additional abstraction allows application contracts inheriting from AragonApp to start at slot 0, simplifying their storage model, as well as making it easier to upgrade in the future.

DelegateScript and DeployDelegateScript were removed, as they weren't being used and we could not find a satisfiable method of making them safe (changeset).

Raw List of Changes

Important changes are highlighted in bold. Breaking changes from aragonOS 3 are noted with [Breaking].

Lists raw contract changes.

  • cdaed71 (25-10-2018): Document and fix potentially uninitialized bytes array when force casting bytes to and from uint256[]
  • e3fb067 (23-10-2018): [Breaking] Publicly expose EVMScriptRunner.getEVMScriptRegistry()
  • 9406059 (23-10-2018): [Breaking] Prune unnecessary public constants to optimize gas during deployment
  • c469d8f (22-10-2018): Add clarification comments about how IsContract is meant to be used
  • a684791 (16-10-2018): Add revert reasons
  • 683d4f8 (08-10-2018): Remove redundant kernel check in AragonApp.getRecoveryVault()
  • 7d70ffe (08-10-2018): [Breaking] Change EVMScriptRegistry's executor storage to a mapping instead of an array
  • f67fa5d (08-10-2018): Use non-strict pragma for KernelConstants as it's inherited by AragonApp
  • 7a5078a (28-09-2018): Add the ability to "burn" permission managers, so as to throw away or freeze a permission permanently
  • 8d2f97d (28-09-2018): [Breaking] Change Repo's storage of versions to a mapping instead of an array
  • c7f001b (18-09-2018): Fix visibility order for constants
  • 88619af (05-09-2018): Optimize multiplication in SafeMath64 and SafeMath8
  • 7fca564 (04-09-2018): Use TimeHelpers in ACL
  • a56234e (04-09-2018): [Breaking] Allow depositable functionality to be enabled or disabled, and default to disabled
  • e07c379 (04-09-2018): [Breaking] Allow apps to be initialized when being instantiated from a Kernel
  • 5b880fc (03-09-2018): [Breaking] Use explicit mappings in Kernel for different namespaces rather than using a hash of concatenated bytes
  • 94f70e5 (30-08-2018): Use auth modifier in ACL
  • d268367 (27-08-2018): [Breaking] Remove unused token contracts from libraries
  • f94d43d (27-08-2018): Add functionality to allow re-enabling executors in EVMScriptRegistry
  • bfed147 (26-08-2018): [Breaking] Upgrade to [email protected]
  • 5bec9d0 (23-08-2018): [Breaking] Always check that base contracts are a contract
  • 1e4ce6c (22-08-2018): [Breaking] Add Petrifiable
  • 3e5c75d (22-08-2018): [Breaking] Use explicit nonces to calculate hashes in the ACL
  • db0ecb6 (22-08-2018): [Breaking] Remove sender param from ACL
  • 1ee632b (22-08-2018): [Breaking] Move to unstructured storage
  • ae97af2 (22-08-2018): Add type getter to EVMScript executors
  • 5064958 (22-08-2018): Emit events when enabling or disabling executors in EVMScriptRegistry
  • 4b873bb (15-08-2018): Update SafeMath libraries to current gas-optimized versions
  • 796ebfd (15-08-2018): Log when permissions are set with parameters
  • 898310f (10-08-2018): Add TimeHelpers and UintHelpers to use the same interface for obtaining uint64 time values
  • 1c2ba2c (01-08-2018): Add another helper to ACLSyntaxSugar
  • 2392a50 (27-07-2018): Use static types more, rather than raw addresses
  • 6466d21 (26-07-2018): Add log for EVM script result after execution
  • 540c4ae (26-07-2018): Make fallbacks external
  • 623c498 (25-07-2018): Remove obsolete kernelIntegrity modifier
  • 9e673e7 (13-07-2018): Add SafeMath8 for math operations on uint8s
  • f3ba361 (13-07-2018): Explicitly define state visibility
  • be4522b (06-06-2018): [Breaking] Remove DelegateScript and DeployDelegateScript executors
  • b127811 (24-04-2018): Use hardcoded constants instead of keccaking strings to save gas
  • 2e77439 (15-05-2018): [Breaking] Fix incorrect role hashes in APM apps
  • b8691e9 (14-04-2018): [Breaking] Emit app IDs in new app proxy event
  • 5f24c49 (14-05-2018): Depositable proxies and escape hatches for recoverability
  • 9b1bdd2 (15-04-2018): Remove unnecessary reimplementation of fallback in AppProxyPinned
  • 19e386e (15-04-2018): Minor gas improvements
  • 29d7d11 (04-04-2018): [Breaking] Fix app ID hashes

aragon-apps

The majority of the work in aragon-apps has been to upgrading to aragonOS 4 (changeset), including a simplification to the Vault that adds native ETH support (which also had rippling effects for Finance).

A small migration guide for the apps is provided in #422:

  • Upgrade to pragma solidity 0.4.24
  • Upgrade to [email protected] and [email protected]; doing so requires that any test contracts be placed in contracts/
  • All apps are required to be initialized before they can be used
  • Unnecessary to use isInitialized modifier if the auth or authP modifier is used
  • Changed import locations of @aragon/os/contracts/lib/zeppelin/{token,math} to be @aragon/os/contracts/lib/{token,math}
  • Removed token implementations (StandardToken and MinimeToken) from aragonOS
  • Apps inheriting from AragonApp are automatically petrified upon deployment, so any tests directly using the base contract will fail and need updating (e.g. Finance and Survey)

General

  • 50a841a (23-10-2018): Large gas optimizations by only storing most string data in events
  • 66ccde1 (23-10-2018): Update radspec
  • c12c59f (17-10-2018): Further state optimizations by packing more uint256s into uint64s
  • cdaee27 (16-10-2018): Add revert reasons
  • 0caee4a (18-09-2018): Move all protection modifiers in all (e.g. initialization) to be in externally accessible interfaces, to simplify mental model of when protection checks are needed
  • 89d80c4 (18-09-2018): Use mappings instead of arrays for storage, to aid struct upgradeability
  • 6193cc0 (18-09-2018): Cosmetic improvements for comments, code style
  • dbc0990 (17-09-2018): Upgrade to aragonOS 4 (also upgrading to pragma solidity 0.4.24)
    • Also includes changes for the simplified Vault
  • Initialization checks: a69551b, 5c44f9b, and finally superseded by the upgrade to aragonOS 4
  • 5cdff73 (24-07-2018): Explicitly define state visibility
  • 40d87c8 (03-04-2018): Use SafeMath more in all apps

Finance

Capability matrix:

Lifecycle Recoverability Depositability
Petrified (with Kernel) State impossible State impossible
Petrified (without Kernel) False False
Uninitialized True False
Initialized False False

Base contract will be petrified on deployment.

Depositing to the Finance's proxy is disabled, but assets can be deposited to the finance.vault().

Finance provides its own custom deposit functionality that creates a record and sends funds to the vault.

Changes:

  • Depositing
    • 3d6a4db (18-09-2018): Refactor depositing functionality, and ensure that native ETH has the same interface as tokens
    • 5009920 (25-04-2018): Require deposits to have value
    • 096f70c (25-04-2018): Require positive value for recurring payments
  • Fix budgeting
    • 4cce038 (01-08-2018): Add hasBudget to auth modifiers for CHANGE_BUDGETS_ROLE
    • 2f4813d (24-07-2018): Don't use transitionsPeriod on getBudget() as getters should be constant
    • 6eefcc6 (24-07-2018): Set the budget to 0 when removing a budget
    • f10105f (25-04-2018): Expose getRemainingBudget() and only return budget settings from getBudget()
  • Improve period transitions
    • f17bf63 (26-07-2018): Remove limit on number of period transitions per transaction
    • 29b1662 (24-07-2018): Add transitionsPeriod to fallback
    • ccf9883 (26-04-2018): Set minimum period duration to 1 day
    • 8a2f035 (25-04-2018): Avoid reverting on overflow when transitioning periods
    • c36b8e9 (25-04-2018): Refactor tryTransitionAccountingPeriod() into a loop instead of recursion
  • Misc
    • 7e3303a (25-10-2018): Add comments explaining why setPaymentStatus() doesn't transition periods
    • 3e97d90 (25-10-2018): Radspec adjustments
    • ebc5b04 (16-10-2018): Rename setPaymentDisabled() to setPaymentStatus(), and rename role to MANAGE_PAYMENTS_ROLE to better reflect capability
    • 9b29427 (19-09-2018): Optimize storage variables by consistently using uint64
    • 39c12b3 (18-09-2018): Make uint constants internal
    • c10c08d (18-09-2018): Reorder state variables
    • 9b75bc8 (24-07-2018): Make fallback external
    • 61335b8 (25-04-2018): Pass amount to auth check when executing recurring payment
    • a52f369 (25-04-2018): Include amount in recorded transaction event
    • 7b30e2c (25-04-2018): Include payment repeat number in recorded transactions
    • f424938 (25-04-2018): Only allow a recurring payment to be created if it can be executed at least once

Token Manager

Capability matrix:

Lifecycle Recoverability Depositability
Petrified (with Kernel) State impossible State impossible
Petrified (without Kernel) False False
Uninitialized False False
Initialized True (only for non-managed token) False

Base contract will be petrified on deployment.

Changes:

  • 3b2ec3c (18-09-2018): Math optimizations to remove unnecessary usages of SafeMath
  • 7ea3c53 (18-09-2018): Cosmetic function reordering
  • 7c0ef11 (18-09-2018): Remove logging of token holders
  • 671b400 (18-09-2018): Remove unnecessary function for getting vesting length
  • 389fcdb (17-09-2018 as part of upgrade to aragonOS 4): Disable recoverability for managed token
  • 4f2d9a7 (25-04-2018): Add more information to vesting events
  • 95635e3 (25-04-2018): Offload all responsibility for handling untrasferable tokens to the Minime token

Vault

The Vault has been completely redone and simplified. The current vault is intended to only hold ETH and ERC20 tokens, with simple access controls for transferring held funds.

Capability matrix:

Lifecycle Recoverability Depositability
Petrified (with Kernel) State impossible State impossible
Petrified (without Kernel) False False
Uninitialized False False
Initialized False True

Base contract will be petrified on deployment.

Changes:

Voting

Capability matrix:

Lifecycle Recoverability Depositability
Petrified (with Kernel) State impossible State impossible
Petrified (without Kernel) False False
Uninitialized True False
Initialized True False

Base contract will be petrified on deployment.

Changes:

  • 6addb83 (23-10-2018): Rename totalVoters to votingPower for clarity and consistency
  • 5621d4f (16-10-2018): Only allow votes to be created if the token snapshot is positive
  • 0e8f3a5 (08-10-2018): Tweak radspec
  • a1050d9 (19-09-2018): Change voting thresholds to use strict inequality checks (rather than "or equal to" checks) to better mimic real world use cases
  • 738387c (18-09-2018): Allow the required support threshold to be changed, needed for Multisigs, when adding more addresses
  • d946356 (17-09-2018): Add parameter when creating a new vote whether it should automatically execute when possible
  • 79e9aec (17-09-2018): Cosmetic reordering of quorum sanity checks
  • a149c05 (16-05-2018): Fixes for calculating if a vote passed its thresholds
  • db615e7 (23-04-2018): Allow a vote to be created but not voted on immediately by the creator

Deployments

We now document our deployments in aragon/deployments.

User-facing Contracts

Contracts inheriting from AragonApp are meant to be deployed by third-party developers, to be installable by organizations to extend their functionality. Our official apps, aragon-apps, include the Finance, TokenManager, Vault, and Voting contracts that will be petrified on deployment and only usable behind a proxy (either AppUpgradeableProxy or AppPinnedProxy) by users who create an organization.

aragonOS includes two other applications inheriting from AragonApp–the ACL and EVMScriptRegistry–that will be petrified on deployment and only usable behind a proxy by users. By default, the EVMScriptRegistry will include a reference to a deployed CallsScript executor, that includes the logic for sending calls scripts (essentially batched function calls).

The Kernel contract in aragonOS will be the backbone for each organization, and its base contract will also be petrified on deployment so as to force users to only use it behind a proxy (KernelProxy).

Finally, aragonOS also includes a number of factory contracts (DAOFactory, EVMScriptFactory) that will be deployed and used directly by other factories (e.g. those in DAO-kits) to create organizations for users. See aragonOS/scripts/deploy-daofactory.js for how these factories will be deployed.

For the most part, we foresee most users interacting with only the deployed factories to create organizations through a web frontend. These factories will atomically and deterministically create, initialize, and set up permissions on the organization and its installed applications in one transaction, to avoid any potentially dangerous states (e.g. a contract not being initialized or set up properly). Users should not be deploying their own base contracts, unless they specifically desire to do so, and it will be their responsibility to ensure those contract are correctly used.

After using a factory, users will interact with the application proxies installed on their organizations for functionality like depositing ETH or tokens, voting, etc. Users may also install new applications, although at this point only technical users will access this functionality as it requires either sending raw transactions or using aragon-cli.

Aragon Package Manager

The Aragon Package Manager ("APM") is meant to be a generic on-chain repository of contracts and associated code. For more information, see Deploying and Distributing Aragon Core.

Right now, all the code for APM lives in aragonOS.

The AragonApps comprising the Aragon Package Manager, APMRegistry and Repo, will be deployed and used behind proxies by a "Aragon Package Manager" DAO.

aragonOS includes the ENSFactory and APMRegistryFactory contracts to create new instances of APM. See aragonOS/scripts/deploy-beta-ens.js and aragonOS/scripts/deploy-beta-apm.js for how these factories will be deployed.