From: Chris Duncan Date: Mon, 11 Aug 2025 12:52:06 +0000 (-0700) Subject: Move Ledger constants into Ledger class instead of shared constants file. X-Git-Tag: v0.10.5~41^2~124 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=f96cd1781068be16d4252315bda3652f079109d0;p=libnemo.git Move Ledger constants into Ledger class instead of shared constants file. --- diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 48c67ca..31bbe04 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -24,31 +24,6 @@ export const DIFFICULTY_RECEIVE = 0xfffffe0000000000n export const DIFFICULTY_SEND = 0xfffffff800000000n export const XNO = 'Ó¾' -export const LEDGER_STATUS_CODES: { [key: number]: string } = Object.freeze({ - 0x6700: 'INCORRECT_LENGTH', - 0x670a: 'NO_APPLICATION_SPECIFIED', - 0x6807: 'APPLICATION_NOT_INSTALLED', - 0x6d00: 'APPLICATION_ALREADY_LAUNCHED', - 0x6982: 'SECURITY_STATUS_NOT_SATISFIED', - 0x6985: 'CONDITIONS_OF_USE_NOT_SATISFIED', - 0x6a81: 'INVALID_SIGNATURE', - 0x6a82: 'CACHE_MISS', - 0x6b00: 'INCORRECT_PARAMETER', - 0x6e01: 'TRANSPORT_STATUS_ERROR', - 0x9000: 'OK' -}) - -export const LEDGER_ADPU_CODES: { [key: string]: number } = Object.freeze({ - class: 0xa1, - bip32DerivationLevel: 0x03, - version: 0x01, - account: 0x02, - cacheBlock: 0x03, - signBlock: 0x04, - signNonce: 0x05, - paramUnused: 0x00 -}) - export const UNITS: { [key: string]: number } = Object.freeze({ RAW: 0, RAI: 24, @@ -84,7 +59,5 @@ export default ` const DIFFICULTY_RECEIVE = ${DIFFICULTY_RECEIVE} const DIFFICULTY_SEND = ${DIFFICULTY_SEND} const XNO = '${XNO}' - const LEDGER_STATUS_CODES = ${JSON.stringify(LEDGER_STATUS_CODES)} - const LEDGER_ADPU_CODES = ${JSON.stringify(LEDGER_ADPU_CODES)} const UNITS = ${JSON.stringify(UNITS)} ` diff --git a/src/lib/wallet/ledger.ts b/src/lib/wallet/ledger.ts index 773a028..9f471c6 100644 --- a/src/lib/wallet/ledger.ts +++ b/src/lib/wallet/ledger.ts @@ -7,7 +7,7 @@ import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb' import { default as TransportHID } from '@ledgerhq/hw-transport-webhid' import { Account, AccountList } from '../account' import { Block } from '../block' -import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_ADPU_CODES, LEDGER_STATUS_CODES } from '../constants' +import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET } from '../constants' import { bytes, dec, hex } from '../convert' import { Database } from '../database' import { Rpc } from '../rpc' @@ -21,15 +21,40 @@ import { DeviceStatus, LedgerAccountResponse, LedgerResponse, LedgerSignResponse * is responsible for using Ledger technology to back up these pieces of data. */ export class Ledger extends Wallet { - static #derivationPath: Uint8Array = new Uint8Array([ - LEDGER_ADPU_CODES.bip32DerivationLevel, + static #isInternal: boolean = false + + static #ADPU_CODES: { [key: string]: number } = Object.freeze({ + class: 0xa1, + bip32DerivationLevel: 0x03, + version: 0x01, + account: 0x02, + cacheBlock: 0x03, + signBlock: 0x04, + signNonce: 0x05, + paramUnused: 0x00 + }) + static #DERIVATION_PATH: Uint8Array = new Uint8Array([ + Ledger.#ADPU_CODES.bip32DerivationLevel, ...dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4), ...dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4) ]) - static #isInternal: boolean = false - static INTERNAL: Symbol = Symbol('Ledger') + static #STATUS_CODES: { [key: number]: string } = Object.freeze({ + 0x6700: 'INCORRECT_LENGTH', + 0x670a: 'NO_APPLICATION_SPECIFIED', + 0x6807: 'APPLICATION_NOT_INSTALLED', + 0x6d00: 'APPLICATION_ALREADY_LAUNCHED', + 0x6982: 'SECURITY_STATUS_NOT_SATISFIED', + 0x6985: 'CONDITIONS_OF_USE_NOT_SATISFIED', + 0x6a81: 'INVALID_SIGNATURE', + 0x6a82: 'CACHE_MISS', + 0x6b00: 'INCORRECT_PARAMETER', + 0x6e01: 'TRANSPORT_STATUS_ERROR', + 0x9000: 'OK' + }) static DynamicTransport: typeof TransportBLE | typeof TransportUSB | typeof TransportHID + static SYMBOL: Symbol = Symbol('Ledger') + static get listenTimeout (): 30000 { return 30000 } static get openTimeout (): 3000 { return 3000 } @@ -37,7 +62,7 @@ export class Ledger extends Wallet { * Check which transport protocols are supported by the browser and return the * transport type according to the following priorities: USB, Bluetooth, HID. */ - static get isUnsupported (): boolean { + static get #isUnsupported (): boolean { console.log('Checking browser Ledger support...') if (typeof globalThis.navigator?.usb?.getDevices === 'function') { this.DynamicTransport = TransportUSB @@ -62,7 +87,7 @@ export class Ledger extends Wallet { */ static async create (): Promise { try { - if (this.isUnsupported) throw new Error('Browser is unsupported') + if (this.#isUnsupported) throw new Error('Browser is unsupported') this.#isInternal = true const self = new this() await Database.add({ [self.id]: { id: self.id, type: 'Ledger' } }, Wallet.DB_NAME) @@ -399,10 +424,10 @@ export class Ledger extends Wallet { const name = new TextEncoder().encode('Nano') const transport = await Ledger.DynamicTransport.create(Ledger.openTimeout, Ledger.listenTimeout) const response = await transport - .send(0xe0, 0xd8, LEDGER_ADPU_CODES.paramUnused, LEDGER_ADPU_CODES.paramUnused, name as Buffer) + .send(0xe0, 0xd8, Ledger.#ADPU_CODES.paramUnused, Ledger.#ADPU_CODES.paramUnused, name as Buffer) .then(res => bytes.toDec(res)) .catch(err => err.statusCode) as number - return new Promise(r => setTimeout(r, 1000, { status: LEDGER_STATUS_CODES[response] })) + return new Promise(r => setTimeout(r, 1000, { status: Ledger.#STATUS_CODES[response] })) } /** @@ -421,10 +446,10 @@ export class Ledger extends Wallet { async #close (): Promise { const transport = await Ledger.DynamicTransport.create(Ledger.openTimeout, Ledger.listenTimeout) const response = await transport - .send(0xb0, 0xa7, LEDGER_ADPU_CODES.paramUnused, LEDGER_ADPU_CODES.paramUnused) + .send(0xb0, 0xa7, Ledger.#ADPU_CODES.paramUnused, Ledger.#ADPU_CODES.paramUnused) .then(res => bytes.toDec(res)) .catch(err => err.statusCode) as number - return new Promise(r => setTimeout(r, 1000, { status: LEDGER_STATUS_CODES[response] })) + return new Promise(r => setTimeout(r, 1000, { status: Ledger.#STATUS_CODES[response] })) } /** @@ -437,16 +462,16 @@ export class Ledger extends Wallet { throw new TypeError('Invalid account index') } const account = dec.toBytes(index + HARDENED_OFFSET, 4) - const data = new Uint8Array([...Ledger.#derivationPath, ...account]) + const data = new Uint8Array([...Ledger.#DERIVATION_PATH, ...account]) const transport = await Ledger.DynamicTransport.create(Ledger.openTimeout, Ledger.listenTimeout) const response = await transport - .send(LEDGER_ADPU_CODES.class, LEDGER_ADPU_CODES.account, show ? 1 : 0, LEDGER_ADPU_CODES.paramUnused, data as Buffer) + .send(Ledger.#ADPU_CODES.class, Ledger.#ADPU_CODES.account, show ? 1 : 0, Ledger.#ADPU_CODES.paramUnused, data as Buffer) .catch(err => dec.toBytes(err.statusCode)) as Uint8Array await transport.close() const statusCode = bytes.toDec(response.slice(-2)) as number - const status = LEDGER_STATUS_CODES[statusCode] ?? 'UNKNOWN_ERROR' + const status = Ledger.#STATUS_CODES[statusCode] ?? 'UNKNOWN_ERROR' if (status !== 'OK') { return { status, publicKey: null, address: null } } @@ -494,16 +519,16 @@ export class Ledger extends Wallet { const representative = hex.toBytes(block.representative.publicKey, 32) const balance = hex.toBytes(block.balance.toString(16), 16) const signature = hex.toBytes(block.signature, 64) - const data = new Uint8Array([LEDGER_ADPU_CODES.bip32DerivationLevel, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance, ...signature]) + const data = new Uint8Array([Ledger.#ADPU_CODES.bip32DerivationLevel, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance, ...signature]) const transport = await Ledger.DynamicTransport.create(Ledger.openTimeout, Ledger.listenTimeout) const response = await transport - .send(LEDGER_ADPU_CODES.class, LEDGER_ADPU_CODES.cacheBlock, LEDGER_ADPU_CODES.paramUnused, LEDGER_ADPU_CODES.paramUnused, data as Buffer) + .send(Ledger.#ADPU_CODES.class, Ledger.#ADPU_CODES.cacheBlock, Ledger.#ADPU_CODES.paramUnused, Ledger.#ADPU_CODES.paramUnused, data as Buffer) .then(res => bytes.toDec(res)) .catch(err => err.statusCode) as number await transport.close() - return { status: LEDGER_STATUS_CODES[response] } + return { status: Ledger.#STATUS_CODES[response] } } /** @@ -529,16 +554,16 @@ export class Ledger extends Wallet { const link = block.link const representative = hex.toBytes(block.representative.publicKey, 32) const balance = hex.toBytes(BigInt(block.balance).toString(16), 16) - const data = new Uint8Array([...Ledger.#derivationPath, ...account, ...previous, ...link, ...representative, ...balance]) + const data = new Uint8Array([...Ledger.#DERIVATION_PATH, ...account, ...previous, ...link, ...representative, ...balance]) const transport = await Ledger.DynamicTransport.create(Ledger.openTimeout, Ledger.listenTimeout) const response = await transport - .send(LEDGER_ADPU_CODES.class, LEDGER_ADPU_CODES.signBlock, LEDGER_ADPU_CODES.paramUnused, LEDGER_ADPU_CODES.paramUnused, data as Buffer) + .send(Ledger.#ADPU_CODES.class, Ledger.#ADPU_CODES.signBlock, Ledger.#ADPU_CODES.paramUnused, Ledger.#ADPU_CODES.paramUnused, data as Buffer) .catch(err => dec.toBytes(err.statusCode)) as Uint8Array await transport.close() const statusCode = bytes.toDec(response.slice(-2)) as number - const status = LEDGER_STATUS_CODES[statusCode] ?? 'UNKNOWN_ERROR' + const status = Ledger.#STATUS_CODES[statusCode] ?? 'UNKNOWN_ERROR' if (response.byteLength === 2) { return { status, signature: null } @@ -570,16 +595,16 @@ export class Ledger extends Wallet { } const derivationAccount = dec.toBytes(index + HARDENED_OFFSET, 4) - const data = new Uint8Array([...Ledger.#derivationPath, ...derivationAccount, ...nonce]) + const data = new Uint8Array([...Ledger.#DERIVATION_PATH, ...derivationAccount, ...nonce]) const transport = await Ledger.DynamicTransport.create(Ledger.openTimeout, Ledger.listenTimeout) const response = await transport - .send(LEDGER_ADPU_CODES.class, LEDGER_ADPU_CODES.signNonce, LEDGER_ADPU_CODES.paramUnused, LEDGER_ADPU_CODES.paramUnused, data as Buffer) + .send(Ledger.#ADPU_CODES.class, Ledger.#ADPU_CODES.signNonce, Ledger.#ADPU_CODES.paramUnused, Ledger.#ADPU_CODES.paramUnused, data as Buffer) .catch(err => dec.toBytes(err.statusCode)) as Uint8Array await transport.close() const statusCode = bytes.toDec(response.slice(-2)) as number - const status = LEDGER_STATUS_CODES[statusCode] ?? 'UNKNOWN_ERROR' + const status = Ledger.#STATUS_CODES[statusCode] ?? 'UNKNOWN_ERROR' if (response.byteLength === 2) { return { status, signature: null } @@ -603,12 +628,12 @@ export class Ledger extends Wallet { async #version (): Promise { const transport = await Ledger.DynamicTransport.create(Ledger.openTimeout, Ledger.listenTimeout) const response = await transport - .send(0xb0, LEDGER_ADPU_CODES.version, LEDGER_ADPU_CODES.paramUnused, LEDGER_ADPU_CODES.paramUnused) + .send(0xb0, Ledger.#ADPU_CODES.version, Ledger.#ADPU_CODES.paramUnused, Ledger.#ADPU_CODES.paramUnused) .catch(err => dec.toBytes(err.statusCode)) as Uint8Array await transport.close() const statusCode = bytes.toDec(response.slice(-2)) as number - const status = LEDGER_STATUS_CODES[statusCode] ?? 'UNKNOWN_ERROR' + const status = Ledger.#STATUS_CODES[statusCode] ?? 'UNKNOWN_ERROR' if (status !== 'OK') { return { status, name: null, version: null } }