darkfid.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. use async_trait::async_trait;
  2. use clap::clap_app;
  3. use log::debug;
  4. use serde_json::{json, Value};
  5. use async_std::sync::{Arc, Mutex};
  6. use std::path::PathBuf;
  7. use std::str::FromStr;
  8. use drk::{
  9. blockchain::Rocks,
  10. cli::{Config, DarkfidConfig},
  11. client::Client,
  12. rpc::{
  13. jsonrpc::{error as jsonerr, request as jsonreq, response as jsonresp, send_request},
  14. jsonrpc::{ErrorCode::*, JsonRequest, JsonResult},
  15. rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
  16. },
  17. serial::{deserialize, serialize},
  18. util::{
  19. assign_id, decimals, decode_base10, expand_path, generate_id, join_config_path,
  20. DrkTokenList, NetworkName, SolTokenList,
  21. },
  22. wallet::WalletDb,
  23. Result,
  24. };
  25. struct Darkfid {
  26. config: DarkfidConfig,
  27. client: Arc<Mutex<Client>>,
  28. sol_tokenlist: SolTokenList,
  29. drk_tokenlist: DrkTokenList,
  30. }
  31. #[async_trait]
  32. impl RequestHandler for Darkfid {
  33. async fn handle_request(&self, req: JsonRequest) -> JsonResult {
  34. if req.params.as_array().is_none() {
  35. return JsonResult::Err(jsonerr(InvalidParams, None, req.id));
  36. }
  37. debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());
  38. match req.method.as_str() {
  39. Some("say_hello") => return self.say_hello(req.id, req.params).await,
  40. Some("create_wallet") => return self.create_wallet(req.id, req.params).await,
  41. Some("key_gen") => return self.key_gen(req.id, req.params).await,
  42. Some("get_key") => return self.get_key(req.id, req.params).await,
  43. Some("get_token_id") => return self.get_token_id(req.id, req.params).await,
  44. Some("features") => return self.features(req.id, req.params).await,
  45. Some("deposit") => return self.deposit(req.id, req.params).await,
  46. Some("withdraw") => return self.withdraw(req.id, req.params).await,
  47. Some("transfer") => return self.transfer(req.id, req.params).await,
  48. Some(_) | None => return JsonResult::Err(jsonerr(MethodNotFound, None, req.id)),
  49. };
  50. }
  51. }
  52. impl Darkfid {
  53. async fn new(config: DarkfidConfig, wallet: Arc<WalletDb>) -> Result<Self> {
  54. debug!(target: "DARKFID", "INIT WALLET WITH PATH {}", config.wallet_path);
  55. let rocks = Rocks::new(expand_path(&config.database_path.clone())?.as_path())?;
  56. let client = Client::new(
  57. rocks,
  58. (
  59. config.gateway_protocol_url.parse()?,
  60. config.gateway_publisher_url.parse()?,
  61. ),
  62. (
  63. expand_path(&config.mint_params_path.clone())?,
  64. expand_path(&config.spend_params_path.clone())?,
  65. ),
  66. wallet.clone(),
  67. )
  68. .await?;
  69. let client = Arc::new(Mutex::new(client));
  70. let sol_tokenlist = SolTokenList::new()?;
  71. let drk_tokenlist = DrkTokenList::new(sol_tokenlist.clone())?;
  72. Ok(Self {
  73. config,
  74. client,
  75. sol_tokenlist,
  76. drk_tokenlist,
  77. })
  78. }
  79. async fn start(&mut self) -> Result<()> {
  80. self.client.lock().await.start().await?;
  81. self.client.lock().await.connect_to_subscriber().await?;
  82. Ok(())
  83. }
  84. // --> {"method": "say_hello", "params": []}
  85. // <-- {"result": "hello world"}
  86. async fn say_hello(&self, id: Value, _params: Value) -> JsonResult {
  87. JsonResult::Resp(jsonresp(json!("hello world"), id))
  88. }
  89. // --> {"method": "create_wallet", "params": []}
  90. // <-- {"result": true}
  91. async fn create_wallet(&self, id: Value, _params: Value) -> JsonResult {
  92. match self.client.lock().await.init_db().await {
  93. Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
  94. Err(e) => {
  95. return JsonResult::Err(jsonerr(ServerError(-32001), Some(e.to_string()), id))
  96. }
  97. }
  98. }
  99. // --> {"method": "key_gen", "params": []}
  100. // <-- {"result": true}
  101. async fn key_gen(&self, id: Value, _params: Value) -> JsonResult {
  102. match self.client.lock().await.key_gen().await {
  103. Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
  104. Err(e) => {
  105. return JsonResult::Err(jsonerr(ServerError(-32002), Some(e.to_string()), id))
  106. }
  107. }
  108. }
  109. // --> {"method": "get_key", "params": []}
  110. // <-- {"result": "vdNS7oBj7KvsMWWmo9r96SV4SqATLrGsH2a3PGpCfJC"}
  111. async fn get_key(&self, id: Value, _params: Value) -> JsonResult {
  112. let pk = self.client.lock().await.main_keypair.public;
  113. let b58 = bs58::encode(serialize(&pk)).into_string();
  114. return JsonResult::Resp(jsonresp(json!(b58), id));
  115. }
  116. // --> {"method": "get_token_id", "params": [token]}
  117. // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
  118. async fn get_token_id(&self, id: Value, params: Value) -> JsonResult {
  119. let args = params.as_array();
  120. if args.is_none() {
  121. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  122. }
  123. let args = args.unwrap();
  124. let symbol = args[0].as_str();
  125. if symbol.is_none() {
  126. return JsonResult::Err(jsonerr(InvalidSymbolParam, None, id));
  127. }
  128. let symbol = symbol.unwrap();
  129. let result: Result<Value> = async {
  130. let token_id = self.sol_tokenlist.clone().search_id(symbol)?;
  131. Ok(json!(token_id))
  132. }
  133. .await;
  134. match result {
  135. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(res))),
  136. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  137. }
  138. }
  139. // --> {""method": "features", "params": []}
  140. // <-- {"result": { "network": ["btc", "sol"] } }
  141. async fn features(&self, id: Value, _params: Value) -> JsonResult {
  142. let req = jsonreq(json!("features"), json!([]));
  143. let rep: JsonResult;
  144. match send_request(&self.config.cashier_rpc_url, json!(req)).await {
  145. Ok(v) => rep = v,
  146. Err(e) => {
  147. return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id))
  148. }
  149. }
  150. match rep {
  151. JsonResult::Resp(r) => return JsonResult::Resp(r),
  152. JsonResult::Err(e) => return JsonResult::Err(e),
  153. JsonResult::Notif(_) => return JsonResult::Err(jsonerr(InternalError, None, id)),
  154. }
  155. }
  156. // --> {"method": "deposit", "params": [network, token, publickey]}
  157. // The publickey sent here is used so the cashier can know where to send
  158. // assets once the deposit is received.
  159. // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
  160. async fn deposit(&self, id: Value, params: Value) -> JsonResult {
  161. let args = params.as_array();
  162. if args.is_none() {
  163. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  164. }
  165. let args = args.unwrap();
  166. if args.len() != 2 {
  167. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  168. }
  169. let network = &args[0];
  170. let token = &args[1];
  171. if token.as_str().is_none() {
  172. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  173. }
  174. let token = token.as_str().unwrap();
  175. if network.as_str().is_none() {
  176. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  177. }
  178. let network = network.as_str().unwrap();
  179. let token_id = match assign_id(&network, &token, self.sol_tokenlist.clone()) {
  180. Ok(t) => t,
  181. Err(e) => {
  182. debug!(target: "DARKFID", "TOKEN ID IS ERR");
  183. return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
  184. }
  185. };
  186. // TODO: Optional sanity checking here, but cashier *must* do so too.
  187. let pk = self.client.lock().await.main_keypair.public;
  188. let pubkey = bs58::encode(serialize(&pk)).into_string();
  189. // Send request to cashier. If the cashier supports the requested network
  190. // (and token), it shall return a valid address where assets can be deposited.
  191. // If not, an error is returned, and forwarded to the method caller.
  192. let req = jsonreq(json!("deposit"), json!([network, token_id, pubkey]));
  193. let rep: JsonResult;
  194. match send_request(&self.config.cashier_rpc_url, json!(req)).await {
  195. Ok(v) => rep = v,
  196. Err(e) => {
  197. debug!(target: "DARKFID", "REQUEST IS ERR");
  198. return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id));
  199. }
  200. }
  201. match rep {
  202. JsonResult::Resp(r) => return JsonResult::Resp(r),
  203. JsonResult::Err(e) => return JsonResult::Err(e),
  204. JsonResult::Notif(_n) => return JsonResult::Err(jsonerr(InternalError, None, id)),
  205. }
  206. }
  207. // --> {"method": "withdraw", "params": [network, token, publickey, amount]}
  208. // The publickey sent here is the address where the caller wants to receive
  209. // the tokens they plan to withdraw.
  210. // On request, send request to cashier to get deposit address, and then transfer
  211. // dark assets to the cashier's wallet. Following that, the cashier should return
  212. // a transaction ID of them sending the funds that are requested for withdrawal.
  213. // <-- {"result": "txID"}
  214. async fn withdraw(&self, id: Value, params: Value) -> JsonResult {
  215. let args = params.as_array();
  216. if args.is_none() {
  217. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  218. }
  219. let args = args.unwrap();
  220. if args.len() != 4 {
  221. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  222. }
  223. let network = &args[0];
  224. let token = &args[1];
  225. let address = &args[2];
  226. let amount = &args[3];
  227. if token.as_str().is_none() {
  228. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  229. }
  230. let token = token.as_str().unwrap();
  231. if network.as_str().is_none() {
  232. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  233. }
  234. let network = network.as_str().unwrap();
  235. if amount.as_f64().is_none() {
  236. return JsonResult::Err(jsonerr(InvalidAmountParam, None, id));
  237. }
  238. let amount = amount.as_f64().unwrap();
  239. let decimals = match decimals(network, token, self.sol_tokenlist.clone()) {
  240. Ok(d) => d,
  241. Err(e) => {
  242. return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
  243. }
  244. };
  245. let amount_in_apo = match decode_base10(&amount.to_string(), decimals, true) {
  246. Ok(a) => a,
  247. Err(e) => {
  248. return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
  249. }
  250. };
  251. let token_id = match assign_id(&network, &token, self.sol_tokenlist.clone()) {
  252. Ok(t) => t,
  253. Err(e) => {
  254. debug!(target: "DARKFID", "TOKEN ID IS ERR");
  255. return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
  256. }
  257. };
  258. let req = jsonreq(
  259. json!("withdraw"),
  260. json!([network, token_id, address, amount_in_apo]),
  261. );
  262. let mut rep: JsonResult;
  263. match send_request(&self.config.cashier_rpc_url, json!(req)).await {
  264. Ok(v) => rep = v,
  265. Err(e) => {
  266. debug!(target: "DARKFID", "REQUEST IS ERR");
  267. return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id));
  268. }
  269. }
  270. // send drk to cashier_public
  271. if let JsonResult::Resp(cashier_public) = &rep {
  272. let result: Result<()> = async {
  273. let cashier_public = cashier_public.result.as_str().unwrap();
  274. let cashier_public: jubjub::SubgroupPoint =
  275. deserialize(&bs58::decode(cashier_public).into_vec()?)?;
  276. self.client
  277. .lock()
  278. .await
  279. .send(
  280. cashier_public,
  281. amount_in_apo,
  282. generate_id(&token_id, &NetworkName::from_str(network)?)?,
  283. true,
  284. )
  285. .await?;
  286. Ok(())
  287. }
  288. .await;
  289. match result {
  290. Err(e) => {
  291. rep = JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id.clone()))
  292. }
  293. Ok(_) => {
  294. rep = JsonResult::Resp(jsonresp(
  295. json!(format!(
  296. "Sent request to withdraw {} amount of {}",
  297. amount, token_id
  298. )),
  299. json!(id.clone()),
  300. ))
  301. }
  302. }
  303. };
  304. match rep {
  305. JsonResult::Resp(r) => return JsonResult::Resp(r),
  306. JsonResult::Err(e) => return JsonResult::Err(e),
  307. JsonResult::Notif(_n) => return JsonResult::Err(jsonerr(InternalError, None, id)),
  308. }
  309. }
  310. // --> {"method": "transfer", [dToken, address, amount]}
  311. // <-- {"result": "txID"}
  312. async fn transfer(&self, id: Value, params: Value) -> JsonResult {
  313. let args = params.as_array();
  314. if args.is_none() {
  315. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  316. }
  317. let args = args.unwrap();
  318. if args.len() != 3 {
  319. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  320. }
  321. let token = &args[0];
  322. let address = &args[1];
  323. let amount = &args[2];
  324. if token.as_str().is_none() {
  325. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  326. }
  327. let _token = token.as_str().unwrap();
  328. //let token_vec = self.wallet.get_token_ids();
  329. //for (network_name, token_id) in self.drk_tokenlist.iter() {}
  330. if address.as_str().is_none() {
  331. return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
  332. }
  333. let _address = address.as_str().unwrap();
  334. if amount.as_f64().is_none() {
  335. return JsonResult::Err(jsonerr(InvalidAmountParam, None, id));
  336. }
  337. let _amount = amount.as_f64().unwrap();
  338. // TODO: get tokenID from walletdb
  339. //let result: Result<()> = async {
  340. // let token_id = parse_wrapped_token(token, self.tokenlist.clone())?;
  341. // let address = bs58::decode(&address).into_vec()?;
  342. // let address: jubjub::SubgroupPoint = deserialize(&address)?;
  343. // self.client
  344. // .lock()
  345. // .await
  346. // .transfer(token_id, address, amount)
  347. // .await?;
  348. // Ok(())
  349. //}
  350. //.await;
  351. //match result {
  352. // Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(id))),
  353. // Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  354. //}
  355. return JsonResult::Err(jsonerr(
  356. ServerError(-32005),
  357. Some("failed to withdraw".to_string()),
  358. id,
  359. ));
  360. }
  361. }
  362. #[async_std::main]
  363. async fn main() -> Result<()> {
  364. let args = clap_app!(darkfid =>
  365. (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
  366. (@arg CASHIERKEY: --cashier-key +takes_value "Sets cashier public key")
  367. (@arg verbose: -v --verbose "Increase verbosity")
  368. )
  369. .get_matches();
  370. let config_path = if args.is_present("CONFIG") {
  371. PathBuf::from(args.value_of("CONFIG").unwrap())
  372. } else {
  373. join_config_path(&PathBuf::from("darkfid.toml"))?
  374. };
  375. let loglevel = if args.is_present("verbose") {
  376. log::Level::Debug
  377. } else {
  378. log::Level::Info
  379. };
  380. simple_logger::init_with_level(loglevel)?;
  381. let config: DarkfidConfig = Config::<DarkfidConfig>::load(config_path)?;
  382. let wallet = WalletDb::new(
  383. expand_path(&config.wallet_path)?.as_path(),
  384. config.wallet_password.clone(),
  385. )?;
  386. if let Some(cashier_public) = args.value_of("CASHIERKEY") {
  387. let cashier_public: jubjub::SubgroupPoint =
  388. deserialize(&bs58::decode(cashier_public).into_vec()?)?;
  389. wallet.put_cashier_pub(&cashier_public)?;
  390. println!("Cashier public key set successfully");
  391. return Ok(());
  392. }
  393. let mut darkfid = Darkfid::new(config.clone(), wallet.clone()).await?;
  394. let server_config = RpcServerConfig {
  395. socket_addr: config.rpc_listen_address.clone(),
  396. use_tls: config.serve_tls,
  397. identity_path: expand_path(&config.tls_identity_path.clone())?,
  398. identity_pass: config.tls_identity_password.clone(),
  399. };
  400. darkfid.start().await?;
  401. listen_and_serve(server_config, Arc::new(darkfid)).await
  402. }