From 51cf45c182f5cfcd56626df1ab6903b276bdb132 Mon Sep 17 00:00:00 2001 From: neocybereth Date: Mon, 18 Aug 2025 19:44:35 +1200 Subject: [PATCH 1/8] fix: add alias - shielded for all gas spendnig keys --- .../src/App/Common/TransactionReceipt.tsx | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/apps/namadillo/src/App/Common/TransactionReceipt.tsx b/apps/namadillo/src/App/Common/TransactionReceipt.tsx index ed9ea3e7e..c74ee71ee 100644 --- a/apps/namadillo/src/App/Common/TransactionReceipt.tsx +++ b/apps/namadillo/src/App/Common/TransactionReceipt.tsx @@ -10,10 +10,12 @@ import { SelectedChain } from "App/Transfer/SelectedChain"; import { SelectedWallet } from "App/Transfer/SelectedWallet"; import { TokenAmountCard } from "App/Transfer/TokenAmountCard"; import { TransferArrow } from "App/Transfer/TransferArrow"; +import { accountsAtom } from "atoms/accounts"; import { getChainRegistryByChainId } from "atoms/integrations"; import BigNumber from "bignumber.js"; import clsx from "clsx"; import { wallets } from "integrations"; +import { useAtomValue } from "jotai"; import { useMemo } from "react"; import { FaCheckCircle } from "react-icons/fa"; import { GoHourglass, GoXCircle } from "react-icons/go"; @@ -40,6 +42,12 @@ const stepDescription: Record = { const TransferTransactionReceipt = ({ transaction, }: TransactionReceiptProps): JSX.Element => { + const accounts = useAtomValue(accountsAtom); + + const shieldedAddress = accounts.data?.find((acc) => + isShieldedAddress(acc.address) + )?.address; + const getChain = (chainId: string, address: string): Chain | undefined => { const chain = getChainRegistryByChainId(chainId)?.chain; if (isNamadaAddress(address) && chain) { @@ -48,6 +56,13 @@ const TransferTransactionReceipt = ({ return chain; }; + const getShieldedDisplayContent = (address: string): React.ReactNode => { + const alias = accounts.data?.find( + (account) => account.address === address + )?.alias; + return alias ? `${alias} - Shielded` : "Shielded"; + }; + const sourceChain = useMemo(() => { return getChain(transaction.chainId, transaction.sourceAddress || ""); }, [transaction]); @@ -61,8 +76,10 @@ const TransferTransactionReceipt = ({ ); }, [transaction]); + // Used whenever the source funds are coming from the shielded pool + const isGasSpendingKey = transaction.sourceAddress?.length === 470; const sourceWallet = - isNamadaAddress(transaction.sourceAddress || "") ? + isNamadaAddress(transaction.sourceAddress || "") || isGasSpendingKey ? wallets.namada : wallets.keplr; @@ -81,13 +98,27 @@ const TransferTransactionReceipt = ({ wallet={sourceChain ? sourceWallet : undefined} /> )} - {sourceWallet && ( - - )} + {sourceWallet && + (( + isShieldedAddress(transaction.sourceAddress || "") || + isGasSpendingKey + ) ? +
+ + {getShieldedDisplayContent( + isGasSpendingKey ? + shieldedAddress || "" + : transaction.sourceAddress || "" + )} + +
+ : )}
Date: Wed, 20 Aug 2025 15:57:35 +1200 Subject: [PATCH 2/8] fix: cleanup and add impl changes --- .../src/App/Common/TransactionReceipt.tsx | 57 +-- packages/shared/lib/src/types/masp.rs | 346 ++++++++++++++++++ 2 files changed, 375 insertions(+), 28 deletions(-) create mode 100644 packages/shared/lib/src/types/masp.rs diff --git a/apps/namadillo/src/App/Common/TransactionReceipt.tsx b/apps/namadillo/src/App/Common/TransactionReceipt.tsx index c74ee71ee..ffd17b93c 100644 --- a/apps/namadillo/src/App/Common/TransactionReceipt.tsx +++ b/apps/namadillo/src/App/Common/TransactionReceipt.tsx @@ -1,5 +1,6 @@ import { Chain } from "@chain-registry/types"; import { CopyToClipboardControl, Stack } from "@namada/components"; +import { PseudoExtendedKey } from "@namada/sdk/web"; import { shortenAddress } from "@namada/utils"; import { isNamadaAddress, @@ -56,11 +57,15 @@ const TransferTransactionReceipt = ({ return chain; }; - const getShieldedDisplayContent = (address: string): React.ReactNode => { - const alias = accounts.data?.find( - (account) => account.address === address - )?.alias; - return alias ? `${alias} - Shielded` : "Shielded"; + const isExtendedKey = (address: string) => { + if (!address) return false; + + try { + const pseudoKey = PseudoExtendedKey.decode(address); + return true; + } catch { + return false; // Not a valid PseudoExtendedKey + } }; const sourceChain = useMemo(() => { @@ -75,11 +80,17 @@ const TransferTransactionReceipt = ({ transaction.destinationAddress || "" ); }, [transaction]); + const decodedPseudokey = PseudoExtendedKey.decode( + transaction.sourceAddress || "" + ); + const encodedViewingKey = decodedPseudokey.to_viewing_key().encode(); // Used whenever the source funds are coming from the shielded pool - const isGasSpendingKey = transaction.sourceAddress?.length === 470; const sourceWallet = - isNamadaAddress(transaction.sourceAddress || "") || isGasSpendingKey ? + ( + isNamadaAddress(transaction.sourceAddress || "") || + isExtendedKey(transaction.sourceAddress || "") + ) ? wallets.namada : wallets.keplr; @@ -98,27 +109,17 @@ const TransferTransactionReceipt = ({ wallet={sourceChain ? sourceWallet : undefined} /> )} - {sourceWallet && - (( - isShieldedAddress(transaction.sourceAddress || "") || - isGasSpendingKey - ) ? -
- - {getShieldedDisplayContent( - isGasSpendingKey ? - shieldedAddress || "" - : transaction.sourceAddress || "" - )} - -
- : )} + {sourceWallet && ( + + )}
Result { + let xfvk: zip32::ExtendedFullViewingKey = BorshDeserialize::try_from_slice(key) + .map_err(|err| format!("{}: {:?}", MaspError::BorshDeserialize, err))?; + + let vk = NamadaExtendedViewingKey::from(xfvk); + + Ok(ExtendedViewingKey(vk)) + } + + /// Return ExtendedViewingKey as Bech32-encoded String + pub fn encode(&self) -> String { + self.0.to_string() + } + + pub fn default_payment_address(&self) -> Result { + let xfvk = zip32::ExtendedFullViewingKey::from(self.0); + let (diversifier_index, payment_address) = xfvk.default_address(); + let div_idx = u32::try_from(diversifier_index)?; + + to_js_result((div_idx, PaymentAddress(payment_address.into()).encode())) + } +} + +#[wasm_bindgen] +pub struct ProofGenerationKey(pub(crate) sapling::ProofGenerationKey); + +#[wasm_bindgen] +impl ProofGenerationKey { + pub fn from_bytes(ak: Vec, nsk: Vec) -> ProofGenerationKey { + let concatenated: Vec = ak.iter().chain(nsk.iter()).cloned().collect(); + let pgk = sapling::ProofGenerationKey::try_from_slice(concatenated.as_slice()) + .expect("Deserializing ProofGenerationKey should not fail!"); + + ProofGenerationKey(pgk) + } + + pub fn encode(&self) -> String { + hex::encode( + borsh::to_vec(&self.0).expect("Serializing ProofGenerationKey should not fail!"), + ) + } + + pub fn decode(encoded: String) -> ProofGenerationKey { + let decoded = hex::decode(encoded).expect("Decoding ProofGenerationKey should not fail!"); + + ProofGenerationKey( + sapling::ProofGenerationKey::try_from_slice(decoded.as_slice()) + .expect("Deserializing ProofGenerationKey should not fail!"), + ) + } +} + +/// Wrap ExtendedSpendingKey +#[wasm_bindgen] +pub struct PseudoExtendedKey(pub(crate) zip32::PseudoExtendedKey); + +#[wasm_bindgen] +impl PseudoExtendedKey { + pub fn encode(&self) -> String { + hex::encode(borsh::to_vec(&self.0).expect("Serializing PseudoExtendedKey should not fail!")) + } + + pub fn decode(encoded: String) -> Result { + let decoded = hex::decode(encoded).map_err(|err| JsError::new(&err.to_string()))?; + let pek = zip32::PseudoExtendedKey::try_from_slice(decoded.as_slice()) + .map_err(|err| JsError::new(&err.to_string()))?; + + Ok(PseudoExtendedKey(pek)) + } + + pub fn from(xvk: ExtendedViewingKey, pgk: ProofGenerationKey) -> Self { + let mut pxk = zip32::PseudoExtendedKey::from(zip32::ExtendedFullViewingKey::from(xvk.0)); + pxk.augment_proof_generation_key(pgk.0) + .expect("Augmenting proof generation key should not fail!"); + + pxk.augment_spend_authorizing_key_unchecked(sapling::redjubjub::PrivateKey( + jubjub::Fr::default(), + )); + + Self(pxk) + } + + pub fn to_viewing_key(&self) -> Result { + let xfvk = self.0.to_viewing_key(); + ExtendedViewingKey::new(&borsh::to_vec(&xfvk).map_err(|e| e.to_string())?) + } +} + +/// Wrap ExtendedSpendingKey +#[wasm_bindgen] +pub struct ExtendedSpendingKey(pub(crate) NamadaExtendedSpendingKey); + +/// wasm_bindgen bindings for ExtendedViewingKey +#[wasm_bindgen] +impl ExtendedSpendingKey { + /// Instantiate ExtendedSpendingKey from serialized vector + #[wasm_bindgen(constructor)] + pub fn new(key: Uint8Array) -> Result { + let xsk: zip32::ExtendedSpendingKey = + BorshDeserialize::try_from_slice(key.to_vec().as_slice()) + .map_err(|err| format!("{}: {:?}", MaspError::BorshDeserialize, err))?; + + let xsk = NamadaExtendedSpendingKey::from(xsk); + + Ok(ExtendedSpendingKey(xsk)) + } + + pub fn from_string(xsk: String) -> Result { + let xsk = NamadaExtendedSpendingKey::from_str(&xsk).map_err(|err| err.to_string())?; + + Ok(ExtendedSpendingKey(xsk)) + } + + pub fn to_viewing_key(&self) -> Result { + ExtendedViewingKey::new(&self.0.to_viewing_key().to_bytes()) + } + + pub fn to_default_address(&self) -> Result { + let xsk = zip32::ExtendedSpendingKey::from(self.0); + let xfvk = zip32::ExtendedFullViewingKey::from(&xsk); + let (div_idx, payment_address) = xfvk.default_address(); + + let index = u32::try_from(div_idx)?; + to_js_result((index, PaymentAddress(payment_address.into()).encode())) + } + + pub fn to_proof_generation_key(&self) -> ProofGenerationKey { + let xsk = zip32::ExtendedSpendingKey::from(self.0); + let pgk = xsk + .to_proof_generation_key() + .expect("Converting to proof generation key should not fail!"); + + ProofGenerationKey(pgk) + } + + pub fn to_pseudo_extended_key(&self) -> PseudoExtendedKey { + let xsk = zip32::ExtendedSpendingKey::from(self.0); + let mut pxk = zip32::PseudoExtendedKey::from(xsk); + pxk.augment_spend_authorizing_key_unchecked(sapling::redjubjub::PrivateKey( + jubjub::Fr::default(), + )); + + PseudoExtendedKey(pxk) + } + + /// Return ExtendedSpendingKey as Bech32-encoded String + pub fn encode(&self) -> String { + self.0.to_string() + } +} + +/// Wrap PaymentAddress +#[wasm_bindgen] +pub struct PaymentAddress(pub(crate) NamadaPaymentAddress); + +/// wasm_bindgen bindings for PaymentAddress +#[wasm_bindgen] +impl PaymentAddress { + /// Instantiate PaymentAddress from serialized vector + #[wasm_bindgen(constructor)] + pub fn new(address: &[u8]) -> Result { + let payment_address: sapling::PaymentAddress = BorshDeserialize::try_from_slice(address) + .map_err(|err| format!("{}: {:?}", MaspError::BorshDeserialize, err))?; + let payment_address = NamadaPaymentAddress::from(payment_address); + Ok(PaymentAddress(payment_address)) + } + + /// Retrieve PaymentAddress hash + pub fn hash(&self) -> String { + self.0.hash() + } + + /// Return PaymentAddress as Bech32-encoded String + pub fn encode(&self) -> String { + self.0.to_string() + } +} + +/// Find next payment address from current index for viewing key +#[wasm_bindgen] +pub fn gen_payment_address(vk: String, index: u32) -> Result { + let diversifier_index = DiversifierIndex::from(index); + + let xfvk = zip32::ExtendedFullViewingKey::from( + NamadaExtendedViewingKey::from_str(&vk) + .expect("Parsing ExtendedViewingKey should not fail!"), + ); + let (div_idx, masp_payment_addr) = xfvk + .find_address(diversifier_index) + .expect("Exhausted payment addresses"); + + let payment_addr = NamadaPaymentAddress::from(masp_payment_addr); + let payment_address = PaymentAddress(payment_addr); + let index: u32 = u32::try_from(div_idx)?; + + to_js_result((index, payment_address.encode())) +} + +#[wasm_bindgen] +pub struct DatedViewingKey(pub(crate) DatedKeypair); + +#[wasm_bindgen] +impl DatedViewingKey { + #[wasm_bindgen(constructor)] + pub fn new(key: String, birthday: String) -> Result { + let xfvk = zip32::ExtendedFullViewingKey::from( + NamadaExtendedViewingKey::from_str(&key) + .expect("Parsing ExtendedViewingKey should not fail!"), + ) + .fvk + .vk; + let birthday = BlockHeight::from_str(&birthday).expect("Parsing birthday should not fail!"); + + Ok(DatedViewingKey(DatedKeypair { + key: xfvk, + birthday, + })) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use wasm_bindgen_test::*; + + #[wasm_bindgen_test] + fn can_deserialize_an_extended_spending_key() { + // BorshSerialize'd slice, generated from @namada/crypto - zip32 + let encoded_xsk: &[u8] = &[ + 1, 233, 222, 184, 155, 1, 0, 0, 0, 232, 94, 130, 41, 9, 58, 197, 35, 245, 249, 232, + 225, 222, 38, 148, 105, 204, 14, 230, 30, 241, 22, 214, 38, 221, 49, 17, 147, 255, 136, + 219, 250, 71, 230, 226, 2, 146, 75, 94, 233, 234, 254, 128, 142, 209, 73, 65, 180, 64, + 235, 159, 125, 24, 77, 12, 246, 113, 174, 41, 217, 5, 190, 215, 6, 76, 189, 55, 31, 96, + 85, 114, 22, 215, 250, 140, 98, 162, 95, 203, 154, 180, 0, 231, 40, 172, 36, 137, 30, + 142, 181, 225, 143, 180, 110, 135, 2, 213, 181, 237, 102, 55, 178, 202, 2, 123, 161, + 104, 49, 91, 37, 62, 52, 132, 72, 103, 7, 60, 110, 171, 49, 22, 100, 146, 44, 79, 205, + 112, 25, 36, 51, 226, 228, 45, 242, 201, 220, 212, 220, 58, 92, 127, 47, 214, 59, 174, + 182, 74, 90, 65, 229, 187, 76, 65, 246, 34, 237, 107, 208, 178, 243, + ]; + let xsk = ExtendedSpendingKey::new(encoded_xsk.into()) + .expect("Instantiating ExtendedSpendingKey struct should not fail!"); + + let key = xsk.encode(); + let expected_key = + format!( + "{}{}{}", + "zsknam1q85aawymqyqqqq8gt6pzjzf6c53lt70gu80zd9rfes8wv8h3zmtzdhf3zxfllzxmlfr7dcszjf94a602l6qga52fgx6yp6ul05vy6r", + "8kwxhznkg9hmtsvn9axu0kq4tjzmtl4rrz5f0uhx45qrnj3tpy3y0gad0p376xapcz6k676e3hkt9qy7apdqc4kff7xjzysec883h2kvgkvjf", + "zcn7dwqvjgvlzuskl9jwu6nwr5hrl9ltrht4kffdyredmf3qlvghdd0gt9ucw4ccj7", + ); + + assert!(key.starts_with("zsknam")); + assert_eq!(key, expected_key); + } + + #[wasm_bindgen_test] + fn can_deserialize_an_extended_viewing_key() { + // BorshSerialize'd slice, generated from @namada/crypto - zip32 + let encoded_xfvk: &[u8] = &[ + 1, 233, 222, 184, 155, 1, 0, 0, 0, 232, 94, 130, 41, 9, 58, 197, 35, 245, 249, 232, + 225, 222, 38, 148, 105, 204, 14, 230, 30, 241, 22, 214, 38, 221, 49, 17, 147, 255, 136, + 219, 250, 231, 141, 253, 33, 141, 45, 47, 253, 94, 99, 2, 58, 233, 84, 152, 142, 60, + 45, 175, 100, 10, 5, 32, 126, 133, 46, 214, 50, 136, 235, 250, 73, 125, 112, 103, 142, + 119, 204, 205, 75, 30, 208, 119, 223, 218, 19, 88, 206, 173, 185, 244, 228, 224, 32, + 104, 193, 189, 255, 9, 147, 22, 21, 240, 191, 213, 181, 237, 102, 55, 178, 202, 2, 123, + 161, 104, 49, 91, 37, 62, 52, 132, 72, 103, 7, 60, 110, 171, 49, 22, 100, 146, 44, 79, + 205, 112, 25, 36, 51, 226, 228, 45, 242, 201, 220, 212, 220, 58, 92, 127, 47, 214, 59, + 174, 182, 74, 90, 65, 229, 187, 76, 65, 246, 34, 237, 107, 208, 178, 243, + ]; + let xfvk = ExtendedViewingKey::new(encoded_xfvk) + .expect("Instantiating ExtendedViewingKey struct should not fail!"); + + let key = xfvk.encode(); + let expected_key = + format!( + "{}{}{}", + "zvknam1q85aawymqyqqqq8gt6pzjzf6c53lt70gu80zd9rfes8wv8h3zmtzdhf3zxfllzxmltncmlfp35kjll27vvpr4625nz8rctd0vs9", + "q2gr7s5hdvv5ga0ayjltsv7880nxdfv0dqa7lmgf43n4dh86wfcpqdrqmmlcfjvtptu9l6k676e3hkt9qy7apdqc4kff7xjzysec883h2k", + "vgkvjfzcn7dwqvjgvlzuskl9jwu6nwr5hrl9ltrht4kffdyredmf3qlvghdd0gt9uce7vx4v", + ); + assert!(key.starts_with("zvknam")); + assert_eq!(key, expected_key); + } + + #[wasm_bindgen_test] + fn can_deserialize_a_payment_address() { + // BorshSerialize'd slice, generated from @namada/crypto - zip32 + let encoded_payment_address: &[u8] = &[ + 100, 199, 34, 96, 93, 67, 18, 95, 86, 139, 123, 213, 141, 228, 147, 169, 218, 247, 75, + 83, 195, 72, 73, 44, 65, 232, 243, 229, 209, 63, 183, 1, 87, 87, 203, 40, 180, 242, + 103, 187, 245, 224, 36, + ]; + let payment_address = PaymentAddress::new(encoded_payment_address) + .expect("Instantiating PaymentAddress struct should not fail!"); + + let address = payment_address.encode(); + let hash = payment_address.hash(); + + let expected_address = + "znam1vnrjyczagvf9745t002cmeyn48d0wj6ncdyyjtzpare7t5flkuq4w47t9z60yeam7hszgyhdw2j"; + + let expected_hash = "4E11B97D220F336CF36A14E8DDFE15ED34BC489D"; + + assert!(address.starts_with("znam")); + assert_eq!(address, expected_address); + assert_eq!(hash, expected_hash); + } +} From e48cf361830e55211d170972ed7e83e725a1e99f Mon Sep 17 00:00:00 2001 From: neocybereth Date: Wed, 20 Aug 2025 15:58:43 +1200 Subject: [PATCH 3/8] fix: cleanup --- apps/namadillo/src/App/Common/TransactionReceipt.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/namadillo/src/App/Common/TransactionReceipt.tsx b/apps/namadillo/src/App/Common/TransactionReceipt.tsx index ffd17b93c..241ae532b 100644 --- a/apps/namadillo/src/App/Common/TransactionReceipt.tsx +++ b/apps/namadillo/src/App/Common/TransactionReceipt.tsx @@ -11,12 +11,10 @@ import { SelectedChain } from "App/Transfer/SelectedChain"; import { SelectedWallet } from "App/Transfer/SelectedWallet"; import { TokenAmountCard } from "App/Transfer/TokenAmountCard"; import { TransferArrow } from "App/Transfer/TransferArrow"; -import { accountsAtom } from "atoms/accounts"; import { getChainRegistryByChainId } from "atoms/integrations"; import BigNumber from "bignumber.js"; import clsx from "clsx"; import { wallets } from "integrations"; -import { useAtomValue } from "jotai"; import { useMemo } from "react"; import { FaCheckCircle } from "react-icons/fa"; import { GoHourglass, GoXCircle } from "react-icons/go"; @@ -43,12 +41,6 @@ const stepDescription: Record = { const TransferTransactionReceipt = ({ transaction, }: TransactionReceiptProps): JSX.Element => { - const accounts = useAtomValue(accountsAtom); - - const shieldedAddress = accounts.data?.find((acc) => - isShieldedAddress(acc.address) - )?.address; - const getChain = (chainId: string, address: string): Chain | undefined => { const chain = getChainRegistryByChainId(chainId)?.chain; if (isNamadaAddress(address) && chain) { From 382c2e9170f1871ff3808526a36ceb703e5a7cb8 Mon Sep 17 00:00:00 2001 From: neocybereth Date: Wed, 20 Aug 2025 21:23:16 +1200 Subject: [PATCH 4/8] fix: clean --- packages/shared/lib/src/types/masp.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/shared/lib/src/types/masp.rs b/packages/shared/lib/src/types/masp.rs index 184c4cdb1..eb21c27b6 100644 --- a/packages/shared/lib/src/types/masp.rs +++ b/packages/shared/lib/src/types/masp.rs @@ -118,8 +118,7 @@ impl PseudoExtendedKey { } pub fn to_viewing_key(&self) -> Result { - let xfvk = self.0.to_viewing_key(); - ExtendedViewingKey::new(&borsh::to_vec(&xfvk).map_err(|e| e.to_string())?) + Ok(ExtendedViewingKey(NamadaExtendedViewingKey::from(xfvk))) } } From b1b5dadb0c0c264b5121ef1b4d76ef55cbdfd457 Mon Sep 17 00:00:00 2001 From: neocybereth Date: Wed, 20 Aug 2025 21:33:50 +1200 Subject: [PATCH 5/8] fix: cleanup --- .../src/App/Common/TransactionReceipt.tsx | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/apps/namadillo/src/App/Common/TransactionReceipt.tsx b/apps/namadillo/src/App/Common/TransactionReceipt.tsx index 241ae532b..caf8e3d28 100644 --- a/apps/namadillo/src/App/Common/TransactionReceipt.tsx +++ b/apps/namadillo/src/App/Common/TransactionReceipt.tsx @@ -49,15 +49,9 @@ const TransferTransactionReceipt = ({ return chain; }; - const isExtendedKey = (address: string) => { + const isExtendedKey = (address: string): boolean => { if (!address) return false; - - try { - const pseudoKey = PseudoExtendedKey.decode(address); - return true; - } catch { - return false; // Not a valid PseudoExtendedKey - } + return PseudoExtendedKey.can_decode(address); }; const sourceChain = useMemo(() => { @@ -72,10 +66,14 @@ const TransferTransactionReceipt = ({ transaction.destinationAddress || "" ); }, [transaction]); - const decodedPseudokey = PseudoExtendedKey.decode( - transaction.sourceAddress || "" - ); - const encodedViewingKey = decodedPseudokey.to_viewing_key().encode(); + + const getEncodedViewingKey = (address: string): string => { + const canDecode = PseudoExtendedKey.can_decode(address); + if (!canDecode) return ""; + const decodedPseudokey = PseudoExtendedKey.decode(address); + const encodedViewingKey = decodedPseudokey.to_viewing_key().encode(); + return encodedViewingKey; + }; // Used whenever the source funds are coming from the shielded pool const sourceWallet = @@ -106,7 +104,7 @@ const TransferTransactionReceipt = ({ wallet={sourceWallet} address={ isExtendedKey(transaction.sourceAddress || "") ? - encodedViewingKey + getEncodedViewingKey(transaction.sourceAddress || "") : transaction.sourceAddress } displayTooltip={!isExtendedKey(transaction.sourceAddress || "")} From ddfd662ea002361dc49ceed225f4ffa3ed16f197 Mon Sep 17 00:00:00 2001 From: neocybereth Date: Wed, 20 Aug 2025 21:34:06 +1200 Subject: [PATCH 6/8] fix: cleanup --- packages/shared/lib/src/types/masp.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/shared/lib/src/types/masp.rs b/packages/shared/lib/src/types/masp.rs index eb21c27b6..c5df8b1f5 100644 --- a/packages/shared/lib/src/types/masp.rs +++ b/packages/shared/lib/src/types/masp.rs @@ -97,6 +97,11 @@ impl PseudoExtendedKey { hex::encode(borsh::to_vec(&self.0).expect("Serializing PseudoExtendedKey should not fail!")) } + pub fn can_decode(encoded: String) -> Result { + let decoded = hex::decode(encoded); + Ok(decoded.is_ok()) + } + pub fn decode(encoded: String) -> Result { let decoded = hex::decode(encoded).map_err(|err| JsError::new(&err.to_string()))?; let pek = zip32::PseudoExtendedKey::try_from_slice(decoded.as_slice()) @@ -118,6 +123,7 @@ impl PseudoExtendedKey { } pub fn to_viewing_key(&self) -> Result { + let xfvk = self.0.to_viewing_key(); Ok(ExtendedViewingKey(NamadaExtendedViewingKey::from(xfvk))) } } From 5af37f3d262336e6c7449fc2f8263e3d4717fc05 Mon Sep 17 00:00:00 2001 From: neocybereth Date: Thu, 21 Aug 2025 08:55:45 +1200 Subject: [PATCH 7/8] fix: cleanup --- apps/namadillo/src/App/Common/TransactionReceipt.tsx | 6 ++---- packages/shared/lib/src/types/masp.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/namadillo/src/App/Common/TransactionReceipt.tsx b/apps/namadillo/src/App/Common/TransactionReceipt.tsx index caf8e3d28..e8f5259d1 100644 --- a/apps/namadillo/src/App/Common/TransactionReceipt.tsx +++ b/apps/namadillo/src/App/Common/TransactionReceipt.tsx @@ -49,10 +49,8 @@ const TransferTransactionReceipt = ({ return chain; }; - const isExtendedKey = (address: string): boolean => { - if (!address) return false; - return PseudoExtendedKey.can_decode(address); - }; + const isExtendedKey = (address: string): boolean => + PseudoExtendedKey.can_decode(address); const sourceChain = useMemo(() => { return getChain(transaction.chainId, transaction.sourceAddress || ""); diff --git a/packages/shared/lib/src/types/masp.rs b/packages/shared/lib/src/types/masp.rs index c5df8b1f5..6b5c5ad97 100644 --- a/packages/shared/lib/src/types/masp.rs +++ b/packages/shared/lib/src/types/masp.rs @@ -97,7 +97,7 @@ impl PseudoExtendedKey { hex::encode(borsh::to_vec(&self.0).expect("Serializing PseudoExtendedKey should not fail!")) } - pub fn can_decode(encoded: String) -> Result { + pub fn can_decode(encoded: String) -> bool { let decoded = hex::decode(encoded); Ok(decoded.is_ok()) } From 36b957d98b8006657cb07f4d7316ad2b30a36752 Mon Sep 17 00:00:00 2001 From: neocybereth Date: Thu, 21 Aug 2025 09:38:48 +1200 Subject: [PATCH 8/8] fix: cleanup --- apps/namadillo/src/App/Common/TransactionReceipt.tsx | 2 -- packages/shared/lib/src/types/masp.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/namadillo/src/App/Common/TransactionReceipt.tsx b/apps/namadillo/src/App/Common/TransactionReceipt.tsx index e8f5259d1..34acb30da 100644 --- a/apps/namadillo/src/App/Common/TransactionReceipt.tsx +++ b/apps/namadillo/src/App/Common/TransactionReceipt.tsx @@ -66,8 +66,6 @@ const TransferTransactionReceipt = ({ }, [transaction]); const getEncodedViewingKey = (address: string): string => { - const canDecode = PseudoExtendedKey.can_decode(address); - if (!canDecode) return ""; const decodedPseudokey = PseudoExtendedKey.decode(address); const encodedViewingKey = decodedPseudokey.to_viewing_key().encode(); return encodedViewingKey; diff --git a/packages/shared/lib/src/types/masp.rs b/packages/shared/lib/src/types/masp.rs index 6b5c5ad97..06f49a04d 100644 --- a/packages/shared/lib/src/types/masp.rs +++ b/packages/shared/lib/src/types/masp.rs @@ -99,7 +99,7 @@ impl PseudoExtendedKey { pub fn can_decode(encoded: String) -> bool { let decoded = hex::decode(encoded); - Ok(decoded.is_ok()) + decoded.is_ok() } pub fn decode(encoded: String) -> Result {