diff --git a/.changeset/funny-knives-refuse.md b/.changeset/funny-knives-refuse.md new file mode 100644 index 0000000000..7acb371c34 --- /dev/null +++ b/.changeset/funny-knives-refuse.md @@ -0,0 +1,5 @@ +--- +'@penumbra-zone/wasm': minor +--- + +Added noble forwarding address wasm helpers diff --git a/packages/wasm/crate/Cargo.lock b/packages/wasm/crate/Cargo.lock index 2076d2b253..b814453641 100644 --- a/packages/wasm/crate/Cargo.lock +++ b/packages/wasm/crate/Cargo.lock @@ -805,7 +805,7 @@ dependencies = [ [[package]] name = "decaf377-fmd" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "ark-ff", "ark-serialize", @@ -819,7 +819,7 @@ dependencies = [ [[package]] name = "decaf377-ka" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "ark-ff", "decaf377", @@ -2104,7 +2104,7 @@ dependencies = [ [[package]] name = "penumbra-asset" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2142,7 +2142,7 @@ dependencies = [ [[package]] name = "penumbra-auction" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2187,7 +2187,7 @@ dependencies = [ [[package]] name = "penumbra-community-pool" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2217,7 +2217,7 @@ dependencies = [ [[package]] name = "penumbra-compact-block" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2248,7 +2248,7 @@ dependencies = [ [[package]] name = "penumbra-dex" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2301,7 +2301,7 @@ dependencies = [ [[package]] name = "penumbra-distributions" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "async-trait", @@ -2317,7 +2317,7 @@ dependencies = [ [[package]] name = "penumbra-fee" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2341,7 +2341,7 @@ dependencies = [ [[package]] name = "penumbra-governance" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2390,7 +2390,7 @@ dependencies = [ [[package]] name = "penumbra-ibc" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2425,7 +2425,7 @@ dependencies = [ [[package]] name = "penumbra-keys" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "aes", "anyhow", @@ -2469,7 +2469,7 @@ dependencies = [ [[package]] name = "penumbra-num" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2505,7 +2505,7 @@ dependencies = [ [[package]] name = "penumbra-proof-params" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ec", @@ -2530,7 +2530,7 @@ dependencies = [ [[package]] name = "penumbra-proto" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "async-trait", @@ -2557,7 +2557,7 @@ dependencies = [ [[package]] name = "penumbra-sct" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2590,7 +2590,7 @@ dependencies = [ [[package]] name = "penumbra-shielded-pool" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2641,7 +2641,7 @@ dependencies = [ [[package]] name = "penumbra-stake" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2682,7 +2682,7 @@ dependencies = [ [[package]] name = "penumbra-tct" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "ark-ed-on-bls12-377", "ark-ff", @@ -2710,7 +2710,7 @@ dependencies = [ [[package]] name = "penumbra-transaction" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "ark-ff", @@ -2761,7 +2761,7 @@ dependencies = [ [[package]] name = "penumbra-txhash" version = "0.80.5" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.80.5#43f6e9375354b4684d4232e89270244e803175f6" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=5e8ea2b12777e5956db6ea5c620877e5d1aa2de5#5e8ea2b12777e5956db6ea5c620877e5d1aa2de5" dependencies = [ "anyhow", "blake2b_simd 1.0.2", diff --git a/packages/wasm/crate/Cargo.toml b/packages/wasm/crate/Cargo.toml index b8782283ca..aeca1c44b0 100644 --- a/packages/wasm/crate/Cargo.toml +++ b/packages/wasm/crate/Cargo.toml @@ -14,21 +14,22 @@ default = ["console_error_panic_hook"] mock-database = [] [dependencies] -penumbra-auction = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-auction", default-features = false } -penumbra-asset = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-asset" } -penumbra-compact-block = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-compact-block", default-features = false } -penumbra-dex = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-dex", default-features = false } -penumbra-fee = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-fee", default-features = false } -penumbra-governance = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-governance", default-features = false } -penumbra-keys = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-keys" } -penumbra-num = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-num" } -penumbra-proof-params = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-proof-params", default-features = false } -penumbra-proto = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-proto", default-features = false } -penumbra-sct = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-sct", default-features = false } -penumbra-shielded-pool = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-shielded-pool", default-features = false } -penumbra-stake = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-stake", default-features = false } -penumbra-tct = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-tct" } -penumbra-transaction = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.80.5", package = "penumbra-transaction", default-features = false } +# Update to tag dependency once https://github.com/penumbra-zone/penumbra/pull/4878 is in a release +penumbra-auction = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-auction", default-features = false } +penumbra-asset = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-asset" } +penumbra-compact-block = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-compact-block", default-features = false } +penumbra-dex = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-dex", default-features = false } +penumbra-fee = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-fee", default-features = false } +penumbra-governance = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-governance", default-features = false } +penumbra-keys = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-keys" } +penumbra-num = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-num" } +penumbra-proof-params = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-proof-params", default-features = false } +penumbra-proto = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-proto", default-features = false } +penumbra-sct = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-sct", default-features = false } +penumbra-shielded-pool = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-shielded-pool", default-features = false } +penumbra-stake = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-stake", default-features = false } +penumbra-tct = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-tct" } +penumbra-transaction = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "5e8ea2b12777e5956db6ea5c620877e5d1aa2de5", package = "penumbra-transaction", default-features = false } anyhow = "1.0.89" ark-ff = { version = "0.4.2", features = ["std"] } diff --git a/packages/wasm/crate/src/keys.rs b/packages/wasm/crate/src/keys.rs index 209d26a350..1838ff75ca 100644 --- a/packages/wasm/crate/src/keys.rs +++ b/packages/wasm/crate/src/keys.rs @@ -1,7 +1,5 @@ -use std::str::FromStr; - use anyhow; -use penumbra_keys::keys::{Bip44Path, SeedPhrase, SpendKey}; +use penumbra_keys::keys::{AddressIndex, Bip44Path, SeedPhrase, SpendKey}; use penumbra_keys::{Address, FullViewingKey}; use penumbra_proof_params::{ CONVERT_PROOF_PROVING_KEY, DELEGATOR_VOTE_PROOF_PROVING_KEY, OUTPUT_PROOF_PROVING_KEY, @@ -10,6 +8,7 @@ use penumbra_proof_params::{ use penumbra_proto::core::keys::v1 as pb; use penumbra_proto::DomainType; use rand_core::OsRng; +use std::str::FromStr; use wasm_bindgen::prelude::*; use crate::error::WasmResult; @@ -136,3 +135,49 @@ pub fn is_controlled_address(full_viewing_key: &[u8], address: &[u8]) -> WasmRes pub fn is_controlled_inner(fvk: &FullViewingKey, address: &Address) -> bool { fvk.address_index(address).is_some() } + +#[wasm_bindgen(getter_with_clone)] +pub struct ForwardingAddrResponse { + /// A noble address that will be used for registration on the noble network + pub noble_addr_bech32: String, + /// Byte representation of the noble forwarding address. Used for broadcasting cosmos message. + pub noble_addr_bytes: Vec, + /// The penumbra address that a deposit to the noble address with forward to + /// Vec encoded `pb::Address` + pub penumbra_addr_bytes: Vec, +} + +/// Generates an address that can be used as a forwarding address for Noble +/// Returns: Uint8Array representing encoded Address +#[wasm_bindgen] +pub fn get_noble_forwarding_addr( + sequence: u16, + full_viewing_key: &[u8], + channel: &str, + account: Option, +) -> WasmResult { + let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; + let penumbra_addr = forwarding_addr_inner(sequence, account, &fvk); + let noble_addr = penumbra_addr.noble_forwarding_address(channel); + Ok(ForwardingAddrResponse { + noble_addr_bech32: noble_addr.to_string(), + noble_addr_bytes: noble_addr.bytes(), + penumbra_addr_bytes: penumbra_addr.encode_to_vec(), + }) +} + +/// Noble Randomizer: [0xff; 10] followed by LE16(sequence) +pub fn forwarding_addr_inner(sequence: u16, account: Option, fvk: &FullViewingKey) -> Address { + let mut randomizer: [u8; 12] = [0xff; 12]; // Initialize all 12 bytes to 0xff + let seq_bytes = sequence.to_le_bytes(); + randomizer[10..].copy_from_slice(&seq_bytes); // Replace the last 2 bytes with seq_bytes + + let index = AddressIndex { + account: account.unwrap_or_default(), + randomizer, + }; + + let (address, _dtk) = fvk.incoming().payment_address(index); + + address +} diff --git a/packages/wasm/crate/tests/test_keys.rs b/packages/wasm/crate/tests/test_keys.rs index 13b8d62d25..1abb478ef5 100644 --- a/packages/wasm/crate/tests/test_keys.rs +++ b/packages/wasm/crate/tests/test_keys.rs @@ -6,8 +6,8 @@ use penumbra_keys::keys::{ use penumbra_keys::{Address, FullViewingKey}; use penumbra_proto::{DomainType, Message}; use penumbra_wasm::keys::{ - generate_spend_key, get_address_by_index, get_full_viewing_key, get_wallet_id, - is_controlled_address, + forwarding_addr_inner, generate_spend_key, get_address_by_index, get_full_viewing_key, + get_wallet_id, is_controlled_address, }; use rand_core::OsRng; use std::str::FromStr; @@ -87,3 +87,97 @@ fn returns_false_on_unknown_addr() { .0; assert!(!is_controlled_address(&fvk.encode_to_vec(), &other_address.encode_to_vec()).unwrap()); } + +#[test] +fn test_forwarding_addr_sequence_variation() { + let spend_key = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes = get_full_viewing_key(spend_key.as_slice()).unwrap(); + let fvk = FullViewingKey::decode(fvk_bytes.as_slice()).unwrap(); + + // Use two different sequences + let sequence1 = 1234; + let sequence2 = 5678; + let account = Some(1); + + let address1 = forwarding_addr_inner(sequence1, account, &fvk); + let address2 = forwarding_addr_inner(sequence2, account, &fvk); + + // Check that the addresses are different + assert_ne!(address1, address2); +} + +#[test] +fn test_forwarding_addr_account_variation() { + let spend_key = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes = get_full_viewing_key(spend_key.as_slice()).unwrap(); + let fvk = FullViewingKey::decode(fvk_bytes.as_slice()).unwrap(); + + let sequence = 1234; + + let account1 = Some(1); + let account2 = Some(2); + + let address1 = forwarding_addr_inner(sequence, account1, &fvk); + let address2 = forwarding_addr_inner(sequence, account2, &fvk); + + // Check that the addresses are different + assert_ne!(address1, address2); +} + +#[test] +fn test_forwarding_addr_sequence_boundaries() { + let spend_key = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes = get_full_viewing_key(spend_key.as_slice()).unwrap(); + let fvk = FullViewingKey::decode(fvk_bytes.as_slice()).unwrap(); + + let account = Some(1); + + let sequence_min = 0; + let sequence_max = u16::MAX; + + let address_min = forwarding_addr_inner(sequence_min, account, &fvk); + let address_max = forwarding_addr_inner(sequence_max, account, &fvk); + + // Check that the addresses are different + assert_ne!(address_min, address_max); +} + +#[test] +fn test_forwarding_addr_same_sequence_and_account() { + let spend_key = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes = get_full_viewing_key(spend_key.as_slice()).unwrap(); + let fvk = FullViewingKey::decode(fvk_bytes.as_slice()).unwrap(); + + let sequence = 1234; + let account = Some(1); + + let address1 = forwarding_addr_inner(sequence, account, &fvk); + let address2 = forwarding_addr_inner(sequence, account, &fvk); + + // Check that the addresses are the same + assert_eq!(address1, address2); +} + +#[test] +fn test_forwarding_addr_different_fvks() { + // Generate first Full Viewing Key + let spend_key1 = generate_spend_key(TEST_SEED_PHRASE).unwrap(); + let fvk_bytes1 = get_full_viewing_key(spend_key1.as_slice()).unwrap(); + let fvk1 = FullViewingKey::decode(fvk_bytes1.as_slice()).unwrap(); + + // Generate second Full Viewing Key with different seed phrase + const TEST_SEED_PHRASE_2: &str = + "flag public tonight parrot gospel treat tiny section useless smoke swim armor"; + let spend_key2 = generate_spend_key(TEST_SEED_PHRASE_2).unwrap(); + let fvk_bytes2 = get_full_viewing_key(spend_key2.as_slice()).unwrap(); + let fvk2 = FullViewingKey::decode(fvk_bytes2.as_slice()).unwrap(); + + let sequence = 1234; + let account = Some(1); + + let address1 = forwarding_addr_inner(sequence, account, &fvk1); + let address2 = forwarding_addr_inner(sequence, account, &fvk2); + + // Check that the addresses are different + assert_ne!(address1, address2); +} diff --git a/packages/wasm/src/keys.ts b/packages/wasm/src/keys.ts index 45e9b372c7..24340e210f 100644 --- a/packages/wasm/src/keys.ts +++ b/packages/wasm/src/keys.ts @@ -3,6 +3,7 @@ import { get_address_by_index, get_ephemeral_address, get_full_viewing_key, + get_noble_forwarding_addr, get_wallet_id, } from '../wasm/index.js'; import { @@ -30,3 +31,27 @@ export const getEphemeralByIndex = (fullViewingKey: FullViewingKey, index: numbe export const getWalletId = (fullViewingKey: FullViewingKey) => WalletId.fromBinary(get_wallet_id(fullViewingKey.toBinary())); + +export interface NobleAddrResponse { + // A noble address that will be used for registration on the noble network + nobleAddrBech32: string; + // Byte representation of the noble forwarding address. Used for broadcasting cosmos message. + nobleAddrBytes: Uint8Array; + // The penumbra address that a deposit to the noble address with forward to + penumbraAddr: Address; +} + +// Generates an address that can be used as a forwarding address for Noble +export const getNobleForwardingAddr = ( + sequence: number, + fvk: FullViewingKey, + channel: string, + account?: number, +): NobleAddrResponse => { + const res = get_noble_forwarding_addr(sequence, fvk.toBinary(), channel, account); + return { + nobleAddrBech32: res.noble_addr_bech32, + nobleAddrBytes: res.noble_addr_bytes, + penumbraAddr: Address.fromBinary(res.penumbra_addr_bytes), + }; +};