Skip to content

Commit

Permalink
refactor: use getNetworkOptions(Demand) for network options
Browse files Browse the repository at this point in the history
Gets rid of some boilerplate to convert a string to a network object

Issue: BTC-1351
  • Loading branch information
OttoAllmendinger committed Sep 26, 2024
1 parent 97e8dea commit c37c2c3
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 32 deletions.
30 changes: 30 additions & 0 deletions modules/utxo-bin/src/args/parseNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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> = T & { demandOption: true };

type NetworkOption<TDefault> = {
type: 'string';
description: string;
default: TDefault;
coerce: (arg: string) => utxolib.Network;
};

export function getNetworkOptions(defaultValue?: string): {
network: NetworkOption<typeof defaultValue>;
} {
return {
network: {
type: 'string',
description: 'network name',
default: defaultValue,
coerce: getNetworkForName,
},
};
}

export function getNetworkOptionsDemand(defaultValue?: string): {
network: DemandOption<NetworkOption<typeof defaultValue>>;
} {
return {
network: { ...getNetworkOptions(defaultValue).network, demandOption: true },
};
}
51 changes: 19 additions & 32 deletions modules/utxo-bin/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -58,22 +58,22 @@ type ArgsParseTransaction = ReadStringOptions & {
} & Omit<TxParserArgs, 'parseSignatureData'>;

type ArgsParseAddress = {
network?: string;
network?: utxolib.Network;
all: boolean;
format: OutputFormat;
convert: boolean;
address: string;
};

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[];
Expand All @@ -95,17 +95,6 @@ function formatString(parsed: ParserNode, argv: yargs.Arguments<FormatStringArgs
throw new Error(`invalid format ${argv.format}`);
}

function resolveNetwork<T extends { network?: string }>(
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<ArgsParseTransaction>): TxParser {
if (argv.all) {
return new TxParser({ ...argv, ...TxParser.PARSE_ALL });
Expand All @@ -121,11 +110,11 @@ export function getTxParser(argv: yargs.Arguments<ArgsParseTransaction>): 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 = {
Expand All @@ -140,14 +129,14 @@ export const cmdParseTx = {
builder(b: yargs.Argv<unknown>): yargs.Argv<ArgsParseTransaction> {
return b
.options(readStringOptions)
.options(getNetworkOptionsDemand())
.option('txid', { type: 'string' })
.option('blockHeight', { type: 'number' })
.option('txIndex', { type: 'number' })
.option('fetchAll', { type: 'boolean', default: false })
.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 })
Expand Down Expand Up @@ -178,7 +167,6 @@ export const cmdParseTx = {
},

async handler(argv: yargs.Arguments<ArgsParseTransaction>): Promise<void> {
const network = getNetwork(argv);
let data;

const httpClient = await getClient({ cache: argv.cache });
Expand All @@ -191,7 +179,7 @@ export const cmdParseTx = {
blockHeight: argv.blockHeight,
txIndex: argv.txIndex,
},
network
argv.network
);
}

Expand All @@ -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) {
Expand All @@ -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:
Expand All @@ -247,7 +235,7 @@ export const cmdParseAddress = {
describe: 'parse address',
builder(b: yargs.Argv<unknown>): yargs.Argv<ArgsParseAddress> {
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 })
Expand All @@ -265,7 +253,7 @@ export const cmdParseScript = {
describe: 'parse script',
builder(b: yargs.Argv<unknown>): yargs.Argv<ArgsParseScript> {
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 });
Expand All @@ -282,7 +270,7 @@ export const cmdGenerateAddress = {
describe: 'generate addresses',
builder(b: yargs.Argv<unknown>): yargs.Argv<ArgsGenerateAddress> {
return b
.option('network', { alias: 'n', type: 'string' })
.options(getNetworkOptionsDemand('bitcoin'))
.options(keyOptions)
.option('format', {
type: 'string',
Expand Down Expand Up @@ -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));
Expand Down

0 comments on commit c37c2c3

Please sign in to comment.