main.rs 6.2 KB

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