LogoLogo
These products have been deprecated and are no longer being maintained. For a better experience and support, please check out our new stack Aragon OSx.
Aragon Legacy Documentation
Aragon Legacy Documentation
  • 🔷Aragon
    • Aragon Legacy Documentation
    • Aragon Values, Finances, and Legal
      • Legal and technical infrastructure
      • Financial infrastructure
      • Meet your DAO support network
    • Learn about DAOs
      • What is a DAO?
      • Why do we need DAOs?
      • What is decentralized autonomous governance?
      • What is the AN DAO?
      • TAO Voting
      • Why use Aragon to build a DAO?
  • 🌐Products
    • Prerequisites
    • Quickstart
    • Setting up a Metamask Wallet
      • Getting started with Ethereum
      • Getting started with Goerli Testnet
      • Getting started with Polygon
      • Getting started with Mumbai Testnet
      • Getting started with Harmony
      • Getting started with Harmony testnet
      • Getting started with Metis Andromeda
      • Getting started with Stardust Testnet
      • Getting started with BSC Testnet
      • How to sign a transaction?
      • Import your seed wallet to Metamask
      • Gas Tracker
    • Setting up a Frame Wallet
    • Setting up a Gnosis Safe MultiSig Wallet
    • Aragon Client
      • What is Aragon Client
      • How to create a DAO
        • Templates
        • Using the Company Template
        • Using the Membership Template
        • Use the Reputation template
      • How to create a DAO on Polygon
      • How to create a DAO on Harmony
      • How to navigate your DAO
        • Home
        • The Apps
          • Tokens App
          • Voting App
          • Finance App
          • Agent App
            • How to install the Agent App in your DAO
            • Using Agent with Frame
        • System Setting
          • Permissions Setting
          • App Center
          • Organization Setting
      • After you've started a DAO
        • How to change the Quorum of your DAO
          • Change Quorum using Aragon Console
          • Change Quorum using EVMcrispr
        • How to create a Legal Wrapper for your DAO with Otoco
        • How to Operate your DAO from your Mobile Phone
      • How to Brick your DAO 🧱
    • Aragon Govern
      • What is Aragon Govern?
      • How to create a Govern DAO
      • Navigate into your Govern DAO
        • How to mint and assign DAO tokens to others
        • How to deposit funds
        • Challenging a transaction
      • Reasons for the delay period in the transaction
      • Collateral for scheduling or challenging a transaction. Why?
      • Acting as a guardian for an Aragon Govern dispute
      • Using the Client DAO with the Govern DAO
    • Aragon Voice
      • What is Aragon Voice?
      • Creating a voting proposal
      • Creating a voting proposal using your token
      • Voting on a proposal
    • Aragon Vocdoni
      • What is Aragon Vocdoni
      • Creating a Vodconi organization
      • Accessing your Vocdoni organization
      • Navigating your Vocdoni organization
        • Creating a voting proposal
        • Voting on a proposal (anonymous voting disabled)
        • Voting on a proposal (anonymous voting enabled)
    • Aragon Court
      • What is Aragon Court
      • Court Dashboard
      • Dispute lifecycle
      • Acting as guardian for a dispute
      • Glossary
  • 🛠️Developers
    • Legacy Developer Documentation
    • General Tools
      • The Basics
        • Before starting
        • Quick start
        • Tech Stack
        • App permissions
        • Forwarding
        • Upgradeability
        • Package management
        • Templates
        • Aragon client
        • Human readable transactions
      • Guides
        • How to create your first custom DAO using Aragon CLI!
        • How to use the Agent App
          • Installing Aragon Agent from aragonCLI
          • Setting and Checking permissions
          • Interacting with Aragon Agent
        • How to build your first Aragon App!
        • How to publish an Aragon App to aragonPM
        • How to migrate existing Aragon App to Buidler plugin
        • How to change the Quorum of your DAO
          • Change Quorum using Aragon Console
          • Change Quorum using EVMcrispr
        • Deploying Aragon Client in new Chains
          • Deployments information
            • Harmony testnet
            • BSC Tesnet
            • Harmony
            • Metis stardust
            • Metis Andromeda
        • How to Brick your DAO 🧱
        • How to sign with Web3 providers
          • Setting up a Metamask Wallet
            • Import your seed phrase into Metamask
            • Import your private key into Metamask
            • Sign a transaction with Metamask
          • Setting up a Frame Wallet
            • Sign a Transaction with Frame
        • Troubleshooting
      • aragonOS
        • Introduction
        • Motivations
        • Developing with aragonOS
        • Reference documentation
        • Migrating to aragonOS 4 from aragonOS 3
        • Reference (aragonOS 3)
        • Smart Contract References
          • ACL
            • ACL
            • ACLSyntaxSugar
            • ACLHelpers
            • IACL
            • IACLOracle
          • APM
            • APMNamehash
            • APMRegistry
            • APMInternalAppNames
            • Repo
          • APPS
            • AppProxyBase
            • AppProxyPinned
            • AppProxyUpgradeable
            • AppStorage
            • AragonApp
            • UnsafeAragonApp
          • COMMON
            • Autopetrified
            • ConversionHelpers
            • DelegateProxy
            • DepositableDelegateProxy
            • DepositableStorage
            • EtherTokenConstant
            • IForwarder
            • IForwarderFee
            • IVaultRecoverable
            • Initializable
            • IsContract
            • Petrifiable
            • ReentrancyGuard
            • SafeERC20
            • TimeHelpers
            • Uint256Helpers
            • UnstructuredStorage
            • VaultRecoverable
          • ENS
            • ENSConstants
            • ENSSubdomainRegistrar
          • EVMSCRIPT
            • EVMScriptRegistry
            • EVMScriptRunner
            • IEVMScriptExecutor
            • IEVMScriptRegistry
            • EVMScriptRegistryConstants
            • ScriptHelpers
          • EVMSCRIPT/EXECUTORS
            • BaseEVMScriptExecutor
            • CallsScript
          • FACTORY
            • APMRegistryFactory
            • AppProxyFactory
            • DAOFactory
            • ENSFactory
            • EVMScriptRegistryFactory
          • KERNEL
            • IKernel
            • IKernelEvents
            • Kernel
            • KernelAppIds
            • KernelNamespaceConstants
            • KernelProxy
            • KernelStorage
      • aragonCLI
        • Introduction
        • Main commands
        • DAO commands
        • APM commands
        • IPFS commands
        • Global configuration
      • aragonPM
        • Introduction
        • Architecture
        • Reference documentation
      • aragonAPI
        • Introduction
        • Javascript
          • Quick Start
          • App API
          • React API
          • Wrapper
          • Providers
          • Architecture of apps
          • Background Scripts
      • aragonUI
        • Getting started
        • How to upgrade
        • BASE
          • Spacing
          • Colors
          • Text styles
          • Icons
          • Main
        • ACTIONS
          • Button
          • ContextMenu
        • NAVIGATION
          • Tabs
          • Pagination
          • BackButton
          • Link
          • Header
        • STRUCTURE
          • Bar
          • Box
          • Card
          • Split
          • DataView
          • Table
          • EmptyStateCard
          • IdentityBadge
          • TransactionBadge
          • Tag
          • Accordion
          • Timer
          • TokenAmount
          • EthIdenticon
          • TransactionProgress
        • DATA ENTRY
          • AutoComplete
          • DateRangePicker
          • DropDown
          • Switch
          • Radio
          • CheckBox
          • Slider
          • TextInput
          • SearchInput
          • AddressField
          • RadioGroup
          • RadioList
          • TextCopy
          • Field
        • VISUALIZATION
          • CircleGraph
          • LineChart
          • Distribution
        • FEEDBACK
          • Info
          • ProgressBar
          • LoadingRing
          • Toast
          • SyncIndicator
          • FloatIndicator
        • OVERLAYS
          • Help
          • Popover
          • Modal
          • SidePanel
        • ADVANCES
          • ButtonBase
          • FocusVisible
          • PublicUrl
          • Redraw
          • RedrawFromDate
          • Root
          • RootPortal
          • Viewport
      • aragonDS
        • Guidelines
          • Layout
          • Color
          • Iconography
          • Typography
          • Illustrations
        • Components
          • Overview
      • Aragon Connect
        • Guides
          • Aragon Basics
          • Getting started
          • Usage with React
        • Advanced
          • Custom Subgraph queries
          • Writing an App Subgraph
          • Writing an App Connector
        • Connectors
          • Organizations
          • Tokens app
          • Voting app
          • Finance app
        • API reference
          • connect()
          • App
          • Connectors
          • Organization
          • Permission
          • Repo
          • Role
          • TransactionIntent
          • TransactionPath
          • TransactionRequest
          • Types
          • Errors
      • App Center
        • App Center
        • Preparing Assets
        • Submitting Your App to the App Center
    • Product Tools
      • Aragon Govern
        • README
        • Introduction
          • Concepts and background
            • Govern Core concepts
            • ERC3000
          • Developers
            • Getting started
            • Govern.js API
            • Historical deployments
            • GraphQL API
            • Smart contracts breakdown
        • Deployments
          • Mainnet
          • Rinkeby
        • Packages
          • ERC 3k
          • Govern Console
          • Govern contract utils
          • Types
          • govern-create
          • Govern Server
          • govern-subgraph
          • govern-token
          • govern.js
      • Aragon Vocdoni
    • Aragon Client Glossary
  • THE ANT TOKEN
    • Aragon Network Token
      • About ANT
      • Historical token sale
    • ANTv1
      • Non-standard behaviours and gotchas
      • About the MiniMe token
      • The initial token sale flow
    • ANTv2
      • Upgrade portal
        • Troubleshooting
      • Contract interaction
      • Migrating on-chain liquidity
    • Developers
      • Quick start
      • Integrating ANT
      • Historical deployments
      • Security policy
  • ‼️FAQ
    • Products
      • Aragon Client
        • Where is my DAO?
        • DAO creation taking a long time to confirm
        • DAO is taking a long time to load
        • Failed DAO creation transaction
        • Why do I see a Blue Screen?
        • An unexpected error has occurred
        • App does not appear in Firefox
        • Receiving funds directly to the Agent or Vault address
        • How to Recover Funds accidentally sent to an Aragon App address
        • Depositing EURS in the Finance app
        • Which templates are available on the Ethereum Network?
        • Which templates are available on the Polygon Network?
        • Which templates are available on the Harmony Network?
        • Which templates are available on the Metis Andromeda Network?
        • How to delete a DAO
      • Aragon Govern
        • Which was the wallet address used to create the Aragon Govern DAO?
        • Where are my DAO tokens?
        • How to delete a DAO
        • How can I transfer funds to the Aragon Govern DAO?
      • Aragon Vocdoni
        • Is Vocdoni easy to use?
        • Is Vocdoni anonymous?
        • Is Vocdoni free?
        • Is my data safe with Vocdoni?
        • As an Organization, what can I do with Vocdoni?
      • Aragon Court
        • What is the current duration of the different stages of a dispute?
        • Dispute - Which fees need to be paid to create a dispute?
        • Dispute - Do I need to put collateral to create a dispute?
        • Appeals - How much money is needed to appeal a dispute? And to confirm the appeal? What is it for?
        • Appeals - If I have tokens staked or activated, can I lose them if I appeal a dispute?
        • Appeals - What happens to the collateral put up
        • Voting - Is a majority needed to win a vote?
        • Voting - What happens if there is a tie?
        • Voting - What does "Refuse to vote" mean? What happens if it's the most voted option?
        • Voting - Another guardian tried to collude. Can I punish this guardian?
        • Voting - What's the penalty for leaked votes?
        • Governance - Which parameters of Court can be changed? How?
        • Governance - Do parameter changes affect ongoing disputes?
        • Technical - Where is the Court "hosted"?
        • Technical - Where can I find the source code and technical documentation for Aragon Court?
        • ANJ conversion - What date will the lock-up period end?
        • ANJ conversion - If I have not staked my $ANJ, do I still get the lockup period price?
        • ANJ conversion - Will I get the 0.044 conversion if I convert after September 5th 2021?
        • ANJ conversion - How much will it cost to be a Guardian in Aragon Court with $ANT?
        • I can't see my tokens in the Dashboard
        • I activated my tokens but I can't see my probability of being drafted
    • Miscellaneous
      • Metamask wallet transaction alert
      • Is Aragon open source?
      • Where can I browse through the DAOs created on Aragon?
      • How to migrate from "old" DAI to "new" DAI
      • Security notice for organizations created before Aragon 0.8
      • General troubleshooting tips
    • ANT Token
      • What can I do with ANT?
      • Who holds ANT?
      • Who are the biggest ANT holders?
      • Long-term holding ANT - What benefits?
      • Can I delegate my network votes to somebody else?
      • Can I do flash loans with ANT?
      • Is there an ANT options market?
      • Are you planning to launch new network tokens?
      • My wallet isn't available on the Upgrade Portal
      • How can connect my Ledger to the Upgrade Portal?
      • I accidentally sent my "old" ANT to an exchange
      • ANJ conversion - What is the minimum number of $ANJ I need to participate in the 0.044 conversion?
      • ANJ conversion - What is the conversion rate ANJ to ANT v2?
