فهرست منبع

drk: DAO Propose stub.

parazyd 3 سال پیش
والد
کامیت
8be7625b18
2فایلهای تغییر یافته به همراه92 افزوده شده و 5 حذف شده
  1. 26 4
      bin/drk/src/main.rs
  2. 66 1
      bin/drk/src/rpc_dao.rs

+ 26 - 4
bin/drk/src/main.rs

@@ -25,7 +25,7 @@ use std::{
 
 use anyhow::{anyhow, Context, Result};
 use clap::{Parser, Subcommand};
-use darkfi::{tx::Transaction, zk::halo2::Field};
+use darkfi::{tx::Transaction, util::parse::decode_base10, zk::halo2::Field};
 use darkfi_money_contract::client::Coin;
 use darkfi_sdk::{
     crypto::{PublicKey, SecretKey, TokenId},
@@ -271,10 +271,10 @@ enum DaoSubcmd {
         dao_id: u64,
 
         /// Pubkey to send tokens to with proposal success
-        recv_pubkey: String,
+        recipient: String,
 
         /// Amount to send from DAO with proposal success
-        amount: u64,
+        amount: String,
 
         /// Token ID to send from DAO with proposal success
         token_id: String,
@@ -792,7 +792,29 @@ async fn main() -> Result<()> {
                 Ok(())
             }
 
-            DaoSubcmd::Propose { dao_id, recv_pubkey, amount, token_id, serial } => todo!(),
+            DaoSubcmd::Propose { dao_id, recipient, amount, token_id, serial } => {
+                let _ = f64::from_str(&amount).with_context(|| "Invalid amount")?;
+                let amount = decode_base10(&amount, 8, true)?;
+
+                let rcpt = PublicKey::from_str(&recipient).with_context(|| "Invalid recipient")?;
+                let token_id =
+                    TokenId::try_from(token_id.as_str()).with_context(|| "Invalid Token ID")?;
+                let serial = serial.into(); // <-- TODO: Should this be pallas::Base?
+
+                let rpc_client = RpcClient::new(args.endpoint.clone())
+                    .await
+                    .with_context(|| "Could not connect to darkfid RPC endpoint")?;
+
+                let drk = Drk { rpc_client };
+
+                let tx = drk
+                    .dao_propose(dao_id, rcpt, amount, token_id, serial)
+                    .await
+                    .with_context(|| "Failed to create DAO proposal")?;
+
+                println!("{}", bs58::encode(&serialize(&tx)).into_string());
+                Ok(())
+            }
 
             DaoSubcmd::Proposals { dao_id } => todo!(),
 

+ 66 - 1
bin/drk/src/rpc_dao.rs

@@ -20,6 +20,7 @@ use anyhow::{anyhow, Result};
 use darkfi::{
     rpc::jsonrpc::JsonRequest,
     tx::Transaction,
+    util::parse::encode_base10,
     wallet::walletdb::QueryType,
     zk::{empty_witnesses, ProvingKey, ZkCircuit},
     zkas::ZkBinary,
@@ -33,8 +34,10 @@ use darkfi_dao_contract::{
     },
     DaoFunction, DAO_CONTRACT_ZKAS_DAO_MINT_NS,
 };
+use darkfi_money_contract::client::OwnCoin;
 use darkfi_sdk::{
-    crypto::{PublicKey, DAO_CONTRACT_ID},
+    crypto::{PublicKey, TokenId, DAO_CONTRACT_ID},
+    pasta::pallas,
     ContractCall,
 };
 use darkfi_serial::{deserialize, serialize, Encodable};
@@ -193,4 +196,66 @@ impl Drk {
 
         Ok(tx)
     }
+
+    /// Create a DAO proposal
+    pub async fn dao_propose(
+        &self,
+        dao_id: u64,
+        rcpt: PublicKey,
+        amount: u64,
+        token_id: TokenId,
+        serial: pallas::Base,
+    ) -> Result<Transaction> {
+        let daos = self.wallet_get_daos().await?;
+        let Some(dao) = daos.get(dao_id as usize - 1) else {
+            return Err(anyhow!("DAO not found in wallet"))
+        };
+
+        let bulla = dao.bulla();
+        let owncoins = self.wallet_coins(false).await?;
+        let mut dao_owncoins: Vec<OwnCoin> = owncoins.iter().map(|x| x.0.clone()).collect();
+        dao_owncoins.retain(|x| {
+            x.note.token_id == token_id &&
+                x.note.spend_hook == DAO_CONTRACT_ID.inner() &&
+                x.note.user_data == bulla.inner()
+        });
+
+        if dao_owncoins.is_empty() {
+            return Err(anyhow!("Did not find any {} coins owned by this DAO", token_id))
+        }
+
+        let mut dao_balance = 0;
+        for coin in dao_owncoins.iter() {
+            dao_balance += coin.note.value;
+        }
+
+        if dao_balance < amount {
+            return Err(anyhow!(
+                "Not enough balance for token ID: {}, found: {}",
+                token_id,
+                encode_base10(dao_balance, 8)
+            ))
+        }
+
+        let mut user_owncoins: Vec<OwnCoin> = owncoins.iter().map(|x| x.0.clone()).collect();
+        user_owncoins.retain(|x| x.note.token_id == dao.gov_token_id);
+
+        if user_owncoins.is_empty() {
+            return Err(anyhow!("Did not find any governance {} coins in wallet", dao.gov_token_id))
+        }
+
+        let mut user_balance = 0;
+        for coin in user_owncoins.iter() {
+            user_balance += coin.note.value;
+        }
+
+        if user_balance < dao.proposer_limit {
+            return Err(anyhow!(
+                "Not enough governance token {} balance found to create proposal",
+                dao.gov_token_id
+            ))
+        }
+
+        todo!();
+    }
 }