Prechádzať zdrojové kódy

dao: all documentation updated

skoupidi 1 rok pred
rodič
commit
c96fb2a0d8

+ 15 - 13
bin/drk/dao.sql

@@ -5,29 +5,29 @@
 --   $ drk dao create_dao \
 --       PROPOSER_LIMIT \
 --       QUORUM \
---       APPROVAL_RATIO_BASE \
---       APPROVAL_RATIO_QUOTIENT \
---       GOV_TOKEN_ID > dao.dat
+--       EARLY_EXEC_QUORUM \
+--       APPROVAL_RATIO \
+--       GOV_TOKEN_ID > dao.toml
 --
--- dat.dat contains:
+-- dat.toml contains:
 --
 -- * DAO parameters as listed above
--- * secret key for the DAO
--- * bulla blind
+-- * Secret keys for the DAO
+-- * Bulla blind
 --
 -- We can view the data like so:
 --
---   $ drk dao view < dao.dat
+--   $ drk dao view < dao.toml
 --
--- Now everyone inside the DAO exchanges dao.dat out of band will import
--- it into their wallets.
+-- Now everyone inside the DAO exchanges dao.toml out of band,
+-- will import it into their wallets.
 --
---   $ drk dao import DAO_NAME < dao.dat
+--   $ drk dao import DAO_NAME < dao.toml
 --   Imported DAO ccb8XXX8af6
 --
 -- Where ccb8XXX8af6 is the DAO's name.
 --
--- Next one person will mint it on chain
+-- Next someone that holds all the keys will mint it on chain
 --
 --   $ drk dao mint DAO_NAME > dao_mint_tx
 --   $ drk broadcast < dao_mint_tx
@@ -56,8 +56,9 @@
 --       RECV_PUBKEY
 --
 -- If we don't have enough tokens to meet the proposer_limit threshold
--- then this call will simply fail with an error message. Nothing will
--- be added to the database or sent to the network.
+-- or don't hold the proposer key, then this call will simply fail with
+-- an error message. Nothing will be added to the database or sent to the
+-- network.
 --
 -- Once a proposal has been generated, it can be exported and shared
 -- to other participants.
@@ -73,6 +74,7 @@
 -- # DAO::vote()
 --
 -- You have received a proposal which is active. You can now vote on it.
+-- You will see other votes only if you hold the DAO votes view key.
 --
 --   $ drk dao proposals DAO_NAME
 --   0. f6cae63ced53d02b372206a8d3ed5ac03fde18da306a520285fd56e8d031f6cf

+ 0 - 5
bin/drk/src/dao.rs

@@ -2758,11 +2758,6 @@ impl Drk {
             )))
         }
 
