main.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. use std::{process::exit, str::FromStr, time::Instant};
  2. use clap::{Parser, Subcommand};
  3. use serde_json::json;
  4. use simplelog::{ColorChoice, TermLogger, TerminalMode};
  5. use url::Url;
  6. use darkfi::{
  7. cli_desc,
  8. crypto::address::Address,
  9. rpc::{client::RpcClient, jsonrpc::JsonRequest},
  10. util::{cli::log_config, NetworkName},
  11. Result,
  12. };
  13. #[derive(Parser)]
  14. #[clap(name = "drk", about = cli_desc!(), version)]
  15. #[clap(arg_required_else_help(true))]
  16. struct Args {
  17. #[clap(short, parse(from_occurrences))]
  18. /// Increase verbosity (-vvv supported)
  19. verbose: u8,
  20. #[clap(short, long, default_value = "tcp://127.0.0.1:8340")]
  21. /// darkfid JSON-RPC endpoint
  22. endpoint: Url,
  23. #[clap(subcommand)]
  24. command: DrkSubcommand,
  25. }
  26. #[derive(Subcommand)]
  27. enum DrkSubcommand {
  28. /// Send a ping request to the RPC
  29. Ping,
  30. /// Send an airdrop request to the faucet
  31. Airdrop {
  32. #[clap(long, parse(try_from_str))]
  33. /// Address where the airdrop should be requested
  34. /// (default is darkfid's wallet default)
  35. address: Option<Address>,
  36. #[clap(long)]
  37. /// JSON-RPC endpoint of the faucet
  38. faucet_endpoint: Url,
  39. /// f64 amount requested for airdrop
  40. amount: f64,
  41. },
  42. /// Wallet operations
  43. Wallet {
  44. #[clap(long)]
  45. /// Generate a new keypair in the wallet
  46. keygen: bool,
  47. #[clap(long)]
  48. /// Query the wallet for known balances
  49. balance: bool,
  50. #[clap(long)]
  51. /// Get the default address in the wallet
  52. address: bool,
  53. #[clap(long)]
  54. /// Get all addresses in the wallet
  55. all_addresses: bool,
  56. },
  57. /// Transfer of value
  58. Transfer {
  59. /// Recipient address
  60. #[clap(parse(try_from_str))]
  61. recipient: Address,
  62. /// Amount to transfer
  63. amount: f64,
  64. /// Coin network
  65. #[clap(short, long, default_value = "darkfi", parse(try_from_str))]
  66. network: NetworkName,
  67. /// Token ID
  68. #[clap(short, long)]
  69. token_id: String,
  70. },
  71. }
  72. struct Drk {
  73. pub rpc_client: RpcClient,
  74. }
  75. impl Drk {
  76. async fn close_connection(&self) -> Result<()> {
  77. self.rpc_client.close().await
  78. }
  79. async fn ping(&self) -> Result<()> {
  80. let start = Instant::now();
  81. let req = JsonRequest::new("ping", json!([]));
  82. let rep = self.rpc_client.request(req).await?;
  83. let latency = Instant::now() - start;
  84. println!("Got reply: {}", rep);
  85. println!("Latency: {:?}", latency);
  86. Ok(())
  87. }
  88. async fn airdrop(&self, address: Option<Address>, endpoint: Url, amount: f64) -> Result<()> {
  89. let addr = if address.is_some() {
  90. address.unwrap()
  91. } else {
  92. let req = JsonRequest::new("wallet.get_key", json!([0_i64]));
  93. let rep = self.rpc_client.request(req).await?;
  94. Address::from_str(rep.as_array().unwrap()[0].as_str().unwrap())?
  95. };
  96. println!("Requesting airdrop for {}", addr);
  97. let req = JsonRequest::new("airdrop", json!([json!(addr.to_string()), amount]));
  98. let rpc_client = RpcClient::new(endpoint).await?;
  99. let rep = rpc_client.request(req).await?;
  100. rpc_client.close().await?;
  101. println!("Success! Transaction ID: {}", rep);
  102. Ok(())
  103. }
  104. async fn wallet_keygen(&self) -> Result<()> {
  105. let req = JsonRequest::new("wallet.keygen", json!([]));
  106. let rep = self.rpc_client.request(req).await?;
  107. println!("New address: {}", rep);
  108. Ok(())
  109. }
  110. async fn wallet_balance(&self) -> Result<()> {
  111. let req = JsonRequest::new("wallet.get_balances", json!([]));
  112. let rep = self.rpc_client.request(req).await?;
  113. // TODO: Better representation
  114. println!("Balances:\n{:#?}", rep);
  115. Ok(())
  116. }
  117. async fn wallet_address(&self) -> Result<()> {
  118. let req = JsonRequest::new("wallet.get_key", json!([0_i64]));
  119. let rep = self.rpc_client.request(req).await?;
  120. println!("Default wallet address: {}", rep);
  121. Ok(())
  122. }
  123. async fn wallet_all_addresses(&self) -> Result<()> {
  124. let req = JsonRequest::new("wallet.get_key", json!([-1]));
  125. let rep = self.rpc_client.request(req).await?;
  126. println!("Wallet addresses:\n{:#?}", rep);
  127. Ok(())
  128. }
  129. async fn tx_transfer(
  130. &self,
  131. network: NetworkName,
  132. token_id: String,
  133. recipient: Address,
  134. amount: f64,
  135. ) -> Result<()> {
  136. println!("Attempting to transfer {} tokens to {}", amount, recipient);
  137. let req = JsonRequest::new(
  138. "tx.transfer",
  139. json!([network.to_string(), token_id, recipient.to_string(), amount]),
  140. );
  141. let rep = self.rpc_client.request(req).await?;
  142. println!("Success! Transaction ID: {}", rep);
  143. Ok(())
  144. }
  145. }
  146. #[async_std::main]
  147. async fn main() -> Result<()> {
  148. let args = Args::parse();
  149. let (lvl, conf) = log_config(args.verbose.into())?;
  150. TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
  151. let rpc_client = RpcClient::new(args.endpoint).await?;
  152. let drk = Drk { rpc_client };
  153. match args.command {
  154. DrkSubcommand::Ping => drk.ping().await,
  155. DrkSubcommand::Airdrop { address, faucet_endpoint, amount } => {
  156. drk.airdrop(address, faucet_endpoint, amount).await
  157. }
  158. DrkSubcommand::Wallet { keygen, balance, address, all_addresses } => {
  159. if keygen {
  160. return drk.wallet_keygen().await
  161. }
  162. if balance {
  163. return drk.wallet_balance().await
  164. }
  165. if address {
  166. return drk.wallet_address().await
  167. }
  168. if all_addresses {
  169. return drk.wallet_all_addresses().await
  170. }
  171. eprintln!("Run 'drk wallet -h' to see the subcommand usage.");
  172. exit(2);
  173. }
  174. DrkSubcommand::Transfer { recipient, amount, network, token_id } => {
  175. drk.tx_transfer(network, token_id, recipient, amount).await
  176. }
  177. }?;
  178. drk.close_connection().await
  179. }