Powered by GitBook
On this page
  • The AragonApp contract
  • Upgradeability: bases and proxies
  • Constructor and initialization
  • Roles and the Access Control List
  • Forwarding and EVMScripts
  • Fund recovery
  • Recommendations
  • Conventions
  • Safety conveniences
  • UNIX philosophy
  • Permissioning
  • Examples

Was this helpful?

  1. Developers
  2. General Tools
  3. aragonOS

Developing with aragonOS

PreviousMotivationsNextReference documentation

Last updated 2 years ago

Was this helpful?

aragonOS enables apps to be upgradeable and share a generic governance interface. To use it to its full potential, however, the following instructions need to be followed.

The AragonApp contract

Contracts using aragonOS have to inherit from the AragonApp contract. It makes the following functionality available.

The AragonApp contract manages two very important state variables in the app:

  • kernel: A reference to the Kernel contract. The Kernel manages upgradeability and access control for the app.

  • appId: An identifier for the app (the ENS name of the package repo of the app).

These variables are set by AppProxy on its constructor and should never be modified by the app as it could produce an unexpected state and leave the app unprotected or inaccessible.

import "@aragon/os/contracts/apps/AragonApp.sol";

contract MyApp is AragonApp {

}

Upgradeability: bases and proxies

The upgradeability pattern separates the contract implementation code or bases (the business logic) and the actual instances of the apps (thin proxies that use the base contract as their logic). The way upgradeability occurs is by changing the reference of the base contract in the proxy. Updating this reference effectively upgrades the logic that the proxy instances will execute when used.

