diff --git a/.github/workflows/rust-checks.yml b/.github/workflows/rust-checks.yml new file mode 100644 index 0000000..1b5fb2d --- /dev/null +++ b/.github/workflows/rust-checks.yml @@ -0,0 +1,39 @@ +name: Rust-Checks + +on: + pull_request: + push: + branches: main + +jobs: + fmt: + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Rust toolchain + uses: ./.github/actions/install-rust-toolchain + with: + components: rustfmt + + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + clippy: + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Rust toolchain + uses: ./.github/actions/install-rust-toolchain + with: + components: clippy + + - uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all --all-targets -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index 8b214bc..ee6ba20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1522,6 +1522,8 @@ dependencies = [ "getrandom", "indexed_db_futures", "js-sys", + "ripemd", + "sha2", "thiserror", "tonic-build", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 6cc75bb..5212fe4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,8 @@ console_error_panic_hook = { version = "0.1.7", optional = true } wasm-bindgen-futures = "0.4.42" indexed_db_futures = "0.5.0" web-sys = { version = "0.3.69", features = ["console"] } +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 399a742..ae791ec 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,6 +19,8 @@ pub enum Error { message: String, code: u16, }, + #[error("Address generation error")] + AddressGenerationError(#[from] zcash_keys::keys::AddressGenerationError), } impl From for JsValue { diff --git a/src/lib.rs b/src/lib.rs index 70b4139..76ea0d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT //! This is the top level documentation! +#![allow(async_fn_in_trait)] pub mod account; pub mod error; diff --git a/tests/web_accounts.rs b/tests/web_accounts.rs index 5f21e54..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 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); }