From 5945e7804304c672c769fbcc7f2b6ec6af5f2c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Landabaso=20D=C3=ADaz?= Date: Fri, 8 Sep 2023 11:19:05 +0200 Subject: [PATCH] Refactor Descriptor Types (use DescriptorInstance to express the type of an instance of the Descriptor class instead of Descriptor, which would lead to confussion) and Improve Documentation --- CHANGELOG.md | 10 +-- src/descriptors.ts | 20 +++--- src/index.ts | 12 ++-- src/ledger.ts | 10 +-- src/signers.ts | 6 +- src/types.ts | 104 ++++++++++++++-------------- test/integration/ledger.ts | 4 +- test/integration/standardOutputs.ts | 4 +- 8 files changed, 87 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3203db3..42b1a0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,14 +10,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **Configuration**: - - Adopted sharable configs from `@bitcoinerlab/configs` to improve the maintainability of the library. + - Adopted sharable configurations from `@bitcoinerlab/configs` to enhance library maintainability. - **Exported Types**: - - Changed the exported type for descriptors: - - **Before**: The library exported `DescriptorInterfaceConstructor` which was primarily used for typing the methods of a descriptor instance but not its constructor. - - **Now**: The library exports `Descriptor`, a more comprehensive type derived using `InstanceType['Descriptor']>;`. This type represents an instance of the descriptor class returned by the factory, including its methods. + - Revised the exported types for descriptors: + - **Before**: The library previously exported both `DescriptorInterface` and `DescriptorInterfaceConstructor`. + - **Now**: The library now exports `DescriptorInstance`, a more comprehensive type derived using `InstanceType['Descriptor']>;`. This type embodies an instance of the descriptor class returned by the factory, inclusive of its methods. Furthermore, the library now exports `DescriptorConstructor` in place of `DescriptorInterfaceConstructor`. - If you had previously relied on `DescriptorInterface` for typing instances of the descriptor class, please update your implementations to use the new `Descriptor` type. The new type offers more accurate typings and includes methods as well as properties of descriptor instances. + If you previously used `DescriptorInterface` for type annotations with instances of the descriptor class, it's recommended to transition to the newly introduced `DescriptorInstance` type. For example: `const descriptor: DescriptorInterface = new Descriptor();` should now be `const descriptor: DescriptorInstance = new Descriptor();`. This new type not only offers more precise typings but also has a more appropriate name. ## [1.0.1] - 2023-07-14 diff --git a/src/descriptors.ts b/src/descriptors.ts index 1c3af80..bc96a4d 100644 --- a/src/descriptors.ts +++ b/src/descriptors.ts @@ -836,17 +836,15 @@ export function DescriptorsFactory(ecc: TinySecp256k1Interface) { return { Descriptor, parseKeyExpression, expand, ECPair, BIP32 }; } /** - * The {@link DescriptorsFactory | `DescriptorsFactory`} function internally creates and returns an instance of the {@link _Internal_.Descriptor | `Descriptor`} class. - * This instance is specialized for the provided `TinySecp256k1Interface`. + * The {@link DescriptorsFactory | `DescriptorsFactory`} function internally creates and returns the {@link _Internal_.Descriptor | `Descriptor`} class. + * This class is specialized for the provided `TinySecp256k1Interface`. + * Use `DescriptorInstance` to declare instances for this class: `const: DescriptorInstance = new Descriptor();` * * See the {@link _Internal_.Descriptor | documentation for the internal Descriptor class} for a complete list of available methods. */ -type Descriptor = InstanceType< - ReturnType['Descriptor'] ->; -//type Expand = ReturnType['expand']; -//type ParseKeyExpression = ReturnType< -// typeof DescriptorsFactory -//>['parseKeyExpression']; - -export { Descriptor }; +type DescriptorConstructor = ReturnType< + typeof DescriptorsFactory +>['Descriptor']; +type DescriptorInstance = InstanceType; + +export { DescriptorInstance, DescriptorConstructor }; diff --git a/src/index.ts b/src/index.ts index d7911a2..562f8f3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,14 @@ // Copyright (c) 2023 Jose-Luis Landabaso - https://bitcoinerlab.com // Distributed under the MIT software license -export type { Expand, ParseKeyExpression } from './types'; +export type { KeyInfo, Expansion } from './types'; import type { Psbt } from 'bitcoinjs-lib'; -import type { Descriptor } from './descriptors'; -export { DescriptorsFactory, Descriptor } from './descriptors'; +import type { DescriptorInstance } from './descriptors'; +export { + DescriptorsFactory, + DescriptorInstance, + DescriptorConstructor +} from './descriptors'; export { DescriptorChecksum as checksum } from './checksum'; import * as signers from './signers'; @@ -16,7 +20,7 @@ export function finalizePsbt({ validate = true }: { psbt: Psbt; - descriptors: Descriptor[]; + descriptors: DescriptorInstance[]; validate?: boolean | undefined; }) { descriptors.forEach((descriptor, inputIndex) => diff --git a/src/ledger.ts b/src/ledger.ts index 0ccfbed..b14ed6f 100644 --- a/src/ledger.ts +++ b/src/ledger.ts @@ -24,7 +24,7 @@ * All the conditions above are checked in function descriptorToLedgerFormat. */ -import type { Descriptor } from './descriptors'; +import type { DescriptorInstance } from './descriptors'; import { Network, networks } from 'bitcoinjs-lib'; import { reOriginPath } from './re'; @@ -237,7 +237,7 @@ export async function descriptorToLedgerFormat({ ledgerClient, ledgerState }: { - descriptor: Descriptor; + descriptor: DescriptorInstance; ledgerClient: unknown; ledgerState: LedgerState; }): Promise<{ ledgerTemplate: string; keyRoots: string[] } | null> { @@ -334,7 +334,7 @@ export async function registerLedgerWallet({ ledgerState, policyName }: { - descriptor: Descriptor; + descriptor: DescriptorInstance; ledgerClient: unknown; ledgerState: LedgerState; policyName: string; @@ -390,7 +390,7 @@ export async function ledgerPolicyFromStandard({ ledgerClient, ledgerState }: { - descriptor: Descriptor; + descriptor: DescriptorInstance; ledgerClient: unknown; ledgerState: LedgerState; }): Promise { @@ -439,7 +439,7 @@ export async function ledgerPolicyFromState({ ledgerClient, ledgerState }: { - descriptor: Descriptor; + descriptor: DescriptorInstance; ledgerClient: unknown; ledgerState: LedgerState; }): Promise { diff --git a/src/signers.ts b/src/signers.ts index f9fb1e9..8dcb85a 100644 --- a/src/signers.ts +++ b/src/signers.ts @@ -4,7 +4,7 @@ import type { Psbt } from 'bitcoinjs-lib'; import type { ECPairInterface } from 'ecpair'; import type { BIP32Interface } from 'bip32'; -import type { Descriptor } from './descriptors'; +import type { DescriptorInstance } from './descriptors'; import { importAndValidateLedgerBitcoin, comparePolicies, @@ -86,7 +86,7 @@ export async function signInputLedger({ }: { psbt: Psbt; index: number; - descriptor: Descriptor; + descriptor: DescriptorInstance; ledgerClient: unknown; ledgerState: LedgerState; }): Promise { @@ -158,7 +158,7 @@ export async function signLedger({ ledgerState }: { psbt: Psbt; - descriptors: Descriptor[]; + descriptors: DescriptorInstance[]; ledgerClient: unknown; ledgerState: LedgerState; }): Promise { diff --git a/src/types.ts b/src/types.ts index d91f2df..ce12541 100644 --- a/src/types.ts +++ b/src/types.ts @@ -77,6 +77,58 @@ export interface TinySecp256k1Interface { privateNegate(d: Uint8Array): Uint8Array; } +export type Expansion = { + /** + * The corresponding [bitcoinjs-lib Payment](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts) for the provided expression, if applicable. + */ + payment?: Payment; + + /** + * The expanded descriptor expression. + */ + expandedExpression?: string; + + /** + * The extracted miniscript from the expression, if any. + */ + miniscript?: string; + + /** + * A map of key expressions in the descriptor to their corresponding expanded keys. + */ + expansionMap?: ExpansionMap; + + /** + * A boolean indicating whether the descriptor represents a SegWit script. + */ + isSegwit?: boolean; + + /** + * The expanded miniscript, if any. + */ + expandedMiniscript?: string; + + /** + * The redeem script for the descriptor, if applicable. + */ + redeemScript?: Buffer; + + /** + * The witness script for the descriptor, if applicable. + */ + witnessScript?: Buffer; + + /** + * Whether this expression represents a ranged-descriptor. + */ + isRanged: boolean; + + /** + * This is the preferred or authoritative representation of the descriptor expression. + */ + canonicalExpression: string; +}; + /** * The {@link DescriptorsFactory | `DescriptorsFactory`} function creates and returns an implementation of the `Expand` interface. * This returned implementation is tailored for the provided `TinySecp256k1Interface`. @@ -110,57 +162,7 @@ export interface Expand { * @defaultValue false */ allowMiniscriptInP2SH?: boolean; - }): { - /** - * The corresponding [bitcoinjs-lib Payment](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts) for the provided expression, if applicable. - */ - payment?: Payment; - - /** - * The expanded descriptor expression. - */ - expandedExpression?: string; - - /** - * The extracted miniscript from the expression, if any. - */ - miniscript?: string; - - /** - * A map of key expressions in the descriptor to their corresponding expanded keys. - */ - expansionMap?: ExpansionMap; - - /** - * A boolean indicating whether the descriptor represents a SegWit script. - */ - isSegwit?: boolean; - - /** - * The expanded miniscript, if any. - */ - expandedMiniscript?: string; - - /** - * The redeem script for the descriptor, if applicable. - */ - redeemScript?: Buffer; - - /** - * The witness script for the descriptor, if applicable. - */ - witnessScript?: Buffer; - - /** - * Whether this expression represents a ranged-descriptor. - */ - isRanged: boolean; - - /** - * This is the preferred or authoritative representation of the descriptor expression. - */ - canonicalExpression: string; - }; + }): Expansion; } /** diff --git a/test/integration/ledger.ts b/test/integration/ledger.ts index 1928376..5efd3f3 100644 --- a/test/integration/ledger.ts +++ b/test/integration/ledger.ts @@ -78,7 +78,7 @@ import { keyExpressionLedger, scriptExpressions, DescriptorsFactory, - Descriptor, + DescriptorInstance, ledger, LedgerState } from '../../dist/'; @@ -105,7 +105,7 @@ let txId: string; let vout: number; let inputIndex: number; //In this array, we will keep track of the descriptors of each input: -const psbtInputDescriptors: Descriptor[] = []; +const psbtInputDescriptors: DescriptorInstance[] = []; (async () => { let transport; diff --git a/test/integration/standardOutputs.ts b/test/integration/standardOutputs.ts index 91a5b1a..2dd2bda 100644 --- a/test/integration/standardOutputs.ts +++ b/test/integration/standardOutputs.ts @@ -20,7 +20,7 @@ const SOFT_MNEMONIC = import * as ecc from '@bitcoinerlab/secp256k1'; import { DescriptorsFactory, - Descriptor, + DescriptorInstance, scriptExpressions, keyExpressionBIP32, signers @@ -60,7 +60,7 @@ const expressionsECPair = [ (async () => { const psbtMultiInputs = new Psbt(); - const multiInputsDescriptors: Descriptor[] = []; + const multiInputsDescriptors: DescriptorInstance[] = []; for (const expression of expressionsBIP32) { const descriptorBIP32 = new Descriptor({ expression, network: NETWORK });