DAO JS Example

Cordite has the concept of DAOs. There is a Cordite Foundation DAO, called the committee. You can also create your own DAOs, either by using the DaoService or by extending this code for your own purposes (in which case please contribute your awesome changes back to Cordite).

By this stage you know how to connect using the CLI or the Braid JS Client so follow along with your chosen client.

This page explains how to:

  • create your own DAO
  • other people can request membership
  • create proposals
  • vote for proposals
  • accept proposals

The full code can be found here

Connecting to two cordite nodes

DAOs don’t make sense unless you have a few Parties that want to be part of the DAO. In this case we are going to work with two parties; the EMEA and AMER nodes on the Test network. This introduces some slight complexity over and above the Braid JS Client tutorial because we need to wait for two braid proxies to connect before we can start. There are many ways of solving this, one of which is shown below:

const Proxy = require('braid-client').Proxy;

// set up using test network
let emeaAddress = "https://emea-test.cordite.foundation:8080/api/"
let amerAddress = "https://amer-test.cordite.foundation:8080/api/"

const emea = new Proxy({url: emeaAddress}, onOpenEmea, onClose, onError, {strictSSL: false})
var amer

function onOpenEmea() {
    console.log("connected to emea.  connecting to amer...")
    amer = new Proxy({url: amerAddress}, onBothReady, onClose, onError, {strictSSL: false})
}

function onBothReady() {
    console.log("also connected to amer...starting test")
}

function onClose() {
    console.log("closed")
}

function onError(err) {
    console.error(err)
}

With this we will be adding most of our code to the onBothReady method.

Create your own DAO

First, let’s create a new DAO - you need to give this a unique name (atleast for the node you’re running on). For the purposes of this walkthrough we will call our DAO “My Dapp Dao”. Its purpose is to gather together some interested parties to fund, build and then later run a decentralised app that several people want to build together.

Note this assumes you have two js apps connected to the emea and amer nodes in the cordite test network.

let saltedDaoName = 'testDao-'+new Date().getTime()
var daoKey
let meteringNotaryName = "O=Cordite Metering Notary, OU=Cordite Foundation, L=London,C=GB"

function onBothReady() {
    console.log("also connected to amer...starting test")

    emea.dao.createDao(saltedDaoName, meteringNotaryName).then(daoState => {
        daoKey = daoState.daoKey
        console.log("emea created dao with name",saltedDaoName,"and key",daoKey)

    }).catch(error => {
        console.error(error)
    })
}

Amer joins the DAO

Next, the amer party would like to join the DAO. So it needs to get the sponsoring node (in this case the only existing DAO member is emea, so we use this) and the daoName.

In this case, the proposer implicitly supports the new member so there are already enough supporters to propose acceptance of the proposal so we will do that here. If there were more DAO members we would have garner more support before proposing acceptance.

var emeaParty
let emeaNodeName = "OU=Cordite Foundation, O=Cordite EMEA, L=London, C=GB"

function onBothReady() {
    console.log("also connected to amer...starting test")

    emea.dao.createDao(saltedDaoName, meteringNotaryName).then(daoState => {
        daoKey = daoState.daoKey
        console.log("emea created dao with name",saltedDaoName,"and key",daoKey)
        return amer.network.getNodeByLegalName(emeaNodeName)
    }).then(emeaNode => {
        emeaParty = emeaNode.legalIdentities[0]
        console.log("amer asking to join dao")
        return amer.dao.createNewMemberProposal(saltedDaoName, emeaParty)
    }).then(proposalState => {
        console.log("proposalKey:",proposalState.proposal.proposalKey)
        console.log("both members already support so we can just propose acceptance")
        return amer.dao.acceptNewMemberProposal(proposalState.proposal.proposalKey, emeaParty)
    }).then(proposal => {
        console.log("proposal state now:", proposal.lifecycleState)
        console.log("dao members now", proposal.members.map(x => x.name).join())
    }).catch(error => {
        console.error(error)
    })
}

Amer proposes change to voting rules

Finally, the amer node would like to propose making a small change to the voting rules. So it must:

  • create a new proposal
  • talk the emea node into voting for it
  • propose acceptance of the proposal

The full code is now:

const Proxy = require('braid-client').Proxy;

// set up using test network
let emeaAddress = "https://emea-test.cordite.foundation:8080/api/"
let amerAddress = "https://amer-test.cordite.foundation:8080/api/"

const emea = new Proxy({url: emeaAddress}, onOpenEmea, onClose, onError, {strictSSL: false})
var amer

let saltedDaoName = 'testDao-'+new Date().getTime()
let meteringNotaryName = "O=Cordite Metering Notary, OU=Cordite Foundation, L=London,C=GB"
let emeaNodeName = "OU=Cordite Foundation, O=Cordite EMEA, L=London, C=GB"

var daoKey
var emeaParty
var normalProposalKey

function onOpenEmea() {
    console.log("connected to emea.  conneting to amer...")
    amer = new Proxy({url: amerAddress}, onBothReady, onClose, onError, {strictSSL: false})
}

function onBothReady() {
    console.log("also connected to amer...starting test")

    emea.dao.createDao(saltedDaoName, meteringNotaryName).then(daoState => {
        daoKey = daoState.daoKey
        console.log("emea created dao with name",saltedDaoName,"and key",daoKey)
        return amer.network.getNodeByLegalName(emeaNodeName)
    }).then(emeaNode => {
        emeaParty = emeaNode.legalIdentities[0]
        console.log("amer asking to join dao")
        return amer.dao.createNewMemberProposal(saltedDaoName, emeaParty)
    }).then(proposalState => {
        console.log("proposalKey:",proposalState.proposal.proposalKey)
        console.log("both members already support so we can just propose acceptance")
        return amer.dao.acceptNewMemberProposal(proposalState.proposal.proposalKey, emeaParty)
    }).then(proposal => {
        console.log("proposal state now:", proposal.lifecycleState)
        console.log("dao members now", proposal.members.map(x => x.name).join())
        console.log("now amer proposes to change the membership rules")
        return amer.dao.createProposal("change voting percentage","change the voting percentage of people needed to accept", daoKey)
    }).then(normProposalState => {
        normalProposalKey = normProposalState.proposal.proposalKey
        console.log("new proposal created with key",normalProposalKey)
        console.log("emea decides to support proposal")
        return emea.dao.voteForProposal(normalProposalKey)
    }).then(votedProposalState => {
        console.log("should be two supporters now", votedProposalState.supporters.length)
        console.log("amer proposes to accept")
        return amer.dao.acceptProposal(normalProposalKey)
    }).then(acceptedProposal => {
        console.log("should be accepted",acceptedProposal.lifecycleState)
        console.log("and we are done :-)")
}).catch(error => {
        console.error(error)
    })
}

function onClose() {
    console.log("closed")
}

function onError(err) {
    console.error(err)
}