2022-11-06 04:50:51 -08:00
|
|
|
use crate::{AccountData, DbAdapter};
|
2022-10-30 03:03:38 -07:00
|
|
|
use anyhow::anyhow;
|
|
|
|
use orchard::keys::{FullViewingKey, Scope};
|
2022-11-06 04:50:51 -08:00
|
|
|
use orchard::Address;
|
2022-10-30 03:03:38 -07:00
|
|
|
use zcash_address::unified::{Container, Encoding, Receiver};
|
2022-11-06 04:50:51 -08:00
|
|
|
use zcash_address::{unified, ToAddress, ZcashAddress};
|
|
|
|
use zcash_client_backend::encoding::{
|
|
|
|
decode_payment_address, encode_payment_address, AddressCodec,
|
|
|
|
};
|
2022-10-30 03:03:38 -07:00
|
|
|
use zcash_primitives::consensus::{Network, Parameters};
|
|
|
|
use zcash_primitives::legacy::TransparentAddress;
|
|
|
|
use zcash_primitives::sapling::PaymentAddress;
|
|
|
|
|
|
|
|
pub struct UnifiedAddressType {
|
|
|
|
pub transparent: bool,
|
|
|
|
pub sapling: bool,
|
|
|
|
pub orchard: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DecodedUA {
|
|
|
|
pub network: Network,
|
|
|
|
pub transparent: Option<TransparentAddress>,
|
|
|
|
pub sapling: Option<PaymentAddress>,
|
|
|
|
pub orchard: Option<Address>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for DecodedUA {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
2022-11-06 04:50:51 -08:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"DecodedUA: {:?} {:?} {:?}",
|
2022-10-30 03:03:38 -07:00
|
|
|
self.transparent.as_ref().map(|a| a.encode(&self.network)),
|
2022-11-06 04:50:51 -08:00
|
|
|
self.sapling
|
|
|
|
.as_ref()
|
|
|
|
.map(|a| encode_payment_address(self.network.hrp_sapling_payment_address(), a)),
|
2022-10-30 03:03:38 -07:00
|
|
|
self.orchard.as_ref().map(|a| {
|
|
|
|
let ua = unified::Address(vec![Receiver::Orchard(a.to_raw_address_bytes())]);
|
2022-11-05 18:49:17 -07:00
|
|
|
ua.encode(&self.network.address_network().unwrap())
|
2022-10-30 03:03:38 -07:00
|
|
|
})
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-06 04:50:51 -08:00
|
|
|
pub fn get_unified_address(
|
|
|
|
network: &Network,
|
|
|
|
db: &DbAdapter,
|
|
|
|
account: u32,
|
|
|
|
tpe: Option<UnifiedAddressType>,
|
|
|
|
) -> anyhow::Result<String> {
|
|
|
|
let tpe = tpe
|
|
|
|
.ok_or(anyhow!(""))
|
|
|
|
.or_else(|_| db.get_ua_settings(account))?;
|
2022-11-01 04:03:57 -07:00
|
|
|
|
2022-11-12 17:39:12 -08:00
|
|
|
let address = match (tpe.transparent, tpe.sapling, tpe.orchard) {
|
|
|
|
(true, false, false) => {
|
|
|
|
let address = db.get_taddr(account)?.ok_or(anyhow!("Missing t-addr"))?;
|
|
|
|
return Ok(address);
|
2022-10-30 03:03:38 -07:00
|
|
|
}
|
2022-11-12 17:39:12 -08:00
|
|
|
(false, true, false) => {
|
|
|
|
let AccountData { address, .. } = db.get_account_info(account)?;
|
|
|
|
return Ok(address);
|
2022-10-30 03:03:38 -07:00
|
|
|
}
|
2022-11-12 17:39:12 -08:00
|
|
|
_ => {
|
|
|
|
let mut rcvs = vec![];
|
|
|
|
if tpe.transparent {
|
|
|
|
let address = db.get_taddr(account)?;
|
|
|
|
if let Some(address) = address {
|
|
|
|
let address = TransparentAddress::decode(network, &address)?;
|
|
|
|
if let TransparentAddress::PublicKey(pkh) = address {
|
|
|
|
let rcv = Receiver::P2pkh(pkh);
|
|
|
|
rcvs.push(rcv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if tpe.sapling {
|
|
|
|
let AccountData { address, .. } = db.get_account_info(account)?;
|
|
|
|
let pa = decode_payment_address(network.hrp_sapling_payment_address(), &address)
|
|
|
|
.unwrap();
|
|
|
|
let rcv = Receiver::Sapling(pa.to_bytes());
|
|
|
|
rcvs.push(rcv);
|
|
|
|
}
|
|
|
|
if tpe.orchard {
|
|
|
|
let okey = db.get_orchard(account)?;
|
|
|
|
if let Some(okey) = okey {
|
|
|
|
let fvk = FullViewingKey::from_bytes(&okey.fvk).unwrap();
|
|
|
|
let address = fvk.address_at(0usize, Scope::External);
|
|
|
|
let rcv = Receiver::Orchard(address.to_raw_address_bytes());
|
|
|
|
rcvs.push(rcv);
|
|
|
|
}
|
|
|
|
}
|
2022-10-30 03:03:38 -07:00
|
|
|
|
2022-11-12 17:39:12 -08:00
|
|
|
let addresses = unified::Address(rcvs);
|
|
|
|
ZcashAddress::from_unified(network.address_network().unwrap(), addresses)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Ok(address.encode())
|
2022-10-30 03:03:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn decode_unified_address(network: &Network, ua: &str) -> anyhow::Result<DecodedUA> {
|
|
|
|
let mut decoded_ua = DecodedUA {
|
|
|
|
network: network.clone(),
|
|
|
|
transparent: None,
|
|
|
|
sapling: None,
|
2022-11-06 04:50:51 -08:00
|
|
|
orchard: None,
|
2022-10-30 03:03:38 -07:00
|
|
|
};
|
2022-11-05 18:49:17 -07:00
|
|
|
let network = network.address_network().unwrap();
|
2022-10-30 03:03:38 -07:00
|
|
|
let (a_network, ua) = unified::Address::decode(ua)?;
|
|
|
|
if network != a_network {
|
|
|
|
anyhow::bail!("Invalid network")
|
|
|
|
}
|
|
|
|
|
|
|
|
for recv in ua.items_as_parsed() {
|
|
|
|
match recv {
|
|
|
|
Receiver::Orchard(addr) => {
|
|
|
|
decoded_ua.orchard = Address::from_raw_address_bytes(addr).into();
|
|
|
|
}
|
|
|
|
Receiver::Sapling(addr) => {
|
|
|
|
decoded_ua.sapling = PaymentAddress::from_bytes(addr);
|
|
|
|
}
|
|
|
|
Receiver::P2pkh(addr) => {
|
|
|
|
decoded_ua.transparent = Some(TransparentAddress::PublicKey(*addr));
|
|
|
|
}
|
|
|
|
Receiver::P2sh(_) => {}
|
|
|
|
Receiver::Unknown { .. } => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(decoded_ua)
|
|
|
|
}
|
|
|
|
|
2022-11-05 18:49:17 -07:00
|
|
|
pub fn orchard_as_unified(network: &Network, address: &Address) -> ZcashAddress {
|
|
|
|
let unified_address = unified::Address(vec![Receiver::Orchard(address.to_raw_address_bytes())]);
|
|
|
|
ZcashAddress::from_unified(network.address_network().unwrap(), unified_address)
|
|
|
|
}
|