diff --git a/Cargo.lock b/Cargo.lock index bd2aee7..48529f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1411,6 +1411,8 @@ dependencies = [ "console_error_panic_hook", "getrandom", "js-sys", + "ripemd", + "sha2", "thiserror", "tonic-build", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 355efb6..0c3d0e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,8 @@ getrandom = { version = "0.2", features = ["js"] } thiserror = "1.0.63" console_error_panic_hook = { version = "0.1.7", optional = true } wasm-bindgen-futures = "0.4.42" +sha2 = "0.10" +ripemd = "0.1" [dev-dependencies] wasm-bindgen-test = "0.3.42" diff --git a/src/account.rs b/src/account.rs index d540281..c3b6e0d 100644 --- a/src/account.rs +++ b/src/account.rs @@ -1,10 +1,13 @@ // Copyright 2024 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT +use sha2::{Digest, Sha256}; use wasm_bindgen::prelude::*; -use zcash_keys::keys::{Era, UnifiedSpendingKey}; +use zcash_keys::encoding::AddressCodec; +use zcash_keys::keys::{Era, UnifiedAddressRequest, UnifiedSpendingKey}; use zcash_primitives::consensus::MAIN_NETWORK; -use zcash_primitives::zip32::AccountId; +use zcash_primitives::legacy::TransparentAddress; +use zcash_primitives::zip32::{AccountId, DiversifierIndex}; use crate::error::Error; @@ -12,7 +15,8 @@ pub type AccountIndex = u32; #[wasm_bindgen] pub struct Account { - usk: UnifiedSpendingKey, + #[wasm_bindgen(skip)] + pub usk: UnifiedSpendingKey, } #[wasm_bindgen] @@ -42,4 +46,29 @@ impl Account { usk: UnifiedSpendingKey::from_bytes(Era::Orchard, encoded).unwrap(), }) } + + #[wasm_bindgen] + /// Return the string encoded address for this account. This returns a unified address with all address subtypes (orchard, sapling, p2pkh) + /// The diversifier index can be used to derive different valid addresses for the same account. Diversifier index must be > 0 + pub fn unified_address(&self, diversifier_index: u64) -> Result { + Ok(self + .usk + .to_unified_full_viewing_key() + .address( + DiversifierIndex::from(diversifier_index), + UnifiedAddressRequest::all().unwrap(), + )? + .encode(&MAIN_NETWORK)) + } + + #[wasm_bindgen] + /// Return the string encoded address for this accounts transparent address + /// Should this also support a diversifier? + pub fn transparent_address(&self) -> Result { + let pubkey = self.usk.transparent().to_account_pubkey(); + let t_address = TransparentAddress::PublicKeyHash( + *ripemd::Ripemd160::digest(Sha256::digest(pubkey.serialize())).as_ref(), + ); + Ok(t_address.encode(&MAIN_NETWORK)) + } } diff --git a/src/error.rs b/src/error.rs index 9853fe3..34d9be3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,6 +13,8 @@ pub enum Error { // DecodingError(#[from] zcash_keys::keys::DecodingError), #[error("Javascript error")] JsError(JsValue), + #[error("Address generation error")] + AddressGenerationError(#[from] zcash_keys::keys::AddressGenerationError), } impl From for JsValue { diff --git a/tests/web_accounts.rs b/tests/web_accounts.rs index ef854ea..2ab462e 100644 --- a/tests/web_accounts.rs +++ b/tests/web_accounts.rs @@ -4,7 +4,17 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); use webz_core::account::Account; #[wasm_bindgen_test] -fn test_account_from_seed() { +fn test_unified_address_encoding() { let seed = [0; 32]; - let _a = Account::from_seed(&seed, 0).unwrap(); + let a = Account::from_seed(&seed, 0).unwrap(); + let address = a.unified_address(1).unwrap(); + assert_eq!(address.len(), 213); +} + +#[wasm_bindgen_test] +fn test_transparent_address_encoding() { + let seed = [0; 32]; + let a = Account::from_seed(&seed, 0).unwrap(); + let address = a.transparent_address().unwrap(); + assert_eq!(address.len(), 35); }