import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb'\r
import { default as TransportHID } from '@ledgerhq/hw-transport-webhid'\r
import { Account, AccountList } from './account'\r
-import { ChangeBlock, ReceiveBlock, SendBlock } from './block'\r
+import { Block } from './block'\r
import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_ADPU_CODES, LEDGER_STATUS_CODES } from './constants'\r
import { bytes, dec, hex } from './convert'\r
import { Database } from './database'\r
* @param {object} block - Block data to sign\r
* @returns {Promise<string>} Signature\r
*/\r
- async sign (index: number, block: SendBlock | ReceiveBlock | ChangeBlock, frontier?: SendBlock | ReceiveBlock | ChangeBlock): Promise<string> {\r
+ async sign (index: number, block: Block): Promise<Uint8Array<ArrayBuffer>>\r
+ /**\r
+ * Sign a block with the Ledger device.\r
+ *\r
+ * @param {number} index - Account number\r
+ * @param {object} block - Block data to sign\r
+ * @returns {Promise<string>} Signature\r
+ */\r
+ async sign (index: number, block: Block, format?: 'hex', frontier?: Block): Promise<string>\r
+ async sign (index: number, block: Block, format?: 'hex', frontier?: Block): Promise<string | Uint8Array<ArrayBuffer>> {\r
if (typeof index !== 'number' || index < 0 || index >= HARDENED_OFFSET) {\r
throw new TypeError('Invalid account index')\r
}\r
* @param {number} index - Account number\r
* @param {object} block - JSON-formatted block data\r
*/\r
- async updateCache (index: number, block: ChangeBlock | ReceiveBlock | SendBlock): Promise<LedgerResponse>\r
+ async updateCache (index: number, block: Block): Promise<LedgerResponse>\r
/**\r
* Update cache from a block hash by calling out to a node. Suitable for online\r
* use only.\r
const testWallet = await Wallet.import('BIP-44', '', secret)\r
await testWallet.unlock('')\r
const testAccount = await testWallet.account(0)\r
- const testOpenBlock = new ReceiveBlock(\r
+ const testOpenBlock = new Block(\r
testAccount.address,\r
'0',\r
testAccount.address,\r
'0'\r
)\r
await testWallet.sign(0, testOpenBlock)\r
- const testSendBlock = new SendBlock(\r
- testAccount.address,\r
- '0',\r
- testAccount.address,\r
- '0',\r
- testAccount.address,\r
- testOpenBlock.hash\r
- )\r
- const testSignature = await testWallet.sign(0, testOpenBlock)\r
+ const testSendBlock = new Block(testAccount.address, '0', bytes.toHex(testOpenBlock.hash), testAccount.address)\r
+ .send(0)\r
+ .to(testAccount.address)\r
+ const testSignature = await testWallet.sign(0, testOpenBlock, 'hex')\r
try {\r
- const signature = await this.sign(0, testSendBlock, testOpenBlock)\r
+ const signature = await this.sign(0, testSendBlock, 'hex', testOpenBlock)\r
return signature === testSignature\r
} catch (err) {\r
throw new Error('Failed to verify wallet', { cause: err })\r
* @param {any} block - Block data to cache\r
* @returns Status of command\r
*/\r
- async #cacheBlock (index: number = 0, block: ChangeBlock | ReceiveBlock | SendBlock): Promise<LedgerResponse> {\r
+ async #cacheBlock (index: number = 0, block: Block): Promise<LedgerResponse> {\r
if (typeof index !== 'number' || index < 0 || index >= HARDENED_OFFSET) {\r
throw new TypeError('Invalid account index')\r
}\r
- if (!(block instanceof ChangeBlock) && !(block instanceof ReceiveBlock) && !(block instanceof SendBlock)) {\r
+ if (!(block instanceof Block)) {\r
throw new TypeError('Invalid block format')\r
}\r
+ if (!(block.link instanceof Uint8Array)) {\r
+ throw new TypeError('Invalid block link')\r
+ }\r
if (!block.signature) {\r
throw new ReferenceError('Cannot cache unsigned block')\r
}\r
const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4)\r
const account = dec.toBytes(index + HARDENED_OFFSET, 4)\r
const previous = hex.toBytes(block.previous === block.account.publicKey ? '0' : block.previous, 32)\r
- const link = hex.toBytes(block.link, 32)\r
+ const link = block.link\r
const representative = hex.toBytes(block.representative.publicKey, 32)\r
const balance = hex.toBytes(block.balance.toString(16), 16)\r
const signature = hex.toBytes(block.signature, 64)\r
* @param {object} block - Block data to sign\r
* @returns {Promise} Status, signature, and block hash\r
*/\r
- async #signBlock (index: number, block: SendBlock | ReceiveBlock | ChangeBlock): Promise<LedgerSignResponse> {\r
+ async #signBlock (index: number, block: Block): Promise<LedgerSignResponse> {\r
if (typeof index !== 'number' || index < 0 || index >= HARDENED_OFFSET) {\r
throw new TypeError('Invalid account index')\r
}\r
+ if (!(block.link instanceof Uint8Array)) {\r
+ throw new TypeError('Invalid block link')\r
+ }\r
\r
const account = dec.toBytes(index + HARDENED_OFFSET, 4)\r
const previous = hex.toBytes(block.previous, 32)\r
- const link = hex.toBytes(block.link, 32)\r
+ const link = block.link\r
const representative = hex.toBytes(block.representative.publicKey, 32)\r
const balance = hex.toBytes(BigInt(block.balance).toString(16), 16)\r
const data = new Uint8Array([...Ledger.#derivationPath, ...account, ...previous, ...link, ...representative, ...balance])\r
\r
const transport = await Ledger.DynamicTransport.create(Ledger.openTimeout, Ledger.listenTimeout)\r
- const response = await transport.send(LEDGER_ADPU_CODES.class, LEDGER_ADPU_CODES.signBlock, LEDGER_ADPU_CODES.paramUnused, LEDGER_ADPU_CODES.paramUnused, data as Buffer)\r
+ const response = await transport\r
+ .send(LEDGER_ADPU_CODES.class, LEDGER_ADPU_CODES.signBlock, LEDGER_ADPU_CODES.paramUnused, LEDGER_ADPU_CODES.paramUnused, data as Buffer)\r
.catch(err => dec.toBytes(err.statusCode)) as Uint8Array\r
await transport.close()\r
\r
return { status, signature: null }\r
}\r
if (response.byteLength === 98) {\r
- const hash = bytes.toHex(response.slice(0, 32))\r
+ const hash = response.slice(0, 32)\r
const signature = bytes.toHex(response.slice(32, 96))\r
return { status, signature, hash }\r
}\r