Skip to main content

Decentralized Autonomous Organizations

Decentralized Autonomous Organizations (DAOs) are self-organized groups that form around common purposes. Membership, decision-making, and funding are coordinated by publicly voting on proposals through a smart contract.

dao

In contrast with FT and NFT, DAO contract's are not standardized. Because of this, on this page we will use as reference the Astra dao contract. The main concepts covered here should easily generalizable to other DAO implementations.


Create a DAO

The simplest way to create and interact with a DAO is to go through the AstraDAO UI.

Using Sputnik DAO Contract

You can also create a DAO by interacting with the sputnik-dao contract.

import { Wallet } from './near-wallet';

const DAO_FACTORY_CONTRACT_ADDRESS = 'sputnik-dao.near';
const wallet = new Wallet({ createAccessKeyFor: DAO_FACTORY_CONTRACT_ADDRESS });

await wallet.callMethod({
method: 'create',
args: {
name: 'primitives',
args: btoa({
config: {
name: 'Primitives',
purpose: 'Building primitives on NEAR',
metadata: '',
},
policy: ['bob.near'],
}),
},
contractId: DAO_FACTORY_CONTRACT_ADDRESS,
gas: 300000000000000,
deposit: 6000000000000000000000000,
});
note

The full list of roles and permissions you can find here.

The Wallet object comes from our quickstart template


Using Global Contract

You can find out what global contracts are here. But in short, global contracts allow smart contracts to be deployed once and reused by any account without incurring high storage costs.

In other words, you can deploy a DAO contract using our global DAO contract, which is already deployed and basically is just a Sputnik DAO contract without any customization. You need only to call the following deploying command with your initialization parameters.

Deploy by account id:

near contract deploy <account-id> use-global-account-id dao.globals.primitives.testnet \
with-init-call new \
json-args '{"config": {"name": "Primitives", "purpose": "Building primitives on NEAR", "metadata":""}, "policy": ["<account-id>"]}' \
prepaid-gas '100.0 Tgas' \
attached-deposit '0 NEAR' \
network-config testnet \
sign-with-keychain \
send

Deploy by hash:

near contract deploy <account-id> use-global-hash Ea8tHXFSQVszVwGASyzAfLq65DjcRDhkfab4FcPaRpgD \
with-init-call new \
json-args '{"config": {"name": "Primitives", "purpose": "Building primitives on NEAR", "metadata":""}, "policy": ["<account-id>"]}' \
prepaid-gas '100.0 Tgas' \
attached-deposit '0 NEAR' \
network-config testnet \
sign-with-keychain \
send
note

The difference between global contracts deployed by account id and by hash is that the former is updatable, while the latter is immutable. When it's deployed by account id, the owner can redeploy the contract updating it for all its users.

So when you decide which option to use for deploying your DAO contract, you should consider whether you want to it to be updatable by its original owner or not.


Voting policy

Currently, DAOs support two different types of voting policies: TokenWeight, and RoleWeight.

When the vote policy is TokenWeight, the council votes using tokens. The weigh of a vote is the proportion of tokens used for voting over the token's total supply.

When the vote policy is RoleWeight(role), the vote weigh is computed as "one over the total number of people with the role".

Details

Voting Threshold Both voting policies further include a threshold for passing a proposal, which can be a ratio or a fixed number.

The ratio indicates that you need a proportion of people/tokens to approve the proposal (e.g. half the people need to vote, and to vote positively). A fixed number indicated that you need a specific number of votes/tokens to pass the proposal (e.g. 3 people/tokens are enough to approve the proposal).


List of DAOs

Query the list of DAOs existing in Sputnik Dao.

import { Wallet } from './near-wallet';

const DAO_FACTORY_CONTRACT_ADDRESS = 'sputnik-dao.near';
const wallet = new Wallet({ createAccessKeyFor: DAO_FACTORY_CONTRACT_ADDRESS });

await wallet.viewMethod({
method: 'get_dao_list',
args: {},
contractId: DAO_FACTORY_CONTRACT_ADDRESS,
});

The Wallet object comes from our quickstart template


Query Existing Proposals

These snippets will enable you to query the proposals existing in a particular DAO.

import { Wallet } from './near-wallet';

const DAO_CONTRACT_ADDRESS = 'nearweek-news-contribution.sputnik-dao.near';
const wallet = new Wallet({ createAccessKeyFor: DAO_CONTRACT_ADDRESS });

await wallet.viewMethod({
method: 'get_proposals',
args: { from_index: 9262, limit: 2 },
contractId: DAO_CONTRACT_ADDRESS,
});

The Wallet object comes from our quickstart template


Create proposal

Create a proposal so other users can vote in favor or against it.

import { Wallet } from './near-wallet';

const DAO_CONTRACT_ADDRESS = 'primitives.sputnik-dao.near';
const wallet = new Wallet({ createAccessKeyFor: DAO_CONTRACT_ADDRESS });

await wallet.callMethod({
method: 'add_proposal',
args: {
proposal: {
description: 'My first proposal',
kind: {
Transfer: {
token_id: '',
receiver_id: 'bob.near',
amount: '10000000000000000000000000',
},
},
},
},
contractId: DAO_CONTRACT_ADDRESS,
gas: 300000000000000,
deposit: 100000000000000000000000,
});

The Wallet object comes from our quickstart template

info

By default, only council members can create proposals.


Vote for proposal

These snippet will enable your users to cast a vote for proposal of a particular DAO.

import { Wallet } from './near-wallet';

const DAO_CONTRACT_ADDRESS = 'primitives.sputnik-dao.near';
const wallet = new Wallet({ createAccessKeyFor: DAO_CONTRACT_ADDRESS });

await wallet.callMethod({
method: 'act_proposal',
args: { id: 0, action: 'VoteApprove' },
contractId: DAO_CONTRACT_ADDRESS,
gas: 300000000000000,
});
note

Available vote options: VoteApprove, VoteReject, VoteRemove.

The Wallet object comes from our quickstart template


Additional Resources

  1. NEAR Treasury - a Treasury management web app built on top of the Sputnik DAO Contract. Allows users to create and manage treasury funds with ease.
  2. List of DAOs as a NEAR component