extern crate bitcoin as bitcoin_lib;
use std::sync::{Arc, Mutex};
use bitcoin_lib::{
NetworkKind,
bip32::{ChainCode, ChildNumber, Xpub, Fingerprint},
secp256k1::PublicKey
};
use hdpath::{CustomHDPath, HDPath, PathValue};
use crate::{
errors::HWKeyError,
ledger::{
comm::LedgerTransport
}
};
pub mod ethereum;
pub mod bitcoin;
pub use {
ethereum::EthereumApp,
bitcoin::BitcoinApp,
};
pub trait LedgerApp {
type Networks;
fn new(manager: Arc<Mutex<dyn LedgerTransport>>) -> Self;
fn is_open(&self) -> Option<Self::Networks>;
}
pub trait AsPubkey {
fn as_pubkey(&self) -> &PublicKey;
}
pub trait AsChainCode {
fn as_chaincode(&self) -> &ChainCode;
}
pub trait AsExtendedKey: AsPubkey + AsChainCode {}
pub trait PubkeyAddressApp {
fn get_extkey_at(&self, hd_path: &dyn HDPath) -> Result<Box<dyn AsExtendedKey>, HWKeyError>;
fn get_xpub(&self, hd_path: &dyn HDPath, network: NetworkKind) -> Result<Xpub, HWKeyError> {
let pubkey = self.get_extkey_at(hd_path)?;
let index = hd_path.get(hd_path.len() - 1).unwrap();
let parent_fingerprint = if hd_path.len() > 0 {
let mut parent_hd_path = Vec::with_capacity(hd_path.len() as usize - 1);
for i in 0..hd_path.len()-1 {
parent_hd_path.push(hd_path.get(i).unwrap());
}
let parent_hd_path = CustomHDPath::try_new(parent_hd_path)
.expect("No parent HD Path");
let parent_key = self.get_extkey_at(&parent_hd_path)?;
let fp = bitcoin::hash160(&parent_key.as_pubkey().serialize());
Fingerprint::try_from(&fp[0..4]).unwrap()
} else {
Fingerprint::default()
};
let result = Xpub {
network,
depth: hd_path.len(),
public_key: *pubkey.as_pubkey(),
chain_code: *pubkey.as_chaincode(),
child_number: match index {
PathValue::Hardened(i) => ChildNumber::from_hardened_idx(i).unwrap(),
PathValue::Normal(i) => ChildNumber::from_normal_idx(i).unwrap(),
},
parent_fingerprint,
};
Ok(result)
}
}