diff --git a/Cargo.toml b/Cargo.toml index c4b3cc5..264d6b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,6 +76,11 @@ branch = "warp-sync" git = "https://github.com/hhanh00/zcash-params.git" branch = "main" +[dependencies.zcash_address] +git = "https://github.com/hhanh00/librustzcash.git" +rev = "19a97f16945c68c33aedcc89f2a4f4d398658b05" + + [build-dependencies] tonic-build = "0.4.2" diff --git a/src/lib.rs b/src/lib.rs index 2575e29..b54b295 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ mod commitment; mod db; mod hash; mod key; +mod ua; mod mempool; mod pay; mod prices; @@ -46,3 +47,4 @@ pub use crate::pay::{broadcast_tx, sign_offline_tx, Tx}; pub use crate::print::*; pub use crate::scan::{latest_height, scan_all, sync_async}; pub use crate::wallet::{Wallet, WalletBalance}; +pub use crate::ua::{get_sapling, get_ua}; diff --git a/src/ua.rs b/src/ua.rs new file mode 100644 index 0000000..a655482 --- /dev/null +++ b/src/ua.rs @@ -0,0 +1,73 @@ +use zcash_address::unified::{Receiver, Address}; +use zcash_address::{FromAddress, Network, UnsupportedAddress, ZcashAddress, ToAddress}; +use std::convert::TryFrom; + +#[derive(Debug, Clone)] +pub struct MyReceiver { + pub net: Network, + pub receiver: Receiver, +} + +impl FromAddress for MyReceiver { + fn from_sapling(net: Network, data: [u8; 43]) -> Result { + Ok(MyReceiver { net: net, receiver: Receiver::Sapling(data) }) + } + + fn from_unified(net: Network, data: Address) -> Result { + for r in data.receivers().iter() { + match r { + Receiver::Sapling(data) => { + return Ok(MyReceiver { net: net, receiver: Receiver::Sapling(data.clone()) }); + }, + _ => (), + } + } + return FromAddress::from_unified(net, data); + } + + fn from_transparent_p2pkh(net: Network, data: [u8; 20]) -> Result { + Ok(MyReceiver { net: net, receiver: Receiver::P2pkh(data) }) + } +} + +pub fn get_ua(sapling_addr: &str, transparent_addr: &str) -> anyhow::Result { + let sapling_addr = ZcashAddress::try_from_encoded(sapling_addr)?; + let transparent_addr = ZcashAddress::try_from_encoded(transparent_addr)?; + let receivers: Vec<_> = vec![sapling_addr, transparent_addr].iter().map(|r| { + r.clone().convert::().unwrap() + }).collect(); + let net = receivers.first().unwrap().net.clone(); + let receivers: Vec<_> = receivers.iter().map(|r| r.receiver.clone()).collect(); + let ua: Address = Address::try_from(receivers)?; + let ua_address = ZcashAddress::from_unified(net, ua); + Ok(ua_address) +} + +pub fn get_sapling(ua_addr: &str) -> anyhow::Result { + let ua_addr = ZcashAddress::try_from_encoded(ua_addr)?; + let r = ua_addr.convert::()?; + if let Receiver::Sapling(data) = r.receiver { + return Ok(ZcashAddress::from_sapling(r.net, data)); + } + anyhow::bail!("Invalid UA"); +} + +#[cfg(test)] +mod tests { + use crate::ua::{get_ua, get_sapling}; + + #[test] + fn test_ua() -> anyhow::Result<()> { + let ua = get_ua("zs1lvzgfzzwl9n85446j292zg0valw2p47hmxnw42wnqsehsmyuvjk0mhxktcs0pqrplacm2vchh35", "t1UWSSWaojmV5dgDhrSfZC6MAfCwVQ9LLoo")?; + let ua_str = ua.to_string(); + println!("{}", ua); + let za = get_sapling(&ua_str)?; + println!("{}", za); + + Ok(()) + } +} + +// t1UWSSWaojmV5dgDhrSfZC6MAfCwVQ9LLoo +// zs1lvzgfzzwl9n85446j292zg0valw2p47hmxnw42wnqsehsmyuvjk0mhxktcs0pqrplacm2vchh35 +// u16cdcqfguv574pnntjx7dfh78u8m5cu3myxyvs9gedkymstj60u366vpn9qhkcch77e26rzyecyhem7qnzrl7ws2huraj8se8tgek4t3ngn4lfs95l4774mhvgyea4jj93gm92jhg3z7