From c37c2c358c8ad9321d08e9357c82caed2bbb5fbc Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Thu, 26 Sep 2024 09:45:27 +0200 Subject: [PATCH] refactor: use getNetworkOptions(Demand) for network options Gets rid of some boilerplate to convert a string to a network object Issue: BTC-1351 --- modules/utxo-bin/src/args/parseNetwork.ts | 30 +++++++++++++ modules/utxo-bin/src/commands.ts | 51 +++++++++-------------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/modules/utxo-bin/src/args/parseNetwork.ts b/modules/utxo-bin/src/args/parseNetwork.ts index cdc5464298..7c51daa4bc 100644 --- a/modules/utxo-bin/src/args/parseNetwork.ts +++ b/modules/utxo-bin/src/args/parseNetwork.ts @@ -11,3 +11,33 @@ export function getNetworkForName(name: string): utxolib.Network { export function getNetwork(argv: { network: string }): utxolib.Network { return getNetworkForName(argv.network); } + +type DemandOption = T & { demandOption: true }; + +type NetworkOption = { + type: 'string'; + description: string; + default: TDefault; + coerce: (arg: string) => utxolib.Network; +}; + +export function getNetworkOptions(defaultValue?: string): { + network: NetworkOption; +} { + return { + network: { + type: 'string', + description: 'network name', + default: defaultValue, + coerce: getNetworkForName, + }, + }; +} + +export function getNetworkOptionsDemand(defaultValue?: string): { + network: DemandOption>; +} { + return { + network: { ...getNetworkOptions(defaultValue).network, demandOption: true }, + }; +} diff --git a/modules/utxo-bin/src/commands.ts b/modules/utxo-bin/src/commands.ts index 95c530dfc3..bbf4c6413a 100644 --- a/modules/utxo-bin/src/commands.ts +++ b/modules/utxo-bin/src/commands.ts @@ -19,13 +19,13 @@ import { getParserTxProperties } from './ParserTx'; import { ScriptParser } from './ScriptParser'; import { argToString, - KeyOptions, - keyOptions, + stringToBuffer, readStringOptions, ReadStringOptions, - stringToBuffer, - getNetwork, - getNetworkForName, + KeyOptions, + keyOptions, + getNetworkOptions, + getNetworkOptionsDemand, } from './args'; import { formatAddressTree, @@ -40,7 +40,7 @@ import { parseXpub } from './bip32'; type OutputFormat = 'tree' | 'json'; type ArgsParseTransaction = ReadStringOptions & { - network: string; + network: utxolib.Network; txid?: string; blockHeight?: number; txIndex?: number; @@ -58,7 +58,7 @@ type ArgsParseTransaction = ReadStringOptions & { } & Omit; type ArgsParseAddress = { - network?: string; + network?: utxolib.Network; all: boolean; format: OutputFormat; convert: boolean; @@ -66,14 +66,14 @@ type ArgsParseAddress = { }; type ArgsParseScript = { - network?: string; + network?: utxolib.Network; format: OutputFormat; all: boolean; script: string; }; export type ArgsGenerateAddress = KeyOptions & { - network?: string; + network: utxolib.Network; chain?: number[]; format: string; index?: string[]; @@ -95,17 +95,6 @@ function formatString(parsed: ParserNode, argv: yargs.Arguments( - args: T -): T & { - network?: utxolib.Network; -} { - if (args.network) { - return { ...args, network: getNetworkForName(args.network) }; - } - return { ...args, network: undefined }; -} - export function getTxParser(argv: yargs.Arguments): TxParser { if (argv.all) { return new TxParser({ ...argv, ...TxParser.PARSE_ALL }); @@ -121,11 +110,11 @@ export function getTxParser(argv: yargs.Arguments): TxPars } export function getAddressParser(argv: ArgsParseAddress): AddressParser { - return new AddressParser(resolveNetwork(argv)); + return new AddressParser(argv); } export function getScriptParser(argv: ArgsParseScript): ScriptParser { - return new ScriptParser(resolveNetwork(argv)); + return new ScriptParser(argv); } export const cmdParseTx = { @@ -140,6 +129,7 @@ export const cmdParseTx = { builder(b: yargs.Argv): yargs.Argv { return b .options(readStringOptions) + .options(getNetworkOptionsDemand()) .option('txid', { type: 'string' }) .option('blockHeight', { type: 'number' }) .option('txIndex', { type: 'number' }) @@ -147,7 +137,6 @@ export const cmdParseTx = { .option('fetchStatus', { type: 'boolean', default: false }) .option('fetchInputs', { type: 'boolean', default: false }) .option('fetchSpends', { type: 'boolean', default: false }) - .option('network', { alias: 'n', type: 'string', demandOption: true }) .option('parseScriptAsm', { alias: 'scriptasm', type: 'boolean', default: false }) .option('parseScriptData', { alias: 'scriptdata', type: 'boolean', default: false }) .option('parseSignatureData', { alias: 'sigdata', type: 'boolean', default: false }) @@ -178,7 +167,6 @@ export const cmdParseTx = { }, async handler(argv: yargs.Arguments): Promise { - const network = getNetwork(argv); let data; const httpClient = await getClient({ cache: argv.cache }); @@ -191,7 +179,7 @@ export const cmdParseTx = { blockHeight: argv.blockHeight, txIndex: argv.txIndex, }, - network + argv.network ); } @@ -203,8 +191,8 @@ export const cmdParseTx = { const bytes = stringToBuffer(string, 'hex'); let tx = utxolib.bitgo.isPsbt(bytes) - ? utxolib.bitgo.createPsbtFromBuffer(bytes, network) - : utxolib.bitgo.createTransactionFromBuffer(bytes, network, { amountType: 'bigint' }); + ? utxolib.bitgo.createPsbtFromBuffer(bytes, argv.network) + : utxolib.bitgo.createTransactionFromBuffer(bytes, argv.network, { amountType: 'bigint' }); const { id: txid } = getParserTxProperties(tx, undefined); if (tx instanceof utxolib.bitgo.UtxoTransaction) { @@ -228,7 +216,7 @@ export const cmdParseTx = { } const parsed = getTxParser(argv).parse(tx, { - status: argv.fetchStatus && txid ? await fetchTransactionStatus(httpClient, txid, network) : undefined, + status: argv.fetchStatus && txid ? await fetchTransactionStatus(httpClient, txid, argv.network) : undefined, prevOutputs: argv.fetchInputs ? await fetchPrevOutputs(httpClient, tx) : undefined, prevOutputSpends: argv.fetchSpends ? await fetchPrevOutputSpends(httpClient, tx) : undefined, outputSpends: @@ -247,7 +235,7 @@ export const cmdParseAddress = { describe: 'parse address', builder(b: yargs.Argv): yargs.Argv { return b - .option('network', { alias: 'n', type: 'string' }) + .options(getNetworkOptions()) .option('format', { choices: ['tree', 'json'], default: 'tree' } as const) .option('convert', { type: 'boolean', default: false }) .option('all', { type: 'boolean', default: false }) @@ -265,7 +253,7 @@ export const cmdParseScript = { describe: 'parse script', builder(b: yargs.Argv): yargs.Argv { return b - .option('network', { alias: 'n', type: 'string' }) + .options(getNetworkOptions()) .option('format', { choices: ['tree', 'json'], default: 'tree' } as const) .option('all', { type: 'boolean', default: false }) .positional('script', { type: 'string', demandOption: true }); @@ -282,7 +270,7 @@ export const cmdGenerateAddress = { describe: 'generate addresses', builder(b: yargs.Argv): yargs.Argv { return b - .option('network', { alias: 'n', type: 'string' }) + .options(getNetworkOptionsDemand('bitcoin')) .options(keyOptions) .option('format', { type: 'string', @@ -314,7 +302,6 @@ export const cmdGenerateAddress = { for (const address of generateAddress({ ...argv, index: indexRange, - network: getNetworkForName(argv.network ?? 'bitcoin'), })) { if (argv.format === 'tree') { console.log(formatAddressTree(address));