| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- use std::{process::exit, str::FromStr};
- use darkfi_sdk::crypto::MerkleNode;
- use darkfi_serial::{deserialize, serialize};
- use serde_json::json;
- use darkfi::{
- crypto::{
- address::Address,
- coin::OwnCoin,
- note::{EncryptedNote, Note},
- },
- rpc::{client::RpcClient, jsonrpc::JsonRequest},
- Result,
- };
- /// The RPC object with functionality for connecting to darkfid.
- pub struct Rpc {
- pub rpc_client: RpcClient,
- }
- impl Rpc {
- /// Fetch wallet balance of given token ID and return its u64 representation.
- pub async fn balance_of(&self, token_id: &str) -> Result<u64> {
- let req = JsonRequest::new("wallet.get_balances", json!([]));
- let rep = self.rpc_client.request(req).await?;
- if !rep.is_object() {
- eprintln!("Error: Invalid balance data received from darkfid RPC endpoint.");
- exit(1);
- }
- for i in rep.as_object().unwrap().keys() {
- if i == token_id {
- if let Some(balance) = rep[i].as_u64() {
- return Ok(balance)
- }
- eprintln!("Error: Invalid balance data received from darkfid RPC endpoint.");
- exit(1);
- }
- }
- Ok(0)
- }
- /// Fetch default wallet address from the darkfid RPC endpoint.
- pub async fn wallet_address(&self) -> Result<Address> {
- let req = JsonRequest::new("wallet.get_addrs", json!([0_i64]));
- let rep = self.rpc_client.request(req).await?;
- if !rep.is_array() || !rep.as_array().unwrap()[0].is_string() {
- eprintln!("Error: Invalid wallet address received from darkfid RPC endpoint.");
- exit(1);
- }
- match Address::from_str(rep[0].as_str().unwrap()) {
- Ok(v) => Ok(v),
- Err(e) => {
- eprintln!(
- "Error: Invalid wallet address received from darkfid RPC endpoint: {}",
- e
- );
- exit(1)
- }
- }
- }
- /// Query wallet for unspent coins in wallet matching value and token_id.
- pub async fn get_coins_valtok(&self, value: u64, token_id: &str) -> Result<Vec<OwnCoin>> {
- let req = JsonRequest::new("wallet.get_coins_valtok", json!([value, token_id, true]));
- let rep = self.rpc_client.request(req).await?;
- if !rep.is_array() {
- eprintln!("Error: Invalid coin data received from darkfid RPC endpoint.");
- exit(1);
- }
- let rep = rep.as_array().unwrap();
- let mut ret = vec![];
- for i in rep {
- if !i.is_string() {
- eprintln!(
- "Error: Invalid base58 data for OwnCoin received from darkfid RPC endpoint."
- );
- exit(1);
- }
- let data = match bs58::decode(i.as_str().unwrap()).into_vec() {
- Ok(v) => v,
- Err(e) => {
- eprintln!("Error: Failed decoding base58 data for OwnCoin: {}", e);
- exit(1);
- }
- };
- let oc = match deserialize(&data) {
- Ok(v) => v,
- Err(e) => {
- eprintln!("Error: Failed deserializing OwnCoin: {}", e);
- exit(1);
- }
- };
- ret.push(oc);
- }
- Ok(ret)
- }
- /// Fetch the merkle path for a given leaf position in the coin tree
- pub async fn get_merkle_path(&self, leaf_pos: usize) -> Result<Vec<MerkleNode>> {
- let req = JsonRequest::new("wallet.get_merkle_path", json!([leaf_pos as u64]));
- let rep = self.rpc_client.request(req).await?;
- if !rep.is_array() {
- eprintln!("Error: Invalid merkle path data received from darkfid RPC endpoint.");
- exit(1);
- }
- let rep = rep.as_array().unwrap();
- let mut ret = vec![];
- for i in rep {
- if !i.is_string() {
- eprintln!("Error: Invalid base58 data received for MerkleNode");
- exit(1);
- }
- let n = match bs58::decode(i.as_str().unwrap()).into_vec() {
- Ok(v) => v,
- Err(e) => {
- eprintln!("Error: Failed decoding base58 for MerkleNode: {}", e);
- exit(1);
- }
- };
- if n.len() != 32 {
- eprintln!("error: MerkleNode byte length is not 32");
- exit(1);
- }
- let n = MerkleNode::from_bytes(n.try_into().unwrap());
- if n.is_none() {
- eprintln!("Error: Noncanonical bytes of MerkleNode");
- exit(1);
- }
- ret.push(n.unwrap());
- }
- Ok(ret)
- }
- /// Try to decrypt a given `EncryptedNote`
- pub async fn decrypt_note(&self, enc_note: &EncryptedNote) -> Result<Option<Note>> {
- let encoded = bs58::encode(&serialize(enc_note)).into_string();
- let req = JsonRequest::new("wallet.decrypt_note", json!([encoded]));
- let rep = self.rpc_client.oneshot_request(req).await?;
- if !rep.is_string() {
- eprintln!("Error: decrypt_note() RPC call returned invalid data");
- exit(1);
- }
- let decoded = match bs58::decode(rep.as_str().unwrap()).into_vec() {
- Ok(v) => v,
- Err(e) => {
- eprintln!("Error decoding base58 data received from RPC call: {}", e);
- exit(1);
- }
- };
- let note = match deserialize(&decoded) {
- Ok(v) => v,
- Err(e) => {
- eprintln!("Failed deserializing bytes into Note: {}", e);
- exit(1);
- }
- };
- Ok(Some(note))
- }
- }
|