title: DAO demo architecture
This document outlines a simple demo to showcase the smart contract schema underlying the initial DAO MVP. We have tried to mimic the basic DarkFi architecture while remaining as simple as possible.
We do not have a blockchain, p2p network, or encrypted wallet database in this highly simplified demo. It is just a local network of 4 nodes and a relayer. The values are all stored in memory.
bin Located in darkfi/bin/dao.
client.src Located in darkfi/bin/dao/daod.
node
A dao node containing client and wallet submodules.
proof Located in darkfi/bin/dao/proof. Contains the zk proofs.
The following assumes that a user has already compiled the zk contracts
by running make.
This requires a Makescript as follows:
ZK_SRC_FILES := $(wildcard proof/*.zk)
ZK_BIN_FILES := $(patsubst proof/%.zk, proof/%.zk.bin, $(ZK_SRC_FILES))
daod: $(ZK_BIN_FILES)
cargo run --release
proof/%.zk.bin: proof/%.zk
zkas $<
We will also need to write a shell script that opens 9 terminals and runs the following:
Terminal 1: relayerd. Terminal 2-5: 4 instances of daod. Terminal 6-9: 4 instances of dao-cli.
Relayerd and daod should be sent to the background, so the demo will consist visually of 4 terminals running dao-cli.
relayerd starts a listener for all TCP ports specified in config.Note: this happens automatically on daod first run.
daod: starts a listener on the relayer TCP port.daod: creates a client and calls client.init().client: creates a money wallet.money-wallet: generates cashier, faucet keys.client: gets public keys from wallet and calls state.new().state: creates ZkContractTable, StateRegistry.state: loads all zk binaries and saves them in ZkContractTable.state: creates a new money/dao state and registers them in StateRegistry.dao-cli: sends create() rpc request to daod.daod: receives rpc request and calls client.create().client: creates a dao wallet.dao-wallet: specifies the dao params.dao-wallet: creates a dao keypair, bulla blind, and signature secret.build sequence.
Note: Builders differ according to the FuncCall, but the basic sequence is the same.
dao-wallet: build: creates dao_contract::mint::wallet::Builder.dao-wallet: generates a FuncCall from builder.build().dao-wallet: adds FuncCall to a vector.dao-wallet: sign the vector of FuncCalls.send sequence.
dao-wallet: create a Transaction.dao-wallet: send the Transaction to the relayer.relayer: receives a Transaction on one of its connections.relayer: relays the Transaction to all connected nodes.recv sequence.
daod: receives a Transaction on its relayerd listener.validate sequence.
client: validate: creates an empty vector of updates.client: loops through all FuncCalls in the Transaction.client: runs a match statement on the FUNC_ID.client: finds mint FUNC_ID and runs a state transition function.client: pushes the result to Vec
client: outside the loop, atomically applies all updates.client: calls zk_verify() on the Transaction.client: verifies signatures.client: sends Transaction to the relayer.relayer: receives Transaction and relays.dao-wallet: waits until Transction is confirmed. (how?)dao-wallet: look up the dao state and call witness().dao-wallet: get the dao bulla from the Transaction.dao-cli: print "Created DAO {}".Here we are creating a treasury token and sending it to the DAO.
dao-cli: fund() rpc request to daoddaod: receives rpc request and calls client.fund().client: creates treasury token, random token ID and supplyNote: dao-wallet must manually track coins to retrieve coins belonging to its private key.
dao-wallet: looks up the money state, and calls state.wallet_cache.track()
money-wallet: sets spend hook to dao_contract::exec::FUNC_ID
money-wallet: sets user_data to dao_bulla
money-wallet: specifies dao public key and treasury token BuilderOutputInfo.money-wallet: runs the build sequence for money::transfer.money-wallet: create Transaction and send.relayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.Note: here we get all coins associated with the private key.
dao-wallet: looks up the state and calls WalletCache.get_received()dao-wallet: check the coin is valid by recreating Coindaod: sendswith token ID and balance to dao-cli.dao-cli: displays data using pretty table.dao-cli: calls keygen()daod: client.keygen()daod: money-wallet.keygen()money-wallet: creates new keypairmoney-wallet: looks up the money_contract State and calls WalletCache.track()money-wallet: return the public keydao-cli: prints the public keyNote: do this 3 times to generate 3 pubkey keys for different daod instances.
dao-cli: calls mint()daod: call client.mint()client: creates governance token with random token ID and supplydao-cli: prints "created token {} with supply {}"dao-cli: calls airdrop() and passes a value and a pubkey.dao-wallet: runs the build sequence for money::transfer.dao-wallet: create Transaction and send.relayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.money-wallet: state.wallet_cache.get_received()money-wallet: check the coin is valid by recreating Coindaod: sends token ID and balance to clidao-cli: prints "received coin {} with value {}".dao-cli: calls propose() and enter a user pubkey and an amountdao-wallet: runs the build sequence for dao_contract::proposedao-wallet: specifies user pubkey, amount and token ID in Proposaldao-cli: prints "Created proposal to send {} xDRK to {}"dao-wallet: create Transaction and send.relayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.dao-wallet: reads received proposal and tries to decrypt Notedao-wallet: sends decrypted values to daoddao-cli: prints "Proposal is now active"dao-cli: calls vote() and enters a vote option (yes or no) and an amountdaod: calls client.vote()money-wallet: get money_leaf_position and money_merkle_pathmoney-wallet: create builder sequence for dao_contract::votemoney-wallet: specify dao_keypair in vote_keypair fieldmoney-wallet: signs and sendsrelayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.dao-wallet: tries to decrypt the Vote.dao-cli: prints "Received vote {} value {}"Note: repeat 3 times with different values and vote options.
dao-cli: calls exec()dao-wallet: get money_leaf_position and money_merkle_pathdao-wallet: specifies user_kaypair and proposal amount in 1st outputdao-wallet: specifies change in 2nd outputdao-wallet: run build sequence for money_contract::transferdao-wallet: run build sequence for dao_contract::execdao-wallet: signs transaction and sendsrelayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.