From: Chris Duncan Date: Mon, 4 Aug 2025 23:06:11 +0000 (-0700) Subject: Override account derivation for Ledger wallets. X-Git-Tag: v0.10.5~46^2~1 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=7b4453ef6ad880ce261503f4738b79bb2ef32a4f;p=libnemo.git Override account derivation for Ledger wallets. --- diff --git a/src/lib/ledger.ts b/src/lib/ledger.ts index af8b911..40aa05c 100644 --- a/src/lib/ledger.ts +++ b/src/lib/ledger.ts @@ -5,6 +5,7 @@ import { ledgerUSBVendorId } from '@ledgerhq/devices' import { default as TransportBLE } from '@ledgerhq/hw-transport-web-ble' import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb' import { default as TransportHID } from '@ledgerhq/hw-transport-webhid' +import { Account, AccountList } from './account' import { ChangeBlock, ReceiveBlock, SendBlock } from './block' import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_ADPU_CODES, LEDGER_STATUS_CODES } from './constants' import { bytes, dec, hex } from './convert' @@ -78,6 +79,7 @@ export class Ledger extends Wallet { return Ledger.create() } + #accounts: AccountList #status: DeviceStatus = 'DISCONNECTED' get status (): DeviceStatus { return this.#status } @@ -87,6 +89,74 @@ export class Ledger extends Wallet { } Ledger.#isInternal = false super('Ledger') + this.#accounts = new AccountList() + } + + /** + * Gets the public key for an account from the Ledger device. + * + * @param {number[]} indexes - Indexes of the accounts + * @returns {Promise} + */ + async account (index: number): Promise { + const { status, publicKey } = await Ledger.#account(index) + if (status !== 'OK' || publicKey == null) { + throw new Error(`Error getting Ledger account: ${status}`) + } + return Account.import({ index, publicKey }) + } + + /** + * Retrieves accounts from a wallet using its child key derivation function. + * Defaults to the first account at index 0. + * + * The returned object will have keys corresponding with the requested range + * of account indexes. The value of each key will be the Account derived for + * that index in the wallet. + * + * ``` + * console.log(await wallet.accounts(5)) + * // outputs sixth account of the wallet + * // { + * // 5: { + * // privateKey: <...>, + * // index: 5 + * // } + * // } + * ``` + * + * @param {number} from - Start index of secret keys. Default: 0 + * @param {number} to - End index of secret keys. Default: `from` + * @returns {AccountList} Object with keys of account indexes and values of the corresponding Accounts + */ + async accounts (from: number = 0, to: number = from): Promise { + if (from > to) { + const swap = from + from = to + to = swap + } + const output = new AccountList() + const indexes: number[] = [] + for (let i = from; i <= to; i++) { + if (this.#accounts[i] == null) { + indexes.push(i) + } else { + output[i] = this.#accounts[i] + } + } + if (indexes.length > 0) { + const publicAccounts = [] + for (const index of indexes) { + publicAccounts.push(await this.account(index)) + } + for (const a of publicAccounts) { + if (a.index == null) { + throw new RangeError('Index missing for Account') + } + output[a.index] = this.#accounts[a.index] = a + } + } + return output } /** @@ -539,23 +609,4 @@ export class Ledger extends Wallet { return { status, name, version } } - - /** - * Gets the public key for an account from the Ledger device. - * - * @param {number[]} indexes - Indexes of the accounts - * @returns {Promise} - */ - async ckd (indexes: number[]): Promise { - const results: KeyPair[] = [] - for (const index of indexes) { - const { status, publicKey } = await Ledger.#account(index) - if (status === 'OK' && publicKey != null) { - results.push({ publicKey, index }) - } else { - throw new Error(`Error getting Ledger account: ${status}`) - } - } - return results - } }