cashierd.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. use async_std::sync::{Arc, Mutex};
  2. use std::collections::HashMap;
  3. use std::path::PathBuf;
  4. use std::str::FromStr;
  5. use async_trait::async_trait;
  6. use clap::clap_app;
  7. use ff::Field;
  8. use log::debug;
  9. use rand::rngs::OsRng;
  10. use serde_json::{json, Value};
  11. use drk::{
  12. blockchain::{rocks::columns, Rocks, RocksColumn},
  13. cli::{CashierdConfig, Config},
  14. client::{Client, State},
  15. crypto::{
  16. load_params, merkle::CommitmentTree, save_params, setup_mint_prover, setup_spend_prover,
  17. },
  18. rpc::{
  19. jsonrpc::{error as jsonerr, response as jsonresp},
  20. jsonrpc::{ErrorCode::*, JsonRequest, JsonResult},
  21. rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
  22. },
  23. serial::{deserialize, serialize},
  24. service::{bridge, bridge::Bridge},
  25. util::{expand_path, generate_id, join_config_path, parse::truncate, NetworkName},
  26. wallet::{CashierDb, WalletDb},
  27. Error, Result,
  28. };
  29. fn handle_bridge_error(error_code: u32) -> Result<()> {
  30. match error_code {
  31. 1 => Err(Error::BridgeError("Not Supported Client".into())),
  32. 2 => Err(Error::BridgeError("Unable to watch the deposit address".into())),
  33. 3 => Err(Error::BridgeError("Unable to send the token".into())),
  34. _ => Err(Error::BridgeError("Unknown error_code".into())),
  35. }
  36. }
  37. #[derive(Clone, Debug)]
  38. pub struct Network {
  39. pub name: NetworkName,
  40. pub blockchain: String,
  41. pub keypair: String,
  42. }
  43. struct Cashierd {
  44. config: CashierdConfig,
  45. bridge: Arc<Bridge>,
  46. cashier_wallet: Arc<CashierDb>,
  47. networks: Vec<Network>,
  48. }
  49. #[async_trait]
  50. impl RequestHandler for Cashierd {
  51. async fn handle_request(&self, req: JsonRequest) -> JsonResult {
  52. if req.params.as_array().is_none() {
  53. return JsonResult::Err(jsonerr(InvalidParams, None, req.id));
  54. }
  55. debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());
  56. match req.method.as_str() {
  57. Some("deposit") => return self.deposit(req.id, req.params).await,
  58. Some("withdraw") => return self.withdraw(req.id, req.params).await,
  59. Some("features") => return self.features(req.id, req.params).await,
  60. Some(_) => {}
  61. None => {}
  62. };
  63. return JsonResult::Err(jsonerr(MethodNotFound, None, req.id));
  64. }
  65. }
  66. impl Cashierd {
  67. async fn new(config_path: PathBuf) -> Result<Self> {
  68. debug!(target: "CASHIER DAEMON", "Initialize");
  69. let config: CashierdConfig = Config::<CashierdConfig>::load(config_path)?;
  70. let cashier_wallet = CashierDb::new(
  71. expand_path(&config.cashier_wallet_path.clone())?.as_path(),
  72. config.cashier_wallet_password.clone(),
  73. )?;
  74. let mut networks = Vec::new();
  75. for network in config.clone().networks {
  76. networks.push(Network {
  77. name: NetworkName::from_str(&network.name)?,
  78. blockchain: network.blockchain,
  79. keypair: network.keypair,
  80. });
  81. }
  82. let bridge = bridge::Bridge::new();
  83. Ok(Self {
  84. config: config.clone(),
  85. bridge,
  86. cashier_wallet,
  87. networks,
  88. })
  89. }
  90. async fn resume_watch_deposit_keys(
  91. bridge: Arc<Bridge>,
  92. cashier_wallet: Arc<CashierDb>,
  93. networks: Vec<Network>,
  94. ) -> Result<()> {
  95. debug!(target: "CASHIER DAEMON", "Resume watch deposit keys");
  96. for network in networks.iter() {
  97. let keypairs_to_watch =
  98. cashier_wallet.get_deposit_token_keys_by_network(&network.name)?;
  99. for (drk_pub_key, private_key, public_key, _token_id, mint_address) in keypairs_to_watch
  100. {
  101. let bridge = bridge.clone();
  102. let bridge_subscribtion = bridge.subscribe(drk_pub_key, Some(mint_address)).await;
  103. bridge_subscribtion
  104. .sender
  105. .send(bridge::BridgeRequests {
  106. network: network.name.clone(),
  107. payload: bridge::BridgeRequestsPayload::Watch(Some((
  108. private_key,
  109. public_key,
  110. ))),
  111. })
  112. .await?;
  113. }
  114. }
  115. Ok(())
  116. }
  117. async fn listen_for_receiving_coins(
  118. bridge: Arc<Bridge>,
  119. cashier_wallet: Arc<CashierDb>,
  120. recv_coin: async_channel::Receiver<(jubjub::SubgroupPoint, u64)>,
  121. ) -> Result<()> {
  122. // received drk coin
  123. let (drk_pub_key, amount) = recv_coin.recv().await?;
  124. debug!(target: "CASHIER DAEMON", "Receive coin with amount: {}", amount);
  125. // get public key, and token_id of the token
  126. let token = cashier_wallet.get_withdraw_token_public_key_by_dkey_public(&drk_pub_key)?;
  127. // send a request to bridge to send equivalent amount of
  128. // received drk coin to token publickey
  129. if let Some((addr, network, _token_id, mint_address)) = token {
  130. let bridge_subscribtion = bridge.subscribe(drk_pub_key, Some(mint_address)).await;
  131. // send a request to the bridge to send amount of token
  132. // equivalent to the received drk
  133. bridge_subscribtion
  134. .sender
  135. .send(bridge::BridgeRequests {
  136. network: network.clone(),
  137. payload: bridge::BridgeRequestsPayload::Send(addr.clone(), amount),
  138. })
  139. .await?;
  140. // receive a response
  141. let res = bridge_subscribtion.receiver.recv().await?;
  142. // check the response's error
  143. let error_code = res.error as u32;
  144. if error_code != 0 {
  145. return handle_bridge_error(error_code);
  146. }
  147. match res.payload {
  148. bridge::BridgeResponsePayload::Send => {
  149. cashier_wallet.confirm_withdraw_key_record(&addr, &network)?;
  150. }
  151. _ => {
  152. return Err(Error::BridgeError(
  153. "Receive unknown value from Subscription".into(),
  154. ));
  155. }
  156. }
  157. }
  158. Ok(())
  159. }
  160. async fn deposit(&self, id: Value, params: Value) -> JsonResult {
  161. debug!(target: "CASHIER DAEMON", "RECEIVED DEPOSIT REQUEST");
  162. let args: &Vec<serde_json::Value> = params.as_array().unwrap();
  163. if args.len() != 3 {
  164. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  165. }
  166. let network = &args[0];
  167. let mint_address = &args[1];
  168. let drk_pub_key = &args[2];
  169. if network.as_str().is_none() {
  170. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  171. }
  172. let network = network.as_str().unwrap();
  173. let network = match NetworkName::from_str(network) {
  174. Ok(d) => d,
  175. Err(e) => {
  176. return JsonResult::Err(jsonerr(InvalidNetworkParam, Some(e.to_string()), id));
  177. }
  178. };
  179. if mint_address.as_str().is_none() {
  180. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  181. }
  182. let mut mint_address = mint_address.as_str().unwrap().to_string();
  183. if drk_pub_key.as_str().is_none() {
  184. return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
  185. }
  186. let drk_pub_key = drk_pub_key.as_str().unwrap();
  187. // Check if the features list contains this network
  188. if self
  189. .networks
  190. .iter()
  191. .find(|net| net.name == network)
  192. .is_none()
  193. {
  194. return JsonResult::Err(jsonerr(
  195. InvalidParams,
  196. Some(format!("Cashier doesn't support this network: {}", network)),
  197. id,
  198. ));
  199. }
  200. let result: Result<String> = async {
  201. let token_id = generate_id(&mint_address, &network)?;
  202. let mint_address_opt = Self::check_token_id(&network, &mint_address)?;
  203. if mint_address_opt.is_none() {
  204. mint_address = String::new();
  205. }
  206. let drk_pub_key = bs58::decode(&drk_pub_key).into_vec()?;
  207. let drk_pub_key: jubjub::SubgroupPoint = deserialize(&drk_pub_key)?;
  208. // check if the drk public key is already exist
  209. let check = self
  210. .cashier_wallet
  211. .get_deposit_token_keys_by_dkey_public(&drk_pub_key, &network)?;
  212. // start new subscription from the bridge and then cashierd will
  213. // send a request to the bridge to generate keypair for the desired token
  214. // and start watch this token's keypair
  215. // once a bridge receive an update for this token's address
  216. // cashierd will get notification from bridge.listen() function
  217. //
  218. // The "if statement" check from the cashierdb if the node's drk_pub_key already exist
  219. // in this case it will not generate new keypair but it will
  220. // retrieve the old generated keypair
  221. //
  222. // Once receive a response from the bridge, the cashierd then save a deposit
  223. // record in cashierdb with the network name and token id
  224. let bridge = self.bridge.clone();
  225. let bridge_subscribtion = bridge.subscribe(drk_pub_key, mint_address_opt).await;
  226. if check.is_empty() {
  227. bridge_subscribtion
  228. .sender
  229. .send(bridge::BridgeRequests {
  230. network: network.clone(),
  231. payload: bridge::BridgeRequestsPayload::Watch(None),
  232. })
  233. .await?;
  234. } else {
  235. let keypair = check[0].to_owned();
  236. bridge_subscribtion
  237. .sender
  238. .send(bridge::BridgeRequests {
  239. network: network.clone(),
  240. payload: bridge::BridgeRequestsPayload::Watch(Some((keypair.0, keypair.1))),
  241. })
  242. .await?;
  243. }
  244. let bridge_res = bridge_subscribtion.receiver.recv().await?;
  245. let error_code = bridge_res.error as u32;
  246. if error_code != 0 {
  247. return handle_bridge_error(error_code).map(|_| String::new());
  248. }
  249. match bridge_res.payload {
  250. bridge::BridgeResponsePayload::Watch(token_priv, token_pub) => {
  251. // add pairings to db
  252. self.cashier_wallet.put_deposit_keys(
  253. &drk_pub_key,
  254. &token_priv,
  255. &serialize(&token_pub),
  256. &network,
  257. &token_id,
  258. mint_address,
  259. )?;
  260. return Ok(token_pub);
  261. }
  262. bridge::BridgeResponsePayload::Address(token_pub) => {
  263. return Ok(token_pub);
  264. }
  265. _ => Err(Error::BridgeError(
  266. "Receive unknown value from Subscription".into(),
  267. )),
  268. }
  269. }
  270. .await;
  271. match result {
  272. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(id))),
  273. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  274. }
  275. }
  276. async fn withdraw(&self, id: Value, params: Value) -> JsonResult {
  277. debug!(target: "CASHIER DAEMON", "RECEIVED WITHDRAW REQUEST");
  278. let args: &Vec<serde_json::Value> = params.as_array().unwrap();
  279. if args.len() != 4 {
  280. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  281. }
  282. let network = &args[0];
  283. let mint_address = &args[1];
  284. let address = &args[2];
  285. let amount = &args[3];
  286. if network.as_str().is_none() {
  287. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  288. }
  289. let network = NetworkName::from_str(args[0].as_str().unwrap()).unwrap();
  290. if mint_address.as_str().is_none() {
  291. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  292. }
  293. let mut mint_address = mint_address.as_str().unwrap().to_string();
  294. if address.as_str().is_none() {
  295. return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
  296. }
  297. let address = address.as_str().unwrap();
  298. if amount.as_u64().is_none() {
  299. return JsonResult::Err(jsonerr(InvalidAmountParam, None, id));
  300. }
  301. let _amount = amount.as_u64().unwrap();
  302. // Check if the features list contains this network
  303. if self
  304. .networks
  305. .iter()
  306. .find(|net| net.name == network)
  307. .is_none()
  308. {
  309. return JsonResult::Err(jsonerr(
  310. InvalidParams,
  311. Some(format!("Cashier doesn't support this network: {}", network)),
  312. id,
  313. ));
  314. }
  315. let result: Result<String> = async {
  316. let token_id = generate_id(&mint_address, &network)?;
  317. let mint_address_opt = Self::check_token_id(&network, &mint_address)?;
  318. if mint_address_opt.is_none() {
  319. // empty string
  320. mint_address = String::new();
  321. }
  322. let address = serialize(&address.to_string());
  323. let cashier_public: jubjub::SubgroupPoint;
  324. if let Some(addr) = self
  325. .cashier_wallet
  326. .get_withdraw_keys_by_token_public_key(&address, &network)?
  327. {
  328. cashier_public = addr.public;
  329. } else {
  330. let cashier_secret = jubjub::Fr::random(&mut OsRng);
  331. cashier_public =
  332. zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret;
  333. self.cashier_wallet.put_withdraw_keys(
  334. &address,
  335. &cashier_public,
  336. &cashier_secret,
  337. &network,
  338. &token_id,
  339. mint_address,
  340. )?;
  341. }
  342. let cashier_public_str = bs58::encode(serialize(&cashier_public)).into_string();
  343. Ok(cashier_public_str)
  344. }
  345. .await;
  346. match result {
  347. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(id))),
  348. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  349. }
  350. }
  351. async fn features(&self, id: Value, _params: Value) -> JsonResult {
  352. JsonResult::Resp(jsonresp(
  353. json!(self
  354. .networks
  355. .iter()
  356. .map(|net| (net.name.to_string(), net.blockchain.to_owned()))
  357. .collect::<HashMap<String, String>>()),
  358. id,
  359. ))
  360. }
  361. fn check_token_id(network: &NetworkName, _token_id: &str) -> Result<Option<String>> {
  362. match network {
  363. #[cfg(feature = "sol")]
  364. NetworkName::Solana => {
  365. use drk::service::sol::SOL_NATIVE_TOKEN_ID;
  366. if _token_id != SOL_NATIVE_TOKEN_ID {
  367. return Ok(Some(_token_id.to_string()));
  368. }
  369. return Ok(None);
  370. }
  371. #[cfg(feature = "btc")]
  372. NetworkName::Bitcoin => {
  373. // Handle bitcoin address here if needed
  374. Ok(None)
  375. }
  376. _ => Err(Error::NotSupportedNetwork),
  377. }
  378. }
  379. async fn start(
  380. &mut self,
  381. mut client: Client,
  382. state: Arc<Mutex<State>>,
  383. ) -> Result<(
  384. smol::Task<Result<()>>,
  385. smol::Task<Result<()>>,
  386. smol::Task<Result<()>>,
  387. )> {
  388. self.cashier_wallet.init_db().await?;
  389. for network in self.networks.iter() {
  390. match network.name {
  391. #[cfg(feature = "sol")]
  392. NetworkName::Solana => {
  393. debug!(target: "CASHIER DAEMON", "Add sol network");
  394. use drk::service::{sol::SolFailed, SolClient};
  395. use solana_sdk::{signature::Signer, signer::keypair::Keypair};
  396. let bridge2 = self.bridge.clone();
  397. let main_keypair: Keypair;
  398. let main_keypairs = self.cashier_wallet.get_main_keys(&NetworkName::Solana)?;
  399. if network.keypair.is_empty() {
  400. if main_keypairs.is_empty() {
  401. main_keypair = Keypair::new();
  402. self.cashier_wallet.put_main_keys(
  403. &serialize(&main_keypair),
  404. &serialize(&main_keypair.pubkey()),
  405. &NetworkName::Solana,
  406. )?;
  407. } else {
  408. main_keypair = deserialize(&main_keypairs[main_keypairs.len() - 1].0)?;
  409. }
  410. } else {
  411. let keypair_str = drk::cli::cli_config::load_keypair_to_str(
  412. PathBuf::from(expand_path(&network.keypair.clone())?),
  413. )?;
  414. let keypair_bytes: Vec<u8> = serde_json::from_str(&keypair_str)?;
  415. main_keypair = Keypair::from_bytes(&keypair_bytes)
  416. .map_err(|e| SolFailed::ParseError(e.to_string()))?;
  417. }
  418. let sol_client =
  419. SolClient::new(serialize(&main_keypair), &network.blockchain).await?;
  420. bridge2.add_clients(NetworkName::Solana, sol_client).await?;
  421. }
  422. #[cfg(feature = "btc")]
  423. NetworkName::Bitcoin => {
  424. debug!(target: "CASHIER DAEMON", "Add btc network");
  425. use drk::service::btc::{BtcClient, Keypair};
  426. let bridge2 = self.bridge.clone();
  427. let main_keypair: Keypair;
  428. let main_keypairs = self.cashier_wallet.get_main_keys(&NetworkName::Bitcoin)?;
  429. if main_keypairs.is_empty() {
  430. main_keypair = Keypair::new();
  431. self.cashier_wallet.put_main_keys(
  432. &serialize(&main_keypair),
  433. &serialize(&main_keypair.pubkey()),
  434. &NetworkName::Bitcoin,
  435. )?;
  436. } else {
  437. main_keypair = deserialize(&main_keypairs[main_keypairs.len() - 1].0)?;
  438. }
  439. let btc_client =
  440. BtcClient::new(serialize(&main_keypair), &network.blockchain).await?;
  441. bridge2
  442. .add_clients(NetworkName::Bitcoin, btc_client)
  443. .await?;
  444. }
  445. _ => {}
  446. }
  447. }
  448. let resume_watch_deposit_keys_task = smol::spawn(Self::resume_watch_deposit_keys(
  449. self.bridge.clone(),
  450. self.cashier_wallet.clone(),
  451. self.networks.clone(),
  452. ));
  453. client.start().await?;
  454. let (notify, recv_coin) = async_channel::unbounded::<(jubjub::SubgroupPoint, u64)>();
  455. client
  456. .connect_to_subscriber_from_cashier(state, self.cashier_wallet.clone(), notify.clone())
  457. .await?;
  458. let cashier_wallet = self.cashier_wallet.clone();
  459. let bridge = self.bridge.clone();
  460. let listen_for_receiving_coins_task: smol::Task<Result<()>> = smol::spawn(async move {
  461. loop {
  462. Self::listen_for_receiving_coins(
  463. bridge.clone(),
  464. cashier_wallet.clone(),
  465. recv_coin.clone(),
  466. )
  467. .await?;
  468. }
  469. });
  470. let bridge2 = self.bridge.clone();
  471. let listen_for_notification_from_bridge_task: smol::Task<Result<()>> =
  472. smol::spawn(async move {
  473. while let Some(token_notification) = bridge2.clone().listen().await {
  474. debug!(target: "CASHIER DAEMON", "Notification from birdge");
  475. let token_notification = token_notification?;
  476. let received_balance = truncate(
  477. token_notification.received_balance,
  478. 8,
  479. token_notification.decimals,
  480. )?;
  481. client
  482. .send(
  483. token_notification.drk_pub_key,
  484. received_balance,
  485. token_notification.token_id,
  486. true,
  487. )
  488. .await?;
  489. }
  490. Ok(())
  491. });
  492. Ok((
  493. resume_watch_deposit_keys_task,
  494. listen_for_receiving_coins_task,
  495. listen_for_notification_from_bridge_task,
  496. ))
  497. }
  498. }
  499. #[async_std::main]
  500. async fn main() -> Result<()> {
  501. let args = clap_app!(cashierd =>
  502. (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
  503. (@arg ADDRESS: -a --address "Get Cashier Public key")
  504. (@arg verbose: -v --verbose "Increase verbosity")
  505. )
  506. .get_matches();
  507. let config_path = if args.is_present("CONFIG") {
  508. PathBuf::from(args.value_of("CONFIG").unwrap())
  509. } else {
  510. join_config_path(&PathBuf::from("cashierd.toml"))?
  511. };
  512. let loglevel = if args.is_present("verbose") {
  513. log::Level::Debug
  514. } else {
  515. log::Level::Info
  516. };
  517. simple_logger::init_with_level(loglevel)?;
  518. let mut cashierd = Cashierd::new(config_path).await?;
  519. let client_wallet = WalletDb::new(
  520. expand_path(&cashierd.config.client_wallet_path.clone())?.as_path(),
  521. cashierd.config.client_wallet_password.clone(),
  522. )?;
  523. let rocks = Rocks::new(expand_path(&cashierd.config.database_path.clone())?.as_path())?;
  524. let params_paths = (
  525. expand_path(&cashierd.config.mint_params_path.clone())?,
  526. expand_path(&cashierd.config.spend_params_path.clone())?,
  527. );
  528. let mint_params_path = params_paths.0.to_str().unwrap_or("mint.params");
  529. let spend_params_path = params_paths.1.to_str().unwrap_or("spend.params");
  530. // Auto create trusted ceremony parameters if they don't exist
  531. if !params_paths.0.exists() {
  532. let params = setup_mint_prover();
  533. save_params(mint_params_path, &params)?;
  534. }
  535. if !params_paths.1.exists() {
  536. let params = setup_spend_prover();
  537. save_params(spend_params_path, &params)?;
  538. }
  539. // Load trusted setup parameters
  540. let (mint_params, mint_pvk) = load_params(mint_params_path)?;
  541. let (spend_params, spend_pvk) = load_params(spend_params_path)?;
  542. let client = Client::new(
  543. rocks.clone(),
  544. (
  545. cashierd.config.gateway_protocol_url.parse()?,
  546. cashierd.config.gateway_publisher_url.parse()?,
  547. ),
  548. client_wallet.clone(),
  549. mint_params,
  550. spend_params,
  551. )
  552. .await?;
  553. let merkle_roots = RocksColumn::<columns::MerkleRoots>::new(rocks.clone());
  554. let nullifiers = RocksColumn::<columns::Nullifiers>::new(rocks);
  555. let cashier_public_keys = vec![client.main_keypair.public];
  556. let state = Arc::new(Mutex::new(State {
  557. tree: CommitmentTree::empty(),
  558. merkle_roots,
  559. nullifiers,
  560. mint_pvk,
  561. spend_pvk,
  562. public_keys: cashier_public_keys,
  563. }));
  564. if args.is_present("ADDRESS") {
  565. let cashier_public = client.main_keypair.public;
  566. let cashier_public = bs58::encode(&serialize(&cashier_public)).into_string();
  567. println!("Public Key: {}", cashier_public);
  568. return Ok(());
  569. };
  570. let cfg = RpcServerConfig {
  571. socket_addr: cashierd.config.rpc_listen_address.clone(),
  572. use_tls: cashierd.config.serve_tls,
  573. identity_path: expand_path(&cashierd.config.clone().tls_identity_path)?,
  574. identity_pass: cashierd.config.tls_identity_password.clone(),
  575. };
  576. let (t1, t2, t3) = cashierd.start(client, state).await?;
  577. listen_and_serve(cfg, Arc::new(cashierd)).await?;
  578. t1.cancel().await;
  579. t2.cancel().await;
  580. t3.cancel().await;
  581. Ok(())
  582. }