In the case of aragonOS, the Kernel keeps the references for the versions of all of its installed apps. Using the kernel.newAppInstance(address appId, address base) function, an app is registered in the Kernel and a proxy for that app is created. At any point the base contract of the app can be upgraded using kernel.setApp(bytes32 namespace, bytes32 appId, address app).

Making an app available for use with upgradeable proxies requires deploying the contract to the network so its address can be used as a base. By default, if inheriting from AragonApp, the base contract is disabled on deployment and cannot be used directly (only behind proxies). This is a security feature to avoid scenarios when a contract that proxies rely on can be destructed and all proxies are rendered useless.

Constructor and initialization

The constructor of a contract is executed when a contract is created. When using a proxy, however, the constructor code that is run is the proxy's constructor and not the one of the base contract. Because of this, aragonOS apps cannot use a constructor for initializing the contract. An initialization function that can only be executed once is required to both be implemented and called before an app is usable.

AragonApp exposes the onlyInit modifier to protect a function from being called after initialized() has been completed and the auth(), authP(), and isInitialized modifiers to protect against a function from being called before the initialization is complete.

In the following example, if sendFunds() was called before initialization was complete, it would transfer the ETH sent with the call to address(0) since receiver wasn't set. By adding the isInitialized modifier, the function will fail until the contract has been initialized. It is a good practice to require all functions that modify state to be initialized before they can be used.

