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
  • Environment setup
  • The setup
  • Structure
  • Writing a simple contract
  • 3 steps to governance and upgradeability
  • Descriptive transactions
  • Building the frontend
  • Background scripts and building state
  • Displaying State
  • App root component
  • Writing the manifest files
  • arapp.json
  • manifest.json
  • Buidler script hooks
  • Running your app locally
  • Next steps
  • Tests
  • Publishing
  • Documentation
  • Community

Was this helpful?

  1. Developers
  2. General Tools
  3. Guides

How to build your first Aragon App!

PreviousInteracting with Aragon AgentNextHow to publish an Aragon App to aragonPM

Last updated 1 year ago

Was this helpful?

In this guide, we will walk you through building your first Aragon App using aragonOS, the JavaScript implementation of aragonAPI, aragonUI and the Aragon builder plugin.

Environment setup

Before starting you need to check if you have already installed all these prerequisites:

  • the right version of node.js (recommendedv12 LTS version)

  • Metamask web3 provider

  • the aragonCLI (Aragon Command Line Interface)

  • the Aragon Buidler plugin

If you haven't already installed them or if you need more info about this goes to the "Environment Setup" paragraph .

The setup

Let's first set up and bootstrap our project:

npx create-aragon-app foo tutorial

For this particular command switching from node v12 to node v14 LTS or v16 LTS might be required to prevent a node error on install. In that case you have to switch, do not forget to switch back to v12 LTS afterwards!

This will create a new directory named foo, with files cloned from . This particular boilerplate includes everything you need to get started:

  • (now Hardhat),

  • aragonOS,

  • aragonAPI.

Structure

This boilerplate has the following structure:

root
├── app
├ ├── src
├ ├ ├── App.js
├ ├ ├── index.js
├ ├ └── script.js
├ └── package.json
├── contracts
├ └── CounterApp.sol
├── scripts
├ └── buidler-hooks.js
├── arapp.json
├── manifest.json
├── buidler.config.js
└── package.json
  • app: Frontend folder. Completely encapsulated, has its package.json and dependencies.

    • src: Source files.

      • App.js: Aragon app root component.

      • index.js: Aragon app entry point.

      • script.js: Aragon app background script.

  • contracts: Smart Contracts folder.

    • CounterApp.sol: Aragon app contract.

  • scripts: Scripts folder.

    • buidler-hooks.js: Buidler script hook.

Stuck?

Now let's start with it 💪.

Writing a simple contract

To illustrate how easy it is to use aragonOS, we will build our app as a vanilla smart contract, without any Aragon-specific interfaces at all.

Today, we will build a simple counter app — you can increment it, you can decrement it, and it will all be decentralized. Decentralized coffee counter, anyone? If yes, then add the below code to CounterApp.sol:

// contracts/CounterApp.sol
pragma solidity ^0.4.24;

import "@aragon/os/contracts/lib/math/SafeMath.sol";


contract CounterApp {
    using SafeMath for uint256;

    /// Events
    event Increment(address indexed entity, uint256 step);
    event Decrement(address indexed entity, uint256 step);

    /// State
    uint256 public value;

    function increment(uint256 step) external {
        value = value.add(step);
        emit Increment(msg.sender, step);
    }

    function decrement(uint256 step) external {
        value = value.sub(step);
        emit Decrement(msg.sender, step);
    }
}

Pretty simple, right? You might wonder why we would bother adding events to this smart contract, but it comes in handy later for illustration purposes — and we can also create an activity feed from it, if we wanted to.

3 steps to governance and upgradeability

Now for the interesting part: making our simple smart contract an Aragon app.

First, inherit from the Aragon app smart contract. Integrate this code in CounterApp.sol:

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

contract CounterApp is AragonApp {
    // ...
}

Second, define the roles that you want your app to have.

A role can be assigned to other apps or people and those entities will have access to methods guarded by that role.

In this example, we will define a role for incrementing and a role for decrementing but note that you can have a single role to guard all methods in your contract if you find that appropriate. Integrate this code in CounterApp.sol:

contract CounterApp is AragonApp {
    // ...
    bytes32 constant public INCREMENT_ROLE = keccak256("INCREMENT_ROLE");
    bytes32 constant public DECREMENT_ROLE = keccak256("DECREMENT_ROLE");
    // ...
}
contract CounterApp is AragonApp {
    // ...

    function initialize(uint256 _initValue) public onlyInit {
        value = _initValue;

        initialized();
    }

    function increment(uint256 step) auth(INCREMENT_ROLE) external {
        // ...
    }

    function decrement(uint256 step) auth(DECREMENT_ROLE) external {
        // ...
    }
}

Descriptive transactions

