@bitcoinerlab/descriptors-core 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +710 -0
- package/dist/adapters/applyPR2137.d.ts +2 -0
- package/dist/adapters/applyPR2137.js +150 -0
- package/dist/adapters/bitcoinjs.d.ts +8 -0
- package/dist/adapters/bitcoinjs.js +36 -0
- package/dist/adapters/scure/address.d.ts +2 -0
- package/dist/adapters/scure/address.js +50 -0
- package/dist/adapters/scure/bip32.d.ts +2 -0
- package/dist/adapters/scure/bip32.js +16 -0
- package/dist/adapters/scure/common.d.ts +14 -0
- package/dist/adapters/scure/common.js +36 -0
- package/dist/adapters/scure/ecpair.d.ts +2 -0
- package/dist/adapters/scure/ecpair.js +58 -0
- package/dist/adapters/scure/payments.d.ts +2 -0
- package/dist/adapters/scure/payments.js +216 -0
- package/dist/adapters/scure/psbt.d.ts +43 -0
- package/dist/adapters/scure/psbt.js +382 -0
- package/dist/adapters/scure/script.d.ts +20 -0
- package/dist/adapters/scure/script.js +163 -0
- package/dist/adapters/scure/transaction.d.ts +2 -0
- package/dist/adapters/scure/transaction.js +32 -0
- package/dist/adapters/scure.d.ts +6 -0
- package/dist/adapters/scure.js +37 -0
- package/dist/adapters/scureKeys.d.ts +4 -0
- package/dist/adapters/scureKeys.js +135 -0
- package/dist/bip174.d.ts +87 -0
- package/dist/bip174.js +12 -0
- package/dist/bitcoinLib.d.ts +385 -0
- package/dist/bitcoinLib.js +19 -0
- package/dist/bitcoinjs-lib-internals.d.ts +6 -0
- package/dist/bitcoinjs-lib-internals.js +60 -0
- package/dist/bitcoinjs.d.ts +12 -0
- package/dist/bitcoinjs.js +18 -0
- package/dist/checksum.d.ts +6 -0
- package/dist/checksum.js +58 -0
- package/dist/crypto.d.ts +3 -0
- package/dist/crypto.js +79 -0
- package/dist/descriptors.d.ts +481 -0
- package/dist/descriptors.js +1888 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +87 -0
- package/dist/keyExpressions.d.ts +124 -0
- package/dist/keyExpressions.js +310 -0
- package/dist/keyInterfaces.d.ts +5 -0
- package/dist/keyInterfaces.js +50 -0
- package/dist/ledger.d.ts +183 -0
- package/dist/ledger.js +618 -0
- package/dist/miniscript.d.ts +125 -0
- package/dist/miniscript.js +310 -0
- package/dist/multipath.d.ts +13 -0
- package/dist/multipath.js +76 -0
- package/dist/networkUtils.d.ts +3 -0
- package/dist/networkUtils.js +16 -0
- package/dist/networks.d.ts +16 -0
- package/dist/networks.js +31 -0
- package/dist/parseUtils.d.ts +7 -0
- package/dist/parseUtils.js +46 -0
- package/dist/psbt.d.ts +40 -0
- package/dist/psbt.js +228 -0
- package/dist/re.d.ts +31 -0
- package/dist/re.js +79 -0
- package/dist/resourceLimits.d.ts +28 -0
- package/dist/resourceLimits.js +84 -0
- package/dist/scriptExpressions.d.ts +95 -0
- package/dist/scriptExpressions.js +98 -0
- package/dist/scure.d.ts +4 -0
- package/dist/scure.js +10 -0
- package/dist/signers.d.ts +161 -0
- package/dist/signers.js +324 -0
- package/dist/tapMiniscript.d.ts +231 -0
- package/dist/tapMiniscript.js +524 -0
- package/dist/tapTree.d.ts +91 -0
- package/dist/tapTree.js +166 -0
- package/dist/types.d.ts +296 -0
- package/dist/types.js +4 -0
- package/package.json +148 -0
package/dist/tapTree.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_TAPTREE_DEPTH = void 0;
|
|
4
|
+
exports.assertTapTreeDepth = assertTapTreeDepth;
|
|
5
|
+
exports.collectTapTreeLeaves = collectTapTreeLeaves;
|
|
6
|
+
exports.selectTapLeafCandidates = selectTapLeafCandidates;
|
|
7
|
+
exports.parseTapTreeExpression = parseTapTreeExpression;
|
|
8
|
+
const bitcoinjs_lib_internals_1 = require("./bitcoinjs-lib-internals");
|
|
9
|
+
const uint8array_tools_1 = require("uint8array-tools");
|
|
10
|
+
const parseUtils_1 = require("./parseUtils");
|
|
11
|
+
// See BIP341 control block limits and Sipa's Miniscript "Resource limitations":
|
|
12
|
+
// https://bitcoin.sipa.be/miniscript/
|
|
13
|
+
// Taproot script path depth is encoded in the control block as 32-byte hashes,
|
|
14
|
+
// with consensus max depth 128.
|
|
15
|
+
exports.MAX_TAPTREE_DEPTH = 128;
|
|
16
|
+
function tapTreeMaxDepth(tapTree, depth = 0) {
|
|
17
|
+
if ('expression' in tapTree)
|
|
18
|
+
return depth;
|
|
19
|
+
return Math.max(tapTreeMaxDepth(tapTree.left, depth + 1), tapTreeMaxDepth(tapTree.right, depth + 1));
|
|
20
|
+
}
|
|
21
|
+
function assertTapTreeDepth(tapTree) {
|
|
22
|
+
const maxDepth = tapTreeMaxDepth(tapTree);
|
|
23
|
+
if (maxDepth > exports.MAX_TAPTREE_DEPTH)
|
|
24
|
+
throw new Error(`Error: taproot tree depth is too large, ${maxDepth} is larger than ${exports.MAX_TAPTREE_DEPTH}`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Collects taproot leaf metadata with depth from a tree.
|
|
28
|
+
* Traversal is left-first, following the order of `{left,right}` in the
|
|
29
|
+
* expression so tie-breaks are deterministic.
|
|
30
|
+
*
|
|
31
|
+
* Example tree:
|
|
32
|
+
* ```
|
|
33
|
+
* {pk(A),{pk(B),pk(C)}}
|
|
34
|
+
* ```
|
|
35
|
+
* Visual shape:
|
|
36
|
+
* ```
|
|
37
|
+
* root
|
|
38
|
+
* / \
|
|
39
|
+
* pk(A) branch
|
|
40
|
+
* / \
|
|
41
|
+
* pk(B) pk(C)
|
|
42
|
+
* ```
|
|
43
|
+
* Collected leaves with depth:
|
|
44
|
+
* ```
|
|
45
|
+
* [
|
|
46
|
+
* { leaf: pk(A), depth: 1 },
|
|
47
|
+
* { leaf: pk(B), depth: 2 },
|
|
48
|
+
* { leaf: pk(C), depth: 2 }
|
|
49
|
+
* ]
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
function collectTapTreeLeaves(tapTreeInfo) {
|
|
53
|
+
const leaves = [];
|
|
54
|
+
const walk = (node, depth) => {
|
|
55
|
+
if ('expression' in node) {
|
|
56
|
+
leaves.push({ leaf: node, depth });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
walk(node.left, depth + 1);
|
|
60
|
+
walk(node.right, depth + 1);
|
|
61
|
+
};
|
|
62
|
+
walk(tapTreeInfo, 0);
|
|
63
|
+
return leaves;
|
|
64
|
+
}
|
|
65
|
+
function computeTapLeafHash(leaf) {
|
|
66
|
+
return (0, bitcoinjs_lib_internals_1.tapleafHash)({ output: leaf.tapScript, version: leaf.version });
|
|
67
|
+
}
|
|
68
|
+
function normalizeExpressionForMatch(expression) {
|
|
69
|
+
return expression.replace(/\s+/g, '');
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolves taproot leaf candidates based on an optional selector.
|
|
73
|
+
*
|
|
74
|
+
* If `tapLeaf` is undefined, all leaves are returned for auto-selection.
|
|
75
|
+
* If `tapLeaf` is bytes, it is treated as a tapleaf hash and must match
|
|
76
|
+
* exactly one leaf.
|
|
77
|
+
* If `tapLeaf` is a string, it is treated as a raw taproot leaf expression
|
|
78
|
+
* (not expanded). Matching is whitespace-insensitive. If the expression appears
|
|
79
|
+
* more than once, this function throws an error.
|
|
80
|
+
*
|
|
81
|
+
* Example:
|
|
82
|
+
* ```
|
|
83
|
+
* const candidates = selectTapLeafCandidates({ tapTreeInfo, tapLeaf });
|
|
84
|
+
* // tapLeaf can be undefined, bytes (tapleaf hash) or a leaf expression:
|
|
85
|
+
* // f.ex.: 'pk(03bb...)'
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
function selectTapLeafCandidates({ tapTreeInfo, tapLeaf }) {
|
|
89
|
+
const leaves = collectTapTreeLeaves(tapTreeInfo).map(({ leaf, depth }) => ({
|
|
90
|
+
leaf,
|
|
91
|
+
depth,
|
|
92
|
+
tapLeafHash: computeTapLeafHash(leaf)
|
|
93
|
+
}));
|
|
94
|
+
if (tapLeaf === undefined)
|
|
95
|
+
return leaves;
|
|
96
|
+
if (tapLeaf instanceof Uint8Array) {
|
|
97
|
+
const match = leaves.find(entry => (0, uint8array_tools_1.compare)(entry.tapLeafHash, tapLeaf) === 0);
|
|
98
|
+
if (!match)
|
|
99
|
+
throw new Error(`Error: tapleaf hash not found in tapTreeInfo`);
|
|
100
|
+
return [match];
|
|
101
|
+
}
|
|
102
|
+
const normalizedSelector = normalizeExpressionForMatch(tapLeaf);
|
|
103
|
+
const matches = leaves.filter(entry => normalizeExpressionForMatch(entry.leaf.expression) === normalizedSelector);
|
|
104
|
+
if (matches.length === 0)
|
|
105
|
+
throw new Error(`Error: taproot leaf expression not found in tapTreeInfo: ${tapLeaf}`);
|
|
106
|
+
if (matches.length > 1)
|
|
107
|
+
throw new Error(`Error: taproot leaf expression is ambiguous in tapTreeInfo: ${tapLeaf}`);
|
|
108
|
+
return matches;
|
|
109
|
+
}
|
|
110
|
+
function tapTreeError(expression) {
|
|
111
|
+
return new Error(`Error: invalid taproot tree expression: ${expression}`);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Splits the inner tree expression of a branch into left/right parts.
|
|
115
|
+
* The input must be the contents inside `{}` (no outer braces).
|
|
116
|
+
* Example: `pk(@0),{pk(@1),pk(@2)}` => left: `pk(@0)`, right: `{pk(@1),pk(@2)}`.
|
|
117
|
+
*/
|
|
118
|
+
function splitTapTreeExpression(expression) {
|
|
119
|
+
const result = (0, parseUtils_1.splitTopLevelComma)({ expression, onError: tapTreeError });
|
|
120
|
+
if (!result)
|
|
121
|
+
throw tapTreeError(expression);
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Parses a single taproot tree node expression.
|
|
126
|
+
*
|
|
127
|
+
* Note: the field name is intentionally generic (`expression`) because taproot
|
|
128
|
+
* leaves can contain either miniscript fragments (e.g. `pk(...)`) or
|
|
129
|
+
* descriptor-level script expressions (e.g. `sortedmulti_a(...)`).
|
|
130
|
+
* Examples:
|
|
131
|
+
* - `pk(@0)` => { expression: 'pk(@0)' }
|
|
132
|
+
* - `{pk(@0),pk(@1)}` => { left: { expression: 'pk(@0)' }, right: { expression: 'pk(@1)' } }
|
|
133
|
+
* - `{pk(@0),{pk(@1),pk(@2)}}` =>
|
|
134
|
+
* {
|
|
135
|
+
* left: { expression: 'pk(@0)' },
|
|
136
|
+
* right: { left: { expression: 'pk(@1)' }, right: { expression: 'pk(@2)' } }
|
|
137
|
+
* }
|
|
138
|
+
*/
|
|
139
|
+
function parseTapTreeNode(expression) {
|
|
140
|
+
const trimmedExpression = expression.trim();
|
|
141
|
+
if (!trimmedExpression)
|
|
142
|
+
throw tapTreeError(expression);
|
|
143
|
+
if (trimmedExpression.startsWith('{')) {
|
|
144
|
+
if (!trimmedExpression.endsWith('}'))
|
|
145
|
+
throw tapTreeError(expression);
|
|
146
|
+
const inner = trimmedExpression.slice(1, -1).trim();
|
|
147
|
+
if (!inner)
|
|
148
|
+
throw tapTreeError(expression);
|
|
149
|
+
const { left, right } = splitTapTreeExpression(inner);
|
|
150
|
+
return {
|
|
151
|
+
left: parseTapTreeNode(left),
|
|
152
|
+
right: parseTapTreeNode(right)
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (trimmedExpression.includes('{') || trimmedExpression.includes('}'))
|
|
156
|
+
throw tapTreeError(expression);
|
|
157
|
+
return { expression: trimmedExpression };
|
|
158
|
+
}
|
|
159
|
+
function parseTapTreeExpression(expression) {
|
|
160
|
+
const trimmed = expression.trim();
|
|
161
|
+
if (!trimmed)
|
|
162
|
+
throw tapTreeError(expression);
|
|
163
|
+
const tapTree = parseTapTreeNode(trimmed);
|
|
164
|
+
assertTapTreeDepth(tapTree);
|
|
165
|
+
return tapTree;
|
|
166
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import type { Payment, ECPairInterfaceLike, BIP32InterfaceLike } from './bitcoinLib';
|
|
2
|
+
import type { Network } from './networks';
|
|
3
|
+
import type { TapTreeNode, TapTreeInfoNode } from './tapTree';
|
|
4
|
+
/**
|
|
5
|
+
* Preimage
|
|
6
|
+
* Preimage material used by descriptor outputs that include hashlocks.
|
|
7
|
+
*/
|
|
8
|
+
export type Preimage = {
|
|
9
|
+
/**
|
|
10
|
+
* Use same string expressions as in miniscript. For example: "sha256(cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)" or "ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e)"
|
|
11
|
+
*
|
|
12
|
+
* Accepted functions: sha256, hash256, ripemd160, hash160
|
|
13
|
+
*
|
|
14
|
+
* Digest hex lengths by function:
|
|
15
|
+
* - `sha256`, `hash256`: 64 hex chars (32 bytes)
|
|
16
|
+
* - `ripemd160`, `hash160`: 40 hex chars (20 bytes)
|
|
17
|
+
*/
|
|
18
|
+
digest: string;
|
|
19
|
+
/**
|
|
20
|
+
* Hex encoded preimage. Preimages are always 32 bytes (so, 64 character in hex).
|
|
21
|
+
*/
|
|
22
|
+
preimage: string;
|
|
23
|
+
};
|
|
24
|
+
export type TimeConstraints = {
|
|
25
|
+
nLockTime: number | undefined;
|
|
26
|
+
nSequence: number | undefined;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Parsed key-expression metadata.
|
|
30
|
+
*
|
|
31
|
+
* See {@link KeyExpressionParser}.
|
|
32
|
+
*/
|
|
33
|
+
export type KeyInfo = {
|
|
34
|
+
/** Original key expression string. */
|
|
35
|
+
keyExpression: string;
|
|
36
|
+
/**
|
|
37
|
+
* Concrete public key when derivable.
|
|
38
|
+
*
|
|
39
|
+
* This is usually set unless the key expression is ranged (`*`).
|
|
40
|
+
* For taproot keys this is x-only (32 bytes).
|
|
41
|
+
*/
|
|
42
|
+
pubkey?: Uint8Array;
|
|
43
|
+
/**
|
|
44
|
+
* bitcoinjs-compatible single-key signer (when derivable from the expression).
|
|
45
|
+
*/
|
|
46
|
+
ecpair?: ECPairInterfaceLike;
|
|
47
|
+
/**
|
|
48
|
+
* bitcoinjs-compatible HD node (when derivable from the expression).
|
|
49
|
+
*/
|
|
50
|
+
bip32?: BIP32InterfaceLike;
|
|
51
|
+
/** Raw private key bytes, when available. */
|
|
52
|
+
privkey?: Uint8Array;
|
|
53
|
+
/** Parsed extended public key, when present in the expression. */
|
|
54
|
+
xPub?: string;
|
|
55
|
+
/** Parsed extended private key, when present in the expression. */
|
|
56
|
+
xPrv?: string;
|
|
57
|
+
/** BIP32 master fingerprint, when available. */
|
|
58
|
+
masterFingerprint?: Uint8Array;
|
|
59
|
+
/** Path from `masterFingerprint` to the xpub/xprv root. */
|
|
60
|
+
originPath?: string;
|
|
61
|
+
/** Path from the xpub/xprv root. */
|
|
62
|
+
keyPath?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Full path from the master.
|
|
65
|
+
*
|
|
66
|
+
* Format: `m/val/val/...`, where `val` is an integer and hardened elements
|
|
67
|
+
* use `'`.
|
|
68
|
+
*/
|
|
69
|
+
path?: string;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* An `ExpansionMap` contains destructured information of a descriptor expression.
|
|
73
|
+
*
|
|
74
|
+
* For example, this descriptor `sh(wsh(andor(pk(0252972572d465d016d4c501887b8df303eee3ed602c056b1eb09260dfa0da0ab2),older(8640),pk([d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*))))` has the following
|
|
75
|
+
* `expandedExpression`: `sh(wsh(andor(pk(@0),older(8640),pk(@1))))`
|
|
76
|
+
*
|
|
77
|
+
* `key`'s are set using this format: `@i`, where `i` is an integer starting from `0` assigned by parsing and retrieving keys from the descriptor from left to right.
|
|
78
|
+
*
|
|
79
|
+
* For the given example, the `ExpansionMap` is:
|
|
80
|
+
*
|
|
81
|
+
* ```javascript
|
|
82
|
+
* {
|
|
83
|
+
* '@0': {
|
|
84
|
+
* keyExpression:
|
|
85
|
+
* '0252972572d465d016d4c501887b8df303eee3ed602c056b1eb09260dfa0da0ab2'
|
|
86
|
+
* },
|
|
87
|
+
* '@1': {
|
|
88
|
+
* keyExpression:
|
|
89
|
+
* "[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*",
|
|
90
|
+
* keyPath: '/1/2/3/4/*',
|
|
91
|
+
* originPath: "/49'/0'/0'",
|
|
92
|
+
* path: "m/49'/0'/0'/1/2/3/4/*",
|
|
93
|
+
* // Other relevant properties of `KeyInfo`: `pubkey`, `ecpair`, `bip32`,
|
|
94
|
+
* // `privkey`, `xPub`, `xPrv`, `masterFingerprint`, etc.
|
|
95
|
+
* }
|
|
96
|
+
* }
|
|
97
|
+
*```
|
|
98
|
+
*
|
|
99
|
+
*
|
|
100
|
+
*/
|
|
101
|
+
export type ExpansionMap = {
|
|
102
|
+
[key: string]: KeyInfo;
|
|
103
|
+
};
|
|
104
|
+
/** @ignore */
|
|
105
|
+
interface XOnlyPointAddTweakResult {
|
|
106
|
+
parity: 1 | 0;
|
|
107
|
+
xOnlyPubkey: Uint8Array;
|
|
108
|
+
}
|
|
109
|
+
/** @ignore */
|
|
110
|
+
export interface TinySecp256k1Interface {
|
|
111
|
+
isPoint(p: Uint8Array): boolean;
|
|
112
|
+
pointCompress(p: Uint8Array, compressed?: boolean): Uint8Array;
|
|
113
|
+
isPrivate(d: Uint8Array): boolean;
|
|
114
|
+
pointFromScalar(d: Uint8Array, compressed?: boolean): Uint8Array | null;
|
|
115
|
+
pointAddScalar(p: Uint8Array, tweak: Uint8Array, compressed?: boolean): Uint8Array | null;
|
|
116
|
+
privateAdd(d: Uint8Array, tweak: Uint8Array): Uint8Array | null;
|
|
117
|
+
sign(h: Uint8Array, d: Uint8Array, e?: Uint8Array): Uint8Array;
|
|
118
|
+
signSchnorr?(h: Uint8Array, d: Uint8Array, e?: Uint8Array): Uint8Array;
|
|
119
|
+
verify(h: Uint8Array, Q: Uint8Array, signature: Uint8Array, strict?: boolean): boolean;
|
|
120
|
+
verifySchnorr?(h: Uint8Array, Q: Uint8Array, signature: Uint8Array): boolean;
|
|
121
|
+
xOnlyPointAddTweak(p: Uint8Array, tweak: Uint8Array): XOnlyPointAddTweakResult | null;
|
|
122
|
+
isXOnlyPoint(p: Uint8Array): boolean;
|
|
123
|
+
privateNegate(d: Uint8Array): Uint8Array;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* `DescriptorsFactory` creates and returns the {@link DescriptorsFactory | `expand()`}
|
|
127
|
+
* function that parses a descriptor expression and destructures it
|
|
128
|
+
* into its elemental parts. `Expansion` is the type that `expand()` returns.
|
|
129
|
+
*/
|
|
130
|
+
export type Expansion = {
|
|
131
|
+
/**
|
|
132
|
+
* The corresponding [bitcoinjs-lib Payment](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts) for the provided expression, if applicable.
|
|
133
|
+
*/
|
|
134
|
+
payment?: Payment;
|
|
135
|
+
/**
|
|
136
|
+
* The expanded descriptor expression.
|
|
137
|
+
* See {@link ExpansionMap ExpansionMap} for a detailed explanation.
|
|
138
|
+
*/
|
|
139
|
+
expandedExpression?: string;
|
|
140
|
+
/**
|
|
141
|
+
* The extracted miniscript from the expression, if any.
|
|
142
|
+
*/
|
|
143
|
+
miniscript?: string;
|
|
144
|
+
/**
|
|
145
|
+
* A map of key expressions in the descriptor to their corresponding expanded keys.
|
|
146
|
+
* See {@link ExpansionMap ExpansionMap} for a detailed explanation.
|
|
147
|
+
*/
|
|
148
|
+
expansionMap?: ExpansionMap;
|
|
149
|
+
/**
|
|
150
|
+
* A boolean indicating whether the descriptor uses SegWit.
|
|
151
|
+
*/
|
|
152
|
+
isSegwit?: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* A boolean indicating whether the descriptor uses Taproot.
|
|
155
|
+
*/
|
|
156
|
+
isTaproot?: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* The expanded miniscript, if any.
|
|
159
|
+
* It corresponds to the `expandedExpression` without the top-level script
|
|
160
|
+
* expression.
|
|
161
|
+
*/
|
|
162
|
+
expandedMiniscript?: string;
|
|
163
|
+
/**
|
|
164
|
+
* The taproot tree expression, if any. Only defined for `tr(KEY, TREE)`.
|
|
165
|
+
* Example: `{pk(02aa...),{pk(03bb...),pk(02cc...)}}`.
|
|
166
|
+
*/
|
|
167
|
+
tapTreeExpression?: string;
|
|
168
|
+
/**
|
|
169
|
+
* Parsed taproot leaf tree for `tr(KEY, TREE)`, if any.
|
|
170
|
+
*
|
|
171
|
+
* Shape:
|
|
172
|
+
* - Branch nodes: `{ left, right }`
|
|
173
|
+
* - Leaf nodes: `{ expression: string }`
|
|
174
|
+
*
|
|
175
|
+
* Example:
|
|
176
|
+
* ```ts
|
|
177
|
+
* {
|
|
178
|
+
* left: { expression: 'pk(02aa...)' },
|
|
179
|
+
* right: {
|
|
180
|
+
* left: { expression: 'and_v(v:pk(03bb...),older(12960))' },
|
|
181
|
+
* right: { expression: 'pk(02cc...)' }
|
|
182
|
+
* }
|
|
183
|
+
* }
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
tapTree?: TapTreeNode;
|
|
187
|
+
/**
|
|
188
|
+
* Compiled taproot leaf metadata tree for `tr(KEY, TREE)`, if any.
|
|
189
|
+
*
|
|
190
|
+
* Same branch/leaf tree shape as `tapTree`, but each leaf is enriched with:
|
|
191
|
+
* - `expandedExpression`: descriptor-level expanded leaf expression
|
|
192
|
+
* - optional `expandedMiniscript`: miniscript-expanded leaf
|
|
193
|
+
* - `expansionMap`: resolved keys for that leaf (`@0`, `@1`, ...)
|
|
194
|
+
* - `tapScript`: compiled tapscript bytes
|
|
195
|
+
* - `version`: leaf version (typically tapscript `0xc0`)
|
|
196
|
+
*
|
|
197
|
+
* Note: `@i` placeholders are scoped per leaf, since each leaf is expanded
|
|
198
|
+
* and satisfied independently.
|
|
199
|
+
*
|
|
200
|
+
* Example:
|
|
201
|
+
* ```ts
|
|
202
|
+
* {
|
|
203
|
+
* left: {
|
|
204
|
+
* expression: 'pk(02aa...)',
|
|
205
|
+
* expandedExpression: 'pk(@0)',
|
|
206
|
+
* expandedMiniscript: 'pk(@0)',
|
|
207
|
+
* expansionMap: {
|
|
208
|
+
* '@0': { pubkey: Uint8Array(32), ... }
|
|
209
|
+
* },
|
|
210
|
+
* tapScript: Uint8Array(...),
|
|
211
|
+
* version: 0xc0
|
|
212
|
+
* },
|
|
213
|
+
* right: {
|
|
214
|
+
* left: {
|
|
215
|
+
* expression: 'and_v(v:pk(03bb...),older(12960))',
|
|
216
|
+
* expandedExpression: 'and_v(v:pk(@0),older(12960))',
|
|
217
|
+
* expansionMap: { '@0': { pubkey: Uint8Array(32), ... } },
|
|
218
|
+
* tapScript: Uint8Array(...),
|
|
219
|
+
* version: 0xc0
|
|
220
|
+
* },
|
|
221
|
+
* right: {
|
|
222
|
+
* expression: 'pk(02cc...)',
|
|
223
|
+
* expandedExpression: 'pk(@0)',
|
|
224
|
+
* expansionMap: { '@0': { pubkey: Uint8Array(32), ... } },
|
|
225
|
+
* tapScript: Uint8Array(...),
|
|
226
|
+
* version: 0xc0
|
|
227
|
+
* }
|
|
228
|
+
* }
|
|
229
|
+
* }
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
tapTreeInfo?: TapTreeInfoNode;
|
|
233
|
+
/**
|
|
234
|
+
* The redeem script for the descriptor, if applicable.
|
|
235
|
+
*/
|
|
236
|
+
redeemScript?: Uint8Array;
|
|
237
|
+
/**
|
|
238
|
+
* The witness script for the descriptor, if applicable.
|
|
239
|
+
*/
|
|
240
|
+
witnessScript?: Uint8Array;
|
|
241
|
+
/**
|
|
242
|
+
* Whether the descriptor is a ranged-descriptor.
|
|
243
|
+
*/
|
|
244
|
+
isRanged: boolean;
|
|
245
|
+
/**
|
|
246
|
+
* This is the preferred or authoritative representation of an output
|
|
247
|
+
* descriptor expression.
|
|
248
|
+
* It removes the checksum and, if it is a ranged-descriptor, it
|
|
249
|
+
* particularizes it to its index.
|
|
250
|
+
*/
|
|
251
|
+
canonicalExpression: string;
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* The {@link DescriptorsFactory | `DescriptorsFactory`} function creates and
|
|
255
|
+
* returns the `parseKeyExpression` function, which is an implementation of this
|
|
256
|
+
* interface.
|
|
257
|
+
*
|
|
258
|
+
* It parses and destructures a key expression string (xpub, xprv, pubkey or
|
|
259
|
+
* wif) into {@link KeyInfo | `KeyInfo`}.
|
|
260
|
+
*
|
|
261
|
+
* For example, given this `keyExpression`: `[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*`, this is the parsed result:
|
|
262
|
+
*
|
|
263
|
+
* ```javascript
|
|
264
|
+
* {
|
|
265
|
+
* keyExpression:
|
|
266
|
+
* "[d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*",
|
|
267
|
+
* keyPath: '/1/2/3/4/*',
|
|
268
|
+
* originPath: "/49'/0'/0'",
|
|
269
|
+
* path: "m/49'/0'/0'/1/2/3/4/*",
|
|
270
|
+
* // Other relevant properties of `KeyInfo`: `pubkey`, `ecpair`, `bip32`,
|
|
271
|
+
* // `privkey`, `xPub`, `xPrv`, `masterFingerprint`, etc.
|
|
272
|
+
* }
|
|
273
|
+
* ```
|
|
274
|
+
*
|
|
275
|
+
* See {@link KeyInfo} for the complete list of elements retrieved by this function.
|
|
276
|
+
*/
|
|
277
|
+
export interface KeyExpressionParser {
|
|
278
|
+
(params: {
|
|
279
|
+
keyExpression: string;
|
|
280
|
+
/**
|
|
281
|
+
* Indicates if this key expression belongs to a a SegWit output. When set,
|
|
282
|
+
* further checks are done to ensure the public key (if present in the
|
|
283
|
+
* expression) is compressed (33 bytes).
|
|
284
|
+
*/
|
|
285
|
+
isSegwit?: boolean;
|
|
286
|
+
/**
|
|
287
|
+
* Indicates if this key expression belongs to a Taproot output.
|
|
288
|
+
* For Taproot, the key must be represented as an x-only public key
|
|
289
|
+
* (32 bytes). If a 33-byte compressed pubkey is derived, it is converted to
|
|
290
|
+
* its x-only representation.
|
|
291
|
+
*/
|
|
292
|
+
isTaproot?: boolean;
|
|
293
|
+
network?: Network;
|
|
294
|
+
}): KeyInfo;
|
|
295
|
+
}
|
|
296
|
+
export {};
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bitcoinerlab/descriptors-core",
|
|
3
|
+
"description": "This library parses and creates Bitcoin Miniscript Descriptors and generates Partially Signed Bitcoin Transactions (PSBTs). It provides PSBT finalizers and signers for single-signature, BIP32 and Hardware Wallets, with explicit backend wiring for advanced use cases.",
|
|
4
|
+
"homepage": "https://github.com/bitcoinerlab/descriptors",
|
|
5
|
+
"version": "3.1.0",
|
|
6
|
+
"author": "Jose-Luis Landabaso",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/bitcoinerlab/descriptors.git"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"bitcoin",
|
|
14
|
+
"descriptors",
|
|
15
|
+
"miniscript",
|
|
16
|
+
"psbt",
|
|
17
|
+
"bitcoinjs",
|
|
18
|
+
"scure",
|
|
19
|
+
"noble"
|
|
20
|
+
],
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/bitcoinerlab/descriptors/issues"
|
|
23
|
+
},
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"types": "dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./bitcoinjs": {
|
|
32
|
+
"types": "./dist/bitcoinjs.d.ts",
|
|
33
|
+
"default": "./dist/bitcoinjs.js"
|
|
34
|
+
},
|
|
35
|
+
"./scure": {
|
|
36
|
+
"types": "./dist/scure.d.ts",
|
|
37
|
+
"default": "./dist/scure.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"prettier": "@bitcoinerlab/configs/prettierConfig.json",
|
|
41
|
+
"eslintConfig": {
|
|
42
|
+
"extends": "./node_modules/@bitcoinerlab/configs/eslintConfig"
|
|
43
|
+
},
|
|
44
|
+
"jest": {
|
|
45
|
+
"preset": "@bitcoinerlab/configs",
|
|
46
|
+
"transform": {
|
|
47
|
+
"^.+node_modules/(?:@noble|@scure|micro-packed)/.+\\.js$": "<rootDir>/jest-esm-transform.cjs"
|
|
48
|
+
},
|
|
49
|
+
"transformIgnorePatterns": [
|
|
50
|
+
"/node_modules/(?!(@noble|@scure|micro-packed)/)"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"webdocs": "typedoc --options ./webtypedoc.json && node ./scripts/postprocess-docs.js ./webdocs",
|
|
55
|
+
"docs": "typedoc --options ./typedoc.json && node ./scripts/postprocess-docs.js ./docs",
|
|
56
|
+
"build:src": "tsc --project ./node_modules/@bitcoinerlab/configs/tsconfig.src.json",
|
|
57
|
+
"build:fixtures": "node test/tools/generateBitcoinCoreFixtures.js -i test/fixtures/descriptor_tests.cpp | npx prettier --parser typescript > test/fixtures/bitcoinCore.ts",
|
|
58
|
+
"build:test": "npm run build:fixtures && tsc --project ./node_modules/@bitcoinerlab/configs/tsconfig.test.json --resolveJsonModule",
|
|
59
|
+
"build": "npm run build:src && npm run build:test",
|
|
60
|
+
"lint": "./node_modules/@bitcoinerlab/configs/scripts/lint.sh",
|
|
61
|
+
"ensureTester": "./node_modules/@bitcoinerlab/configs/scripts/ensureTester.sh",
|
|
62
|
+
"test:integration:soft": "npm run ensureTester && node test/integration/standardOutputs.js && echo \"\n\n\" && node test/integration/miniscript.js && echo \"\n\n\" && node test/integration/sortedmulti.js && echo \"\n\n\" && node test/integration/taproot.js && echo \"\n\n\" && node test/integration/scure.js",
|
|
63
|
+
"test:integration:ledger": "npm run ensureTester && node test/integration/ledgerTaproot.js && echo \"\n\n\" && node test/integration/ledger.js",
|
|
64
|
+
"test:unit": "jest",
|
|
65
|
+
"test:unit:scure": "cross-env BITCOIN_LIB=scure jest",
|
|
66
|
+
"test:scure-adapter": "node test/scureAdapter.js",
|
|
67
|
+
"test:integration:soft:scure": "cross-env BITCOIN_LIB=scure bash -c 'npm run test:integration:soft'",
|
|
68
|
+
"test:integration:ledger:scure": "cross-env BITCOIN_LIB=scure bash -c 'npm run ensureTester && node test/integration/ledgerTaproot.js && echo \"\" && echo \"\" && node test/integration/ledger.js'",
|
|
69
|
+
"test:matrix": "npm run test:unit && npm run test:unit:scure && npm run test:scure-adapter && npm run test:integration:soft && npm run test:integration:soft:scure",
|
|
70
|
+
"test": "npm run lint && npm run build && npm run test:matrix",
|
|
71
|
+
"test:ledger": "npm run lint && npm run build && echo \"\n\n\" && npm run test:integration:ledger:scure && echo \"\n\n\" && npm run test:integration:ledger",
|
|
72
|
+
"publish:all": "npm publish --access public && npm publish --access public --prefix ./packages/descriptors && npm publish --access public --prefix ./packages/descriptors-scure",
|
|
73
|
+
"prepublishOnly": "npm run test && echo \"\n\n\" && npm run test:integration:ledger:scure && echo \"\n\n\" && npm run test:integration:ledger"
|
|
74
|
+
},
|
|
75
|
+
"files": [
|
|
76
|
+
"dist"
|
|
77
|
+
],
|
|
78
|
+
"peerDependencies": {
|
|
79
|
+
"bitcoinjs-lib": "^7.0.1",
|
|
80
|
+
"bip32": "^5.0.1",
|
|
81
|
+
"ecpair": "^3.0.1",
|
|
82
|
+
"@noble/curves": "^2.0.1",
|
|
83
|
+
"@scure/base": "^2.0.0",
|
|
84
|
+
"@scure/bip32": "^2.0.1",
|
|
85
|
+
"@scure/btc-signer": "^2.0.1",
|
|
86
|
+
"@ledgerhq/ledger-bitcoin": "^0.3.0"
|
|
87
|
+
},
|
|
88
|
+
"peerDependenciesMeta": {
|
|
89
|
+
"@ledgerhq/ledger-bitcoin": {
|
|
90
|
+
"optional": true
|
|
91
|
+
},
|
|
92
|
+
"bitcoinjs-lib": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"bip32": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"ecpair": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"@scure/btc-signer": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"@scure/base": {
|
|
105
|
+
"optional": true
|
|
106
|
+
},
|
|
107
|
+
"@scure/bip32": {
|
|
108
|
+
"optional": true
|
|
109
|
+
},
|
|
110
|
+
"@noble/curves": {
|
|
111
|
+
"optional": true
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"devDependencies": {
|
|
115
|
+
"@babel/core": "^7.29.0",
|
|
116
|
+
"@babel/preset-env": "^7.29.0",
|
|
117
|
+
"@bitcoinerlab/configs": "^2.0.0",
|
|
118
|
+
"@bitcoinerlab/miniscript-policies": "^1.0.0",
|
|
119
|
+
"@bitcoinerlab/secp256k1": "^1.2.0",
|
|
120
|
+
"@ledgerhq/hw-transport-node-hid": "^6.30.0",
|
|
121
|
+
"@ledgerhq/ledger-bitcoin": "^0.3.0",
|
|
122
|
+
"@noble/curves": "^2.0.1",
|
|
123
|
+
"@scure/base": "^2.0.0",
|
|
124
|
+
"@scure/bip32": "^2.0.1",
|
|
125
|
+
"@scure/bip39": "^2.0.1",
|
|
126
|
+
"@scure/btc-signer": "^2.0.1",
|
|
127
|
+
"@types/lodash.memoize": "^4.1.9",
|
|
128
|
+
"babel-jest": "^30.3.0",
|
|
129
|
+
"bip32": "^5.0.1",
|
|
130
|
+
"bip39": "^3.0.4",
|
|
131
|
+
"bip65": "^1.0.3",
|
|
132
|
+
"bip68": "^1.0.4",
|
|
133
|
+
"bitcoinjs-lib": "^7.0.1",
|
|
134
|
+
"cross-env": "^10.1.0",
|
|
135
|
+
"ecpair": "^3.0.1",
|
|
136
|
+
"jest": "^30.3.0",
|
|
137
|
+
"regtest-client": "^0.2.1",
|
|
138
|
+
"ts-jest": "^29.4.6",
|
|
139
|
+
"yargs": "^17.7.2"
|
|
140
|
+
},
|
|
141
|
+
"dependencies": {
|
|
142
|
+
"@bitcoinerlab/miniscript": "^2.0.0",
|
|
143
|
+
"@noble/hashes": "^2.0.1",
|
|
144
|
+
"lodash.memoize": "^4.1.2",
|
|
145
|
+
"uint8array-tools": "^0.0.9",
|
|
146
|
+
"varuint-bitcoin": "^2.0.0"
|
|
147
|
+
}
|
|
148
|
+
}
|