DAO Database - HausDAO/daohaus-monorepo-deprecated GitHub Wiki

Overview

Specification for a ridiculously simple DAO managed database utilizing Poster contracts and the daohaus v3 subgraph.

Features

1. Enable DAOs to own metadata

  • stored in contract events and the daohaus subgraph and esily queried with other dao data
  • only updated by DAO members
    • validations levels: loot holder, share holder, ratified by proposal

2. Flexible and extendable db tables and fields

  • this spec will define the schema for basic DAO profile metadata

3. Store a history of data updates

Specification

Writing data

Writing DAO data will be done through the post function in the poster contract on that DAOs network. Poster has been deployed at 0x000000000000cd17345801aa8147b8D3950260FF on most networks.

contract Poster {

    event NewPost(address indexed user, string content, string indexed tag);

    function post(string calldata content, string calldata tag) public {
        emit NewPost(msg.sender, content, tag);
    }
}

post function arguments

string calldata content

Json string with relevant key/values for the type of record.

DAO profile record:

{
    "dao": "0x0",
    "name": "kovan cco v2",
    "description": "tester",
    "longDescription": "some long description",
    "purpose": "Products",
    "avatarImg": {
        content: "QmWLh8vCksEhmPQsyS6BgXtytkBAmtoJ68qpiTuJx47u22",
        contentType: 'ipfs'
    },
    "links": {
        "website": "",
        "twitter": "",
        "discord": "https://discord.gg/V4M4h5EX",
        "telegram": "",
        "medium": "",
        "other": ""
    },
    "tags": ['some', 'tags'],
}
  • 'dao' is a required field on all posts and will be used for lookup in the subgraph mappings
  • all fields will be interpreted as strings unless indicated as an object with contentType
    • ie) avatarImg should be a ipfs hash
  • future types could include markdown, encoded hash, arweave hash

string calldata tag

String using dot notation that will aid subgraph indexing and parsing. These are emitted as indexed params so they are not human readable in events and subgraph mappings.

Format: <app: daohaus>.<pemission level>.<target table>

Permission levels:

- member: share or loot holder
- shares: share holder
- loot: loot holder
- proposal: post must be done in the execution action of a passed proposal 

We will only have one target table at alpha stage used for DAO profile.

DAO profile record tag: daohaus.shares.daoProfile

Indexing data

The daohaus v3 subgraph will subscribe the the NewPost event and map valid data into Record entities.

type Record @entity {
  id: ID!
  createdAt: String!
  createdBy: Bytes!
  dao: Dao!
  tag: Bytes!
  table: String!
  contentType: String!
  content: String!
}
validation
  • only defined tags will be indexed
  • permission level validation performed in the mapping based on permission level in tag
    • mapping will lookup share/loot holders or ensure the msg.sender is the daos safe address
  • validate content string is json and has a dao property with a valid dao address
mapping
  • ID: block timestamp + log index
  • createdAt: block timestamp
  • createdBy: msg.sender (event.params.address)
  • dao: dao address (parsed from json and validated)
  • tag: event.params.tag
  • table: String (derived form tag)
  • contentType:will always be json for these alpha records, but adding for future flexibility)
  • content: json from post - event.params.content

Reading data

Record entities can be looked up by dao address + table. Sorting by the createdAt field, descending will return the most recent snapshot of the table's data.

example:

{
    records(
        where: {dao: '0x0', table: 'daoProfile'}
        first: 1
        orderBy: createdAt
        orderDirection: desc
      ) 
     {id, content, table}
 }

Reference

Poster Constract Spec

Notes and v2 thoughts