contract CounterApp is AragonApp {
    /**
     * @notice Increment the counter by `step`
     * @param step Amount to increment by
     */
    function increment(uint256 step) auth(INCREMENT_ROLE) external {
        // ...
    }

    /**
     * @notice Decrement the counter by `step`
     * @param step Amount to decrement by
     */
    function decrement(uint256 step) auth(DECREMENT_ROLE) external {
        // ...
    }
}

Building the frontend

Apps are run inside an iframe, which means that it only has access to their own DOM, not the outlying DOM. The app can communicate with the client over our custom RPC protocol.

Then the client takes care of connecting to Ethereum via Web3, and also handles things like signing transactions, displaying notifications and more to the end-user.

Background scripts and building state

Apps usually want to listen to events using Web3 and build an application state from those events. This concept is also known as event sourcing.

aragonAPI was built with event sourcing in mind. To build the state continually without having the app loaded indefinitely, though, we need to run a background script.

Let's start by writing a background script that listens for our Increment and Decrement events, and builds a state, for this example, the current value of our counter. Add the below code to script.js:

// app/src/script.js
import 'core-js/stable'
import 'regenerator-runtime/runtime'
import Aragon, { events } from '@aragon/api'

const app = new Aragon()

app.store(
  async (state, { event }) => {
    const nextState = {
      ...state,
    }

    try {
      switch (event) {
        case 'Increment':
          return { ...nextState, count: await getValue() }
        case 'Decrement':
          return { ...nextState, count: await getValue() }
        case events.SYNC_STATUS_SYNCING:
          return { ...nextState, isSyncing: true }
        case events.SYNC_STATUS_SYNCED:
          return { ...nextState, isSyncing: false }
        default:
          return state
      }
    } catch (err) {
      console.log(err)
    }
  },
  {
    init: initializeState(),
  }
)

/***********************
 *   Event Handlers    *
 ***********************/

function initializeState() {
  return async cachedState => {
    return {
      ...cachedState,
      count: await getValue(),
    }
  }
}

async function getValue() {
  // Get current value from the contract by calling the public getter
  // app.call() returns a single-emission observable that we can immediately turn into a promise
  return parseInt(await app.call('value').toPromise(), 10)
}

The store should be used as the main "event loop" in an application's background script (running inside a WebWorker). Listens for events, passes them through reducer, caches the resulting state, and re-emits that state for easy chaining. Optionally takes a configuration object comprised of an init function, to re-initialize cached state, and an externals array for subscribing to external contract events. See below for more details.

Displaying State

<!-- app/index.html !-->
<!DOCTYPE html>
<html>
  <head>
    <title>Aragon App</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="src/index.js"></script>
  </body>
</html>

Add this code to app/src/index.js:

// app/src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { AragonApi } from '@aragon/api-react'
import App from './App'

const reducer = state => {
  if (state === null) {
    return { count: 0, isSyncing: true }
  }
  return state
}

ReactDOM.render(
  <AragonApi reducer={reducer}>
    <App />
  </AragonApi>,
  document.getElementById('root')
)

Before using any Hook provided, you need to declare the component AragonApi to connect the app. It is generally a good idea to do it near the top level of your React tree. It should only be declared once. It has an optional reducer prop, which lets you process the state coming from the background script. If not provided, the state is passed as-is.

App root component

Add this code to App.js:

// app/src/App.js
import React from 'react'
import { useAragonApi } from '@aragon/api-react'
import {
  Box,
  Button,
  GU,
  Header,
  IconMinus,
  IconPlus,
  Main,
  SyncIndicator,
  Text,
  textStyle,
} from '@aragon/ui'

function App() {
  const { appState } = useAragonApi()
  const { count, isSyncing } = appState

  return (
    <Main>
      {isSyncing && <SyncIndicator />}
      <Header
        primary="Counter"
        secondary={
          <Text
            css={`
              ${textStyle('title2')}
            `}
          >
            {count}
          </Text>
        }
      />
      <Box
        css={`
          display: flex;
          align-items: center;
          justify-content: center;
          text-align: center;
          height: ${50 * GU}px;
          ${textStyle('title3')};
        `}
      >
        Count: {count}
      </Box>
    </Main>
  )
}

export default App
  • appState: Is the app state, after having passed the background script state through the reducer prop of AragonApi.

  • api: This is the current AragonApp instance. Use it to call methods on the contract.

Sending transactions

Our users need to be able to increment and decrement the counter. For this, we send what is called an intent to the client. An intent is an action you would like to occur on a specific contract. This intent is handled by the client, which will calculate a transaction path using the ACL of our DAO.

To understand transaction paths, we must first understand a little bit about how the ACL works.

However, it's entirely possible that users can not perform actions directly. For example, to increment the counter, we might want a decision-making process, such as a vote. The beauty of aragonOS is that we never need to specify this directly, as this is handled by the ACL.

