DAOstack Arc.js sits just above DAOstack Arc on the DAO stack. It is a library that facilitates javascript application access to the DAOstack Arc ethereum smart contracts.
For more information about Arc contracts and the entire DAOstack ecosystem, please refer to the Arc documentation.
- Getting Started
- Working with DAOs
- Create a new DAO with all defaults
- Create a new DAO with founders
- Create a new DAO with schemes
- Create a new DAO overriding the default voting machine
- Create a new DAO with a non-Universal Controller
- Create a new DAO with a non-default DaoCreator scheme
- Get a previously-created DAO
- Get the DAOstack Genesis DAO
- Using the Arc Contracts
- Working with Arc.js Scripts
- Deploying to Other Testnets
- Running Against a Ganache Database
- Run Lint and Tests
- Contribute to Arc.js
- Security
- License
Ensure that NodeJS, v9.4.0 or greater, is installed.
Install the npm package into your project:
npm install @daostack/arc.js --save
Now you can proceed with migrating contracts to a running testnet and configuring Arc.js in your application and environment.
Arc.js runs against an Ethereum network where it assumes that the Arc contracts have been migrated. Out of the box, Arc.js can find contracts migrated to the mainnet. But for testing, you will need to tell it to migrate the Arc contracts to a testnet of your choice. You can do this by running a few Arc.js scripts.
First a note: The following script examples assume you are running the scripts in the root folder of your application. If you happen to be running the scripts in the context of a cloned Arc.js repository, omit the prefix npm explore @daostack/arc.js --
.
To deploy contracts to a Ganache testnet, run the following scripts:
In a separate shell window:
npm explore @daostack/arc.js -- npm start test.ganache.run
If you are running the migration for the first time:
npm explore @daostack/arc.js -- npm start migrateContracts.fetchFromArc
Now migrate the Arc contracts to Ganache:
npm explore @daostack/arc.js -- npm start migrateContracts
Now when your app uses Arc.js, it will be running against Ganache and the contracts you just migrated.
For more on Arc.js scripts, see Working with Arc.js Scripts.
See Deploying to Other Testnets if you want to run against a testnet other-than Ganache.
Import everything from ArcJs as follows:
import * as ArcJs from '@daostack/arc.js';
The default configuration settings for Arc.js can be found in its config/default.json
file. A few examples:
{
"providerUrl": "http://127.0.0.0",
"providerPort": 8545,
"network": "ganache",
"gasLimit_runtime": 6015000
}
To obtain a configuration setting:
import { Config } from '@daostack/arc.js';
Config.get('network');
To override a configuration setting at runtime:
import { Config } from '@daostack/arc.js';
Config.set('network', 'kovan');
You can also override the default configuration settings by setting values on properties of node.env
(see here) with the same name as the corresponding arc.js configuration setting. This enables you to use environment variables to control the arc.js configuration.
Now that you've got Arc.js plugged into your application and configured, and contracts migrated to a running testnet, you are ready to start coding against DAOs and Arc contracts. The following sections describe how.
One thing to remember: All token and reputation amounts should be expressed in Wei.
Arc.js provides a class named "DAO" that enables you to create new DAOs and obtain information about them.
The simplest example of how to create a new DAO uses all defaults: no schemes nor founders, using the Universal Controller and default DaoCreator scheme. See NewDaoConfig
.
const newDao = await DAO.new({
name: "My New DAO",
tokenName: "My new Token",
tokenSymbol: "MNT"
});
Add and remove schemes later using SchemeRegistrar
.
Create a new DAO with founders by including a "founders" array. This will automatically mint tokens and reputation to each founder. See NewDaoConfig
.
const newDao = await DAO.new({
name: "My New DAO",
tokenName: "My new Token",
tokenSymbol: "MNT",
founders: [
{
// the current user
address: accounts[0],
reputation: web3.toWei(1000),
tokens: web3.toWei(40)
},
{
address: anyAddress,
reputation: web3.toWei(1000),
tokens: web3.toWei(40)
},
{
address: anyAddress,
reputation: web3.toWei(1000),
tokens: web3.toWei(40)
}
]
});
Create a new DAO with schemes by including a "schemes" array. This will register the schemes with all default permissions and voting machines. See SchemesConfig
and SchemeConfig
.
const newDao = await DAO.new({
name: "My New DAO",
tokenName: "My new Token",
tokenSymbol: "MNT",
schemes: [
{ name: "SchemeRegistrar" },
{ name: "UpgradeScheme" },
{ name: "GlobalConstraintRegistrar" }
]
});
By default, DAO.new
assigns the AbsoluteVote voting machine to each scheme, with default parameter values for AbsoluteVote. You may override the voting machine's default parameters by adding a "votingMachineParams" element, either at the root level or on individual schemes. You can also specify that you want to assign a completely different type of voting machine, such as GenesisProtocol. See NewDaoVotingMachineConfig
and SchemesConfig
.
const newDao = await DAO.new({
name: "My New DAO",
tokenName: "My new Token",
tokenSymbol: "MNT",
votingMachineParams: {
votePerc: 45,
ownerVote:false
}
});
const newDao = await DAO.new({
name: "My New DAO",
tokenName: "My new Token",
tokenSymbol: "MNT",
votingMachineParams: {
votePerc: 45,
ownerVote:false
votingMachineAddress: anAddress
}
});
This will tell DAO.new
to assign the Arc.js-deployed GenesisProtocol voting machine to every scheme, using default GenesisProtocol parameters.
const newDao = await DAO.new({
name: "My New DAO",
tokenName: "My new Token",
tokenSymbol: "MNT",
votingMachineParams: {
votingMachineName: "GenesisProtocol"
}
});
Important note: If you want to use GenesisProtocol on any scheme, you must also add GenesisProtocol as scheme on the DAO itself (see Create a new DAO with schemes).
const newDao = await DAO.new({
name: "My New DAO",
tokenName: "My new Token",
tokenSymbol: "MNT",
schemes: [
{ name: "SchemeRegistrar" },
{ name: "UpgradeScheme" },
{
name: "GlobalConstraintRegistrar",
votingMachineParams: {
votePerc: 30,
}
}
]
});
Create a DAO using the DAOstack Controller
contract by passing false
for universalController
.
For more information about choosing between Universal an Single Controller, see this article.
const newDao = await DAO.new({
name: "My New DAO",
tokenName: "My new Token",
tokenSymbol: "MNT",
universalController: false
});
Create a DAO using an alternative DaoCreator
scheme by passing its address for daoCreatorScheme
. The alternative scheme must implement the same interface as the Arc DaoCreator
contract.
const newDao = await DAO.new({
name: "My New DAO",
tokenName: "My new Token",
tokenSymbol: "MNT",
daoCreatorScheme: anAddress
});
Get a previously-created DAO using the avatar address:
const dao = await DAO.at(daoAvatarAddress);
The DAOstack DAO is named "Genesis". Obtain it like this:
const genesisDao = await DAO.getGenesisDao();
Arc.js wraps every Arc contract in a JavaScript "wrapper" class. Every wrapper class inherits from ExtendTruffleContract
which provides a common set of functions in addition to all of the functions implemented by the specific Arc contract being wrapped.
Arc contracts and associated Arc.js contract wrapper classes can be categorized as follows:
- SchemeRegistrar
- UpgradeScheme
- GlobalConstraintRegistrar
- ContributionReward
- VoteInOrganizationScheme
- VestingScheme
- GenesisProtocol
- AbsoluteVote
- GenesisProtocol
- TokenCapGC
- DaoCreator
You can pull those categorizations into your code as follows:
import * as ArcJs from '@daostack/arc.js';
const arcJsWrapperCategories = await ArcJs.Contracts.getDeployedContracts();
You may find that getDeployedContracts()
is somewhat time-consuming to run the first time because it fetches all of the wrappers from the chain, but it does cache its results and run much faster thereafter.
getDeployedContracts()
returns a object that contains a wrapper factory and address of each deployed contract that has a wrapper, keyed by the contract name
. See ArcDeployedContracts
.
The following sections show how you can obtain contract wrappers using factories, names and addresses.
You may obtain the names and addresses of all of the schemes that are registered with a DAO using DAO.getSchemes
:
const daoSchemeInfos = await myDao.getSchemes();
Or info about a single scheme:
const daoSchemeInfos = = await myDao.getSchemes("UpgradeScheme");
const upgradeSchemeInfo = daoSchemeInfos[0];
DAO.getSchemes
returns a object that contains name
and address
properties. See DaoSchemeInfo
.
The following sections show how you can get contract wrappers using names and addresses.
Recall from Categories of Arc Contracts that getDeployedContracts()
returns categorized factories, names and addresses of Arc contracts that have wrappers. That information can be used to obtain the wrappers themselves.
import * as ArcJs from '@daostack/arc.js';
const upgradeScheme = await ArcJs.Contracts.getContractWrapper("UpgradeScheme");
import * as ArcJs from '@daostack/arc.js';
const upgradeScheme = await ArcJs.Contracts.getContractWrapper("UpgradeScheme", anAddress);
The identical method is available on the DAO class:
const upgradeScheme = await DAO.getContractWrapper("UpgradeScheme");
Each wrapper has a factory that provides static .new()
, .deployed()
and .at()
methods. These methods are implemented by ContractWrapperFactory
.
Examples of their use:
Obtain the instance of the contract as deployed by Arc.js:
import { UpgradeScheme } from "@daostack/arc.js";
const deployedContract = await UpgradeScheme.deployed();
Call new()
to migrate a new instance of the contract:
import { UpgradeScheme } from "@daostack/arc.js";
const newInstance = await UpgradeScheme.new();
Obtain the wrapper from a given address:
import { UpgradeScheme } from "@daostack/arc.js";
const newInstance = await UpgradeScheme.at(anAddress);
Not all Arc contracts have been given wrapper classes, for example, Avatar
, UController
and many more. But you can obtain a raw TruffleContract for any contract, enabling you to work with the contract:
import { Utils } from "@daostack/arc.js";
const truffleContract = await Utils.requireContract("Avatar");
Although you can always register your own schemes with a DAO, whether they be totally custom non-Arc schemes, or redeployed Arc schemes, by default a DAO is created with Arc schemes that are universal in the sense that the code is implemented in one place, without redundancy. But every scheme registered with a DAO is configured with its own DAO-scoped parameter values, and references DAO-scoped data, such as proposals. All are stored in the DAO's controller where each universal scheme is able to find them. (If the controller is the Universal Controller then the parameters and data are keyed by the DAO's avatar address.)
If you want to obtain a DAO scheme's parameters, you can do it like this:
const schemeParameters = schemeWrapper.getSchemeParameters(avatarAddress);
This will return an object containing the scheme's parameter values. The object will be the same as that which one passes to schemeWrapper.setParameters
when setting parameters on any contract.
For example, to obtain the voting machine address for a scheme that has one as a parameter:
const schemeParameters = schemeWrapper.getSchemeParameters(avatarAddress);
const votingMachineAddress = schemeParameters.votingMachineAddress;
Arc.js contains a set of scripts for building, publishing, running tests and migrating contracts to any network. These scripts are meant to be accessible and readily usable by client applications.
Typically an application will run an Arc.js script by prefixing "npm explore @daostack/arc.js --
" to the Arc.js script. For example, to run the Arc.js script npm start test.ganache.run
from your application, you would run:
npm explore @daostack/arc.js -- npm start test.ganache.run
Otherwise, when running the scripts at the root of Arc.js, you must omit the npm explore @daostack/arc.js --
.
All of the scripts are defined in the package-scripts.js file. You have already seen their most typical use in an application context.
See also Running Against a Ganache Database, Deploying to Other Testnets and Run Lint and Tests
Please refer here for instructions on migrating contracts to other test networks.
It can be very handy to run Arc.js tests or your application against a Ganache database that persists the state of the chain across instances of Ganache. Please refer here for how to do it.
To run lint and the Arc.js tests, run the following script in the Arc.js root folder, assuming you have already installed all the npm packages, are running a testnet with migrated Arc contracts:
npm test
npm start test.bail
Sometimes you want to run just a single test module:
npm start "test.automated test/[filename]"
To bail:
npm start "test.automated test/[filename] --bail"
PRs are welcome but please first consult with the Contribution guide.
Join us on Slack!
Join us on Telegram!
DAOstack Arc.js is still on its alpha version. It is meant to provide secure, tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problem you might experience.
This is an open source project (GPL license).