cashierd.rs 25 KB

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