We simply say that the only one (who) that can perform increments and decrements (what) on our app (where) is the voting app. This is not done at compile-time, it is done at run time.

It's really simple to use. Let's add our intents to our app. Integrate this code into App.js:

// ...

function App() {
  const { api, appState } = useAragonApi()
  const { count, isSyncing } = appState
  const step = 2

  return (
    <Main>
      <Box>
        <div>
          <Button
            display="icon"
            icon={<IconMinus />}
            label="Decrement"
            onClick={() => api.decrement(step).toPromise()}
          />
          <Button
            display="icon"
            icon={<IconPlus />}
            label="Increment"
            onClick={() => api.increment(step).toPromise()}
            css={`
              margin-left: ${2 * GU}px;
            `}
          />
        </div>
      </Box>
    </Main>
  )
}

That's it! Now, whenever the user clicks one of either the increment or decrement buttons, an intent is sent to the wrapper, and it will show the user a transaction to sign.

Writing the manifest files

For aragonAPI to function, it needs some metadata about your app. This metadata is specified in two manifest files; manifest.json and arapp.json.

arapp.json

arapp.json defines the smart contract and aragonPM-specific things like the roles in your app or different environments.

Let's modify arapp.json so that it knows about the roles we defined previously and use the development environment. Add this code to arapp.json:

{
  "roles": [
    {
      "name": "Increment the counter",
      "id": "INCREMENT_ROLE",
      "params": []
    },
    {
      "name": "Decrement the counter",
      "id": "DECREMENT_ROLE",
      "params": []
    }
  ],
  "environments": {
    "default": {
      "network": "rpc",
      "appName": "foo.aragonpm.eth"
    }
  },
  "path": "contracts/CounterApp.sol"
}

The first label in the ENS name is the name of our app. This can be anything you want, given that the full ENS name is not taken.

manifest.json

manifest.json defines end-user specific things like the human-readable name of your app, icons, and a small description of your app. It also (optionally) defines background scripts, of which we have one.

Let's modify it accordingly. Add this code to manifest.json:

{
  "name": "Counter",
  "description": "My first Aragon app",
  "script": "/script.js",
  "start_url": "/index.html"
}

Buidler script hooks

These hooks are called by the Aragon Buidler plugin during the start task's lifecycle. All hooks receive two parameters:

  • Params object that may contain other objects that pertain to the particular hook.

  • A "bre" or BuidlerRuntimeEnvironment object that contains environment objects like web3, Truffle artifacts, etc.

We are going to use the getInitParam hook. Must return an array with the proxy's init parameters.

That is called when the start task needs to know the app proxy's initialized parameters, _initValue for our CounterApp initialize function. Add tis code to buidler-hooks.js:

// scripts/buidler-hooks.js
module.exports = {
  // ...
  getInitParams: async ({}, { web3, artifacts }) => {
    return [15]
  },
  // ...
}

Running your app locally

To test out your app without deploying a DAO yourself, installing apps, setting up permissions and setting up aragonPM, you can simply run:

yarn
yarn start

Please check you have the right compiler version. It is necessary 0.4.24. If not, select the correct one and run npm start again.

If you receive a lot of errors on the console, please be sure to run the right node.js (v12 is required).