import "@aragon/os/contracts/apps/AragonApp.sol";

contract MyApp is AragonApp {
    address receiver;

    function initialize(address _receiver) public onlyInit {
        initialized();
        receiver = _receiver;
    }

    function sendFunds() payable external isInitialized {
        receiver.transfer(msg.value);
    }
}

It is important to note that, using this pattern, anyone can initialize a proxy after it has been deployed. The initialization of a proxy should occur in the same transaction that deploys the proxy to prevent initialization from being front-run by an adversary.

Global variables in apps

Because of our use of Proxies, child contracts won't initialize global variables when created. For example:

contract MyFancyApp is App {
  uint initialState = 1;
}

In the above example, when used behind a proxy, initialState will be 0, even though the expectation reading the code is that it will be 1.

The correct way to handle this situation is to make it something like:

contract MyFancyApp is App {
  uint initialState;

  function initialize() onlyInit { initialState = 1; }
}

Roles and the Access Control List

If the auth() modifier is present in a function it will check with the connected Kernel's ACL whether the entity performing the call is allowed to perform the action in the app prior to its execution.

Roles are identified by a bytes32 value. This identifier can be a constant value so it doesn't take up any storage space. The standard name for a role identifier is the keccak256 hash of its name as other tooling in the stack expects this to be the case. See this example:

