Skip to content

Aragon Connect 0.5.0

Compare
Choose a tag to compare
@bpierre bpierre released this 29 Jul 18:25
· 95 commits to master since this release
18b5f98

This version introduces a series of changes to the API of Connect, aiming to make it easier to use while reducing the amount of boilerplate.

Contributors for this release: @0xGabi, @ajsantander, @bpierre, @onbjerg, @pengiundev 🎉

Breaking changes 🔨

  • New API to initiate an app connection (see next section).
  • New API to implement app connectors (see next section).
  • The @aragon/connect-thegraph-voting package is now @aragon/connect-voting.
  • The @aragon/connect-thegraph-tokens package is now @aragon/connect-tokens.
  • The chainId option of the connect() function is now network, and accepts a chain ID (e.g. 4), a network name (e.g. "rinkeby"), or a network object.
  • The readProvider option of the connect() function is now ethereum.

New app connectors API 🔌

This version is adding important changes to the way we interact with app connectors.

Before the new API

To illustrate these changes, let’s have a look at how a list of votes could get fetch with Connect 0.4.2:

import connect from '@aragon/connect'
import { Voting } from '@aragon/connect-thegraph-voting'

// Connect to an organization on mainnet via The Graph.
const org = await connect('myorg.aragonid.eth', 'thegraph')

// Get the voting app.
const voting = await org.app('voting')

// Instantiate the Voting class, and pass the URL for mainnet.
const votingConnected = new Voting(
  voting.address,
  'https://api.thegraph.com/subgraphs/name/aragon/aragon-voting-mainnet'
)

// Fetch the votes from the votingConnected object.
const votes = await votingConnected.votes()

The example above contains a few things that we wanted to improve:

  • The network (mainnet here) has to be set again on the app connector. The organization and the app live on the same network, so it shouldn’t be necessary.
  • The app connector is specific to a data source (The Graph here). The main library will eventually include several data sources, and app connectors should follow the same direction.
  • We are dealing with two different objects: voting and votingConnected. They might seem similar but are doing different things: one is an App instance, while the other one is coming from the app connector and allows to fetch data.

With the new API

This is how the same example looks with the new API:

import connect from '@aragon/connect'
import connectVoting from '@aragon/connect-voting'

// Connect to an organization on mainnet via The Graph.
const org = await connect('myorg.aragonid.eth', 'thegraph')

// Get and connect to the voting app.
const voting = await connectVoting(org.app('voting'))

// Fetch the votes from voting.
const votes = await voting.votes()

A few things about this last example:

  • The app connector function knows about the current network (mainnet), there is no need to specifiy the URL for The Graph (but it can be done optionally).
  • The app connector is now universal. You might have noticed that @aragon/connect-thegraph-voting is now @aragon/connect-voting. This is because a connector can now support any number of data sources it wants, and we plan to support the same data sources in @aragon/connect and the core app connectors.
  • We are now only using one object: voting. With this new API, the object returned by the app connector gets extended by App, rather than being separate. It means that the API of App is available on this object.
  • connectVoting() accepts either an App or a promise resolving to an App. This is why we can directly pass org.app('voting') to it.

This new API should make app connectors feel more similar to the connect() function, while keeping the boilerplate and code repetition to a minimum, without compromising on the expressiveness as everything can be configured as before − except it’s optional now.

Usage with React

This is how the example presented above looks like with the React library:

import { createAppHook, useApp } from '@aragon/connect-react'
import connectVoting from '@aragon/connect-voting'

// We start by creating a hook for the app connector.
const useVoting = createAppHook(connectVoting)

function Votes() {
  // We fetch the voting app.
  const [voting] = useApp('voting')

  // And we pass the voting app to the useVoting() hook.
  // The second parameter is a callback that returns the data we want.
  const [votes] = useVoting(voting, app => app.votes())

  return (
    <ul>
      {votes ? (
        votes.map(vote => <li key={vote.id}>{formatVote(vote)}</li>)
      ) : (
        <li>Loading votes…</li>
      )}
    </ul>
  )
}

As you can see, we are using the exact same function, connectVoting, to create a React Hook. This means that authors of app connectors don’t have to do anything specific for their connector to work with @aragon/connect-react.

Note: this doesn’t support subscriptions yet. The next version will enable subscriptions using the exact same syntax as above.

Authoring app connectors with the new API

This is how an app connector can get implemented in the simplest way:

import { createAppConnector } from '@aragon/connect-core'

export default createAppConnector(() => ({
  total: () => fetchTotal(),
}))

The createAppConnector() utility takes care of doing the necessary checks, and passing contextual information to the callback.

This is how the connector for the Voting app is implemented using createAppConnector():

import { createAppConnector } from '@aragon/connect-core'
import Voting from './entities/Voting'
import VotingConnectorTheGraph, {
  subgraphUrlFromChainId,
} from './thegraph/connector'

export default createAppConnector(
  ({ app, config, connector, network, verbose }) => {
    if (connector !== 'thegraph') {
      console.warn(
        `Connector unsupported: ${connector}. Using "thegraph" instead.`
      )
    }

    return new MyAppConnector(
      new VotingConnectorTheGraph(
        config.subgraphUrl ?? subgraphUrlFromChainId(network.chainId),
        verbose
      ),
      app.address
    )
  }
)

Pull request

  • connectApp() (#135)

New app connector: Finance 📊

A new app connector has been added, for the Finance app. It uses the new connector API, and you can use it this way:

const org = await connect(env.location, 'thegraph')
const finance = await connectFinance(org.app('finance'))
const transactions = await finance.transactions()

Pull requests

  • Finance connector + subgraph (#149)
  • Finance docs + review (#168)

ES modules exports 📦

Every Connect package is now exported in two formats: CommonJS and standard ES Modules, rather than CommonJS only. Your preferred bundler should detect the most appropriate format, or you should be able to configure it to choose either the main or module field from the package.json file. Nothing will change for Node.js apps, as the CommonJS export is still going to get imported by Node.

If you are using a tool like SnowPack, the integration with Connect will be much better from now on.

Pull request

  • Add ESM exports (#162)

New examples 📬

A few more examples have been added.

Karma template organization deployment

This script demonstrates how to deploy an organization using the Karma template. It doesn’t use Connect yet, but it will be updated when the possibility to deploy an organization from Connect will get added.

Minimal Setup

This example demonstrates the absolute minimum required to build a React app using Connect. Here we are using Parcel to bundle it, and nothing more.

List Votes (CLI + React)

These two examples demonstrate how the new API to connect apps can get used from Node.js or a React app.

Pull requests

  • Examples: Karma template organization (#152)
  • Examples: add minimal setup (#161)
  • connectApp() (#135)

Other changes 📝

  • connect() now accepts actAs as an option (#135)
  • connect() now accepts verbose as an option (#135)
  • The ipfs option of connect() now also accepts an URL template, containing {cid} and {path}.
  • Documentation tweaks (#134)
  • Handle stranger cases in TokenManager (#130)
  • Types: remove some non-null assertion operators (!) (#128)
  • Types: add SubscriptionHandler, Address (#136)
  • Rename ConnectorInterface to IOrganizationConnector (#137)
  • Connectors: make it possible to close the connection (#140)
  • Examples: connect-react-intro: move to SnowPack (#160, #163)
  • Add GRAPHKEY to the deploy scripts and documentation (#145)
  • Subgraph: deployment data of Tokens and Voting on xDai (#155)
  • Add app installation count to Repo entity (#150)
  • Fix: ethers overloads (#158)
  • Connectors: Use official aragon subgraphs url (#167)