@@ -22,6 +24,7 @@ export const LedgerConfirmation = (): JSX.Element => {
diff --git a/apps/extension/src/Setup/Ledger/LedgerConnect.tsx b/apps/extension/src/Setup/Ledger/LedgerConnect.tsx
index 8dd0d176a4..7a09c719b8 100644
--- a/apps/extension/src/Setup/Ledger/LedgerConnect.tsx
+++ b/apps/extension/src/Setup/Ledger/LedgerConnect.tsx
@@ -1,11 +1,20 @@
import { chains } from "@namada/chains";
import { ActionButton, Alert, Image, Stack } from "@namada/components";
-import { Ledger as LedgerApp, makeBip44Path } from "@namada/sdk/web";
+import {
+ ExtendedViewingKey,
+ Ledger as LedgerApp,
+ makeBip44Path,
+ makeSaplingPath,
+ ProofGenerationKey,
+ PseudoExtendedKey,
+} from "@namada/sdk/web";
+import initWasm from "@namada/sdk/web-init";
import { Bip44Path } from "@namada/types";
import { LedgerError } from "@zondax/ledger-namada";
import { LedgerStep } from "Setup/Common";
import { AdvancedOptions } from "Setup/Common/AdvancedOptions";
import Bip44Form from "Setup/Common/Bip44Form";
+import { LedgerApprovalStep } from "Setup/Common/LedgerApprovalStep";
import routes from "Setup/routes";
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
@@ -21,6 +30,9 @@ export const LedgerConnect: React.FC = ({ path, setPath }) => {
const [isLedgerConnecting, setIsLedgerConnecting] = useState(false);
const [ledger, setLedger] = useState();
+ // Import keys steps (transparent, viewing key, proof-gen key)
+ const [currentApprovalStep, setCurrentApprovalStep] = useState(1);
+
const queryLedger = async (ledger: LedgerApp): Promise => {
setError(undefined);
try {
@@ -33,14 +45,47 @@ export const LedgerConnect: React.FC = ({ path, setPath }) => {
}
setIsLedgerConnecting(true);
+ setCurrentApprovalStep(1);
const { address, publicKey } = await ledger.showAddressAndPublicKey(
makeBip44Path(chains.namada.bip44.coinType, path)
);
+
+ // Shielded Keys
+ const zip32Path = makeSaplingPath(chains.namada.bip44.coinType, {
+ account: path.account,
+ });
+
+ setCurrentApprovalStep(2);
+ const { xfvk } = await ledger.getViewingKey(zip32Path);
+
+ setCurrentApprovalStep(3);
+ const { ak, nsk } = await ledger.getProofGenerationKey(zip32Path);
+
+ // SDK wasm init must be called
+ await initWasm();
+
+ const extendedViewingKey = new ExtendedViewingKey(xfvk);
+ const encodedExtendedViewingKey = extendedViewingKey.encode();
+ const encodedPaymentAddress = extendedViewingKey
+ .default_payment_address()
+ .encode();
+
+ const proofGenerationKey = ProofGenerationKey.from_bytes(ak, nsk);
+ const pseudoExtendedKey = PseudoExtendedKey.from(
+ extendedViewingKey,
+ proofGenerationKey
+ );
+ const encodedPseudoExtendedKey = pseudoExtendedKey.encode();
+
setIsLedgerConnecting(false);
+
navigate(routes.ledgerImport(), {
state: {
address,
publicKey,
+ extendedViewingKey: encodedExtendedViewingKey,
+ paymentAddress: encodedPaymentAddress,
+ pseudoExtendedKey: encodedPseudoExtendedKey,
},
});
} catch (e) {
@@ -83,11 +128,7 @@ export const LedgerConnect: React.FC = ({ path, setPath }) => {
return (
-
+
{error && (
{error}
@@ -95,36 +136,41 @@ export const LedgerConnect: React.FC = ({ path, setPath }) => {
)}
{isLedgerConnecting && (
- Review on your Ledger
+
)}
-
-
-
-
- connectUSB()}
- active={!ledger}
- complete={!!ledger}
- buttonDisabled={!!ledger}
- image={
-
- }
- />
-
- connectNamadaApp()}
- buttonDisabled={!ledger || isLedgerConnecting}
- image={
-
- }
- />
+ {!isLedgerConnecting && (
+ <>
+
+
+
+ connectUSB()}
+ active={!ledger}
+ complete={!!ledger}
+ buttonDisabled={!!ledger}
+ image={
+
+ }
+ />
+ connectNamadaApp()}
+ buttonDisabled={!ledger || isLedgerConnecting}
+ image={
+
+ }
+ />
+ >
+ )}
Next
diff --git a/apps/extension/src/Setup/Ledger/LedgerImport.tsx b/apps/extension/src/Setup/Ledger/LedgerImport.tsx
index 6d9fb4ef50..55b9c3598d 100644
--- a/apps/extension/src/Setup/Ledger/LedgerImport.tsx
+++ b/apps/extension/src/Setup/Ledger/LedgerImport.tsx
@@ -10,6 +10,9 @@ import { useLocation, useNavigate } from "react-router-dom";
type LedgerImportLocationState = {
address: string;
publicKey: string;
+ extendedViewingKey: string;
+ pseudoExtendedKey: string;
+ paymentAddress: string;
};
type LedgerProps = {
@@ -55,16 +58,25 @@ export const LedgerImport = ({
await accountManager.savePassword(password);
}
- const { address, publicKey } = locationState;
+ const {
+ address,
+ publicKey,
+ extendedViewingKey,
+ paymentAddress,
+ pseudoExtendedKey,
+ } = locationState;
const account = await accountManager.saveLedgerAccount({
alias,
address,
publicKey,
path,
+ paymentAddress,
+ extendedViewingKey,
+ pseudoExtendedKey,
});
navigate(routes.ledgerComplete(), {
- state: { account: { ...account } },
+ state: { account: { ...account, paymentAddress } },
});
} catch (e) {
console.warn(e);
diff --git a/apps/extension/src/Setup/Setup.tsx b/apps/extension/src/Setup/Setup.tsx
index c08e1a3ea5..28ea9a07ba 100644
--- a/apps/extension/src/Setup/Setup.tsx
+++ b/apps/extension/src/Setup/Setup.tsx
@@ -11,7 +11,7 @@ import {
Container,
LifecycleExecutionWrapper as Wrapper,
} from "@namada/components";
-import { Bip44Path, DerivedAccount } from "@namada/types";
+import { Bip44Path } from "@namada/types";
import { assertNever } from "@namada/utils";
import { AccountSecret, AccountStore } from "background/keyring";
import { AnimatePresence, motion } from "framer-motion";
@@ -81,7 +81,7 @@ export const Setup: React.FC = () => {
});
const [parentAccountStore, setParentAccountStore] = useState();
- const [shieldedAccount, setShieldedAccount] = useState();
+ const [paymentAddress, setPaymentAddress] = useState();
const [completionStatus, setCompletionStatus] = useState();
const [completionStatusInfo, setCompletionStatusInfo] = useState("");
@@ -127,7 +127,7 @@ export const Setup: React.FC = () => {
details,
parentAccount
);
- setShieldedAccount(shieldedAccount);
+ setPaymentAddress(shieldedAccount?.address);
setCompletionStatus(CompletionStatus.Completed);
setCompletionStatusInfo("Done!");
} catch (e) {
@@ -275,7 +275,7 @@ export const Setup: React.FC = () => {
password={accountCreationDetails.password || ""}
path={path}
parentAccountStore={parentAccountStore}
- shieldedAccount={shieldedAccount}
+ paymentAddress={paymentAddress}
status={completionStatus}
statusInfo={completionStatusInfo}
/>
@@ -352,7 +352,7 @@ export const Setup: React.FC = () => {
password={accountCreationDetails.password || ""}
path={path}
parentAccountStore={parentAccountStore}
- shieldedAccount={shieldedAccount}
+ paymentAddress={paymentAddress}
status={completionStatus}
statusInfo={completionStatusInfo}
/>
@@ -398,7 +398,7 @@ export const Setup: React.FC = () => {
+
}
diff --git a/apps/extension/src/Setup/query.ts b/apps/extension/src/Setup/query.ts
index ea8be11553..f7afe1e89d 100644
--- a/apps/extension/src/Setup/query.ts
+++ b/apps/extension/src/Setup/query.ts
@@ -88,10 +88,26 @@ export class AccountManager {
async saveLedgerAccount(
details: LedgerAccountDetails
): Promise {
- const { alias, address, publicKey, path } = details;
+ const {
+ alias,
+ address,
+ publicKey,
+ path,
+ extendedViewingKey,
+ pseudoExtendedKey,
+ paymentAddress,
+ } = details;
return (await this.requester.sendMessage(
Ports.Background,
- new AddLedgerAccountMsg(alias, address, publicKey, path)
+ new AddLedgerAccountMsg(
+ alias,
+ address,
+ publicKey,
+ path,
+ extendedViewingKey,
+ pseudoExtendedKey,
+ paymentAddress
+ )
)) as AccountStore;
}
}
diff --git a/apps/extension/src/Setup/types.ts b/apps/extension/src/Setup/types.ts
index 4ea8253ed3..54d7901c91 100644
--- a/apps/extension/src/Setup/types.ts
+++ b/apps/extension/src/Setup/types.ts
@@ -19,4 +19,7 @@ export type LedgerAccountDetails = {
path: Bip44Path;
address: string;
publicKey: string;
+ extendedViewingKey: string;
+ pseudoExtendedKey: string;
+ paymentAddress: string;
};
diff --git a/apps/extension/src/background/keyring/handler.ts b/apps/extension/src/background/keyring/handler.ts
index 2d86d20d21..e447d5f949 100644
--- a/apps/extension/src/background/keyring/handler.ts
+++ b/apps/extension/src/background/keyring/handler.ts
@@ -105,8 +105,24 @@ const handleAddLedgerAccountMsg: (
service: KeyRingService
) => InternalHandler = (service) => {
return async (_, msg) => {
- const { alias, address, publicKey, bip44Path } = msg;
- return await service.saveLedger(alias, address, publicKey, bip44Path);
+ const {
+ alias,
+ address,
+ publicKey,
+ bip44Path,
+ extendedViewingKey,
+ pseudoExtendedKey,
+ paymentAddress,
+ } = msg;
+ return await service.saveLedger(
+ alias,
+ address,
+ publicKey,
+ bip44Path,
+ extendedViewingKey,
+ pseudoExtendedKey,
+ paymentAddress
+ );
};
};
diff --git a/apps/extension/src/background/keyring/keyring.ts b/apps/extension/src/background/keyring/keyring.ts
index 54352f3233..ef73b1178a 100644
--- a/apps/extension/src/background/keyring/keyring.ts
+++ b/apps/extension/src/background/keyring/keyring.ts
@@ -101,7 +101,10 @@ export class KeyRing {
alias: string,
address: string,
publicKey: string,
- bip44Path: Bip44Path
+ bip44Path: Bip44Path,
+ pseudoExtendedKey: string,
+ extendedViewingKey: string,
+ paymentAddress: string
): Promise {
const id = generateId(UUID_NAMESPACE, alias, address);
const accountStore: AccountStore = {
@@ -125,6 +128,30 @@ export class KeyRing {
sensitive,
});
+ const shieldedId = generateId(UUID_NAMESPACE, alias, paymentAddress);
+ const shieldedAccountStore: AccountStore = {
+ id: shieldedId,
+ alias,
+ address: paymentAddress,
+ publicKey,
+ owner: extendedViewingKey,
+ path: bip44Path,
+ pseudoExtendedKey,
+ parentId: id,
+ type: AccountType.ShieldedKeys,
+ source: "imported",
+ timestamp: 0,
+ };
+
+ const shieldedSensitive = await this.vaultService.encryptSensitiveData({
+ text: "",
+ passphrase: "",
+ });
+ await this.vaultStorage.add(KeyStore, {
+ public: shieldedAccountStore,
+ sensitive: shieldedSensitive,
+ });
+
await this.setActiveAccount(id, AccountType.Ledger);
return accountStore;
}
diff --git a/apps/extension/src/background/keyring/messages.ts b/apps/extension/src/background/keyring/messages.ts
index 927657485d..f658183a94 100644
--- a/apps/extension/src/background/keyring/messages.ts
+++ b/apps/extension/src/background/keyring/messages.ts
@@ -186,27 +186,23 @@ export class AddLedgerAccountMsg extends Message {
public readonly address: string,
public readonly publicKey: string,
public readonly bip44Path: Bip44Path,
- public readonly parentId?: string
+ public readonly extendedViewingKey: string,
+ public readonly pseudoExtendedKey: string,
+ public readonly paymentAddress: string
) {
super();
}
validate(): void {
- if (!this.alias) {
- throw new Error("Alias must not be empty!");
- }
-
- if (!this.address) {
- throw new Error("Address was not provided!");
- }
-
- if (!this.publicKey) {
- throw new Error("Public key was not provided!");
- }
-
- if (!this.bip44Path) {
- throw new Error("BIP44 Path was not provided!");
- }
+ validateProps(this, [
+ "alias",
+ "address",
+ "publicKey",
+ "bip44Path",
+ "extendedViewingKey",
+ "pseudoExtendedKey",
+ "paymentAddress",
+ ]);
}
route(): string {
@@ -269,13 +265,7 @@ export class SetActiveAccountMsg extends Message {
}
validate(): void {
- if (!this.accountId) {
- throw new Error("Account ID is not set!");
- }
-
- if (!this.accountType) {
- throw new Error("Account Type is required!");
- }
+ validateProps(this, ["accountId", "accountType"]);
}
route(): string {
@@ -369,10 +359,7 @@ export class QueryAccountDetailsMsg extends Message<
}
validate(): void {
- if (!this.address) {
- throw new Error("Account address is required!");
- }
- return;
+ validateProps(this, ["address"]);
}
route(): string {
@@ -397,12 +384,7 @@ export class AppendLedgerSignatureMsg extends Message {
}
validate(): void {
- if (!this.txBytes) {
- throw new Error("txBytes is required!");
- }
- if (!this.signature) {
- throw new Error("signature is required!");
- }
+ validateProps(this, ["txBytes", "signature"]);
}
route(): string {
diff --git a/apps/extension/src/background/keyring/service.ts b/apps/extension/src/background/keyring/service.ts
index 4be1e92b53..7c806f6f03 100644
--- a/apps/extension/src/background/keyring/service.ts
+++ b/apps/extension/src/background/keyring/service.ts
@@ -81,7 +81,10 @@ export class KeyRingService {
alias: string,
address: string,
publicKey: string,
- bip44Path: Bip44Path
+ bip44Path: Bip44Path,
+ extendedViewingKey: string,
+ pseudoExtendedKey: string,
+ paymentAddress: string
): Promise {
const account = await this._keyRing.queryAccountByAddress(address);
if (account) {
@@ -94,7 +97,10 @@ export class KeyRingService {
alias,
address,
publicKey,
- bip44Path
+ bip44Path,
+ pseudoExtendedKey,
+ extendedViewingKey,
+ paymentAddress
);
await this.broadcaster.updateAccounts();
diff --git a/packages/sdk/package.json b/packages/sdk/package.json
index 6b394d00b6..a637a6f4d9 100644
--- a/packages/sdk/package.json
+++ b/packages/sdk/package.json
@@ -60,11 +60,11 @@
"@cosmjs/encoding": "^0.29.0",
"@dao-xyz/borsh": "^5.1.5",
"@ledgerhq/hw-transport": "^6.31.4",
- "@ledgerhq/hw-transport-webhid": "^6.29.4",
"@ledgerhq/hw-transport-webusb": "^6.29.4",
- "@zondax/ledger-namada": "^1.0.0",
+ "@zondax/ledger-namada": "^2.0.0",
"bignumber.js": "^9.1.1",
"buffer": "^6.0.3",
+ "semver": "^7.6.3",
"slip44": "^3.0.18"
},
"devDependencies": {
diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts
index cd7c35ece4..29db7341ee 100644
--- a/packages/sdk/src/index.ts
+++ b/packages/sdk/src/index.ts
@@ -1,13 +1,10 @@
// Make Ledger available for direct-import as it is not dependent on Sdk initialization
-export {
- Ledger,
- initLedgerHIDTransport,
- initLedgerUSBTransport,
-} from "./ledger";
+export { Ledger, initLedgerUSBTransport } from "./ledger";
export type {
LedgerAddressAndPublicKey,
- LedgerShieldedKeys,
+ LedgerProofGenerationKey,
LedgerStatus,
+ LedgerViewingKey,
} from "./ledger";
// Export types
@@ -37,6 +34,11 @@ export { ProgressBarNames, Sdk, SdkEvents } from "./sdk";
export { publicKeyToBech32 } from "./keys";
+export {
+ ExtendedViewingKey,
+ ProofGenerationKey,
+ PseudoExtendedKey,
+} from "./masp";
export type { Masp } from "./masp";
export { PhraseSize } from "./mnemonic";
export type { Mnemonic } from "./mnemonic";
diff --git a/packages/sdk/src/ledger.ts b/packages/sdk/src/ledger.ts
index e4ad28ee40..f39281bb42 100644
--- a/packages/sdk/src/ledger.ts
+++ b/packages/sdk/src/ledger.ts
@@ -1,5 +1,4 @@
import Transport from "@ledgerhq/hw-transport";
-import TransportHID from "@ledgerhq/hw-transport-webhid";
import TransportUSB from "@ledgerhq/hw-transport-webusb";
import { chains } from "@namada/chains";
import {
@@ -12,21 +11,18 @@ import {
ResponseVersion,
ResponseViewKey,
} from "@zondax/ledger-namada";
-import { makeBip44Path } from "./utils";
+import semver from "semver";
+import { makeBip44Path, makeSaplingPath } from "./utils";
const { coinType } = chains.namada.bip44;
export type LedgerAddressAndPublicKey = { address: string; publicKey: string };
-export type LedgerShieldedKeys = {
- viewingKey: {
- viewKey?: string;
- ivk?: string;
- ovk?: string;
- };
- proofGenerationKey: {
- ak?: string;
- nsk?: string;
- };
+export type LedgerViewingKey = {
+ xfvk: Uint8Array;
+};
+export type LedgerProofGenerationKey = {
+ ak: Uint8Array;
+ nsk: Uint8Array;
};
export type LedgerStatus = {
@@ -34,6 +30,8 @@ export type LedgerStatus = {
info: ResponseAppInfo;
};
+const LEDGER_MIN_VERSION_ZIP32 = "2.0.0";
+
/**
* Initialize USB transport
* @async
@@ -43,21 +41,16 @@ export const initLedgerUSBTransport = async (): Promise => {
return await TransportUSB.create();
};
-/**
- * Initialize HID transport
- * @async
- * @returns Transport object
- */
-export const initLedgerHIDTransport = async (): Promise => {
- return await TransportHID.create();
-};
-
export const DEFAULT_LEDGER_BIP44_PATH = makeBip44Path(coinType, {
account: 0,
change: 0,
index: 0,
});
+export const DEFAULT_LEDGER_ZIP32_PATH = makeSaplingPath(coinType, {
+ account: 0,
+});
+
/**
* Functionality for interacting with NamadaApp for Ledger Hardware Wallets
*/
@@ -147,20 +140,52 @@ export class Ledger {
}
/**
- * Prompt user to get viewing and proof gen key associated with optional path, otherwise, use default path.
- * Throw exception if app is not initialized.
+ * Prompt user to get viewing key associated with optional path, otherwise, use default path.
+ * Throw exception if app is not initialized, zip32 is not supported, or key is not returned.
* @async
- * @param [path] Bip44 path for deriving key
+ * @param [path] Zip32 path for deriving key
* @param [promptUser] boolean to determine whether to display on Ledger device and require approval
* @returns ShieldedKeys
*/
- public async getShieldedKeys(
- path: string = DEFAULT_LEDGER_BIP44_PATH,
+ public async getViewingKey(
+ path: string = DEFAULT_LEDGER_ZIP32_PATH,
promptUser = true
- ): Promise {
+ ): Promise {
try {
- const { viewKey, ivk, ovk }: ResponseViewKey =
- await this.namadaApp.retrieveKeys(path, NamadaKeys.ViewKey, promptUser);
+ await this.validateVersionForZip32();
+
+ const { xfvk }: ResponseViewKey = await this.namadaApp.retrieveKeys(
+ path,
+ NamadaKeys.ViewKey,
+ promptUser
+ );
+
+ if (!xfvk) {
+ throw new Error("Did not receive viewing key!");
+ }
+
+ return {
+ xfvk: new Uint8Array(xfvk),
+ };
+ } catch (e) {
+ throw new Error(`${e}`);
+ }
+ }
+
+ /**
+ * Prompt user to get proof generation key associated with optional path, otherwise, use default path.
+ * Throw exception if app is not initialized, zip32 is not supported, or key is not returned.
+ * @async
+ * @param [path] Zip32 path for deriving key
+ * @param [promptUser] boolean to determine whether to display on Ledger device and require approval
+ * @returns ShieldedKeys
+ */
+ public async getProofGenerationKey(
+ path: string = DEFAULT_LEDGER_ZIP32_PATH,
+ promptUser = true
+ ): Promise {
+ try {
+ await this.validateVersionForZip32();
const { ak, nsk }: ResponseProofGenKey =
await this.namadaApp.retrieveKeys(
@@ -169,19 +194,16 @@ export class Ledger {
promptUser
);
+ if (!ak || !nsk) {
+ throw new Error("Did not receive proof generation key!");
+ }
+
return {
- viewingKey: {
- viewKey: viewKey?.toString(),
- ivk: ivk?.toString(),
- ovk: ovk?.toString(),
- },
- proofGenerationKey: {
- ak: ak?.toString(),
- nsk: nsk?.toString(),
- },
+ ak: new Uint8Array(ak),
+ nsk: new Uint8Array(nsk),
};
- } catch (_) {
- throw new Error(`Could not retrieve Viewing Key`);
+ } catch (e) {
+ throw new Error(`${e}`);
}
}
@@ -228,4 +250,35 @@ export class Ledger {
public async closeTransport(): Promise {
return await this.namadaApp.transport.close();
}
+
+ /**
+ * Check if Zip32 is supported by the installed app's version.
+ * Throws error if app is not initialized
+ * @async
+ * @retuns boolean
+ */
+ public async isZip32Supported(): Promise {
+ const {
+ info: { appVersion },
+ } = await this.status();
+ return !semver.lt(appVersion, LEDGER_MIN_VERSION_ZIP32);
+ }
+
+ /**
+ * Validate the version against the minimum required version for Zip32 functionality.
+ * Throw error if it is unsupported or app is not initialized.
+ * @async
+ * @returns void
+ */
+ private async validateVersionForZip32(): Promise {
+ if (!(await this.isZip32Supported())) {
+ const {
+ info: { appVersion },
+ } = await this.status();
+ throw new Error(
+ `This method requires Zip32 and is unsupported in ${appVersion}! ` +
+ `Please update to at least ${LEDGER_MIN_VERSION_ZIP32}!`
+ );
+ }
+ }
}
diff --git a/packages/sdk/src/masp/index.ts b/packages/sdk/src/masp/index.ts
new file mode 100644
index 0000000000..9a8f1db3cf
--- /dev/null
+++ b/packages/sdk/src/masp/index.ts
@@ -0,0 +1,2 @@
+export * from "./masp";
+export * from "./types";
diff --git a/packages/sdk/src/masp.ts b/packages/sdk/src/masp/masp.ts
similarity index 100%
rename from packages/sdk/src/masp.ts
rename to packages/sdk/src/masp/masp.ts
diff --git a/packages/sdk/src/masp/types.ts b/packages/sdk/src/masp/types.ts
new file mode 100644
index 0000000000..1123ea2cbd
--- /dev/null
+++ b/packages/sdk/src/masp/types.ts
@@ -0,0 +1,5 @@
+export {
+ ExtendedViewingKey,
+ ProofGenerationKey,
+ PseudoExtendedKey,
+} from "@namada/shared";
diff --git a/packages/sdk/src/tests/ledger.test.ts b/packages/sdk/src/tests/ledger.test.ts
index 3aa9969cca..0934e984f2 100644
--- a/packages/sdk/src/tests/ledger.test.ts
+++ b/packages/sdk/src/tests/ledger.test.ts
@@ -1,13 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
-import TransportHID from "@ledgerhq/hw-transport-webhid";
import TransportUSB from "@ledgerhq/hw-transport-webusb";
import * as LedgerNamadaNS from "@zondax/ledger-namada";
import * as LedgerNS from "../ledger";
-import {
- Ledger,
- initLedgerHIDTransport,
- initLedgerUSBTransport,
-} from "../ledger";
+import { Ledger, initLedgerUSBTransport } from "../ledger";
// Needed otherwise we can't redefine the classes from this module
jest.mock("@zondax/ledger-namada", () => {
@@ -37,17 +32,6 @@ describe("ledger", () => {
});
});
- describe("initLedgerHIDTransport", () => {
- it("should initialize a Ledger HID transport", async () => {
- const returned = { hid: true };
- jest.spyOn(TransportHID, "create").mockResolvedValue(returned as any);
- const res = await initLedgerHIDTransport();
-
- expect(TransportHID.create).toHaveBeenCalled();
- expect(res).toEqual(returned);
- });
- });
-
describe("Ledger", () => {
describe("init", () => {
it("should initialize a ledger with provided Transport", async () => {
diff --git a/packages/shared/lib/src/types/masp.rs b/packages/shared/lib/src/types/masp.rs
index cff5b901e8..e18de76e3f 100644
--- a/packages/shared/lib/src/types/masp.rs
+++ b/packages/shared/lib/src/types/masp.rs
@@ -47,6 +47,13 @@ impl ExtendedViewingKey {
pub fn encode(&self) -> String {
self.0.to_string()
}
+
+ pub fn default_payment_address(&self) -> PaymentAddress {
+ let xfvk = zip32::ExtendedFullViewingKey::from(self.0);
+ let (_, payment_address) = xfvk.default_address();
+
+ PaymentAddress(payment_address.into())
+ }
}
#[wasm_bindgen]
@@ -54,11 +61,20 @@ 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!");
@@ -78,6 +94,7 @@ 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) -> PseudoExtendedKey {
let decoded = hex::decode(encoded).expect("Decoding PseudoExtendedKey should not fail!");
@@ -86,6 +103,18 @@ impl PseudoExtendedKey {
.expect("Deserializing ProofGenerationKey should not fail!"),
)
}
+
+ 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)
+ }
}
/// Wrap ExtendedSpendingKey
diff --git a/yarn.lock b/yarn.lock
index bd8d2aa800..a64c1219e0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3209,7 +3209,7 @@ __metadata:
languageName: node
linkType: hard
-"@ledgerhq/devices@npm:8.4.4, @ledgerhq/devices@npm:^8.4.4":
+"@ledgerhq/devices@npm:^8.4.4":
version: 8.4.4
resolution: "@ledgerhq/devices@npm:8.4.4"
dependencies:
@@ -3228,18 +3228,6 @@ __metadata:
languageName: node
linkType: hard
-"@ledgerhq/hw-transport-webhid@npm:^6.29.4":
- version: 6.30.0
- resolution: "@ledgerhq/hw-transport-webhid@npm:6.30.0"
- dependencies:
- "@ledgerhq/devices": "npm:8.4.4"
- "@ledgerhq/errors": "npm:^6.19.1"
- "@ledgerhq/hw-transport": "npm:^6.31.4"
- "@ledgerhq/logs": "npm:^6.12.0"
- checksum: 10c0/1cb6ddb50127d6cb73d80259e10da687a2b7aa87ebbac8cc3e770ac5b95a3ef0001bdaf77109da0eb62509cb8668a9642858b59cb0ff355c1adb0fe2114c532c
- languageName: node
- linkType: hard
-
"@ledgerhq/hw-transport-webusb@npm:^6.29.4":
version: 6.29.4
resolution: "@ledgerhq/hw-transport-webusb@npm:6.29.4"
@@ -3430,7 +3418,6 @@ __metadata:
"@cosmjs/encoding": "npm:^0.29.0"
"@dao-xyz/borsh": "npm:^5.1.5"
"@ledgerhq/hw-transport": "npm:^6.31.4"
- "@ledgerhq/hw-transport-webhid": "npm:^6.29.4"
"@ledgerhq/hw-transport-webusb": "npm:^6.29.4"
"@svgr/webpack": "npm:^6.3.1"
"@types/chrome": "npm:^0.0.237"
@@ -3443,7 +3430,7 @@ __metadata:
"@types/w3c-web-usb": "npm:^1.0.10"
"@types/webextension-polyfill": "npm:^0.10.6"
"@types/zxcvbn": "npm:^4.4.1"
- "@zondax/ledger-namada": "npm:^1.0.0"
+ "@zondax/ledger-namada": "npm:^2.0.0"
bignumber.js: "npm:^9.1.1"
buffer: "npm:^6.0.3"
copy-webpack-plugin: "npm:^11.0.0"
@@ -3707,11 +3694,10 @@ __metadata:
"@cosmjs/encoding": "npm:^0.29.0"
"@dao-xyz/borsh": "npm:^5.1.5"
"@ledgerhq/hw-transport": "npm:^6.31.4"
- "@ledgerhq/hw-transport-webhid": "npm:^6.29.4"
"@ledgerhq/hw-transport-webusb": "npm:^6.29.4"
"@types/jest": "npm:^29.5.12"
"@types/node": "npm:^20.11.4"
- "@zondax/ledger-namada": "npm:^1.0.0"
+ "@zondax/ledger-namada": "npm:^2.0.0"
babel-jest: "npm:^29.0.3"
bignumber.js: "npm:^9.1.1"
buffer: "npm:^6.0.3"
@@ -3727,6 +3713,7 @@ __metadata:
jest-mock-server: "npm:^0.1.0"
jsdoc-babel: "npm:^0.5.0"
rimraf: "npm:^5.0.5"
+ semver: "npm:^7.6.3"
slip44: "npm:^3.0.18"
ts-jest: "npm:^29.2.5"
ts-node: "npm:^10.9.1"
@@ -6072,12 +6059,12 @@ __metadata:
languageName: node
linkType: hard
-"@zondax/ledger-namada@npm:^1.0.0":
- version: 1.0.0
- resolution: "@zondax/ledger-namada@npm:1.0.0"
+"@zondax/ledger-namada@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "@zondax/ledger-namada@npm:2.0.0"
dependencies:
"@ledgerhq/hw-transport": "npm:^6.30.6"
- checksum: 10c0/f7490964ccd41f9a63f2bc8d89ea9f01e7d6a58be796db0b454a3f1455dcc8dc8dd578a8642aa0f0799c93f838e8e3afd69f59f7e9947816b9471338c2b9dd63
+ checksum: 10c0/1fa2a9a537bc42df01444332529a606ed77f608a2cc1dbb029915ed854ff447976930a4338c2d68d50d98869828cd76b1a4f4b5c2c989fd84af7b66d55dc51fc
languageName: node
linkType: hard