| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- use std::{process::exit, str::FromStr, time::Instant};
- use clap::{Parser, Subcommand};
- use serde_json::json;
- use simplelog::{ColorChoice, TermLogger, TerminalMode};
- use url::Url;
- use darkfi::{
- cli_desc,
- crypto::address::Address,
- rpc::{client::RpcClient, jsonrpc::JsonRequest},
- util::{cli::log_config, NetworkName},
- Result,
- };
- #[derive(Parser)]
- #[clap(name = "drk", about = cli_desc!(), version)]
- #[clap(arg_required_else_help(true))]
- struct Args {
- #[clap(short, parse(from_occurrences))]
- /// Increase verbosity (-vvv supported)
- verbose: u8,
- #[clap(short, long, default_value = "tcp://127.0.0.1:8340")]
- /// darkfid JSON-RPC endpoint
- endpoint: Url,
- #[clap(subcommand)]
- command: DrkSubcommand,
- }
- #[derive(Subcommand)]
- enum DrkSubcommand {
- /// Send a ping request to the RPC
- Ping,
- /// Send an airdrop request to the faucet
- Airdrop {
- #[clap(long, parse(try_from_str))]
- /// Address where the airdrop should be requested
- /// (default is darkfid's wallet default)
- address: Option<Address>,
- #[clap(long)]
- /// JSON-RPC endpoint of the faucet
- faucet_endpoint: Url,
- /// f64 amount requested for airdrop
- amount: f64,
- },
- /// Wallet operations
- Wallet {
- #[clap(long)]
- /// Generate a new keypair in the wallet
- keygen: bool,
- #[clap(long)]
- /// Query the wallet for known balances
- balance: bool,
- #[clap(long)]
- /// Get the default address in the wallet
- address: bool,
- #[clap(long)]
- /// Get all addresses in the wallet
- all_addresses: bool,
- },
- /// Transfer of value
- Transfer {
- /// Recipient address
- #[clap(parse(try_from_str))]
- recipient: Address,
- /// Amount to transfer
- amount: f64,
- /// Coin network
- #[clap(short, long, default_value = "darkfi", parse(try_from_str))]
- network: NetworkName,
- /// Token ID
- #[clap(short, long)]
- token_id: String,
- },
- }
- struct Drk {
- pub rpc_client: RpcClient,
- }
- impl Drk {
- async fn close_connection(&self) -> Result<()> {
- self.rpc_client.close().await
- }
- async fn ping(&self) -> Result<()> {
- let start = Instant::now();
- let req = JsonRequest::new("ping", json!([]));
- let rep = self.rpc_client.request(req).await?;
- let latency = Instant::now() - start;
- println!("Got reply: {}", rep);
- println!("Latency: {:?}", latency);
- Ok(())
- }
- async fn airdrop(&self, address: Option<Address>, endpoint: Url, amount: f64) -> Result<()> {
- let addr = if address.is_some() {
- address.unwrap()
- } else {
- let req = JsonRequest::new("wallet.get_key", json!([0_i64]));
- let rep = self.rpc_client.request(req).await?;
- Address::from_str(rep.as_array().unwrap()[0].as_str().unwrap())?
- };
- println!("Requesting airdrop for {}", addr);
- let req = JsonRequest::new("airdrop", json!([json!(addr.to_string()), amount]));
- let rpc_client = RpcClient::new(endpoint).await?;
- let rep = rpc_client.request(req).await?;
- rpc_client.close().await?;
- println!("Success! Transaction ID: {}", rep);
- Ok(())
- }
- async fn wallet_keygen(&self) -> Result<()> {
- let req = JsonRequest::new("wallet.keygen", json!([]));
- let rep = self.rpc_client.request(req).await?;
- println!("New address: {}", rep);
- Ok(())
- }
- async fn wallet_balance(&self) -> Result<()> {
- let req = JsonRequest::new("wallet.get_balances", json!([]));
- let rep = self.rpc_client.request(req).await?;
- // TODO: Better representation
- println!("Balances:\n{:#?}", rep);
- Ok(())
- }
- async fn wallet_address(&self) -> Result<()> {
- let req = JsonRequest::new("wallet.get_key", json!([0_i64]));
- let rep = self.rpc_client.request(req).await?;
- println!("Default wallet address: {}", rep);
- Ok(())
- }
- async fn wallet_all_addresses(&self) -> Result<()> {
- let req = JsonRequest::new("wallet.get_key", json!([-1]));
- let rep = self.rpc_client.request(req).await?;
- println!("Wallet addresses:\n{:#?}", rep);
- Ok(())
- }
- async fn tx_transfer(
- &self,
- network: NetworkName,
- token_id: String,
- recipient: Address,
- amount: f64,
- ) -> Result<()> {
- println!("Attempting to transfer {} tokens to {}", amount, recipient);
- let req = JsonRequest::new(
- "tx.transfer",
- json!([network.to_string(), token_id, recipient.to_string(), amount]),
- );
- let rep = self.rpc_client.request(req).await?;
- println!("Success! Transaction ID: {}", rep);
- Ok(())
- }
- }
- #[async_std::main]
- async fn main() -> Result<()> {
- let args = Args::parse();
- let (lvl, conf) = log_config(args.verbose.into())?;
- TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
- let rpc_client = RpcClient::new(args.endpoint).await?;
- let drk = Drk { rpc_client };
- match args.command {
- DrkSubcommand::Ping => drk.ping().await,
- DrkSubcommand::Airdrop { address, faucet_endpoint, amount } => {
- drk.airdrop(address, faucet_endpoint, amount).await
- }
- DrkSubcommand::Wallet { keygen, balance, address, all_addresses } => {
- if keygen {
- return drk.wallet_keygen().await
- }
- if balance {
- return drk.wallet_balance().await
- }
- if address {
- return drk.wallet_address().await
- }
- if all_addresses {
- return drk.wallet_all_addresses().await
- }
- eprintln!("Run 'drk wallet -h' to see the subcommand usage.");
- exit(2);
- }
- DrkSubcommand::Transfer { recipient, amount, network, token_id } => {
- drk.tx_transfer(network, token_id, recipient, amount).await
- }
- }?;
- drk.close_connection().await
- }
|