-        // Check we know the plaintext data
-        if proposal.data.is_none() {
-            return Err(Error::Custom("[dao_vote] Proposal plainext data is empty".to_string()))
-        }
-
         // Fetch DAO and check its deployed
         let Ok(dao) = self.get_dao_by_bulla(&proposal.proposal.dao_bulla).await else {
             return Err(Error::Custom(format!(

+ 43 - 42
contrib/localnet/darkfid-single-node/README.md

@@ -35,45 +35,46 @@ testnet user guide.
 Note: List is not exhaustive. Missing functionalities that are not part
 of the guide can be added for future regressions.
 
-| #  | Description               | Command                                                  | Status             |
-|----|---------------------------|----------------------------------------------------------|--------------------|
-| 0  | Initialization            | wallet --initialize                                      | Pass               |
-| 1  | Key generation            | wallet --keygen                                          | Pass               |
-| 2  | Set default wallet        | wallet --default-address {ADDR_ID}                       | Pass               |
-| 3  | Default address retrieval | wallet --address                                         | Pass               |
-| 4  | Block scanning            | scan                                                     | Pass               |
-| 5  | Block subscribing         | subscribe                                                | Pass               |
-| 6  | Balance retrieval         | wallet --balance                                         | Pass               |
-| 7  | Aliases retrieval         | alias show                                               | Pass               |
-| 8  | Mint auth generation      | token generate-mint                                      | Pass               |
-| 9  | Mint auths retrieval      | token list                                               | Pass               |
-| 10 | Alias add                 | alias add {ALIAS} {TOKEN}                                | Pass               |
-| 11 | Aliases retrieval         | alias show                                               | Pass               |
-| 12 | Mint generation           | token mint {ALIAS} {AMOUNT} {ADDR}                       | Pass               |
-| 13 | Token freeze              | token freeze {ALIAS}                                     | Pass               |
-| 14 | Transfer                  | transfer {AMOUNT} {ALIAS} {ADDR}                         | Pass               |
-| 15 | Coins retrieval           | wallet --coins                                           | Pass               |
-| 16 | OTC initialization        | otc init -v {AMOUNT}:{AMOUNT} -t {ALIAS}:{ALIAS}         | Pass               |
-| 17 | OTC join                  | otc join                                                 | Pass               |
-| 18 | OTC sign                  | otc sign                                                 | Pass               |
-| 19 | DAO create                | dao create {LIMIT} {QUORUM} {RATIO} {TOKEN}              | Pass               |
-| 20 | DAO view                  | dao view                                                 | Pass               |
-| 21 | DAO import                | dao import                                               | Pass               |
-| 22 | DAO list                  | dao list                                                 | Pass               |
-| 23 | DAO mint                  | dao mint {DAO}                                           | Pass               |
-| 24 | DAO balance               | dao balance {DAO}                                        | Pass               |
-| 25 | DAO proposals retrieval   | dao proposals {DAO}                                      | Pass               |
-| 26 | DAO propose a transfer    | dao propose-transfer {DAO} {DUR} {AMOUNT} {TOKEN} {ADDR} | Pass               |
-| 27 | DAO proposals retrieval   | dao proposals {DAO}                                      | Pass               |
-| 28 | DAO proposal retrieval    | dao proposal {PROPOSAL_BULLA}                            | Pass               |
-| 29 | DAO proposal export       | dao proposal {PROPOSAL_BULLA} --export                   | Pass               |
-| 30 | DAO proposal import       | dao proposal-import                                      | Pass               |
-| 31 | DAO proposal mint         | dao proposal {PROPOSAL_BULLA} --mint-proposal            | Pass               |
-| 32 | DAO vote                  | dao vote {PROPOSAL_BULLA} {VOTE} {WEIGHT}                | Pass               |
-| 33 | DAO proposal execution    | dao exec {PROPOSAL_BULLA}                                | Pass               |
-| 34 | Coins unspend             | unspend {COIN}                                           | Pass               |
-| 35 | Transaction inspect       | inspect                                                  | Pass               |
-| 36 | Transaction simulate      | explorer simulate-tx                                     | Pass               |
-| 37 | Transaction broadcast     | broadcast                                                | Pass               |
-| 38 | Transaction attach fee    | attach-fee                                               | Pass               |
-
+| #  | Description                  | Command                                                         | Status |
+|----|------------------------------|-----------------------------------------------------------------|--------|
+| 0  | Initialization               | wallet --initialize                                             | Pass   |
+| 1  | Key generation               | wallet --keygen                                                 | Pass   |
+| 2  | Set default wallet           | wallet --default-address {ADDR_ID}                              | Pass   |
+| 3  | Default address retrieval    | wallet --address                                                | Pass   |
+| 4  | Block scanning               | scan                                                            | Pass   |
+| 5  | Block subscribing            | subscribe                                                       | Pass   |
+| 6  | Balance retrieval            | wallet --balance                                                | Pass   |
+| 7  | Aliases retrieval            | alias show                                                      | Pass   |
+| 8  | Mint auth generation         | token generate-mint                                             | Pass   |
+| 9  | Mint auths retrieval         | token list                                                      | Pass   |
+| 10 | Alias add                    | alias add {ALIAS} {TOKEN}                                       | Pass   |
+| 11 | Aliases retrieval            | alias show                                                      | Pass   |
+| 12 | Mint generation              | token mint {ALIAS} {AMOUNT} {ADDR}                              | Pass   |
+| 13 | Token freeze                 | token freeze {ALIAS}                                            | Pass   |
+| 14 | Transfer                     | transfer {AMOUNT} {ALIAS} {ADDR}                                | Pass   |
+| 15 | Coins retrieval              | wallet --coins                                                  | Pass   |
+| 16 | OTC initialization           | otc init -v {AMOUNT}:{AMOUNT} -t {ALIAS}:{ALIAS}                | Pass   |
+| 17 | OTC join                     | otc join                                                        | Pass   |
+| 18 | OTC sign                     | otc sign                                                        | Pass   |
+| 19 | DAO create                   | dao create {LIMIT} {QUORUM} {EARLY_EXEC_QUORUM} {RATIO} {TOKEN} | Pass   |
+| 20 | DAO view                     | dao view                                                        | Pass   |
+| 21 | DAO import                   | dao import                                                      | Pass   |
+| 22 | DAO update keys              | dao update-keys                                                 | Pass   |
+| 23 | DAO list                     | dao list                                                        | Pass   |
+| 24 | DAO mint                     | dao mint {DAO}                                                  | Pass   |
+| 25 | DAO balance                  | dao balance {DAO}                                               | Pass   |
+| 26 | DAO proposals retrieval      | dao proposals {DAO}                                             | Pass   |
+| 27 | DAO propose a transfer       | dao propose-transfer {DAO} {DUR} {AMOUNT} {TOKEN} {ADDR}        | Pass   |
+| 28 | DAO propose generic          | dao propose-generic  {DAO} {DUR} {AMOUNT} {TOKEN} {ADDR}        | Pass   |
+| 29 | DAO proposal retrieval       | dao proposal {PROPOSAL_BULLA}                                   | Pass   |
+| 30 | DAO proposal export          | dao proposal {PROPOSAL_BULLA} --export                          | Pass   |
+| 31 | DAO proposal import          | dao proposal-import                                             | Pass   |
+| 32 | DAO proposal mint            | dao proposal {PROPOSAL_BULLA} --mint-proposal                   | Pass   |
+| 33 | DAO vote                     | dao vote {PROPOSAL_BULLA} {VOTE} {WEIGHT}                       | Pass   |
+| 34 | DAO proposal execution       | dao exec {PROPOSAL_BULLA}                                       | Pass   |
+| 35 | DAO proposal early execution | dao exec --early {PROPOSAL_BULLA}                               | Pass   |
+| 36 | Coins unspend                | unspend {COIN}                                                  | Pass   |
+| 37 | Transaction inspect          | inspect                                                         | Pass   |
+| 38 | Transaction simulate         | explorer simulate-tx                                            | Pass   |
+| 39 | Transaction broadcast        | broadcast                                                       | Pass   |
+| 40 | Transaction attach fee       | attach-fee                                                      | Pass   |

+ 30 - 33
contrib/localnet/darkfid-single-node/run-dao-test.sh

@@ -5,12 +5,14 @@ set -x
 # Path to `drk` binary
 DRK="../../../drk -c drk.toml"
 
-# First run the consensus node and the faucet:
+# First run the darkfid node and the miner:
 #
 #   ./clean.sh
+#   ./init-wallet.sh
 #   ./tmux_sessions.sh -vv
 #
-# In another term run the wallet syncing:
+# In another term run the wallet syncing,
+# and wait until some blocks are mined:
 #
 #   ./sync-wallet.sh
 #
@@ -61,8 +63,8 @@ wait_tokens() {
 }
 
 mint_dao() {
-    $DRK dao create 20 10 0.67 MLDY > /tmp/dao.dat
-    $DRK dao import MiladyMakerDAO < /tmp/dao.dat
+    $DRK dao create 20 10 10 0.67 MLDY > /tmp/dao.toml
+    $DRK dao import MiladyMakerDAO < /tmp/dao.toml
     $DRK dao list
     $DRK dao list MiladyMakerDAO
 
@@ -70,19 +72,20 @@ mint_dao() {
 }
 
 wait_dao_mint() {
-    while [ "$($DRK dao list MiladyMakerDAO | grep '^Tx hash: ' | awk '{print $3}')" = None ]; do
+    while [ "$($DRK dao list MiladyMakerDAO | grep '^Transaction hash: ' | awk '{print $3}')" = None ]; do
         sleep 1
     done
 }
 
 fill_treasury() {
-    PUBKEY="$($DRK dao list 1 | grep '^Public key: ' | cut -d ' ' -f3)"
-    BULLA="$($DRK dao list 1 | grep '^Bulla: ' | cut -d' ' -f2)"
-    $DRK transfer 20 WCKD "$PUBKEY" --dao "$BULLA" | tee /tmp/xfer.tx | $DRK broadcast
+    PUBKEY="$($DRK dao list MiladyMakerDAO | grep '^Notes Public key: ' | cut -d ' ' -f4)"
+    SPEND_HOOK="$($DRK dao spend-hook)"
+    BULLA="$($DRK dao list MiladyMakerDAO | grep '^Bulla: ' | cut -d' ' -f2)"
+    $DRK transfer 20 WCKD "$PUBKEY" "$SPEND_HOOK" "$BULLA" | tee /tmp/xfer.tx | $DRK broadcast
 }
 
 dao_balance() {
-    BALANCE=$($DRK dao balance 1 2>/dev/null)
+    BALANCE=$($DRK dao balance MiladyMakerDAO 2>/dev/null)
     # No tokens received at all yet
     if echo "$BALANCE" | grep -q "No unspent balances found"; then
         echo 0
@@ -108,51 +111,44 @@ wait_dao_treasury() {
 
 propose() {
     MY_ADDR=$($DRK wallet --address)
-    $DRK dao balance MiladyMakerDAO
-    $DRK dao propose MiladyMakerDAO "$MY_ADDR" 0.1 WCKD > /tmp/propose.tx
+    PROPOSAL="$($DRK dao propose-transfer MiladyMakerDAO 1 5 WCKD "$MY_ADDR" | cut -d' ' -f3)"
+    $DRK dao proposal "$PROPOSAL" --mint-proposal > /tmp/propose.tx
     $DRK broadcast < /tmp/propose.tx
 }
 
-proposal_status() {
-    PROPOSALS_LEN=$($DRK dao proposals MiladyMakerDAO | wc -l)
-    if [ "$PROPOSALS_LEN" = 0 ]; then
-        echo 0
-    else
-        echo 1
-    fi
-}
-
 wait_proposal() {
-    while [ "$(proposal_status)" = 0 ]; do
+    PROPOSAL="$($DRK dao proposals MiladyMakerDAO | cut -d' ' -f2)"
+    while [ "$($DRK dao proposal $PROPOSAL | grep '^Proposal transaction hash: ' | awk '{print $4}')" = None ]; do
         sleep 1
     done
 }
 
 vote() {
-    PROPOSAL_ID=1
-    $DRK dao vote MiladyMakerDAO "$PROPOSAL_ID" 1 20 > /tmp/dao-vote.tx
+    PROPOSAL="$($DRK dao proposals MiladyMakerDAO | cut -d' ' -f2)"
+    $DRK dao vote "$PROPOSAL" 1 > /tmp/dao-vote.tx
     $DRK broadcast < /tmp/dao-vote.tx
 }
 
-vote_status() {
-	PROPOSAL_ID=1
-    $DRK dao proposal MiladyMakerDAO "$PROPOSAL_ID" | grep -q yes
-    echo $?
-}
-
 wait_vote() {
-    while [ "$(vote_status)" != 0 ]; do
+    PROPOSAL="$($DRK dao proposals MiladyMakerDAO | cut -d' ' -f2)"
+    while [ "$($DRK dao proposal $PROPOSAL | grep '^Current proposal outcome: ' | awk '{print $4}')" != "Approved" ]; do
         sleep 1
     done
 }
 
 do_exec() {
-    PROPOSAL_ID=1
-    $DRK dao exec MiladyMakerDAO "$PROPOSAL_ID" > /tmp/dao-exec.tx
+    PROPOSAL="$($DRK dao proposals MiladyMakerDAO | cut -d' ' -f2)"
+    $DRK dao exec --early $PROPOSAL > /tmp/dao-exec.tx
     $DRK broadcast < /tmp/dao-exec.tx
 }
 
-$DRK wallet --keygen
+wait_exec() {
+    PROPOSAL="$($DRK dao proposals MiladyMakerDAO | cut -d' ' -f2)"
+    while [ "$($DRK dao proposal $PROPOSAL | grep '^Proposal was executed on transaction: ' | awk '{print $6}')" = None ]; do
+        sleep 1
+    done
+}
+
 mint_tokens
 wait_tokens
 mint_dao
@@ -164,3 +160,4 @@ wait_proposal
 vote
 wait_vote
 do_exec
+wait_exec

+ 1 - 1
contrib/localnet/darkfid-single-node/sync-wallet.sh

@@ -3,7 +3,7 @@ set -e
 set -x
 
 # Path to `drk` binary
-DRK="../../../drk -vv -c drk.toml"
+DRK="../../../drk -c drk.toml"
 
 while true; do
     if $DRK ping 2> /dev/null; then

+ 83 - 47
doc/src/arch/dao.md

@@ -14,49 +14,70 @@ these bullas.
 
 ## `DAO::mint()`: Establishing the DAO
 
-From `darkfi/src/contract/dao/proof/dao-mint.zk`:
+From `darkfi/src/contract/dao/proof/mint.zk`:
 ```zkas
 	bulla = poseidon_hash(
-		dao_proposer_limit,
-		dao_quorum,
-		dao_approval_ratio_quot,
-		dao_approval_ratio_base,
+		proposer_limit,
+		quorum,
+		early_exec_quorum,
+		approval_ratio_quot,
+		approval_ratio_base,
 		gov_token_id,
-		dao_public_x,
-		dao_public_y,
-		dao_bulla_blind,
-	);
+		notes_public_x,
+		notes_public_y,
+		proposer_public_x,
+		proposer_public_y,
+		proposals_public_x,
+		proposals_public_y,
+		votes_public_x,
+		votes_public_y,
+		exec_public_x,
+		exec_public_y,
+		early_exec_public_x,
+		early_exec_public_y,
+		bulla_blind,
+    );
 ```
 
 Brief description of the DAO bulla params:
 
-* **proposer_limit**: minimum deposit required for proposals to become valid.
-  TODO: rename to `min_deposit`.
-* **quorum**: minimum threshold of votes before it's allowed to pass.
+* **proposer_limit**: the minimum amount of governance tokens needed to open a proposal.
+* **quorum**: minimal threshold of participating total tokens needed for a proposal to pass.
   Normally this is implemented as min % of voting power, but we do this in
   absolute value
-* **approval_ratio**: proportion of winners to losers for a proposal to pass.
-
-Currently there is no notion of veto although it could be trivially added
-if desired.
+* **early_exec_quorum**: minimal threshold of participating total tokens needed for a proposal
+  to be considered as strongly supported, enabling early execution. Must be greater or equal
+  to normal quorum.
+* **approval_ratio**: the ratio of winning/total votes needed for a proposal to pass.
+* **gov_token_id**: DAO's governance token ID.
+* **notes_public_key**: notes(coins) decryption public key
+* **proposer_public_key**: proposals creator public key
+* **proposals_public_key**: proposals viewer public key
+* **votes_public_key**: votes viewer public key
+* **exec_public_key**: proposals executor public key
+* **early_exec_public_key**: strongly supported proposals executor public key
+* **bulla_blind**: bulla blind
+
+DAO creators/founders have full control on how they want to configure and share
+the actions keys, giving them the ability to veto if needed.
 
 ## `DAO::propose()`: Propose the Vote
 
-From `darkfi/src/contract/dao/proof/dao-propose-main.zk`:
+From `darkfi/src/contract/dao/proof/propose-main.zk`:
 ```zkas
 	proposal_bulla = poseidon_hash(
-		proposal_dest_x,
-		proposal_dest_y,
-		proposal_amount,
-		proposal_token_id,
+		proposal_auth_calls_commit,
+		proposal_creation_blockwindow,
+		proposal_duration_blockwindows,
+		proposal_user_data,
 		dao_bulla,
 		proposal_blind,
 	);
 ```
 
-We create a proposal which will send tokens to the dest provided.
-This will soon be changed to be generic. Proposals will commit to
-calling params or code instead.
+Proposals are committed to a specific calls set, therefore they
+are generic and we can attach various calls to it. We will use a
+money transfer as the example for rest sections.
 
 ## `DAO::vote()`: Vote on a Proposal
 
@@ -366,37 +387,52 @@ be executed early. We should add this option to DarkFi DAO params.
 
 ## Suggested Changes
 
-DAO params:
+~~DAO params:~~
 
-* Voting period (currently called duration) should be moved from proposals to
-  DAO params.
-    * upgrayedd: we should just have minimum allowed period in the DAO, but keep
-      this param in the proposal.
-* Window (currently set at 4 hours of blocks) should be customizable. We need a
-  terminology for the unit of time. Maybe `time_units`.
-    * This should be switched from block index to using timestamps.
+* ~~Voting period (currently called duration) should be moved from proposals to
+  DAO params.~~
+    * ~~upgrayedd: we should just have minimum allowed period in the DAO, but keep
+      this param in the proposal.~~
+* ~~Window (currently set at 4 hours of blocks) should be customizable. We need a
+  terminology for the unit of time. Maybe `time_units`.~~
+    * ~~This should be switched from block index to using timestamps.
       See the quoted paragraph in the OpenZeppelin section above for the
-      reasoning.
-    * upgrayedd: stick with block index.
-* Early execution bool flag. If true, then passed proposals can be `exec()`uted
-  asap, otherwise the entire voting period must pass.
+      reasoning.~~
+    * ~~upgrayedd: stick with block index.~~
+* ~~Early execution bool flag. If true, then passed proposals can be `exec()`uted
+  asap, otherwise the entire voting period must pass.~~
+
+~~No changes to proposals, except moving duration to DAO params.~~
 
-No changes to proposals, except moving duration to DAO params.
+> Resolution:
+> The full voting period must pass in order to be able to execute a proposal.
+> A new configuration parameter was introduced, called early exec quorum,
+> where we can define the quorum for a proposal to be considered as strongly
+> supported/voted on, which should always be greater or equal to normal quorum.
+> With this addition, we can execute proposals before the voting period has
+> passed, if they were accepted.
 
-Currently the DAO public key is used for:
+~~Currently the DAO public key is used for:~~
 
-* Encrypting votes.
-* Calling exec.
+* ~~Encrypting votes.~~
+* ~~Calling exec.~~
 
-We should introduce a new key:
+~~We should introduce a new key:~~
 
-* Proposer role, which is needed to make proposals. This can be shared openly
+* ~~Proposer role, which is needed to make proposals. This can be shared openly
   amongst DAO members if they wish to remove the restriction on who can make
-  proposals.
-    * OZ does this with a canceller role that has the ability to cancel
-      proposals.
-    * In the future allow multiple keys for this so you can see who makes
-      proposals.
+  proposals.~~
+    * ~~OZ does this with a canceller role that has the ability to cancel
+      proposals.~~
+    * ~~In the future allow multiple keys for this so you can see who makes
+      proposals.~~
+
+> Resolution:
+> DAO public key was split into six other keys, providing maximum control over
+> each DAO action. Now the DAO creator can define who can view the coin notes,
+> create proposals, view proposals, view votes, execute proposals and early
+> execute proposals. They can configure the keys however they like like reusing
+> keys if they want some actions to have same key.
 
 Optional: many DAOs these days implement Abstain, which increases the quorum
 without voting yes. This is for when you want to weak support a measure,

+ 15 - 5
doc/src/spec/contract/dao/concepts.md

@@ -7,12 +7,16 @@ The governance process is divided in a few steps that are outlined below:
 * **Exec:** if the proposal passes within the time limit then the proposal is
   executed.
 
+> Note:
+> There is a special case where a proposal can be executed before voting period
+> passes, if its strongly supported, based on the configured early execution quorum.
+
 ## Propose
 
 To prevent spam, proposals must be submitted by holders with a certain number
-of governance tokens. Several members of the DAO can add inputs separately to
-a proposal before it is posted on chain so that their combined inputs meet the
-proposal governance token limit.
+of governance tokens and the DAO proposers key. Several members of the DAO can
+add inputs separately to a proposal before it is posted on chain so that their
+combined inputs meet the proposal governance token limit.
 
 Once proposals are posted on chain, they are immediately active.
 
@@ -46,8 +50,14 @@ no longer vote on the proposal, and it is considered *expired*.
 
 ### Quorum
 
-Quorum is defined as the minimum absolute number of governance tokens voting
-yes required for a proposal to become accepted.
+Quorum is defined as the minimal threshold of participating total governance tokens need for
+a proposal to pass. Normally this is implemented as min % of voting power, but we do this in
+absolute value.
+
+### Early Execution Quorum
+Early execytuib quorum is defined as the minimal threshold of participating total tokens needed
+for a proposal to be considered as strongly supported, enabling early execution. Must be greater
+or equal to normal quorum.
 
 ### Approval Ratio
 

+ 32 - 6
doc/src/spec/contract/dao/model.md

@@ -13,20 +13,31 @@ The DAO contains the main parameters that define DAO operation:
   come from multiple token holders.
 * Quorum $Q$ specifies the absolute minimum number of tokens required for
   before a proposal can be accepted.
+* Early exec quorum $EEQ$ specifies the absolute minimum number of tokens
+  required for before a proposal can be considered as strongly accepted.
 * The approval ratio $A^\%$ is a tuple that specifies the minimum theshold
   of affirmative yes votes for a proposal to become accepted.
-* The public key $PK$ serves a dual role for both encrypted notes, and as
-  a key to authorize accepted proposals to be executed.
-  This key may be shared widely with all DAO members or within a privileged
-  group.
+* Notes public key $NPK$ controls who can view encrypted notes.
+* Proposer public key $pPK$ controls who can mint proposals.
+* Proposals public key $PPK$ controls who can view the proposals.
+* Votes public key $VPK$ controls who can view votes.
+* Executor public key $EPK$ controls who can execute proposals.
+* Early executor public key $EEPK$ controls who can execute proposals that
+  are strongly accepted.
 
 Define the DAO params
 $$ \begin{aligned}
   \t{Params}_\t{DAO}.L &∈ ℕ₆₄ \\
   \t{Params}_\t{DAO}.Q &∈ ℕ₆₄ \\
+  \t{Params}_\t{DAO}.EEQ &∈ ℕ₆₄ \\
   \t{Params}_\t{DAO}.A^\% &∈ ℕ₆₄ × ℕ₆₄ \\
   \t{Params}_\t{DAO}.τ &∈ 𝔽ₚ \\
-  \t{Params}_\t{DAO}.\t{PK} &∈ ℙₚ
+  \t{Params}_\t{DAO}.\t{NPK} &∈ ℙₚ \\
+  \t{Params}_\t{DAO}.\t{pPK} &∈ ℙₚ \\
+  \t{Params}_\t{DAO}.\t{PPK} &∈ ℙₚ \\
+  \t{Params}_\t{DAO}.\t{VPK} &∈ ℙₚ \\
+  \t{Params}_\t{DAO}.\t{EPK} &∈ ℙₚ \\
+  \t{Params}_\t{DAO}.\t{EEPK} &∈ ℙₚ
 \end{aligned} $$
 where the approval ratio $\t{Approval}^\% = (q, d)$ defines the equivalence
 class $[\frac{q}{d}]$ of fractions defined by $q₁d₂ = q₂d₁ ⟺  [\frac{q₁}{d₁}] \~ [\frac{q₂}{d₂}]$.
@@ -36,7 +47,22 @@ class $[\frac{q}{d}]$ of fractions defined by $q₁d₂ = q₂d₁ ⟺  [\frac{q
 ```
 
 $$ \t{Bulla}_\t{DAO} : \t{Params}_\t{DAO} × 𝔽ₚ → 𝔽ₚ $$
-$$ \t{Bulla}_\t{DAO}(p, b_\t{DAO}) = \t{Bulla}(ℕ₆₄2𝔽ₚ(p.L), ℕ₆₄2𝔽ₚ(p.Q), ℕ₆₄2𝔽ₚ(p.A^\%), p.τ, \mathcal{X}(p.\t{PK}), \mathcal{Y}(p.\t{PK}), b_\t{DAO}) $$
+$$ \begin{aligned}
+\t{Bulla}_\t{DAO}(p, b_\t{DAO}) = \t{Bulla}( \\
+ℕ₆₄2𝔽ₚ(p.L), \\
+ℕ₆₄2𝔽ₚ(p.Q), \\
+ℕ₆₄2𝔽ₚ(p.EEQ), \\
+ℕ₆₄2𝔽ₚ(p.A^\%), \\
+p.τ, \\
+\mathcal{X}(p.\t{NPK}), \mathcal{Y}(p.\t{NPK}), \\
+\mathcal{X}(p.\t{pPK}), \mathcal{Y}(p.\t{pPK}), \\
+\mathcal{X}(p.\t{PPK}), \mathcal{Y}(p.\t{PPK}), \\
+\mathcal{X}(p.\t{VPK}), \mathcal{Y}(p.\t{VPK}), \\
+\mathcal{X}(p.\t{EPK}), \mathcal{Y}(p.\t{EPK}), \\
+\mathcal{X}(p.\t{EEPK}), \mathcal{Y}(p.\t{EEPK}), \\
+b_\t{DAO} \\
+)
+\end{aligned} $$
 
 ## Proposals
 

+ 88 - 19
doc/src/spec/contract/dao/scheme.md

@@ -23,7 +23,7 @@ the DAO params and then add the bulla to the set.
 
 * Wallet builder: `src/contract/dao/src/client/mint.rs`
 * WASM VM code: `src/contract/dao/src/entrypoint/mint.rs`
-* ZK proof: `src/contract/dao/proof/dao-mint.zk`
+* ZK proof: `src/contract/dao/proof/mint.zk`
 
 ### Function Params
 
@@ -45,22 +45,41 @@ Let there be a prover auxiliary witness inputs:
 $$ \begin{aligned}
   L &∈ ℕ₆₄ \\
   Q &∈ ℕ₆₄ \\
+  EEQ &∈ ℕ₆₄ \\
   A^\% &∈ ℕ₆₄ × ℕ₆₄ \\
   τ &∈ 𝔽ₚ \\
-  x &∈ 𝔽ₚ \\
+  Nx &∈ 𝔽ₚ \\
+  px &∈ 𝔽ₚ \\
+  Px &∈ 𝔽ₚ \\
+  Vx &∈ 𝔽ₚ \\
+  Ex &∈ 𝔽ₚ \\
+  EEx &∈ 𝔽ₚ \\
   b_\t{DAO} &∈ 𝔽ₚ
 \end{aligned} $$
 
 Attach a proof $π$ such that the following relations hold:
 
-**Proof of public key ownership** &emsp; $\t{PK} = \t{DerivePubKey}(x)$.
+**Proof of notes public key ownership** &emsp; $\t{NPK} = \t{DerivePubKey}(Nx)$.
 
-**DAO bulla integrity** &emsp; $ℬ  = \t{Bulla}_\t{DAO}((L, Q, A^\%, τ, \t{PK}), b_\t{DAO})$
+**Proof of proposer public key ownership** &emsp; $\t{pPK} = \t{DerivePubKey}(px)$.
+
+**Proof of proposals public key ownership** &emsp; $\t{PPK} = \t{DerivePubKey}(Px)$.
+
+**Proof of votes public key ownership** &emsp; $\t{VPK} = \t{DerivePubKey}(Vx)$.
+
+**Proof of executor public key ownership** &emsp; $\t{EPK} = \t{DerivePubKey}(Ex)$.
+
+**Proof of early executor public key ownership** &emsp; $\t{EEPK} = \t{DerivePubKey}(EEx)$.
+
+**Proof that early execution quorum is greater than normal quorum** &emsp; $Q <= EEQ1$.
+
+**DAO bulla integrity** &emsp; $ℬ  = \t{Bulla}_\t{DAO}((L, Q, EEQ, A^\%, τ,
+\t{NPK}, \t{pPK}, \t{PPK}, \t{VPK}, \t{EPK}, \t{EEPK}), b_\t{DAO})$
 
 ### Signatures
 
 There should be a single signature attached, which uses
-$\t{PK}$ as the signature public key.
+$\t{NPK}$ as the signature public key.
 
 ## Propose
 
@@ -89,8 +108,8 @@ A proposal contains a list of auth calls as specified in [Auth Calls](model.md#a
 * Wallet builder: `src/contract/dao/src/client/propose.rs`
 * WASM VM code: `src/contract/dao/src/entrypoint/propose.rs`
 * ZK proofs:
-  * `src/contract/dao/proof/dao-propose-main.zk`
-  * `src/contract/dao/proof/dao-propose-input.zk`
+  * `src/contract/dao/proof/propose-main.zk`
+  * `src/contract/dao/proof/propose-input.zk`
 
 ### Function Params
 
@@ -146,6 +165,8 @@ Attach a proof $π_𝒫 $ such that the following relations hold:
 **Governance token commit** &emsp; export the DAO token ID as an encrypted pedersen
 commit $T = \t{PedersenCommit}(d.τ, b_τ)$ where $T = ∑_{i ∈ 𝐢} Tᵢ$.
 
+**Proof of proposer public key ownership** &emsp; $\t{pPK} = \t{DerivePubKey}(px)$.
+
 **DAO bulla integrity** &emsp; $𝒟  = \t{Bulla}_\t{DAO}(d, b_d)$
 
 **DAO existence** &emsp; $R_\t{DAO} = \t{MerkleRoot}(ψ, Π, 𝒟 )$
@@ -200,8 +221,8 @@ public key $i.\t{PK}_σ$.
 After `DAO::propose()` is called, DAO members can then call this contract
 function. Using a similar method as before, they attach inputs proving ownership
 of a certain value of governance tokens. This is how we achieve token weighted
-voting. The result of the vote is communicated to other DAO members through the
-encrypted note $\t{note}$.
+voting. The result of the vote is communicated to DAO members that can view votes
+through the encrypted note $\t{note}$.
 
 Each nullifier $𝒩 $ is stored uniquely per proposal. Additionally as before,
 there is a leakage here connecting the coins when spent. However prodigious
@@ -220,8 +241,8 @@ and the yes votes by $V_\t{yes}$.
 * Wallet builder: `src/contract/dao/src/client/vote.rs`
 * WASM VM code: `src/contract/dao/src/entrypoint/vote.rs`
 * ZK proofs:
-  * `src/contract/dao/proof/dao-vote-main.zk`
-  * `src/contract/dao/proof/dao-vote-input.zk`
+  * `src/contract/dao/proof/vote-main.zk`
+  * `src/contract/dao/proof/vote-input.zk`
 
 ### Function Params
 
@@ -247,8 +268,9 @@ selected such that their sum is a valid field element in $𝔽ₚ$ so the blind
 for $∑ V$ can be verifiably encrypted. Likewise we do the same for the blind
 used to calculate $V_\t{yes}$.
 
-This allows DAO members to securely receive all secrets for votes on a proposal.
-This is then used in the Exec phase when we work on the sum of DAO votes.
+This allows DAO members that hold the votes key to securely receive all secrets
+for votes on a proposal. This is then used in the Exec phase when we work on the
+sum of DAO votes.
 
 ```rust
 {{#include ../../../../../src/contract/dao/src/model.rs:dao-vote-params}}
@@ -300,7 +322,7 @@ and then check $t_\t{now} < t_\t{end}$.
 
 **Verifiable encryption of vote commit secrets** &emsp;
 let $𝐧 = (o, b_y, v, bᵥ)$, and verify
-$\t{enc\_vote} = \t{ElGamal}.\t{Encrypt}(𝐧, \t{esk}, d.\t{PK})$.
+$\t{enc\_vote} = \t{ElGamal}.\t{Encrypt}(𝐧, \t{esk}, d.\t{VPK})$.
 
 For each input $i ∈ 𝐢$, perform the following checks:
 
@@ -343,8 +365,8 @@ public key $i.\t{PK}_σ$.
 
 Exec is the final stage after voting is [Accepted](concepts.md#proposal-states).
 
-It checks the correct voting conditions have been met in accordance with the
-[DAO params](model.md#dao) such as quorum and approval ratio.
+It checks that voting has passed, and correct conditions have been met, in accordance
+with the [DAO params](model.md#dao) such as quorum and approval ratio.
 $V_\t{yes}$ and $V_\t{all}$ are pedersen commits to $v_\t{yes}$ and $v_\t{all}$ respectively.
 
 It also checks that child calls have been attached in accordance with the auth
@@ -354,7 +376,9 @@ function. Currently the DAO provides a single preset for executing
 
 * Wallet builder: `src/contract/dao/src/client/exec.rs`
 * WASM VM code: `src/contract/dao/src/entrypoint/exec.rs`
-* ZK proof: `src/contract/dao/proof/dao-exec.zk`
+* ZK proofs:
+  * `src/contract/dao/proof/exec.zk`
+  * `src/contract/dao/proof/early-exec.zk`
 
 ### Function Params
 
@@ -402,11 +426,16 @@ $$ \begin{aligned}
 \end{aligned} $$
 Attach a proof $π$ such that the following relations hold:
 
+**Proof of executor public key ownership** &emsp; $\t{EPK} = \t{DerivePubKey}(Ex)$.
+
 **DAO bulla integrity** &emsp; $𝒟 = \t{Bulla}_\t{DAO}(d, b_d)$
 
 **Proposal bulla integrity** &emsp; $𝒫 = \t{Bulla}_\t{Proposal}(p, b_p)$
 where $p.𝒜  = 𝒜 $.
 
+**Proposal has expired** &emsp; let $t_\t{end} = ℕ₆₄2𝔽ₚ(p.t₀) + ℕ₆₄2𝔽ₚ(p.D)$,
+and then check $t_\t{end} <= t_\t{now}$.
+
 **Yes vote commit** &emsp; $V_\t{yes} = \t{PedersenCommit}(v_y, b_y)$
 
 **All vote commit** &emsp; $V_\t{all} = \t{PedersenCommit}(v_a, b_a)$
@@ -417,6 +446,46 @@ where $p.𝒜  = 𝒜 $.
 $\frac{A^\%_q}{A^\%_b} ≤ \frac{v_y}{v_a}$. Instead we perform the
 equivalent check that $v_a A^\%_q ≤ v_y A^\%_b$.
 
+### EarlyExec
+
+This is a special case of Exec for when we want to execute a strongly accepted proposal
+before voting period has passed. A different proof statement is used in this case.
+
+Let there be prover auxiliary witness inputs:
+$$ \begin{aligned}
+  p &∈ \t{Params}_\t{Proposal} \\
+  b_p &∈ 𝔽ₚ \\
+  d &∈ \t{Params}_\t{DAO} \\
+  b_d &∈ 𝔽ₚ \\
+  v_y &∈ 𝔽ₚ \\
+  v_a &∈ 𝔽ₚ \\
+  b_y &∈ 𝔽ᵥ \\
+  b_a &∈ 𝔽ᵥ \\
+\end{aligned} $$
+Attach a proof $π$ such that the following relations hold:
+
+**Proof of executor public key ownership** &emsp; $\t{EPK} = \t{DerivePubKey}(Ex)$.
+
+**Proof of early executor public key ownership** &emsp; $\t{EEPK} = \t{DerivePubKey}(EEx)$.
+
+**DAO bulla integrity** &emsp; $𝒟 = \t{Bulla}_\t{DAO}(d, b_d)$
+
+**Proposal bulla integrity** &emsp; $𝒫 = \t{Bulla}_\t{Proposal}(p, b_p)$
+where $p.𝒜  = 𝒜 $.
+
+**Proposal has not expired** &emsp; let $t_\t{end} = ℕ₆₄2𝔽ₚ(p.t₀) + ℕ₆₄2𝔽ₚ(p.D)$,
+and then check $t_\t{now} < t_\t{end}$.
+
+**Yes vote commit** &emsp; $V_\t{yes} = \t{PedersenCommit}(v_y, b_y)$
+
+**All vote commit** &emsp; $V_\t{all} = \t{PedersenCommit}(v_a, b_a)$
+
+**All votes pass early execution quorum** &emsp; $EEQ ≤ v_a$
+
+**Approval ratio satisfied** &emsp; we wish to check that
+$\frac{A^\%_q}{A^\%_b} ≤ \frac{v_y}{v_a}$. Instead we perform the
+equivalent check that $v_a A^\%_q ≤ v_y A^\%_b$.
+
 ### Signatures
 
 No signatures are attached.
@@ -437,8 +506,8 @@ DAO treasury but be unspendable.
 * Wallet builder: `src/contract/dao/src/client/auth_xfer.rs`
 * WASM VM code: `src/contract/dao/src/entrypoint/auth_xfer.rs`
 * ZK proofs:
-  * `src/contract/dao/proof/dao-auth-money-transfer.zk`
-  * `src/contract/dao/proof/dao-auth-money-transfer-enc-coin.zk`
+  * `src/contract/dao/proof/auth-money-transfer.zk`
+  * `src/contract/dao/proof/auth-money-transfer-enc-coin.zk`
 
 ### Function Params
 

+ 82 - 26
doc/src/testnet/dao.md

@@ -8,6 +8,7 @@ Let's create a DAO with the following parameters:
 
 * Proposer limit: `20`
 * Quorum: `10`
+* Early execution quorum: `10`
 * Approval ratio: `0.67`
 * Governance token: `MLDY`
 
@@ -20,17 +21,21 @@ $ ./drk help dao create
 Let's create our DAO.
 
 ```
-$ ./drk dao create 20 10 0.67 MLDY > dao_mldy.dat
-$ ./drk dao view < dao_mldy.dat
+$ ./drk dao create 20 10 10 0.67 MLDY > dao_mldy.toml
+$ ./drk dao view < dao_mldy.toml
 ```
 
-Now this file can be shared amongst all dao members, so they
-hold the generated DAO information and keys. The view command
-will show us the parameters. If everything looks fine, we can
-now import it into our wallet:
+Since its a normal `toml` file, you may open it with you favourite
+editor, modify they keys configuration and/or keep different versions
+for different members. By default all keys are different, so its up
+to the DAO founders to chose what configuration they are going to use.
+After configuring the file(s) properly, it can be shared amonst the
+dao members, so they hold the generated DAO information and keys.
+The view command will show us the parameters. If everything looks fine,
+we can now import it into our wallet:
 
 ```
-$ ./drk dao import MiladyMakerDAO < dao_mldy.dat
+$ ./drk dao import MiladyMakerDAO < dao_mldy.toml
 $ ./drk dao list
 $ ./drk dao list MiladyMakerDAO
 ```
@@ -39,7 +44,8 @@ $ ./drk dao list MiladyMakerDAO
 
 If parameters are shown, this means the DAO was successfully imported
 into our wallet. We use the DAO name to reference it. Now we can create
-a transaction that will mint the DAO on-chain, and broadcast it:
+a transaction that will mint the DAO on-chain, if we hold all its keys,
+and broadcast it:
 
 ```
 $ ./drk dao mint MiladyMakerDAO > dao_mldy_mint_tx
@@ -55,19 +61,19 @@ should see a leaf position and a transaction hash when running
 
 Let's send some tokens to the DAO's treasury so we're able to make
 a proposal to send those somewhere. First, find the DAO bulla, the
-dao contract spend hook and the DAO public key a d then create a
-transfer transaction:
+dao contract spend hook and the DAO notes public key and then create
+a transfer transaction:
 
 ```
 $ ./drk dao spend-hook
 $ ./drk dao list MiladyMakerDAO
-$ ./drk transfer 10 WCKD {DAO_PUBLIC_KEY} \
+$ ./drk transfer 10 WCKD {DAO_NOTES_PUBLIC_KEY} \
     {DAO_CONTRACT_SPEND_HOOK} {DAO_BULLA} > dao_mldy_transfer_tx
 $ ./drk broadcast < dao_mldy_transfer_tx
 ```
 
 Wait for it to confirm, and if subscribed, you should see the DAO
-receive the funds:
+receive the funds, if you hold the DAO notes key:
 
 ```
 $ ./drk dao balance MiladyMakerDAO
@@ -77,23 +83,24 @@ $ ./drk dao balance MiladyMakerDAO
 
 Now that the DAO has something in its treasury, we can generate a
 transfer proposal to send it somewhere, that will be up to vote
-for 1 block period. Let's propose to send 5 of the 10 tokens to
-our address (we can find that with `drk wallet --address`):
+for 1 block period, if we hold the DAO proposer key. Let's propose
+to send 5 of the 10 tokens to our address (we can find that with
+`drk wallet --address`):
 
 ```
 $ ./drk dao propose-transfer MiladyMakerDAO 1 5 WCKD {YOUR_ADDRESS}
 ```
 
 After command was executed, it will output the generated proposal
-bulla, which we will use to full the proposal information:
+bulla, which we will use to view the proposal full information:
 
 ```
 $ ./drk dao proposal {PROPOSAL_BULLA}
 ```
 
 We can export this proposal, to share with rest DAO members.
-The exported file will be encrypted using the DAO keys, so only
-its members can decrypt and import it.
+The exported file will be encrypted using the DAO proposals view key,
+so only its members can decrypt and import it.
 
 ```
 $ ./drk dao proposal {PROPOSAL_BULLA} --export > dao_mldy_transfer_proposal.dat
@@ -142,32 +149,74 @@ $ ./drk broadcast < dao_mldy_transfer_proposal_vote_tx
 ```
 
 Once confirmed and scanned, you should see votes information and
-current status when running `dao proposal {PROPOSAL_BULLA}`.
+current status when running `dao proposal {PROPOSAL_BULLA}`,
+assuming you hold the votes view key.
 
 ## Executing the proposal
 
-Once the block period has passed and enough votes have been cast that
+Once the block period has passed(~4h) and enough votes have been cast that
 meet the required minimum (quorum), and assuming the yes:no votes ratio
 ratio is bigger than the approval ratio, then we are ready to confirm
-the vote. Any DAO member can perform this action.
+the vote. Only DAO members with the executor key can perform this action.
+
+```
+$ ./drk dao exec {PROPOSAL_BULLA} > dao_mldy_transfer_proposal_exec_tx
+$ ./drk broadcast < dao_mldy_transfer_proposal_exec_tx
+```
 
 Since in our tutorial the `MLDY` governance tokens we used surpass the
-quorum, we can execute the proposal right away:
+early execution quorum, we can execute the proposal right away, if we hold
+both the DAO executor and early executor keys:
 
 ```
-$ ./drk dao exec {PROPOSAL_BULLA} > dao_mldy_transfer_proposal_exec_tx
+$ ./drk dao exec --early {PROPOSAL_BULLA} > dao_mldy_transfer_proposal_exec_tx
 $ ./drk broadcast < dao_mldy_transfer_proposal_exec_tx
 ```
 
 After the proposal has been executed on chain, we will see that
-the DAO balance has been reduced by 5 `WCKD`, while our own balance
-has been increased by the same amount:
+the DAO balance has been reduced by 5 `WCKD`, if we hold the DAO notes key,
+while our own balance has been increased by the same amount:
 
 ```
 $ ./drk dao balance MiladyMakerDAO
 $ ./drk wallet --balance
 ```
 
+## Generic proposal
+
+DAOs can vote on off-chain operations by creating what is known as generic
+proposals, meaning that no on-chain action is tied to it:
+
+```
+$ ./drk dao propose-generic MiladyMakerDAO 1
+$ ./drk dao proposal {PROPOSAL_BULLA} --mint-proposal > dao_mldy_generic_proposal_mint_tx
+$ ./drk broadcast < dao_mldy_generic_proposal_mint_tx
+```
+
+Vote on the proposal:
+
+```
+$ ./drk dao vote {PROPOSAL_BULLA} 1 > dao_mldy_generic_proposal_vote_tx
+$ ./drk broadcast < dao_mldy_generic_proposal_vote_tx
+```
+
+And execute it, after the vote period(1 block period) has passed:
+
+```
+$ ./drk dao exec {PROPOSAL_BULLA} > dao_mldy_generic_proposal_exec_tx
+$ ./drk broadcast < dao_mldy_generic_proposal_exec_tx
+```
+
+Or right away, since the early execution quorum has been reached:
+
+```
+$ ./drk dao exec --early {PROPOSAL_BULLA} > dao_mldy_generic_proposal_exec_tx
+$ ./drk broadcast < dao_mldy_generic_proposal_exec_tx
+```
+
+Executing the proposal will just confirm it on-chain, without any
+other actions taken.
+
 ## DAO->DAO
 
 Let's now try some more exotic operations!
@@ -192,8 +241,8 @@ $ ./drk dao balance MiladyMakerDAO
 Now we will create a second dao:
 
 ```
-$ ./drk dao create 20 10 0.67 WCKD > dao_wckd.dat
-$ ./drk dao import WickedDAO < dao_wckd.dat
+$ ./drk dao create 20 10 10 0.67 WCKD > dao_wckd.toml
+$ ./drk dao import WickedDAO < dao_wckd.toml
 $ ./drk dao mint WickedDAO > dao_wckd_mint_tx
 $ ./drk broadcast < dao_wckd_mint_tx
 ```
@@ -223,6 +272,13 @@ $ ./drk dao exec {PROPOSAL_BULLA} > dao_mldy_transfer_proposal_wckd_exec_tx
 $ ./drk broadcast < dao_mldy_transfer_proposal_wckd_exec_tx
 ```
 
+Or right away, since the early execution quorum has been reached:
+
+```
+$ ./drk dao exec --early {PROPOSAL_BULLA} > dao_mldy_transfer_proposal_wckd_exec_tx
+$ ./drk broadcast < dao_mldy_transfer_proposal_wckd_exec_tx
+```
+
 After the proposal has been executed on chain, we will see that
 the DAO governance token balance has been reduced by 6.9 `MLDY`,
 while the new DAO balance has been increased by the same amount: