Browse Source

dao_demo: mint DAO treasury from command-line

lunar-mining 3 years ago
parent
commit
750987389f
5 changed files with 134 additions and 22 deletions
  1. 18 3
      bin/dao/dao-cli/src/main.rs
  2. 14 2
      bin/dao/dao-cli/src/rpc.rs
  3. 34 2
      bin/dao/daod/src/main.rs
  4. 48 14
      bin/dao/daod/src/rpc.rs
  5. 20 1
      bin/dao/daod/src/util.rs

+ 18 - 3
bin/dao/dao-cli/src/main.rs

@@ -22,7 +22,17 @@ pub enum CliDaoSubCommands {
         dao_approval_ratio_base: u64,
         dao_approval_ratio_base: u64,
     },
     },
     /// Mint tokens
     /// Mint tokens
-    Mint {},
+    Addr {},
+    Mint {
+        /// Number of treasury tokens to mint.
+        token_supply: u64,
+
+        /// Public key of the DAO treasury.
+        dao_addr: String,
+
+        /// DAO public identifier.
+        dao_bulla: String,
+    },
     /// Airdrop tokens
     /// Airdrop tokens
     Airdrop {},
     Airdrop {},
     /// Propose
     /// Propose
@@ -70,8 +80,13 @@ async fn start(options: CliDao) -> Result<()> {
             println!("Server replied: {}", &reply.to_string());
             println!("Server replied: {}", &reply.to_string());
             return Ok(())
             return Ok(())
         }
         }
-        Some(CliDaoSubCommands::Mint {}) => {
-            let reply = client.mint().await?;
+        Some(CliDaoSubCommands::Addr {}) => {
+            let reply = client.addr().await?;
+            println!("Server replied: {}", &reply.to_string());
+            return Ok(())
+        }
+        Some(CliDaoSubCommands::Mint { token_supply, dao_addr, dao_bulla }) => {
+            let reply = client.mint(token_supply, dao_addr, dao_bulla).await?;
             println!("Server replied: {}", &reply.to_string());
             println!("Server replied: {}", &reply.to_string());
             return Ok(())
             return Ok(())
         }
         }

+ 14 - 2
bin/dao/dao-cli/src/rpc.rs

