use std::convert::TryInto; use gumdrop::Options; use zcash_client_backend::encoding::{decode_extended_full_viewing_key, encode_payment_address}; use zcash_primitives::{ constants::{mainnet, testnet}, zip32::{DiversifierIndex, ExtendedFullViewingKey}, }; fn parse_viewing_key(s: &str) -> Result<(ExtendedFullViewingKey, bool), &'static str> { decode_extended_full_viewing_key(mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, s) .ok() .flatten() .map(|vk| (vk, true)) .or_else(|| { decode_extended_full_viewing_key(testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, s) .ok() .flatten() .map(|vk| (vk, false)) }) .ok_or("Invalid Sapling viewing key") } fn parse_diversifier_index(s: &str) -> Result { let i: u128 = s.parse().map_err(|_| "Diversifier index is not a number")?; if i >= (1 << 88) { return Err("Diversifier index too large"); } Ok(DiversifierIndex(i.to_le_bytes()[..11].try_into().unwrap())) } fn encode_diversifier_index(di: &DiversifierIndex) -> u128 { let mut bytes = [0; 16]; bytes[..11].copy_from_slice(&di.0); u128::from_le_bytes(bytes) } #[derive(Debug, Options)] struct MyOptions { #[options(help = "Print this help message and exit.")] help: bool, #[options( free, help = "The Sapling viewing key to generate diversified addresses from", parse(try_from_str = "parse_viewing_key") )] viewing_key: Option<(ExtendedFullViewingKey, bool)>, #[options( free, help = "The index of the diversified address to generate (default 0). Some indices don't have a corresponding address.", parse(try_from_str = "parse_diversifier_index") )] diversifier_index: DiversifierIndex, } fn main() { let opts = MyOptions::parse_args_default_or_exit(); let (extfvk, is_mainnet) = if let Some(res) = opts.viewing_key { res } else { eprintln!("Missing Sapling viewing key"); return; }; let (diversifier_index, address) = extfvk.find_address(opts.diversifier_index).unwrap(); println!( "# Diversifier index: {}", encode_diversifier_index(&diversifier_index) ); println!( "{}", encode_payment_address( if is_mainnet { mainnet::HRP_SAPLING_PAYMENT_ADDRESS } else { testnet::HRP_SAPLING_PAYMENT_ADDRESS }, &address ) ); }