0xekez / item-dao

simple dao built on juno which manages 'items' composed of titles and bodies
https://item-dao.zmedley.com
1 stars 0 forks source link

Item DAO

A simple DAO for managing 'items'. Items consist of a name and some contents. One might use items to store pages on a website or dictionary definitions for a conlang group.

Item DAO implements the base CW20 spec providing a token called IDAO which is used for voting.

A schema which provides information about the format of messages that can be sent to Item DAO can be generated by running cargo schema and browsing schmea/.

Functionality

An example

Say we want to create an item dao that holds contact information about our group.

First, we instantiate a version of itemdao. Here we use code_id 94 as that is the most recent version of item dao listed below in the "Addresses" section. During the instantiation we'll send some tokens to some of our friends who are part of the DAO. Here's the command:

junod tx wasm instantiate 94 '{"quorum":"100","proposal_cost":"1","token_info":{"name":"Item DAO","symbol":"IDAO","decimals":0,"initial_balances":[{"address":"juno1m7a7nva00p82xr0tssye052r8sxsxvcy2v5qz6","amount":"1000000"},{"address":"juno1754qkhjmpx79swk445zgg5vge2sh33ejzgc28z","amount":"1000000"}]}}' --label 'v0.5' --from ocax101 --chain-id uni --gas auto --fees 5000ujunox

This is a big command. You'll want to replace the --from line with the name of a key you have on your local machine. You'll also want to replace the addresses above with the address of your friends who you would like to send tokens to.

Here's a better look at the initialization message that we're sending to the contract:

{
    "quorum": "100",
    "proposal_cost": "1",
    "token_info": {
        "name": "Item DAO",
        "symbol": "IDAO",
        "decimals": 0,
        "initial_balances": [
            {
                "address": "juno1m7a7nva00p82xr0tssye052r8sxsxvcy2v5qz6",
                "amount": "1000000"
            },
            {
                "address": "juno1754qkhjmpx79swk445zgg5vge2sh33ejzgc28z",
                "amount": "1000000"
            }
        ]
    }
}

As you can see in the initial_balances section we are sending a million tokens to our friends who will be part of the DAO. You need these tokens to vote.

Having instantiated the DAO lets submit a proposal that will add a contact for ourselves. Our proposal will look like this:

{
    "propose": {
        "title": "add zeke to the address book",
        "body": "zeke is a good friend and we should keep their email around",
        "action": {
            "add_item": {
                "name": "zeke",
                "contents": "zekemedley@gmail.com"
            }
        }
    }
}

Our command to submit the proposal will look like this:

junod tx wasm execute juno15ah47zrj2qdcfa3ane6psv0xnylsdjuj3ccxlqprun4ymzsh8kkqzjhxv0 '{"propose":{"title":"add zeke to the address book","body":"zeke is a good friend and we should keep their email around","action":{"add_item":{"name":"zeke","contents":"zekemedley@gmail.com"}}}}' --from ocax101 --output json --yes --fees 6000ujunox --gas auto

Having done that we can query the DAO to see what the status of our proposal is. Because this is the first proposal to be submitted to the DAO it has ID 0.

junod query wasm contract-state smart juno1eu70kcgh0d2rlm0n88dgtry9wpqnerf5n2fdzt5sxm6d3vrqq3xqa5e9x8 '{"get_proposal":{"proposal_id":0}}' --output json | jq

Cool! This will show us output like this:

{
  "data": {
    "title": "add zeke to the address book",
    "body": "zeke is a good friend and we should keep their email around",
    "action": {
      "add_item": {
        "name": "zeke",
        "contents": "zekemedley@gmail.com"
      }
    },
    "status": "Pending",
    "yes": [],
    "no": [],
    "abstain": [],
    "proposer": "juno1754qkhjmpx79swk445zgg5vge2sh33ejzgc28z",
    "proposal_cost": "1"
  }
}

Now lets vote on the proposal. In this case we have enough tokens to pass it ourselves. In a world where your DAO is managed by your friends you'd probably want to set the quorum to be high enough that this is less easy.

junod tx wasm execute juno1eu70kcgh0d2rlm0n88dgtry9wpqnerf5n2fdzt5sxm6d3vrqq3xqa5e9x8 '{"vote":{"proposal_id":0,"position":"yes","amount":"100"}}' --from ocax101 --output json --yes --fees 6000ujunox --gas auto

Now if we query the proposal state again we can see that the proposal has passed!

{
  "data": {
    "title": "add zeke to the address book",
    "body": "zeke is a good friend and we should keep their email around",
    "action": {
      "add_item": {
        "name": "zeke",
        "contents": "zekemedley@gmail.com"
      }
    },
    "status": "Passed",
    "yes": [
      [
        "juno1754qkhjmpx79swk445zgg5vge2sh33ejzgc28z",
        "100"
      ]
    ],
    "no": [],
    "abstain": [],
    "proposer": "juno1754qkhjmpx79swk445zgg5vge2sh33ejzgc28z",
    "proposal_cost": "1"
  }
}

The output of this proposal was a new item. In the yes section we can see that our vote and the amount of tokens we staked was recorded. We can also query the contract to see that new item as follows:

junod query wasm contract-state smart juno1eu70kcgh0d2rlm0n88dgtry9wpqnerf5n2fdzt5sxm6d3vrqq3xqa5e9x8 '{"get_item":{"item_id":0}}' --output json | jq
{
  "data": {
    "name": "zeke",
    "contents": "zekemedley@gmail.com"
  }
}

Finally, we can verify that the tokens that we used to vote were sent back to us when the vote completed by running:

junod query wasm contract-state smart juno1eu70kcgh0d2rlm0n88dgtry9wpqnerf5n2fdzt5sxm6d3vrqq3xqa5e9x8 '{"balance":{"address":"juno1754qkhjmpx79swk445zgg5vge2sh33ejzgc28z"}}'

This is just a sample of the commands avaliable to interact with the DAO. For a complete reference see src/msg.rs

Design

Item DAO was initially designed as two contracts: a CW20 token and a DAO which used that token for voting. After some consideration I opted to implement the CW20 interface inside of the DAO. Doing so meant that there was no longer a need to pay gas fees for the return of tokens to voters after the completion of a proposal.

Item DAO has two parameters: quorum and proposal_cost. The quorum that is set determines how many tokens must be staked to a vote before that vote can pass. The proposal cost determines how many tokens must be staked to create a proposal. Upon the completion of a vote all staked tokens are returned.

Architecture

Addresses

Item DAO is deployed on the uni testnet. The most recent version which completes the DAO is not yet published as I am out of ujunox until the faucet comes back online.

token program: Initial mint of 100,000 tokens. Unmodified cw20-base contract. This is DAO prehistory from when the DAO was two contracts.

dao program v0.1 Does nothing. Just tests that I understand how passing arguments into queries and executions work.

dao program v0.2 Allows creation of proposals and voting on those proposals. All coins sent to contract are burned. Features a bug where enums were not converted to snake case during serialization.

dao program v0.3 Same as v0.2 but with the snake case bug fixed.

dao program v0.4 The DAO now implements the cw20 interface.

dao program v0.5 Deployment pending. Implements all of the functionality described in src/msg.rs.

dao program v0.6 Bugfixes