@@ -28,8 +28,20 @@ impl Rpc {
 
 
     // --> {"jsonrpc": "2.0", "method": "mint", "params": [], "id": 42}
     // --> {"jsonrpc": "2.0", "method": "mint", "params": [], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": "minting tokens...", "id": 42}
     // <-- {"jsonrpc": "2.0", "result": "minting tokens...", "id": 42}
-    pub async fn mint(&self) -> Result<Value> {
-        let req = JsonRequest::new("mint", json!([]));
+    pub async fn addr(&self) -> Result<Value> {
+        let req = JsonRequest::new("get_dao_addr", json!([]));
+        self.client.request(req).await
+    }
+
+    // --> {"jsonrpc": "2.0", "method": "mint", "params": [], "id": 42}
+    // <-- {"jsonrpc": "2.0", "result": "minting tokens...", "id": 42}
+    pub async fn mint(
+        &self,
+        token_supply: u64,
+        dao_addr: String,
+        dao_bulla: String,
+    ) -> Result<Value> {
+        let req = JsonRequest::new("mint", json!([token_supply, dao_addr, dao_bulla]));
         self.client.request(req).await
         self.client.request(req).await
     }
     }
 
 

+ 34 - 2
bin/dao/daod/src/main.rs

@@ -65,7 +65,7 @@ impl Client {
     }
     }
 
 
     fn init(&mut self) -> Result<()> {
     fn init(&mut self) -> Result<()> {
-        // We use these to initialize the money state.
+        //We use these to initialize the money state.
         let faucet_signature_secret = SecretKey::random(&mut OsRng);
         let faucet_signature_secret = SecretKey::random(&mut OsRng);
         let faucet_signature_public = PublicKey::from_secret(faucet_signature_secret);
         let faucet_signature_public = PublicKey::from_secret(faucet_signature_secret);
 
 
@@ -184,6 +184,27 @@ impl Client {
         Ok(dao_bulla.0)
         Ok(dao_bulla.0)
     }
     }
 
 
+    pub fn mint_treasury(
+        &mut self,
+        token_id: pallas::Base,
+        token_supply: u64,
+        dao_bulla: pallas::Base,
+        recipient: PublicKey,
+    ) -> Result<u64> {
+        self.dao_wallet.track(&mut self.states);
+
+        let tx =
+            self.cashier.mint(*XDRK_ID, token_supply, dao_bulla, recipient, &self.zk_bins).unwrap();
+
+        self.validate(&tx).unwrap();
+
+        let own_coin = self.dao_wallet.balances(&mut self.states)?;
+
+        let balance = own_coin.note.value;
+
+        Ok(balance)
+    }
+
     // TODO: Change these into errors instead of expects.
     // TODO: Change these into errors instead of expects.
     fn validate(&mut self, tx: &Transaction) -> Result<()> {
     fn validate(&mut self, tx: &Transaction) -> Result<()> {
         let mut updates = vec![];
         let mut updates = vec![];
@@ -285,6 +306,17 @@ impl DaoWallet {
         Self { keypair, signature_secret, bulla_blind, leaf_position, params, vote_notes }
         Self { keypair, signature_secret, bulla_blind, leaf_position, params, vote_notes }
     }
     }
 
 
+    fn get_public_key(&self) -> PublicKey {
+        self.keypair.public
+    }
+
+    fn track(&self, states: &mut StateRegistry) -> Result<()> {
+        let state =
+            states.lookup_mut::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
+        state.wallet_cache.track(self.keypair.secret);
+        Ok(())
+    }
+
     // Mint the DAO bulla.
     // Mint the DAO bulla.
     fn mint_tx(
     fn mint_tx(
         &mut self,
         &mut self,
@@ -733,7 +765,7 @@ impl Cashier {
         PublicKey::from_secret(self.signature_secret)
         PublicKey::from_secret(self.signature_secret)
     }
     }
 
 
-    fn mint_treasury(
+    fn mint(
         &mut self,
         &mut self,
         token_id: pallas::Base,
         token_id: pallas::Base,
         token_supply: u64,
         token_supply: u64,

+ 48 - 14
bin/dao/daod/src/rpc.rs

@@ -3,16 +3,23 @@ use std::sync::Arc;
 use async_std::sync::Mutex;
 use async_std::sync::Mutex;
 use async_trait::async_trait;
 use async_trait::async_trait;
 use log::debug;
 use log::debug;
-use pasta_curves::group::ff::PrimeField;
+use pasta_curves::{group::ff::PrimeField, pallas};
+use std::str::FromStr;
 
 
 use serde_json::{json, Value};
 use serde_json::{json, Value};
 
 
-use darkfi::rpc::{
-    jsonrpc::{ErrorCode::*, JsonError, JsonRequest, JsonResponse, JsonResult},
-    server::RequestHandler,
+use darkfi::{
+    crypto::keypair::PublicKey,
+    rpc::{
+        jsonrpc::{ErrorCode::*, JsonError, JsonRequest, JsonResponse, JsonResult},
+        server::RequestHandler,
+    },
 };
 };
 
 
-use crate::{util::GDRK_ID, Client};
+use crate::{
+    util::{parse_b58, GDRK_ID, XDRK_ID},
+    Client,
+};
 
 
 pub struct JsonRpcInterface {
 pub struct JsonRpcInterface {
     client: Arc<Mutex<Client>>,
     client: Arc<Mutex<Client>>,
@@ -31,6 +38,7 @@ impl RequestHandler for JsonRpcInterface {
 
 
         match req.method.as_str() {
         match req.method.as_str() {
             Some("create") => return self.create_dao(req.id, params).await,
             Some("create") => return self.create_dao(req.id, params).await,
+            Some("get_dao_addr") => return self.get_dao_addr(req.id, params).await,
             Some("mint") => return self.mint_treasury(req.id, params).await,
             Some("mint") => return self.mint_treasury(req.id, params).await,
             Some("keygen") => return self.keygen(req.id, params).await,
             Some("keygen") => return self.keygen(req.id, params).await,
             Some("airdrop") => return self.airdrop_tokens(req.id, params).await,
             Some("airdrop") => return self.airdrop_tokens(req.id, params).await,
@@ -68,22 +76,48 @@ impl JsonRpcInterface {
                 *GDRK_ID,
                 *GDRK_ID,
             )
             )
             .unwrap();
             .unwrap();
-        // TODO: return dao_bulla to command line
-        // Encode as base58.
 
 
         let bulla: String = bs58::encode(dao_bulla.to_repr()).into_string();
         let bulla: String = bs58::encode(dao_bulla.to_repr()).into_string();
         JsonResponse::new(json!(bulla), id).into()
         JsonResponse::new(json!(bulla), id).into()
     }
     }
+
+    // --> {"method": "get_dao_addr", "params": []}
+    // <-- {"result": "getting dao public addr..."}
+    async fn get_dao_addr(&self, id: Value, params: &[Value]) -> JsonResult {
+        let mut client = self.client.lock().await;
+        let pubkey = client.dao_wallet.get_public_key();
+        let addr: String = bs58::encode(pubkey.to_bytes()).into_string();
+
+        JsonResponse::new(json!(addr), id).into()
+    }
+
     // --> {"method": "mint_treasury", "params": []}
     // --> {"method": "mint_treasury", "params": []}
     // <-- {"result": "minting treasury..."}
     // <-- {"result": "minting treasury..."}
-    async fn mint_treasury(&self, id: Value, _params: &[Value]) -> JsonResult {
-        let mut client = self.client.lock().await;
-        let zk_bins = &client.zk_bins;
+    async fn mint_treasury(&self, id: Value, params: &[Value]) -> JsonResult {
         // TODO: pass DAO params + zk_bins into mint_treasury
         // TODO: pass DAO params + zk_bins into mint_treasury
-        //let tx = client.cashier.mint_treasury();
-        // client.client.validate(tx);
-        // client.client.wallet.balances();
-        JsonResponse::new(json!("tokens minted"), id).into()
+        // TODO: error handling
+        let mut client = self.client.lock().await;
+
+        let token_supply = params[0].as_u64().unwrap();
+        let addr = params[1].as_str().unwrap();
+        let bulla = params[2].as_str().unwrap();
+
+        let dao_bulla = parse_b58(bulla).unwrap();
+
+        let dao_addr = PublicKey::from_str(addr).unwrap();
+        //match PublicKey::from_str(addr) {
+        //    Ok(addr) => {
+        //        debug!(target: "daod::rpc", "Decoded correctly: {:?}", addr)
+        //    }
+        //    Err(e) => {
+        //        debug!(target: "daod::rpc", "Decoded incorrectly: {}", e)
+        //    }
+        //}
+
+        let balance = client.mint_treasury(*XDRK_ID, token_supply, dao_bulla, dao_addr).unwrap();
+
+        JsonResponse::new(json!(balance), id).into()
+        //JsonResponse::new(json!("test"), id).into()
     }
     }
 
 
     // Create a new wallet for governance tokens.
     // Create a new wallet for governance tokens.

+ 20 - 1
bin/dao/daod/src/util.rs

@@ -18,9 +18,23 @@ use darkfi::{
     util::serial::Encodable,
     util::serial::Encodable,
     zk::{vm::ZkCircuit, vm_stack::empty_witnesses},
     zk::{vm::ZkCircuit, vm_stack::empty_witnesses},
     zkas::decoder::ZkBinary,
     zkas::decoder::ZkBinary,
+    Error,
 };
 };
 
 
-// TODO: base58 encoding/ decoding
+/// Parse pallas::Base from a base58-encoded string
+pub fn parse_b58(s: &str) -> std::result::Result<pallas::Base, darkfi::Error> {
+    let bytes = bs58::decode(s).into_vec()?;
+    if bytes.len() != 32 {
+        return Err(Error::ParseFailed("Failed parsing DrkTokenId from base58 string"))
+    }
+
+    let ret = pallas::Base::from_repr(bytes.try_into().unwrap());
+    if ret.is_some().unwrap_u8() == 1 {
+        return Ok(ret.unwrap())
+    }
+
+    Err(Error::ParseFailed("Failed parsing DrkTokenId from base58 string"))
+}
 
 
 lazy_static! {
 lazy_static! {
     pub static ref XDRK_ID: pallas::Base = pallas::Base::random(&mut OsRng);
     pub static ref XDRK_ID: pallas::Base = pallas::Base::random(&mut OsRng);
@@ -40,22 +54,27 @@ impl std::hash::Hash for HashableBase {
     }
     }
 }
 }
 
 
+#[derive(Clone)]
 pub struct ZkBinaryContractInfo {
 pub struct ZkBinaryContractInfo {
     pub k_param: u32,
     pub k_param: u32,
     pub bincode: ZkBinary,
     pub bincode: ZkBinary,
     pub proving_key: ProvingKey,
     pub proving_key: ProvingKey,
     pub verifying_key: VerifyingKey,
     pub verifying_key: VerifyingKey,
 }
 }
+
+#[derive(Clone)]
 pub struct ZkNativeContractInfo {
 pub struct ZkNativeContractInfo {
     pub proving_key: ProvingKey,
     pub proving_key: ProvingKey,
     pub verifying_key: VerifyingKey,
     pub verifying_key: VerifyingKey,
 }
 }
 
 
+#[derive(Clone)]
 pub enum ZkContractInfo {
 pub enum ZkContractInfo {
     Binary(ZkBinaryContractInfo),
     Binary(ZkBinaryContractInfo),
     Native(ZkNativeContractInfo),
     Native(ZkNativeContractInfo),
 }
 }
 
 
+#[derive(Clone)]
 pub struct ZkContractTable {
 pub struct ZkContractTable {
     // Key will be a hash of zk binary contract on chain
     // Key will be a hash of zk binary contract on chain
     table: HashMap<String, ZkContractInfo>,
     table: HashMap<String, ZkContractInfo>,