|
|
@@ -2,8 +2,8 @@ use async_std::sync::Mutex;
|
|
|
use std::{str::FromStr, sync::Arc};
|
|
|
|
|
|
use async_trait::async_trait;
|
|
|
-use log::debug;
|
|
|
-use pasta_curves::{group::ff::PrimeField, pallas};
|
|
|
+use log::{debug, error};
|
|
|
+use pasta_curves::group::ff::PrimeField;
|
|
|
use rand::rngs::OsRng;
|
|
|
use serde_json::{json, Value};
|
|
|
|
|
|
@@ -17,6 +17,7 @@ use darkfi::{
|
|
|
|
|
|
use crate::{
|
|
|
contract::money_contract::state::OwnCoin,
|
|
|
+ error::{server_error, RpcError},
|
|
|
util::{parse_b58, DRK_ID, GOV_ID},
|
|
|
Client, MoneyWallet,
|
|
|
};
|
|
|
@@ -64,25 +65,48 @@ impl JsonRpcInterface {
|
|
|
// --> {"method": "create", "params": []}
|
|
|
// <-- {"result": "creating dao..."}
|
|
|
async fn create_dao(&self, id: Value, params: &[Value]) -> JsonResult {
|
|
|
- let dao_proposer_limit = params[0].as_u64().unwrap();
|
|
|
- let dao_quorum = params[1].as_u64().unwrap();
|
|
|
- let dao_approval_ratio_quot = params[2].as_u64().unwrap();
|
|
|
- let dao_approval_ratio_base = params[3].as_u64().unwrap();
|
|
|
+ let dao_proposer_limit = params[0].as_u64();
|
|
|
+ if dao_proposer_limit.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let dao_proposer_limit = dao_proposer_limit.unwrap();
|
|
|
+
|
|
|
+ let dao_quorum = params[1].as_u64();
|
|
|
+ if dao_quorum.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let dao_quorum = dao_quorum.unwrap();
|
|
|
+
|
|
|
+ let dao_approval_ratio_quot = params[2].as_u64();
|
|
|
+ if dao_approval_ratio_quot.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let dao_approval_ratio_quot = dao_approval_ratio_quot.unwrap();
|
|
|
+
|
|
|
+ let dao_approval_ratio_base = params[3].as_u64();
|
|
|
+ if dao_approval_ratio_base.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let dao_approval_ratio_base = dao_approval_ratio_base.unwrap();
|
|
|
|
|
|
let mut client = self.client.lock().await;
|
|
|
|
|
|
- let dao_bulla = client
|
|
|
- .create_dao(
|
|
|
- dao_proposer_limit,
|
|
|
- dao_quorum,
|
|
|
- dao_approval_ratio_quot,
|
|
|
- dao_approval_ratio_base,
|
|
|
- *GOV_ID,
|
|
|
- )
|
|
|
- .unwrap();
|
|
|
-
|
|
|
- let bulla: String = bs58::encode(dao_bulla.to_repr()).into_string();
|
|
|
- JsonResponse::new(json!(bulla), id).into()
|
|
|
+ match client.create_dao(
|
|
|
+ dao_proposer_limit,
|
|
|
+ dao_quorum,
|
|
|
+ dao_approval_ratio_quot,
|
|
|
+ dao_approval_ratio_base,
|
|
|
+ *GOV_ID,
|
|
|
+ ) {
|
|
|
+ Ok(bulla) => {
|
|
|
+ let bulla: String = bs58::encode(bulla.to_repr()).into_string();
|
|
|
+ JsonResponse::new(json!(bulla), id).into()
|
|
|
+ }
|
|
|
+ Err(e) => {
|
|
|
+ error!("Failed to create DAO: {}", e);
|
|
|
+ return server_error(RpcError::Create, id)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// --> {"method": "get_dao_addr", "params": []}
|
|
|
@@ -149,26 +173,60 @@ impl JsonRpcInterface {
|
|
|
|
|
|
async fn user_balance(&self, id: Value, params: &[Value]) -> JsonResult {
|
|
|
let client = self.client.lock().await;
|
|
|
- let nym = params[0].as_str().unwrap();
|
|
|
-
|
|
|
- let pubkey = PublicKey::from_str(nym).unwrap();
|
|
|
-
|
|
|
- let wallet = client.money_wallets.get(&pubkey).unwrap();
|
|
|
- let balance = wallet.balances().unwrap();
|
|
|
- JsonResponse::new(json!(balance), id).into()
|
|
|
+ let nym = params[0].as_str();
|
|
|
+ if nym.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let nym = nym.unwrap();
|
|
|
+
|
|
|
+ match PublicKey::from_str(nym) {
|
|
|
+ Ok(key) => match client.money_wallets.get(&key) {
|
|
|
+ Some(wallet) => {
|
|
|
+ let balance = wallet.balances().unwrap();
|
|
|
+ JsonResponse::new(json!(balance), id).into()
|
|
|
+ }
|
|
|
+ None => {
|
|
|
+ error!("No wallet found for provided key");
|
|
|
+ return server_error(RpcError::Balance, id)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ Err(_) => {
|
|
|
+ error!("Could not parse PublicKey from string");
|
|
|
+ return server_error(RpcError::Parse, id)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
// --> {"method": "mint_treasury", "params": []}
|
|
|
// <-- {"result": "minting treasury..."}
|
|
|
async fn mint_treasury(&self, id: Value, params: &[Value]) -> JsonResult {
|
|
|
let mut client = self.client.lock().await;
|
|
|
|
|
|
- let token_supply = params[0].as_u64().unwrap();
|
|
|
- let addr = params[1].as_str().unwrap();
|
|
|
- let dao_addr = PublicKey::from_str(addr).unwrap();
|
|
|
-
|
|
|
- client.mint_treasury(*DRK_ID, token_supply, dao_addr).unwrap();
|
|
|
+ let token_supply = params[0].as_u64();
|
|
|
+ if token_supply.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let token_supply = token_supply.unwrap();
|
|
|
|
|
|
- JsonResponse::new(json!("DAO treasury minted successfully."), id).into()
|
|
|
+ let addr = params[1].as_str();
|
|
|
+ if addr.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let addr = addr.unwrap();
|
|
|
+
|
|
|
+ match PublicKey::from_str(addr) {
|
|
|
+ Ok(dao_addr) => match client.mint_treasury(*DRK_ID, token_supply, dao_addr) {
|
|
|
+ Ok(_) => JsonResponse::new(json!("DAO treasury minted successfully."), id).into(),
|
|
|
+ Err(e) => {
|
|
|
+ error!("Failed to mint treasury: {}", e);
|
|
|
+ return server_error(RpcError::Mint, id)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ Err(_) => {
|
|
|
+ error!("Failed to parse PublicKey from String");
|
|
|
+ return server_error(RpcError::Parse, id)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Create a new wallet for governance tokens.
|
|
|
@@ -180,15 +238,18 @@ impl JsonRpcInterface {
|
|
|
let signature_secret = SecretKey::random(&mut OsRng);
|
|
|
let own_coins: Vec<(OwnCoin, bool)> = Vec::new();
|
|
|
let money_wallet = MoneyWallet { keypair, signature_secret, own_coins };
|
|
|
- money_wallet.track(&mut client.states).unwrap();
|
|
|
|
|
|
- client.money_wallets.insert(keypair.public, money_wallet);
|
|
|
-
|
|
|
- // let wallet = client.money_wallets.get(&nym).unwrap();
|
|
|
- // let pubkey = wallet.get_public_key();
|
|
|
-
|
|
|
- let addr: String = bs58::encode(keypair.public.to_bytes()).into_string();
|
|
|
- JsonResponse::new(json!(addr), id).into()
|
|
|
+ match money_wallet.track(&mut client.states) {
|
|
|
+ Ok(_) => {
|
|
|
+ client.money_wallets.insert(keypair.public, money_wallet);
|
|
|
+ let addr: String = bs58::encode(keypair.public.to_bytes()).into_string();
|
|
|
+ JsonResponse::new(json!(addr), id).into()
|
|
|
+ }
|
|
|
+ Err(e) => {
|
|
|
+ error!("Failed to airdrop tokens: {}", e);
|
|
|
+ return server_error(RpcError::Keygen, id)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// --> {"method": "airdrop_tokens", "params": []}
|
|
|
@@ -197,62 +258,145 @@ impl JsonRpcInterface {
|
|
|
let mut client = self.client.lock().await;
|
|
|
// let zk_bins = &client.zk_bins;
|
|
|
|
|
|
- let addr = PublicKey::from_str(params[0].as_str().unwrap()).unwrap();
|
|
|
- let value = params[1].as_u64().unwrap();
|
|
|
-
|
|
|
- client.airdrop_user(value, *GOV_ID, addr).unwrap();
|
|
|
+ let addr = params[0].as_str();
|
|
|
+ if addr.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let addr = addr.unwrap();
|
|
|
|
|
|
- JsonResponse::new(json!("Tokens airdropped successfully."), id).into()
|
|
|
+ let value = params[1].as_u64();
|
|
|
+ if value.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let value = value.unwrap();
|
|
|
+
|
|
|
+ match PublicKey::from_str(addr) {
|
|
|
+ Ok(key) => match client.airdrop_user(value, *GOV_ID, key) {
|
|
|
+ Ok(_) => JsonResponse::new(json!("Tokens airdropped successfully."), id).into(),
|
|
|
+ Err(e) => {
|
|
|
+ error!("Failed to airdrop tokens: {}", e);
|
|
|
+ return server_error(RpcError::Airdrop, id)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ Err(_) => {
|
|
|
+ error!("Failed parsing PublicKey from String");
|
|
|
+ return server_error(RpcError::Parse, id)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
// --> {"method": "create_proposal", "params": []}
|
|
|
// <-- {"result": "creating proposal..."}
|
|
|
async fn create_proposal(&self, id: Value, params: &[Value]) -> JsonResult {
|
|
|
let mut client = self.client.lock().await;
|
|
|
|
|
|
- let sender = params[0].as_str().unwrap();
|
|
|
- let recipient = params[1].as_str().unwrap();
|
|
|
- let amount = params[2].as_u64().unwrap();
|
|
|
+ if params.is_empty() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
|
|
|
- let recv_addr = PublicKey::from_str(recipient).unwrap();
|
|
|
- let sndr_addr = PublicKey::from_str(sender).unwrap();
|
|
|
+ let sender = params[0].as_str();
|
|
|
+ if sender.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let sender = sender.unwrap();
|
|
|
|
|
|
- let proposal_bulla = client.propose(recv_addr, *DRK_ID, amount, sndr_addr).unwrap();
|
|
|
- let bulla: String = bs58::encode(proposal_bulla.to_repr()).into_string();
|
|
|
+ let recipient = params[1].as_str();
|
|
|
+ if recipient.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let recipient = recipient.unwrap();
|
|
|
|
|
|
- JsonResponse::new(json!(bulla), id).into()
|
|
|
+ let amount = params[2].as_u64();
|
|
|
+ if amount.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let amount = amount.unwrap();
|
|
|
+
|
|
|
+ let recv_addr = PublicKey::from_str(recipient);
|
|
|
+ if recv_addr.is_err() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let recv_addr = recv_addr.unwrap();
|
|
|
+
|
|
|
+ let sndr_addr = PublicKey::from_str(sender);
|
|
|
+ if sndr_addr.is_err() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let sndr_addr = sndr_addr.unwrap();
|
|
|
+
|
|
|
+ match client.propose(recv_addr, *DRK_ID, amount, sndr_addr) {
|
|
|
+ Ok(bulla) => {
|
|
|
+ let bulla: String = bs58::encode(bulla.to_repr()).into_string();
|
|
|
+
|
|
|
+ JsonResponse::new(json!(bulla), id).into()
|
|
|
+ }
|
|
|
+ Err(e) => {
|
|
|
+ error!("Failed to make Proposal: {}", e);
|
|
|
+ return server_error(RpcError::Propose, id)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
// --> {"method": "vote", "params": []}
|
|
|
// <-- {"result": "voting..."}
|
|
|
async fn vote(&self, id: Value, params: &[Value]) -> JsonResult {
|
|
|
let mut client = self.client.lock().await;
|
|
|
+ let mut vote_bool = true;
|
|
|
|
|
|
- let addr = params[0].as_str().unwrap();
|
|
|
- let vote_str = params[1].as_str().unwrap();
|
|
|
-
|
|
|
- let addr = PublicKey::from_str(addr).unwrap();
|
|
|
+ let addr = params[0].as_str();
|
|
|
+ if addr.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let addr = addr.unwrap();
|
|
|
|
|
|
- // This would be cleaner as a match statement,
|
|
|
- // but we need to sort out error handling first.
|
|
|
- let mut vote_bool = true;
|
|
|
+ let vote_str = params[1].as_str();
|
|
|
+ if vote_str.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let vote_str = vote_str.unwrap();
|
|
|
|
|
|
- if vote_str == "yes" {}
|
|
|
- if vote_str == "no" {
|
|
|
- vote_bool = false
|
|
|
+ match vote_str {
|
|
|
+ "yes" => {}
|
|
|
+ "no" => vote_bool = false,
|
|
|
+ _ => return JsonError::new(InvalidParams, None, id).into(),
|
|
|
}
|
|
|
|
|
|
- client.cast_vote(addr, vote_bool).unwrap();
|
|
|
- JsonResponse::new(json!("Vote cast successfully."), id).into()
|
|
|
+ match PublicKey::from_str(addr) {
|
|
|
+ Ok(key) => match client.cast_vote(key, vote_bool) {
|
|
|
+ Ok(_) => JsonResponse::new(json!("Vote cast successfully."), id).into(),
|
|
|
+ Err(e) => {
|
|
|
+ error!("Failed casting vote: {}", e);
|
|
|
+ return server_error(RpcError::Vote, id)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ Err(_) => {
|
|
|
+ error!("Failed parsing PublicKey from String");
|
|
|
+ return server_error(RpcError::Parse, id)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
// --> {"method": "execute", "params": []}
|
|
|
// <-- {"result": "executing..."}
|
|
|
async fn execute(&self, id: Value, params: &[Value]) -> JsonResult {
|
|
|
let mut client = self.client.lock().await;
|
|
|
|
|
|
- let bulla_str = params[0].as_str().unwrap();
|
|
|
- let bulla: pallas::Base = parse_b58(bulla_str).unwrap();
|
|
|
-
|
|
|
- client.exec_proposal(bulla).unwrap();
|
|
|
-
|
|
|
- JsonResponse::new(json!("Proposal executed successfully."), id).into()
|
|
|
+ let bulla_str = params[0].as_str();
|
|
|
+ if bulla_str.is_none() {
|
|
|
+ return JsonError::new(InvalidParams, None, id).into()
|
|
|
+ }
|
|
|
+ let bulla_str = bulla_str.unwrap();
|
|
|
+
|
|
|
+ let bulla = parse_b58(bulla_str);
|
|
|
+ match bulla {
|
|
|
+ Ok(bulla) => match client.exec_proposal(bulla) {
|
|
|
+ Ok(_) => JsonResponse::new(json!("Proposal executed successfully."), id).into(),
|
|
|
+ Err(e) => {
|
|
|
+ error!("Failed executing proposal: {}", e);
|
|
|
+ return server_error(RpcError::Exec, id)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ Err(e) => {
|
|
|
+ error!("Failed parsing bulla: {}", e);
|
|
|
+ return server_error(RpcError::Parse, id)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|