Browse Source

drk: Initial DAO commands layout.

parazyd 3 years ago
parent
commit
d860174fc8
2 changed files with 203 additions and 2 deletions
  1. 40 0
      bin/drk/src/dao.rs
  2. 163 2
      bin/drk/src/main.rs

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

@@ -0,0 +1,40 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use darkfi_sdk::{
+    crypto::{SecretKey, TokenId},
+    pasta::pallas,
+};
+use darkfi_serial::{SerialDecodable, SerialEncodable};
+
+#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
+pub struct DaoParams {
+    /// The minimum amount of governance tokens needed to open a proposal
+    pub proposer_limit: u64,
+    /// Minimal threshold of participating total tokens needed for a proposal to pass
+    pub quorum: u64,
+    /// The ratio of winning/total votes needed for a proposal to pass
+    pub approval_ratio_base: u64,
+    pub approval_ratio_quot: u64,
+    /// DAO's governance token ID
+    pub gov_token_id: TokenId,
+    /// Secret key for the DAO
+    pub secret_key: SecretKey,
+    /// DAO bulla blind
+    pub bulla_blind: pallas::Base,
+}

+ 163 - 2
bin/drk/src/main.rs

@@ -25,14 +25,15 @@ use std::{
 
 use anyhow::{anyhow, Context, Result};
 use clap::{Parser, Subcommand};
-use darkfi::tx::Transaction;
+use darkfi::{tx::Transaction, zk::halo2::Field};
 use darkfi_money_contract::client::Coin;
 use darkfi_sdk::{
-    crypto::{PublicKey, TokenId},
+    crypto::{PublicKey, SecretKey, TokenId},
     pasta::{group::ff::PrimeField, pallas},
 };
 use darkfi_serial::{deserialize, serialize};
 use prettytable::{format, row, Table};
+use rand::rngs::OsRng;
 use serde_json::json;
 use simplelog::{ColorChoice, TermLogger, TerminalMode};
 use url::Url;
@@ -66,6 +67,10 @@ mod rpc_wallet;
 mod cli_util;
 use cli_util::{parse_token_pair, parse_value_pair};
 
+/// DAO aux functionality
+mod dao;
+use dao::DaoParams;
+
 #[derive(Parser)]
 #[command(about = cli_desc!())]
 struct Args {
@@ -173,6 +178,10 @@ enum Subcmd {
     /// find coins sent to us and fill our wallet with the necessary metadata.
     Subscribe,
 
+    /// DAO functionalities
+    #[command(subcommand)]
+    Dao(DaoSubcmd),
+
     /// Scan the blockchain and parse relevant transactions
     Scan {
         #[arg(long)]
@@ -212,6 +221,92 @@ enum OtcSubcmd {
     Sign,
 }
 
+#[derive(Subcommand)]
+enum DaoSubcmd {
+    /// Create DAO parameters
+    Create {
+        /// The minimum amount of governance tokens needed to open a proposal for this DAO
+        proposer_limit: u64,
+        /// Minimal threshold of participating total tokens needed for a proposal to pass
+        quorum: u64,
+        /// The ratio of winning votes/total votes needed for a proposal to pass (2 decimals),
+        approval_ratio: f64,
+        /// DAO's governance token ID
+        gov_token_id: String,
+    },
+
+    /// View DAO data from stdin
+    View,
+
+    /// List imported DAOs
+    List,
+
+    /// Import DAO data from stdin
+    Import {
+        /// Named identifier for the DAO
+        dao_name: String,
+    },
+
+    /// Mint a DAO on-chain
+    Mint {
+        /// Named identifier for the DAO
+        dao_name: String,
+    },
+
+    /// Create a proposal for a DAO
+    Propose {
+        /// Named identifier for the DAO
+        dao_name: String,
+
+        /// Pubkey to send tokens to with proposal success
+        recv_pubkey: String,
+
+        /// Amount to send from DAO with proposal success
+        amount: u64,
+
+        /// Token ID to send from DAO with proposal success
+        token_id: String,
+
+        serial: u64,
+    },
+
+    /// List DAO proposals
+    Proposals {
+        /// Named identifier for the DAO
+        dao_name: String,
+    },
+
+    /// View a DAO proposal data
+    Proposal {
+        /// Named identifier for the DAO
+        dao_name: String,
+
+        /// Proposal identifier
+        proposal: String,
+    },
+
+    /// Vote on a given proposal
+    Vote {
+        /// Named identifier for the DAO
+        dao_name: String,
+
+        /// Proposal identifier
+        proposal: String,
+
+        /// Vote
+        vote: String,
+    },
+
+    /// Execute a DAO proposal
+    Exec {
+        /// Named identifier for the DAO
+        dao_name: String,
+
+        /// Proposal identifier
+        proposal: String,
+    },
+}
+
 pub struct Drk {
     pub rpc_client: RpcClient,
 }
@@ -592,5 +687,71 @@ async fn main() -> Result<()> {
 
             Ok(())
         }
+
+        Subcmd::Dao(cmd) => match cmd {
+            DaoSubcmd::Create { proposer_limit, quorum, approval_ratio, gov_token_id } => {
+                if approval_ratio > 1.0 {
+                    eprintln!("Error: Approval ratio cannot be >1.0");
+                    exit(1);
+                }
+
+                let approval_ratio_quot = 100_u64;
+                let approval_ratio_base = (approval_ratio * approval_ratio_quot as f64) as u64;
+
+                let gov_token_id =
+                    TokenId::try_from(gov_token_id.as_str()).with_context(|| "Invalid Token ID")?;
+
+                let secret_key = SecretKey::random(&mut OsRng);
+                let bulla_blind = pallas::Base::random(&mut OsRng);
+
+                let dao_params = DaoParams {
+                    proposer_limit,
+                    quorum,
+                    approval_ratio_base,
+                    approval_ratio_quot,
+                    gov_token_id,
+                    secret_key,
+                    bulla_blind,
+                };
+
+                let encoded = bs58::encode(&serialize(&dao_params)).into_string();
+                println!("{}", encoded);
+                Ok(())
+            }
+
+            DaoSubcmd::View => {
+                let mut buf = String::new();
+                stdin().read_to_string(&mut buf)?;
+                let bytes = bs58::decode(&buf.trim()).into_vec()?;
+                let dao_params: DaoParams = deserialize(&bytes)?;
+                println!("DAO Parameters:");
+                println!("Proposer limit: {}", dao_params.proposer_limit);
+                println!("Quorum: {}", dao_params.quorum);
+                println!(
+                    "Approval ratio: {}",
+                    dao_params.approval_ratio_base as f64 / dao_params.approval_ratio_quot as f64
+                );
+                println!("Governance token ID: {}", dao_params.gov_token_id);
+                println!("Secret key: {}", dao_params.secret_key);
+                println!("Bulla blind: {:?}", dao_params.bulla_blind);
+                Ok(())
+            }
+
+            DaoSubcmd::Import { dao_name } => todo!(),
+
+            DaoSubcmd::List => todo!(),
+
+            DaoSubcmd::Mint { dao_name } => todo!(),
+
+            DaoSubcmd::Propose { dao_name, recv_pubkey, amount, token_id, serial } => todo!(),
+
+            DaoSubcmd::Proposals { dao_name } => todo!(),
+
+            DaoSubcmd::Proposal { dao_name, proposal } => todo!(),
+
+            DaoSubcmd::Vote { dao_name, proposal, vote } => todo!(),
+
+            DaoSubcmd::Exec { dao_name, proposal } => todo!(),
+        },
     }
 }