import "@aragon/os/contracts/apps/AragonApp.sol";

contract MyApp is AragonApp {
    bytes32 public constant SET_RECEIVER_ROLE = keccak256("SET_RECEIVER_ROLE");

    address public receiver;

    function initialize(address _receiver) public onlyInit {
        initialized();
        receiver = _receiver;
    }

    function setReceiver(address _newReceiver) external auth(SET_RECEIVER_ROLE) {
        receiver = _newReceiver;
    }

    function sendFunds() external payable isInitialized {
        receiver.transfer(msg.value);
    }
}
{
  "roles": [
    {
      "name": "Set the receiver of funds",
      "id": "SET_RECEIVER_ROLE",
      "params": []
    }
  ]
}

Forwarding and EVMScripts

Forwarders are passed an EVMScript that can be executed by the app. The script executed is always an array of calls that will be performed one after the other.

In order for an app to be a forwarder, it needs to implement these 3 functions in the IForwarder interface:

import "@aragon/os/contracts/apps/AragonApp.sol";
import "@aragon/os/contracts/common/IForwarder.sol";

contract MyApp is IForwarder, AragonApp {
    address receiver;

    function initialize(address _receiver) onlyInit public {
        initialized();
        receiver = _receiver;
    }

    function isForwarder() public pure returns (bool) {
        return true;
    }

    function canForward(address _sender, bytes _evmCallScript) public view returns (bool) {
        // Arbitrary logic for deciding whether to forward a given intent
        return _sender == receiver;
    }

    function forward(bytes _evmScript) public {
        require(canForward(msg.sender, _evmScript));

        // Input is unused at the moment
        bytes memory input = new bytes(0);

        // An array of addresses that cannot be called from the script
        address[] memory blacklist = new address[](0);

        // Either immediately run the script or save it for later execution
        runScript(_evmScript, input, blacklist); // actually executes script
    }
}

