From d8d031fa29a6f70d3aea4dd2b52e79b64d9e5878 Mon Sep 17 00:00:00 2001 From: David Tran Duc Date: Tue, 24 Nov 2020 16:32:20 +0100 Subject: [PATCH] Change key-gen command to accept multiple inputs --- package.json | 2 +- src/command-parser/parserConfig.ts | 8 ++++++-- src/commandExecutor.ts | 11 ++++++----- src/crypto-providers/ledgerCryptoProvider.ts | 8 ++++---- src/crypto-providers/trezorCryptoProvider.ts | 13 ++++++++----- src/crypto-providers/types.ts | 2 +- src/crypto-providers/util.ts | 18 ++++++++++++++++++ src/errors.ts | 1 + src/types.ts | 6 +++--- test/unit/commandParser/commandParser.js | 6 +++--- yarn.lock | 15 ++------------- 11 files changed, 53 insertions(+), 37 deletions(-) diff --git a/package.json b/package.json index caf3413c..34055603 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "homepage": "https://github.com/vacuumlabs/cardano-hw-cli#readme", "dependencies": { "@babel/runtime": "^7.11.2", - "@cardano-foundation/ledgerjs-hw-app-cardano": "https://github.com/vacuumlabs/ledgerjs-cardano-shelley/releases/download/v2.0.2-rc.2/cardano-foundation-ledgerjs-hw-app-cardano-2.0.2-rc.1.tgz", + "@cardano-foundation/ledgerjs-hw-app-cardano": "https://github.com/vacuumlabs/ledgerjs-cardano-shelley/releases/download/bulk-export/cardano-foundation-ledgerjs-hw-app-cardano-2.0.2-rc.1.tgz", "@ledgerhq/hw-transport-node-hid": "^5.25.0", "argparse": "^2.0.1", "bignumber": "^1.1.0", diff --git a/src/command-parser/parserConfig.ts b/src/command-parser/parserConfig.ts index 9344d9ad..a935a7f2 100644 --- a/src/command-parser/parserConfig.ts +++ b/src/command-parser/parserConfig.ts @@ -56,17 +56,21 @@ export const parserConfig = { 'key-gen': { '--path': { required: true, + action: 'append', type: (path: string) => parsePath(path), + dest: 'paths', help: 'Derivation path to the key to sign with.', }, '--hw-signing-file': { required: true, - dest: 'hwSigningFile', + action: 'append', + dest: 'hwSigningFiles', help: 'Output filepath of the verification key.', }, '--verification-key-file': { required: true, - dest: 'verificationKeyFile', + action: 'append', + dest: 'verificationKeyFiles', help: 'Output filepath of the hardware wallet signing file.', }, }, diff --git a/src/commandExecutor.ts b/src/commandExecutor.ts index 72435b3a..39249744 100644 --- a/src/commandExecutor.ts +++ b/src/commandExecutor.ts @@ -16,7 +16,7 @@ import { } from './types' import { LedgerCryptoProvider } from './crypto-providers/ledgerCryptoProvider' import { TrezorCryptoProvider } from './crypto-providers/trezorCryptoProvider' -import { validateSigning, validateWitnessing } from './crypto-providers/util' +import { validateSigning, validateWitnessing, validateKeyGenInputs } from './crypto-providers/util' import { Errors } from './errors' const promiseTimeout = (promise: Promise, ms: number): Promise => { @@ -61,11 +61,12 @@ const CommandExecutor = async () => { } const createSigningKeyFile = async ( - { path, hwSigningFile, verificationKeyFile }: ParsedKeyGenArguments, + { paths, hwSigningFiles, verificationKeyFiles }: ParsedKeyGenArguments, ) => { - const xPubKey = await cryptoProvider.getXPubKey(path) - write(hwSigningFile, HwSigningKeyOutput(xPubKey, path)) - write(verificationKeyFile, HwVerificationKeyOutput(xPubKey, path)) + validateKeyGenInputs(paths, hwSigningFiles, verificationKeyFiles) + const xPubKeys = await cryptoProvider.getXPubKeys(paths) + xPubKeys.forEach((xPubKey, i) => write(hwSigningFiles[i], HwSigningKeyOutput(xPubKey, paths[i]))) + xPubKeys.forEach((xPubKey, i) => write(verificationKeyFiles[i], HwVerificationKeyOutput(xPubKey, paths[i]))) } const createVerificationKeyFile = ( diff --git a/src/crypto-providers/ledgerCryptoProvider.ts b/src/crypto-providers/ledgerCryptoProvider.ts index 2e231896..d38c8889 100644 --- a/src/crypto-providers/ledgerCryptoProvider.ts +++ b/src/crypto-providers/ledgerCryptoProvider.ts @@ -350,9 +350,9 @@ export const LedgerCryptoProvider: () => Promise = async () => { return _shelleyWitnesses.length === 1 ? _shelleyWitnesses[0] : _byronWitnesses[0] } - const getXPubKey = async (path: BIP32Path): Promise => { - const { publicKeyHex, chainCodeHex } = await ledger.getExtendedPublicKey(path) - return publicKeyHex + chainCodeHex + const getXPubKeys = async (paths: BIP32Path[]): Promise => { + const xPubKeys = await ledger.getExtendedPublicKeys(paths) + return xPubKeys.map((xPubKey) => xPubKey.publicKeyHex + xPubKey.chainCodeHex) } return { @@ -360,6 +360,6 @@ export const LedgerCryptoProvider: () => Promise = async () => { showAddress, signTx, witnessTx, - getXPubKey, + getXPubKeys, } } diff --git a/src/crypto-providers/trezorCryptoProvider.ts b/src/crypto-providers/trezorCryptoProvider.ts index 6f65ff7d..1a3b9a17 100644 --- a/src/crypto-providers/trezorCryptoProvider.ts +++ b/src/crypto-providers/trezorCryptoProvider.ts @@ -13,6 +13,7 @@ import { _StakingKeyRegistrationCert, _StakingKeyDeregistrationCert, _PoolRelay, + XPubKeyHex, } from '../transaction/types' import { CryptoProvider, _AddressParameters } from './types' import { @@ -86,12 +87,14 @@ const TrezorCryptoProvider: () => Promise = async () => { if (response.error || !response.success) throw Error(Errors.InvalidAddressParametersProvidedError) } - const getXPubKey = async (path: BIP32Path): Promise => { + const getXPubKeys = async (paths: BIP32Path[]): Promise => { const { payload } = await TrezorConnect.cardanoGetPublicKey({ - path, - showOnTrezor: false, + bundle: paths.map((path) => ({ + path, + showOnTrezor: false, + })) }) - return payload.publicKey + return payload.map(result => result.publicKey) } const prepareInput = (input: _Input, path?: BIP32Path): TrezorInput => ({ @@ -298,7 +301,7 @@ const TrezorCryptoProvider: () => Promise = async () => { showAddress, witnessTx, signTx, - getXPubKey, + getXPubKeys, } } diff --git a/src/crypto-providers/types.ts b/src/crypto-providers/types.ts index bdb03e96..9adec63a 100644 --- a/src/crypto-providers/types.ts +++ b/src/crypto-providers/types.ts @@ -27,7 +27,7 @@ export type CryptoProvider = { network: Network, changeOutputFiles: HwSigningData[], ) => Promise<_ShelleyWitness | _ByronWitness> - getXPubKey: (path: BIP32Path) => Promise + getXPubKeys: (paths: BIP32Path[]) => Promise } export type _AddressParameters = { diff --git a/src/crypto-providers/util.ts b/src/crypto-providers/util.ts index c5aac53e..dc8a8e54 100644 --- a/src/crypto-providers/util.ts +++ b/src/crypto-providers/util.ts @@ -1,5 +1,6 @@ import { HARDENED_THRESHOLD } from '../constants' import { Errors } from '../errors' +import { isBIP32Path } from '../guards' import { XPubKey } from '../transaction/transaction' import { TxCertificateKeys, _Certificate, _TxAux } from '../transaction/types' import { @@ -142,6 +143,22 @@ const validateSigning = ( if (!paymentSigningFiles.length) throw Error(Errors.MissingPaymentSigningFileError) } +const validateKeyGenInputs = ( + paths: BIP32Path[], + hwSigningFiles: string[], + verificationKeyFiles: string[], +): void => { + if ( + !Array.isArray(paths) || + !paths.every(isBIP32Path) || + !Array.isArray(hwSigningFiles) || + !Array.isArray(verificationKeyFiles) || + paths.length < 1 || + paths.length !== hwSigningFiles.length || + paths.length !== verificationKeyFiles.length + ) throw Error(Errors.InvalidKeyGenInputsError) +} + const _packBootStrapAddress = ( file: HwSigningData, network: Network, ): _AddressParameters => { @@ -257,6 +274,7 @@ export { isStakingPath, validateSigning, validateWitnessing, + validateKeyGenInputs, getSigningPath, filterSigningFiles, findSigningPath, diff --git a/src/errors.ts b/src/errors.ts index 66ab2ec4..71ffd404 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -41,6 +41,7 @@ enum Errors { InvalidAddressError = 'Invalid address', LedgerOperationError = 'Ledger operation error', InvalidAddressParametersProvidedError = 'Invalid address parameters provided', + InvalidKeyGenInputsError = 'Invalid key gen inputs error', } export { diff --git a/src/types.ts b/src/types.ts index 713c1bed..0f0f3d7b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -42,9 +42,9 @@ export type ParsedShowAddressArguments = { export type ParsedKeyGenArguments = { command: CommandType.KEY_GEN, - path: BIP32Path, - hwSigningFile: string, - verificationKeyFile: string, + paths: BIP32Path[], + hwSigningFiles: string[], + verificationKeyFiles: string[], } export type ParsedVerificationKeyArguments = { diff --git a/test/unit/commandParser/commandParser.js b/test/unit/commandParser/commandParser.js index a19c4ee8..c0c3c9fe 100644 --- a/test/unit/commandParser/commandParser.js +++ b/test/unit/commandParser/commandParser.js @@ -23,9 +23,9 @@ describe('Command parser', () => { const { parsedArgs } = parse(args) const expectedResult = { command: CommandType.KEY_GEN, - path: [2147485500, 2147485463, 2147483648, 2, 1], - hwSigningFile: 'test/unit/commandParser/res/payment.hwsfile', - verificationKeyFile: 'test/unit/commandParser/res/payment.vkey', + paths: [[2147485500, 2147485463, 2147483648, 2, 1]], + hwSigningFiles: ['test/unit/commandParser/res/payment.hwsfile'], + verificationKeyFiles: ['test/unit/commandParser/res/payment.vkey'], } assert.deepEqual(parsedArgs, expectedResult) }) diff --git a/yarn.lock b/yarn.lock index e07ad065..aa6e51c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -40,20 +40,9 @@ resolved "https://registry.yarnpkg.com/@calebboyd/semaphore/-/semaphore-1.3.1.tgz#4faa403d12f80e5d5c1d6e0d7916d048b6fa79cb" integrity sha512-17z9me12RgAEcMhIgR7f+BiXKbzwF9p1VraI69OxrUUSWGuSMOyOTEHQNVtMKuVrkEDVD0/Av5uiGZPBMYZljw== -"@cardano-foundation/ledgerjs-hw-app-cardano@https://github.com/vacuumlabs/ledgerjs-cardano-shelley/releases/download/v2.0.2-rc.1/cardano-foundation-ledgerjs-hw-app-cardano-2.0.2-rc.1.tgz": +"@cardano-foundation/ledgerjs-hw-app-cardano@https://github.com/vacuumlabs/ledgerjs-cardano-shelley/releases/download/bulk-export/cardano-foundation-ledgerjs-hw-app-cardano-2.0.2-rc.1.tgz": version "2.0.2-rc.1" - resolved "https://github.com/vacuumlabs/ledgerjs-cardano-shelley/releases/download/v2.0.2-rc.1/cardano-foundation-ledgerjs-hw-app-cardano-2.0.2-rc.1.tgz#4586ac3712a285bd6d77d26c9191891820d2dcde" - dependencies: - "@ledgerhq/hw-transport" "^5.12.0" - babel-polyfill "^6.26.0" - babel-runtime "^6.26.0" - base-x "^3.0.5" - bech32 "^1.1.4" - node-int64 "^0.4.0" - -"@cardano-foundation/ledgerjs-hw-app-cardano@https://github.com/vacuumlabs/ledgerjs-cardano-shelley/releases/download/v2.0.2-rc.2/cardano-foundation-ledgerjs-hw-app-cardano-2.0.2-rc.1.tgz": - version "2.0.2-rc.1" - resolved "https://github.com/vacuumlabs/ledgerjs-cardano-shelley/releases/download/v2.0.2-rc.2/cardano-foundation-ledgerjs-hw-app-cardano-2.0.2-rc.1.tgz#015e0223559a3788868f396a73e2e2490b162487" + resolved "https://github.com/vacuumlabs/ledgerjs-cardano-shelley/releases/download/bulk-export/cardano-foundation-ledgerjs-hw-app-cardano-2.0.2-rc.1.tgz#91d7ca5108190f98685c2c559f6449e3b47797bd" dependencies: "@ledgerhq/hw-transport" "^5.12.0" babel-polyfill "^6.26.0"