import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb'
import { default as TransportHID } from '@ledgerhq/hw-transport-webhid'
import { ChangeBlock, ReceiveBlock, SendBlock } from './block'
-import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_STATUS_CODES } from './constants'
+import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_ADPU_CODES, LEDGER_STATUS_CODES } from './constants'
import { bytes, dec, hex, utf8 } from './convert'
import { Rpc } from './rpc'
export class Ledger {
static #isInternal: boolean = false
- static #adpu = {
- class: 0xa1,
- bip32DerivationLevel: 0x03,
- version: 0x01,
- account: 0x02,
- cacheBlock: 0x03,
- signBlock: 0x04,
- signNonce: 0x05,
- paramUnused: 0x00
- }
#status: 'DISCONNECTED' | 'LOCKED' | 'BUSY' | 'CONNECTED' = 'DISCONNECTED'
get status () { return this.#status }
openTimeout = 3000
async open (): Promise<LedgerResponse> {
const name = new TextEncoder().encode('Nano')
const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout)
- const response = await transport.send(0xe0, 0xd8, Ledger.#adpu.paramUnused, Ledger.#adpu.paramUnused, name as Buffer)
+ const response = await transport.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(resolve => setTimeout(resolve, 1000, { status: LEDGER_STATUS_CODES[response] }))
*/
async close (): Promise<LedgerResponse> {
const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout)
- const response = await transport.send(0xb0, 0xa7, Ledger.#adpu.paramUnused, Ledger.#adpu.paramUnused)
+ const response = await transport.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(resolve => setTimeout(resolve, 1000, { status: LEDGER_STATUS_CODES[response] }))
*/
async version (): Promise<LedgerVersionResponse> {
const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout)
- const response = await transport.send(0xb0, Ledger.#adpu.version, Ledger.#adpu.paramUnused, Ledger.#adpu.paramUnused)
+ const response = await transport.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 purpose = dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4)
const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4)
const account = dec.toBytes(index + HARDENED_OFFSET, 4)
- const data = new Uint8Array([Ledger.#adpu.bip32DerivationLevel, ...purpose, ...coin, ...account])
+ const data = new Uint8Array([LEDGER_ADPU_CODES.bip32DerivationLevel, ...purpose, ...coin, ...account])
const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout)
- const response = await transport.send(Ledger.#adpu.class, Ledger.#adpu.account, show ? 0x01 : 0x00, Ledger.#adpu.paramUnused, data as Buffer)
+ const response = await transport.send(LEDGER_ADPU_CODES.class, LEDGER_ADPU_CODES.account, show ? 0x01 : 0x00, LEDGER_ADPU_CODES.paramUnused, data as Buffer)
.catch(err => dec.toBytes(err.statusCode)) as Uint8Array
await transport.close()
const representative = hex.toBytes(block.representative.publicKey)
const balance = hex.toBytes(BigInt(block.balance).toString(16), 16)
const signature = hex.toBytes(block.signature)
- const data = new Uint8Array([Ledger.#adpu.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 this.DynamicTransport.create(this.openTimeout, this.listenTimeout)
- const response = await transport.send(Ledger.#adpu.class, Ledger.#adpu.cacheBlock, Ledger.#adpu.paramUnused, Ledger.#adpu.paramUnused, data as Buffer)
+ const response = await transport.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()
if (nonce.length !== 16) {
throw new RangeError('Nonce must be 16-byte string')
}
- const data = new Uint8Array([Ledger.#adpu.bip32DerivationLevel, ...purpose, ...coin, ...account, ...nonce])
- const response = await transport.send(Ledger.#adpu.class, Ledger.#adpu.signNonce, Ledger.#adpu.paramUnused, Ledger.#adpu.paramUnused, data as Buffer)
+ const data = new Uint8Array([LEDGER_ADPU_CODES.bip32DerivationLevel, ...purpose, ...coin, ...account, ...nonce])
+ const response = await transport.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 link = hex.toBytes(input.link)
const representative = hex.toBytes(input.representative.publicKey)
const balance = hex.toBytes(BigInt(input.balance).toString(16), 16)
- const data = new Uint8Array([Ledger.#adpu.bip32DerivationLevel, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance])
- const response = await transport.send(Ledger.#adpu.class, Ledger.#adpu.signBlock, Ledger.#adpu.paramUnused, Ledger.#adpu.paramUnused, data as Buffer)
+ const data = new Uint8Array([LEDGER_ADPU_CODES.bip32DerivationLevel, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance])
+ const response = await transport.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()