This will do a couple of things for you:

  • It will start a development chain you can interact with (it uses ganache-core, so it's a full testrpc instance) and prints 10 accounts.

  • It compiles the contracts.

  • It deploys the aragonOS bases (ENS, DAO factory, aragonPM registry).

  • It deploys an Aragon DAO with apps and development permissions (i.e. everyone can do everything)

  • It builds your app front-end. Since we're importing Node.js modules in our front-end, we need a build script. For this, we opted to use parcel because it has zero-config, but you can use your favorite bundler.

  • It publishes your app to a local aragonPM instance.

  • It installs your app.

  • It initializes the app proxy with the parameter we defined in getInitParams hook.

  • It starts the client locally, installing it if it's not cached.

After running this command a browser tab should pop up with your freshly created DAO, complete with permissions and your local app installed.

At this point feel free to play around. Both front-end and smart contract files have hot reloading. Yes, even smart contract code, we do a proxy swap on every change under the hood 😎, enjoy.

If you've made it this far, congratulations! 😊🎉😊🎉

Stuck?

Next steps

Tests

Publishing

Documentation

Community

Now you just need to share the great news on Twitter and Reddit, to let people know that you've built something great!

: Frontend npm configuration file.

: Aragon configuration file. Includes Aragon-specific metadata for your app.

: Aragon configuration file. Includes web-specific configurations.

: Buidler (now Hardhat) configuration file.

: Main npm configuration file.

If you get stuck at any point come back to check the diff with changes after the tutorial is completed.

If you need help, please reach out to Aragon core contributors and community members in the off our Discord server.

Note We use for uint256. Using SafeMath is a security convention that allows handling math operations with safety checks that revert on error preventing the risk of overflows.

Third, guard the methods with the auth() modifier that the AragonApp interface gives you and add an to your contract; we use initValue as the starting value of the counter. Integrate this code in CounterApp.sol:

That's it. In 3 steps, you now have an Aragon app, with full upgradeability and modular governance. you can double check whether your code is right.

Aragon wants to be as user friendly as possible, so it provides an easy way for developers to describe what their smart contracts do in a human-readable way. It's called It works by putting @notice statements alongside a human-readable description for the function. In our example, we use the input step to describe what is doing our function at runtime.

Because apps inside the are sandboxed, it also means that apps do not have direct access to Web3.

All of this is achieved by using . aragonAPI is split into two parts: one for clients and one for apps. The client portion of aragonAPI reads requests from the app over RPC, sandboxes apps and performs Web3 actions, whereas the app portion provides a simple API to communicate with the client (to read state, send transactions and more).

Thankfully the will run background scripts specified in the manifest files of our app (more on manifest files later).

If you've worked with before, this might look vaguely familiar.

The store method takes in a reducer function with the signature (state, event) => state, where state is whatever you want it to be (in this example it is an integer), and event is a . The reducer function must always return a state, even if it is the same state as before. Returning undefined will reset the reduced state to its initial null state. Also note that the initial state is always null, not undefined, because of JSONRPC limitations.

The store has block caching automatically applied, such that subsequent loads of the application only fetch new events from a cached ("committed") block height (rather than from 0 or the app's initialization block). This state can be observed in the view portion of your app. Also, note that the store method returns an observable of states. This is a recurring theme in the JavaScript implementation of aragonAPI—almost everything is an observable.

Learn more about it on the .

you can double check whether your code is right.

Now let's write the view portion of our app. In our case, this is a simple HTML file, and a simple React app with the useAragonApi that observes the state that our background script builds for us and returns the data needed to interact with the app contract. Add this code to app/index.html:

you can double check whether your code is right.

useAragonApi() is a React Hook that returns the data needed to interact with the app contract. As with any React Hook, please ensure that you follow the . It returns an object containing the following entries:

These are not all the entries but the ones we are going to use in the tutorial. To learn about all of them check the .

Note We are using several components from aragonUI. aragonUI is a React library based on aragonDS, the Aragon design system. It aims to provide the elements needed to build Aragon apps that feel native to the Aragon ecosystem. We are not going into details of aragonUI on this tutorial. If you feel like to learn more, check the .

Theis a simple mapping of who can perform what actions where. In our case, someone can perform an action guarded by a specific role (the what) on our app (the where).

This works because of a concept called . A forwarder is simply an app that can execute transactions on someone's behalf, if the ACL permits it, and that app can have its arbitrary conditions under which it wants to execute your transaction! In the example of the voting app, the voting app will only execute your transaction if the vote passes.

you can double check whether your code is right.

Notice that we input a fully qualified name for appName. Let's examine the ENS name we entered because it is not entirely arbitrary.

The second and third label is the name of the registry that your repository will be (or is) registered to. For the sake of simplicity, this guide assumes that you have rights to create repositories on aragonpm.eth, but you could deploy your aragonPM registry if you so desire.

you can double check whether your code is right.

Login to metamask (if not already logged in), select the and import the (account mnemonic) listed on the console (if not already done). Select the account you want to use.

If you got stuck at any point check back to check whether there's a diff with your code.

If you feel like to keep learning about the Aragon stack right away. A great way of doing it is including some tests on your app. Check the of the react boilerplate repo for ideas.

Now that we're confident that our app will work and amaze the world, we should publish it. You can follow the publishing guide to learn

A good place to go from here would be to check out . They are fairly self-contained and use some patterns you might find helpful.

There is much more to and , and we even have our own . We encourage you to explore all 3 and provide us feedback.

Join the conversation and ask questions on , and Discord channel and make sure to tell us if you build something amazing!

🛠️
here
your first Aragon app template
buidler
package.json
buidler.config.js
package.json
here
#dev-space channel
SafeMath
initialize function
Here
Radspec.
Aragon client
aragonAPI
Aragon client
Redux
Web3 event
RxJS
store() documentation
Here
React Hook
Here
Rules of Hooks
useAragonApi documentation
Getting started guide
ACL (Access Control List)
forwarders
Here
ENS
aragonPM
Here
Localhost 8545 network
12 words seed phrase
here
test examples
how to publish in different environments.
our existing apps
aragonOS
aragonAPI
UI toolkit
GitHub
Aragon Technical Forum
#dTech-general
arapp.json
manifest.json