use zcash_keys::address::{Address, UnifiedAddress};
use zcash_protocol::consensus;
use super::{Account, WalletRead, error::FindAccountForAddressError};
pub fn address_receiver_matches_ua<P: consensus::Parameters>(
address: &Address,
ua: &UnifiedAddress,
params: &P,
) -> bool {
let zcash_address = address.to_zcash_address(params);
ua.as_understood_receivers()
.iter()
.any(|r| r.corresponds(&zcash_address))
}
pub fn find_account_for_address<W: WalletRead, P: consensus::Parameters>(
wallet: &W,
params: &P,
address: &Address,
) -> Result<Option<W::AccountId>, FindAccountForAddressError<W::Error>> {
let synthesized_ua;
let shielded_ua: Option<&UnifiedAddress> = match address {
Address::Unified(ua) => Some(ua),
Address::Sapling(pa) => {
synthesized_ua = UnifiedAddress::from_receivers(
#[cfg(feature = "orchard")]
None,
Some(*pa),
None,
);
synthesized_ua.as_ref()
}
Address::Transparent(_) | Address::Tex(_) => None,
};
if let Some(ua) = shielded_ua {
let mut found_acc_id: Option<W::AccountId> = None;
for acc_id in wallet.get_account_ids()? {
let Some(account) = wallet.get_account(acc_id)? else {
continue;
};
if !account.uivk().decrypt_diversifiers(ua).is_empty() {
match found_acc_id {
None => found_acc_id = Some(acc_id),
Some(prev) if prev == acc_id => {}
Some(_) => return Err(FindAccountForAddressError::UnifiedAddressConflict),
}
}
}
if found_acc_id.is_some() {
return Ok(found_acc_id);
}
}
let zcash_address = address.to_zcash_address(params);
for acc_id in wallet.get_account_ids()? {
for addr_info in wallet.list_addresses(acc_id)? {
let stored = addr_info.address();
if stored == address {
return Ok(Some(acc_id));
}
if let Address::Unified(stored_ua) = stored
&& stored_ua
.as_understood_receivers()
.iter()
.any(|r| r.corresponds(&zcash_address))
{
return Ok(Some(acc_id));
}
}
}
Ok(None)
}