rpc.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{str::FromStr, sync::Arc};
  19. use async_std::sync::Mutex;
  20. use async_trait::async_trait;
  21. use darkfi_sdk::{
  22. crypto::{Keypair, PublicKey, SecretKey},
  23. pasta::group::ff::PrimeField,
  24. };
  25. use log::{debug, error};
  26. use rand::rngs::OsRng;
  27. use serde_json::{json, Value};
  28. use darkfi::rpc::{
  29. jsonrpc::{ErrorCode::*, JsonError, JsonRequest, JsonResponse, JsonResult},
  30. server::RequestHandler,
  31. };
  32. use crate::{
  33. contract::money::state::OwnCoin,
  34. error::{server_error, RpcError},
  35. util::{parse_b58, DRK_ID, GOV_ID},
  36. Client, MoneyWallet,
  37. };
  38. pub struct JsonRpcInterface {
  39. client: Arc<Mutex<Client>>,
  40. }
  41. #[async_trait]
  42. impl RequestHandler for JsonRpcInterface {
  43. async fn handle_request(&self, req: JsonRequest) -> JsonResult {
  44. if !req.params.is_array() {
  45. return JsonError::new(InvalidParams, None, req.id).into()
  46. }
  47. let params = req.params.as_array().unwrap();
  48. debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());
  49. match req.method.as_str() {
  50. Some("create") => return self.create_dao(req.id, params).await,
  51. Some("get_dao_addr") => return self.get_dao_addr(req.id, params).await,
  52. Some("get_votes") => return self.get_votes(req.id, params).await,
  53. Some("get_proposals") => return self.get_proposals(req.id, params).await,
  54. Some("dao_balance") => return self.dao_balance(req.id, params).await,
  55. Some("dao_bulla") => return self.dao_bulla(req.id, params).await,
  56. Some("user_balance") => return self.user_balance(req.id, params).await,
  57. Some("mint") => return self.mint_treasury(req.id, params).await,
  58. Some("keygen") => return self.keygen(req.id, params).await,
  59. Some("airdrop") => return self.airdrop_tokens(req.id, params).await,
  60. Some("propose") => return self.create_proposal(req.id, params).await,
  61. Some("vote") => return self.vote(req.id, params).await,
  62. Some("exec") => return self.execute(req.id, params).await,
  63. Some(_) | None => return JsonError::new(MethodNotFound, None, req.id).into(),
  64. }
  65. }
  66. }
  67. impl JsonRpcInterface {
  68. pub fn new(client: Client) -> Self {
  69. let client = Arc::new(Mutex::new(client));
  70. Self { client }
  71. }
  72. // --> {"method": "create", "params": []}
  73. // <-- {"result": "creating dao..."}
  74. async fn create_dao(&self, id: Value, params: &[Value]) -> JsonResult {
  75. let dao_proposer_limit = params[0].as_u64();
  76. if dao_proposer_limit.is_none() {
  77. return JsonError::new(InvalidParams, None, id).into()
  78. }
  79. let dao_proposer_limit = dao_proposer_limit.unwrap();
  80. let dao_quorum = params[1].as_u64();
  81. if dao_quorum.is_none() {
  82. return JsonError::new(InvalidParams, None, id).into()
  83. }
  84. let dao_quorum = dao_quorum.unwrap();
  85. let dao_approval_ratio_quot = params[2].as_u64();
  86. if dao_approval_ratio_quot.is_none() {
  87. return JsonError::new(InvalidParams, None, id).into()
  88. }
  89. let dao_approval_ratio_quot = dao_approval_ratio_quot.unwrap();
  90. let dao_approval_ratio_base = params[3].as_u64();
  91. if dao_approval_ratio_base.is_none() {
  92. return JsonError::new(InvalidParams, None, id).into()
  93. }
  94. let dao_approval_ratio_base = dao_approval_ratio_base.unwrap();
  95. let mut client = self.client.lock().await;
  96. match client.create_dao(
  97. dao_proposer_limit,
  98. dao_quorum,
  99. dao_approval_ratio_quot,
  100. dao_approval_ratio_base,
  101. *GOV_ID,
  102. ) {
  103. Ok(bulla) => {
  104. let bulla: String = bs58::encode(bulla.to_repr()).into_string();
  105. JsonResponse::new(json!(bulla), id).into()
  106. }
  107. Err(e) => {
  108. error!("Failed to create DAO: {}", e);
  109. server_error(RpcError::Create, id)
  110. }
  111. }
  112. }
  113. // --> {"method": "get_dao_addr", "params": []}
  114. // <-- {"result": "getting dao public addr..."}
  115. async fn get_dao_addr(&self, id: Value, _params: &[Value]) -> JsonResult {
  116. let client = self.client.lock().await;
  117. let pubkey = client.dao_wallet.get_public_key();
  118. //let addr: String = bs58::encode(pubkey.to_bytes()).into_string();
  119. let addr: String = pubkey.to_string();
  120. JsonResponse::new(json!(addr), id).into()
  121. }
  122. // --> {"method": "get_dao_addr", "params": []}
  123. // <-- {"result": "getting dao public addr..."}
  124. async fn get_votes(&self, id: Value, _params: &[Value]) -> JsonResult {
  125. let client = self.client.lock().await;
  126. let vote_notes = client.dao_wallet.get_votes();
  127. let mut vote_data = vec![];
  128. for note in vote_notes {
  129. let vote_option = note.vote.vote_option;
  130. let vote_value = note.vote_value;
  131. vote_data.push((vote_option, vote_value));
  132. }
  133. JsonResponse::new(json!(vote_data), id).into()
  134. }
  135. // --> {"method": "get_dao_addr", "params": []}
  136. // <-- {"result": "getting dao public addr..."}
  137. async fn get_proposals(&self, id: Value, _params: &[Value]) -> JsonResult {
  138. let client = self.client.lock().await;
  139. let proposals = client.dao_wallet.get_proposals();
  140. let mut proposal_data = vec![];
  141. for proposal in proposals {
  142. let dest = proposal.dest;
  143. let amount = proposal.amount;
  144. let token_id = format!("{}", proposal.token_id);
  145. //let dest: String = bs58::encode(dest.to_bytes()).into_string();
  146. let dest = dest.to_string();
  147. proposal_data.push((dest, amount, token_id));
  148. }
  149. JsonResponse::new(json!(proposal_data), id).into()
  150. }
  151. async fn dao_balance(&self, id: Value, _params: &[Value]) -> JsonResult {
  152. let client = self.client.lock().await;
  153. let balance = client.dao_wallet.balances().unwrap();
  154. JsonResponse::new(json!(balance), id).into()
  155. }
  156. async fn dao_bulla(&self, id: Value, _params: &[Value]) -> JsonResult {
  157. let client = self.client.lock().await;
  158. let dao_bullas = client.dao_wallet.bullas.clone();
  159. let mut bulla_vec = Vec::new();
  160. for bulla in dao_bullas {
  161. let dao_bulla: String = bs58::encode(bulla.0.to_repr()).into_string();
  162. bulla_vec.push(dao_bulla);
  163. }
  164. JsonResponse::new(json!(bulla_vec), id).into()
  165. }
  166. async fn user_balance(&self, id: Value, params: &[Value]) -> JsonResult {
  167. let client = self.client.lock().await;
  168. let nym = params[0].as_str();
  169. if nym.is_none() {
  170. return JsonError::new(InvalidParams, None, id).into()
  171. }
  172. let nym = nym.unwrap();
  173. match PublicKey::from_str(nym) {
  174. Ok(key) => match client.money_wallets.get(&key.to_bytes()) {
  175. Some(wallet) => {
  176. let balance = wallet.balances().unwrap();
  177. JsonResponse::new(json!(balance), id).into()
  178. }
  179. None => {
  180. error!("No wallet found for provided key");
  181. server_error(RpcError::Balance, id)
  182. }
  183. },
  184. Err(_) => {
  185. error!("Could not parse PublicKey from string");
  186. server_error(RpcError::Parse, id)
  187. }
  188. }
  189. }
  190. // --> {"method": "mint_treasury", "params": []}
  191. // <-- {"result": "minting treasury..."}
  192. async fn mint_treasury(&self, id: Value, params: &[Value]) -> JsonResult {
  193. let mut client = self.client.lock().await;
  194. let token_supply = params[0].as_u64();
  195. if token_supply.is_none() {
  196. return JsonError::new(InvalidParams, None, id).into()
  197. }
  198. let token_supply = token_supply.unwrap();
  199. let addr = params[1].as_str();
  200. if addr.is_none() {
  201. return JsonError::new(InvalidParams, None, id).into()
  202. }
  203. let addr = addr.unwrap();
  204. match PublicKey::from_str(addr) {
  205. Ok(dao_addr) => match client.mint_treasury(*DRK_ID, token_supply, dao_addr) {
  206. Ok(_) => JsonResponse::new(json!("DAO treasury minted successfully."), id).into(),
  207. Err(e) => {
  208. error!("Failed to mint treasury: {}", e);
  209. server_error(RpcError::Mint, id)
  210. }
  211. },
  212. Err(_) => {
  213. error!("Failed to parse PublicKey from String");
  214. server_error(RpcError::Parse, id)
  215. }
  216. }
  217. }
  218. // Create a new wallet for governance tokens.
  219. async fn keygen(&self, id: Value, _params: &[Value]) -> JsonResult {
  220. let mut client = self.client.lock().await;
  221. // let nym = params[0].as_str().unwrap().to_string();
  222. let keypair = Keypair::random(&mut OsRng);
  223. let signature_secret = SecretKey::random(&mut OsRng);
  224. let own_coins: Vec<(OwnCoin, bool)> = Vec::new();
  225. let money_wallet = MoneyWallet { keypair, signature_secret, own_coins };
  226. match money_wallet.track(&mut client.states) {
  227. Ok(_) => {
  228. client.money_wallets.insert(keypair.public.to_bytes(), money_wallet);
  229. //let addr: String = bs58::encode(keypair.public.to_bytes()).into_string();
  230. let addr: String = keypair.public.to_string();
  231. JsonResponse::new(json!(addr), id).into()
  232. }
  233. Err(e) => {
  234. error!("Failed to airdrop tokens: {}", e);
  235. server_error(RpcError::Keygen, id)
  236. }
  237. }
  238. }
  239. // --> {"method": "airdrop_tokens", "params": []}
  240. // <-- {"result": "airdropping tokens..."}
  241. async fn airdrop_tokens(&self, id: Value, params: &[Value]) -> JsonResult {
  242. let mut client = self.client.lock().await;
  243. // let zk_bins = &client.zk_bins;
  244. let addr = params[0].as_str();
  245. if addr.is_none() {
  246. return JsonError::new(InvalidParams, None, id).into()
  247. }
  248. let addr = addr.unwrap();
  249. let value = params[1].as_u64();
  250. if value.is_none() {
  251. return JsonError::new(InvalidParams, None, id).into()
  252. }
  253. let value = value.unwrap();
  254. match PublicKey::from_str(addr) {
  255. Ok(key) => match client.airdrop_user(value, *GOV_ID, key) {
  256. Ok(_) => JsonResponse::new(json!("Tokens airdropped successfully."), id).into(),
  257. Err(e) => {
  258. error!("Failed to airdrop tokens: {}", e);
  259. server_error(RpcError::Airdrop, id)
  260. }
  261. },
  262. Err(_) => {
  263. error!("Failed parsing PublicKey from String");
  264. server_error(RpcError::Parse, id)
  265. }
  266. }
  267. }
  268. // --> {"method": "create_proposal", "params": []}
  269. // <-- {"result": "creating proposal..."}
  270. async fn create_proposal(&self, id: Value, params: &[Value]) -> JsonResult {
  271. let mut client = self.client.lock().await;
  272. if params.is_empty() {
  273. return JsonError::new(InvalidParams, None, id).into()
  274. }
  275. let sender = params[0].as_str();
  276. if sender.is_none() {
  277. return JsonError::new(InvalidParams, None, id).into()
  278. }
  279. let sender = sender.unwrap();
  280. let recipient = params[1].as_str();
  281. if recipient.is_none() {
  282. return JsonError::new(InvalidParams, None, id).into()
  283. }
  284. let recipient = recipient.unwrap();
  285. let amount = params[2].as_u64();
  286. if amount.is_none() {
  287. return JsonError::new(InvalidParams, None, id).into()
  288. }
  289. let amount = amount.unwrap();
  290. let recv_addr = PublicKey::from_str(recipient);
  291. if recv_addr.is_err() {
  292. return JsonError::new(InvalidParams, None, id).into()
  293. }
  294. let recv_addr = recv_addr.unwrap();
  295. let sndr_addr = PublicKey::from_str(sender);
  296. if sndr_addr.is_err() {
  297. return JsonError::new(InvalidParams, None, id).into()
  298. }
  299. let sndr_addr = sndr_addr.unwrap();
  300. match client.propose(recv_addr, *DRK_ID, amount, sndr_addr) {
  301. Ok(bulla) => {
  302. let bulla: String = bs58::encode(bulla.to_repr()).into_string();
  303. JsonResponse::new(json!(bulla), id).into()
  304. }
  305. Err(e) => {
  306. error!("Failed to make Proposal: {}", e);
  307. server_error(RpcError::Propose, id)
  308. }
  309. }
  310. }
  311. // --> {"method": "vote", "params": []}
  312. // <-- {"result": "voting..."}
  313. async fn vote(&self, id: Value, params: &[Value]) -> JsonResult {
  314. let mut client = self.client.lock().await;
  315. let mut vote_bool = true;
  316. let addr = params[0].as_str();
  317. if addr.is_none() {
  318. return JsonError::new(InvalidParams, None, id).into()
  319. }
  320. let addr = addr.unwrap();
  321. let balance = match PublicKey::from_str(addr) {
  322. Ok(key) => match client.money_wallets.get(&key.to_bytes()) {
  323. Some(wallet) => {
  324. let balance = wallet.balances().unwrap();
  325. let token_id = format!("{}", *GOV_ID);
  326. if balance.get(&token_id).is_some() {
  327. *balance.get(&token_id).unwrap()
  328. } else {
  329. error!("Balance is empty");
  330. 0
  331. }
  332. }
  333. None => {
  334. error!("No wallet found for provided key");
  335. 0
  336. }
  337. },
  338. Err(_) => {
  339. error!("Could not parse PublicKey from string");
  340. 0
  341. }
  342. };
  343. let vote_str = params[1].as_str();
  344. if vote_str.is_none() {
  345. return JsonError::new(InvalidParams, None, id).into()
  346. }
  347. let vote_str = vote_str.unwrap();
  348. match vote_str {
  349. "yes" => {}
  350. "no" => vote_bool = false,
  351. _ => return JsonError::new(InvalidParams, None, id).into(),
  352. }
  353. match PublicKey::from_str(addr) {
  354. Ok(key) => match client.cast_vote(key, vote_bool) {
  355. Ok(_) => {
  356. let rep = format!(
  357. "Vote cast successfully, you voted {} with value {} GOV.",
  358. vote_str, balance
  359. );
  360. JsonResponse::new(json!(rep), id).into()
  361. }
  362. Err(e) => {
  363. error!("Failed casting vote: {}", e);
  364. server_error(RpcError::Vote, id)
  365. }
  366. },
  367. Err(_) => {
  368. error!("Failed parsing PublicKey from String");
  369. server_error(RpcError::Parse, id)
  370. }
  371. }
  372. }
  373. // --> {"method": "execute", "params": []}
  374. // <-- {"result": "executing..."}
  375. async fn execute(&self, id: Value, params: &[Value]) -> JsonResult {
  376. let mut client = self.client.lock().await;
  377. let bulla_str = params[0].as_str();
  378. if bulla_str.is_none() {
  379. return JsonError::new(InvalidParams, None, id).into()
  380. }
  381. let bulla_str = bulla_str.unwrap();
  382. let bulla = parse_b58(bulla_str);
  383. match bulla {
  384. Ok(bulla) => match client.exec_proposal(bulla) {
  385. Ok(_) => JsonResponse::new(json!("Proposal executed successfully."), id).into(),
  386. Err(e) => {
  387. // Reject proposal instead of returning error?
  388. error!("Failed executing proposal: {}", e);
  389. server_error(RpcError::Exec, id)
  390. }
  391. },
  392. Err(e) => {
  393. error!("Failed parsing bulla: {}", e);
  394. server_error(RpcError::Parse, id)
  395. }
  396. }
  397. }
  398. }