In the example above, the app will always forward an intent if the sender happens to be the receiver in the contract.

Note that a script is only able to perform calls to addresses or contracts that are not in the address blacklist.

Fund recovery

If an app is intended to hold funds, this recovery functionality can be disabled or customized to only tokens that can be recovered:

import "@aragon/os/contracts/apps/AragonApp.sol";

contract MyApp is AragonApp {
    address receiver;

    function initialize(address _receiver) onlyInit public {
        initialized();
        receiver = _receiver;
    }

    function allowRecoverability(address token) public view returns (bool) {
        return token != ETH; // turns off fund recovery for ETH
    }
}

Recommendations

Conventions

Representing ETH as a token

If a function has a token parameter, but you would like to handle ETH as well as other token addresses in the same parameter, use address(0) as the address of ETH. aragonOS includes EtherTokenConstant to define ETH = address(0).

Representing time

Safety conveniences

UNIX philosophy

The design philosophy we use when developing Aragon apps is very similar to the UNIX philosophy. We try to architect apps to do one thing and one thing well and to respect and implement the few aragonOS interfaces so that they play nicely with the rest of the ecosystem.

This results in purely technical benefits such as testability, but it also becomes very powerful when apps are combined and the output of one app becomes the input of an other one. You can think of forwarders resembling UNIX pipes in their philosophy.

Permissioning

We also recommend that all state-changing functionality in an application should be protected by a role and that each separate action should have its own role. This allows one to create granular permissioning schemes and makes securing an application easier.

Examples

\

The supports passing an initialization payload to its constructor. On creation, the proxy will perform a call with the provided initialization payload as the calldata to itself. This can be used to initialize the proxy in its constructor.

If using a , the initialization of an app can be done right after the proxy is created.

Another important note is that if the app uses the for access control, all access control checks will fail unless the app has been initialized.

aragonOS comes with a powerful that apps can leverage for protecting functionality behind permissions. Rather than coding any custom access control logic into your app, such as the infamous onlyOwner, you can just protect functions by adding the auth() or authP() modifiers.

An important note is that the auth() and authP() modifiers will also check whether the app is . If the app hasn't been initialized, the authentication check will fail.

When adding a role to your app you will also need to add it to the file with a description of the functionality protected by the role. You can check Aragon's and below for an example of role descriptions:

aragonOS introduces the concept of , which is a generic interface for apps to send an intent to other apps if some conditions are met. For example, a Voting app can be a forwarder that only forwards the intent if a vote passes. Another example is a Payroll app that only forwards the intents of an organization's employees.

As it is unlikely we'll ever need to worry about uint256-precision for UNIX timestamps (in seconds) or blocks (in ~15s intervals), we generally cast these values down to uint64s so we can pack them to save gas. aragonOS provides and as utility contracts for obtaining these values safely.

As of @aragon/os@4.1.0, is available as a generic library to smooth out ERC20 token interactions. In particular, it adds the ability to transparently handle as well as adding staticcall variants for common read-only interfaces in tokens.

As of @aragon/os@4.2.0, a ReentrancyGuard has been built into AragonApp to prevent exposed app functionality from facing re-entrancy problems. See or more information on making use of it.

We officially build and maintain a number of Aragon apps ourselves, that implement the basic functionalities to manage organizations. These apps are released alongside every Aragon release and are a good reference of how to build Aragon apps. You can view their code in the repo.

🛠️
DelegateProxy
AppProxy
DAO template
ACL
Access Control List (ACL)
forwarding
TimeHelpers
Uint256Helpers
SafeERC20
tokens that don't return properly
aragon/aragon-apps
initialized
Voting app arapp.json
arapp.json
the aragonOS reference documentation f