mod api;
mod data_payments;
mod error;
mod hot_wallet;
mod keys;
mod wallet_file;
mod watch_only;
pub use self::{
api::{WalletApi, WALLET_DIR_NAME},
data_payments::{Payment, PaymentQuote, QuotingMetrics, QUOTE_EXPIRATION_SECS},
error::{Error, Result},
hot_wallet::HotWallet,
keys::bls_secret_from_hex,
wallet_file::wallet_lockfile_name,
watch_only::WatchOnlyWallet,
};
pub(crate) use keys::store_new_keypair;
use crate::{NanoTokens, UniquePubkey};
use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, fs, path::Path};
use wallet_file::wallet_file_name;
#[derive(Default, Serialize, Deserialize)]
pub(super) struct KeyLessWallet {
available_cash_notes: BTreeMap<UniquePubkey, NanoTokens>,
}
impl KeyLessWallet {
pub fn load_from(wallet_dir: &Path) -> Result<Option<Self>> {
let path = wallet_file_name(wallet_dir);
if !path.is_file() {
return Ok(None);
}
let mut attempts = 0;
let mut wallet: Option<Self> = None;
while wallet.is_none() && attempts < 10 {
info!("Attempting to read wallet file");
match fs::read(&path) {
Ok(data) => match rmp_serde::from_slice(&data) {
Ok(deserialized_wallet) => wallet = Some(deserialized_wallet),
Err(_) => {
attempts += 1;
info!("Attempt {attempts} to read wallet file failed... ");
std::thread::sleep(std::time::Duration::from_millis(100));
}
},
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
attempts += 1;
info!("Attempt {attempts} to read wallet file failed... ");
std::thread::sleep(std::time::Duration::from_millis(100));
}
Err(e) => return Err(Error::from(e)),
}
}
if wallet.is_none() {
return Err(Error::from(std::io::Error::new(
std::io::ErrorKind::Other,
"Could not read and deserialize wallet file after multiple attempts",
)));
}
Ok(wallet)
}
pub fn balance(&self) -> NanoTokens {
let mut balance = 0;
for (_unique_pubkey, value) in self.available_cash_notes.iter() {
balance += value.as_nano();
}
NanoTokens::from(balance)
}
}