@kukks/bitcoin-descriptors 3.0.2 → 3.2.1
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 +109 -38
- package/dist/adapters.d.ts +23 -0
- package/dist/adapters.js +321 -0
- package/dist/descriptors.d.ts +5 -4
- package/dist/descriptors.js +4 -2
- package/dist/index.d.ts +89 -0
- package/dist/index.js +5 -0
- package/dist/miniscript.js +19 -3
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -6,12 +6,13 @@ This library parses and creates Bitcoin Miniscript Descriptors and generates Par
|
|
|
6
6
|
|
|
7
7
|
## Differences from upstream
|
|
8
8
|
|
|
9
|
-
This fork migrates the entire library from `bitcoinjs-lib` to the [`@scure/btc-signer`](https://github.com/
|
|
9
|
+
This fork migrates the entire library from `bitcoinjs-lib` to the [`@scure/btc-signer`](https://github.com/paulmillr/scure-btc-signer) and [`@noble`](https://github.com/paulmillr/noble-curves) ecosystem. Key differences:
|
|
10
10
|
|
|
11
11
|
- **`Buffer` replaced with `Uint8Array`** across the entire public API. All methods that previously returned or accepted `Buffer` now use `Uint8Array`. This is a **breaking change**.
|
|
12
|
-
- **Dependencies replaced**: `bitcoinjs-lib`, `ecpair`, `bip32`, `tiny-secp256k1` are no longer used. The library now depends on `@scure/btc-signer
|
|
12
|
+
- **Dependencies replaced**: `bitcoinjs-lib`, `ecpair`, `bip32`, `tiny-secp256k1` are no longer used. The library now depends on [`@scure/btc-signer`](https://github.com/paulmillr/scure-btc-signer), [`@scure/bip32`](https://github.com/paulmillr/scure-bip32), [`@noble/curves`](https://github.com/paulmillr/noble-curves), [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), and [`@scure/base`](https://github.com/paulmillr/scure-base).
|
|
13
|
+
- **Built-in adapters**: Ships `nobleECPair` and `scureBIP32` adapters — no more boilerplate. `DescriptorsFactory()` works with zero arguments.
|
|
13
14
|
- **PSBT class**: Uses `Transaction` from `@scure/btc-signer` instead of `Psbt` from `bitcoinjs-lib`.
|
|
14
|
-
- **Ledger support removed**: The `ledger` module and all Ledger-related functions
|
|
15
|
+
- **Ledger support removed**: The `ledger` module and all Ledger-related functions have been removed.
|
|
15
16
|
- **`lodash.memoize` removed**: Replaced with an inline memoize helper.
|
|
16
17
|
- **Package renamed** from `@bitcoinerlab/descriptors` to `@kukks/bitcoin-descriptors`.
|
|
17
18
|
|
|
@@ -19,18 +20,62 @@ This fork migrates the entire library from `bitcoinjs-lib` to the [`@scure/btc-s
|
|
|
19
20
|
|
|
20
21
|
```bash
|
|
21
22
|
npm install @kukks/bitcoin-descriptors
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you use **miniscript-based descriptors** (`sh(wsh(...))`, `sh(...)`, `wsh(...)` with miniscript expressions), install the optional peer dependency:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
22
28
|
npm install @bitcoinerlab/miniscript
|
|
23
29
|
```
|
|
24
30
|
|
|
31
|
+
Standard descriptors (`pkh`, `wpkh`, `sh(wpkh(...))`, `tr`, `multi`, `sortedmulti`, `addr`) work without it.
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { DescriptorsFactory } from '@kukks/bitcoin-descriptors';
|
|
37
|
+
|
|
38
|
+
// Zero-config — uses built-in @noble/curves + @scure/bip32 adapters
|
|
39
|
+
const { Output, expand } = DescriptorsFactory();
|
|
40
|
+
|
|
41
|
+
const output = new Output({
|
|
42
|
+
descriptor: 'wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9)'
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
console.log(output.getAddress());
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or use the pre-built default factory:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { defaultFactory } from '@kukks/bitcoin-descriptors';
|
|
52
|
+
|
|
53
|
+
const { Output } = defaultFactory;
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Bring your own adapters
|
|
57
|
+
|
|
58
|
+
If you need custom `ECPairAPI` or `BIP32API` implementations, you can still pass them explicitly:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { DescriptorsFactory } from '@kukks/bitcoin-descriptors';
|
|
62
|
+
import type { ECPairAPI, BIP32API } from '@kukks/bitcoin-descriptors';
|
|
63
|
+
|
|
64
|
+
const { Output } = DescriptorsFactory({ ECPair: myECPair, BIP32: myBIP32 });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The built-in adapters are also available as standalone exports:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { nobleECPair, scureBIP32 } from '@kukks/bitcoin-descriptors';
|
|
71
|
+
```
|
|
72
|
+
|
|
25
73
|
## Features
|
|
26
74
|
|
|
27
75
|
- Parses and creates [Bitcoin Descriptors](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md) (including those based on the [Miniscript language](https://bitcoinerlab.com/modules/miniscript)).
|
|
28
76
|
- Generates Partially Signed Bitcoin Transactions (PSBTs).
|
|
29
77
|
- Provides PSBT finalizers and signers for single-signature and BIP32 wallets.
|
|
30
|
-
|
|
31
|
-
## Concepts
|
|
32
|
-
|
|
33
|
-
This library has two main capabilities related to Bitcoin descriptors. Firstly, it can generate `addresses` and `scriptPubKeys` from descriptors. These `addresses` and `scriptPubKeys` can be used to receive funds from other parties. Secondly, the library is able to sign transactions and spend unspent outputs described by those same descriptors. In order to do this, the descriptors must first be set into a PSBT.
|
|
78
|
+
- Ships built-in adapters for `@noble/curves` and `@scure/bip32` — zero boilerplate needed.
|
|
34
79
|
|
|
35
80
|
<details>
|
|
36
81
|
<summary>Concepts</summary>
|
|
@@ -61,21 +106,15 @@ The library can be split into three main parts:
|
|
|
61
106
|
|
|
62
107
|
### Output class
|
|
63
108
|
|
|
64
|
-
The `Output` class is
|
|
65
|
-
|
|
66
|
-
```javascript
|
|
67
|
-
import * as descriptors from '@kukks/bitcoin-descriptors';
|
|
68
|
-
const { Output } = descriptors.DescriptorsFactory({ ECPair, BIP32 });
|
|
69
|
-
```
|
|
109
|
+
The `Output` class is created via `DescriptorsFactory`:
|
|
70
110
|
|
|
71
|
-
|
|
111
|
+
```typescript
|
|
112
|
+
import { DescriptorsFactory } from '@kukks/bitcoin-descriptors';
|
|
72
113
|
|
|
73
|
-
|
|
114
|
+
const { Output } = DescriptorsFactory();
|
|
74
115
|
|
|
75
|
-
```javascript
|
|
76
116
|
const wpkhOutput = new Output({
|
|
77
|
-
descriptor:
|
|
78
|
-
'wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9)'
|
|
117
|
+
descriptor: 'wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9)'
|
|
79
118
|
});
|
|
80
119
|
```
|
|
81
120
|
|
|
@@ -83,33 +122,35 @@ For miniscript-based descriptors, the `signersPubKeys` parameter in the construc
|
|
|
83
122
|
|
|
84
123
|
The `Output` class offers various helpful methods, including `getAddress()`, `getScriptPubKey()` (returns `Uint8Array`), `expand()`, `updatePsbtAsInput()` and `updatePsbtAsOutput()`.
|
|
85
124
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
125
|
+
The library supports a wide range of descriptor types, including:
|
|
126
|
+
- Pay-to-Public-Key-Hash (P2PKH): `pkh(KEY)`
|
|
127
|
+
- Pay-to-Witness-Public-Key-Hash (P2WPKH): `wpkh(KEY)`
|
|
128
|
+
- Pay-to-Script-Hash (P2SH): `sh(SCRIPT)`
|
|
129
|
+
- Pay-to-Witness-Script-Hash (P2WSH): `wsh(SCRIPT)`
|
|
130
|
+
- Pay-to-Taproot (P2TR) with single key: `tr(KEY)`
|
|
131
|
+
- Address-based descriptors: `addr(ADDRESS)`, including Taproot addresses
|
|
93
132
|
|
|
94
133
|
#### Working with PSBTs
|
|
95
134
|
|
|
96
135
|
This library uses `Transaction` from `@scure/btc-signer` as the PSBT class:
|
|
97
136
|
|
|
98
|
-
```
|
|
137
|
+
```typescript
|
|
99
138
|
import { Transaction } from '@scure/btc-signer';
|
|
139
|
+
|
|
100
140
|
const psbt = new Transaction({ allowUnknownOutputs: true, disableScriptCheck: true });
|
|
101
141
|
const inputFinalizer = output.updatePsbtAsInput({ psbt, txHex, vout });
|
|
102
142
|
```
|
|
103
143
|
|
|
104
|
-
Here, `psbt` refers to an instance of the [`@scure/btc-signer` Transaction class](https://github.com/
|
|
144
|
+
Here, `psbt` refers to an instance of the [`@scure/btc-signer` Transaction class](https://github.com/paulmillr/scure-btc-signer). The parameter `txHex` denotes a hex string that serializes the previous transaction containing this output. Meanwhile, `vout` is an integer that marks the position of the output within that transaction.
|
|
105
145
|
|
|
106
146
|
The method returns the `inputFinalizer()` function. This finalizer function completes a PSBT input by adding the unlocking script (`scriptWitness` or `scriptSig`) that satisfies the previous output's spending conditions. Complete all necessary signing operations before calling `inputFinalizer()`.
|
|
107
147
|
|
|
108
148
|
To add an output:
|
|
109
149
|
|
|
110
|
-
```
|
|
111
|
-
const recipientOutput =
|
|
112
|
-
|
|
150
|
+
```typescript
|
|
151
|
+
const recipientOutput = new Output({
|
|
152
|
+
descriptor: 'addr(bc1qgw6xanldsz959z45y4dszehx4xkuzf7nfhya8x)'
|
|
153
|
+
});
|
|
113
154
|
recipientOutput.updatePsbtAsOutput({ psbt, value: 10000 });
|
|
114
155
|
```
|
|
115
156
|
|
|
@@ -117,15 +158,15 @@ recipientOutput.updatePsbtAsOutput({ psbt, value: 10000 });
|
|
|
117
158
|
|
|
118
159
|
The `expand()` function parses Bitcoin descriptors into their component parts:
|
|
119
160
|
|
|
120
|
-
```
|
|
161
|
+
```typescript
|
|
121
162
|
const output = new Output({ descriptor: "your-descriptor-here" });
|
|
122
163
|
const result = output.expand();
|
|
123
164
|
```
|
|
124
165
|
|
|
125
166
|
Or through the factory:
|
|
126
167
|
|
|
127
|
-
```
|
|
128
|
-
const { expand } =
|
|
168
|
+
```typescript
|
|
169
|
+
const { expand } = DescriptorsFactory();
|
|
129
170
|
const result = expand({
|
|
130
171
|
descriptor: "sh(wsh(andor(pk(0252972572d465d016d4c501887b8df303eee3ed602c056b1eb09260dfa0da0ab2),older(8640),pk([d34db33f/49'/0'/0']tpubDCdxmvzJ5QBjTN8oCjjyT2V58AyZvA1fkmCeZRC75QMoaHcVP2m45Bv3hmnR7ttAwkb2UNYyoXdHVt4gwBqRrJqLUU2JrM43HippxiWpHra/1/2/3/4/*))))"
|
|
131
172
|
});
|
|
@@ -135,7 +176,7 @@ const result = expand({
|
|
|
135
176
|
|
|
136
177
|
This library includes two signers: ECPair (single-signature) and BIP32.
|
|
137
178
|
|
|
138
|
-
```
|
|
179
|
+
```typescript
|
|
139
180
|
import { signers } from '@kukks/bitcoin-descriptors';
|
|
140
181
|
|
|
141
182
|
// For BIP32
|
|
@@ -149,13 +190,13 @@ signers.signECPair({ psbt, ecpair });
|
|
|
149
190
|
|
|
150
191
|
1. For each unspent output, call `updatePsbtAsInput`:
|
|
151
192
|
|
|
152
|
-
```
|
|
193
|
+
```typescript
|
|
153
194
|
const inputFinalizer = output.updatePsbtAsInput({ psbt, txHex, vout });
|
|
154
195
|
```
|
|
155
196
|
|
|
156
197
|
2. After signing, finalize each input:
|
|
157
198
|
|
|
158
|
-
```
|
|
199
|
+
```typescript
|
|
159
200
|
inputFinalizer({ psbt });
|
|
160
201
|
```
|
|
161
202
|
|
|
@@ -163,7 +204,7 @@ signers.signECPair({ psbt, ecpair });
|
|
|
163
204
|
|
|
164
205
|
Helper functions for generating descriptor strings:
|
|
165
206
|
|
|
166
|
-
```
|
|
207
|
+
```typescript
|
|
167
208
|
import { scriptExpressions, keyExpressionBIP32 } from '@kukks/bitcoin-descriptors';
|
|
168
209
|
```
|
|
169
210
|
|
|
@@ -171,7 +212,7 @@ The `scriptExpressions` module includes functions like `pkhBIP32()`, `shWpkhBIP3
|
|
|
171
212
|
|
|
172
213
|
The `keyExpressionBIP32` function generates BIP32 key expression strings:
|
|
173
214
|
|
|
174
|
-
```
|
|
215
|
+
```typescript
|
|
175
216
|
keyExpressionBIP32({
|
|
176
217
|
masterNode, // BIP32Interface
|
|
177
218
|
originPath, // e.g. "/44'/0'/0'"
|
|
@@ -181,6 +222,36 @@ keyExpressionBIP32({
|
|
|
181
222
|
});
|
|
182
223
|
```
|
|
183
224
|
|
|
225
|
+
## API Reference
|
|
226
|
+
|
|
227
|
+
### Exports
|
|
228
|
+
|
|
229
|
+
| Export | Type | Description |
|
|
230
|
+
|--------|------|-------------|
|
|
231
|
+
| `DescriptorsFactory` | function | Creates `Output`, `expand`, `parseKeyExpression` — params optional (defaults to built-in adapters) |
|
|
232
|
+
| `defaultFactory` | object | Pre-built factory using built-in adapters |
|
|
233
|
+
| `nobleECPair` | `ECPairAPI` | Built-in ECPair adapter using `@noble/curves` secp256k1 |
|
|
234
|
+
| `scureBIP32` | `BIP32API` | Built-in BIP32 adapter using `@scure/bip32` |
|
|
235
|
+
| `signers` | namespace | `signECPair`, `signBIP32` and related signing functions |
|
|
236
|
+
| `scriptExpressions` | namespace | `pkhBIP32`, `shWpkhBIP32`, `wpkhBIP32`, etc. |
|
|
237
|
+
| `keyExpressionBIP32` | function | Generate BIP32 key expression strings |
|
|
238
|
+
| `networks` | object | `bitcoin`, `testnet`, `regtest` network definitions |
|
|
239
|
+
| `checksum` | function | Compute/validate descriptor checksums |
|
|
240
|
+
|
|
241
|
+
### Types
|
|
242
|
+
|
|
243
|
+
| Type | Description |
|
|
244
|
+
|------|-------------|
|
|
245
|
+
| `ECPairAPI` | Factory interface for creating key pairs |
|
|
246
|
+
| `ECPairInterface` | Key pair instance with `sign`, `verify`, `publicKey`, etc. |
|
|
247
|
+
| `BIP32API` | Factory interface for creating HD keys (`fromSeed`, `fromBase58`, etc.) |
|
|
248
|
+
| `BIP32Interface` | HD key instance with `derivePath`, `derive`, `sign`, etc. |
|
|
249
|
+
| `OutputInstance` | Instance returned by `new Output(...)` |
|
|
250
|
+
| `Network` | Network configuration (`bitcoin`, `testnet`, `regtest`) |
|
|
251
|
+
| `PsbtLike` | PSBT interface (compatible with `@scure/btc-signer` Transaction) |
|
|
252
|
+
| `KeyInfo` | Parsed key expression data |
|
|
253
|
+
| `Expansion` | Parsed descriptor expansion data |
|
|
254
|
+
|
|
184
255
|
## Building from source
|
|
185
256
|
|
|
186
257
|
```bash
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HDKey } from '@scure/bip32';
|
|
2
|
+
import type { ECPairInterface, ECPairAPI, BIP32Interface, BIP32API } from './types.js';
|
|
3
|
+
import { type Network } from './networks.js';
|
|
4
|
+
/**
|
|
5
|
+
* Create an ECPairInterface from a private key and/or public key.
|
|
6
|
+
* Exported for advanced use cases where consumers need to construct
|
|
7
|
+
* key pairs directly.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createECPair(privKey: Uint8Array | undefined, pubKeyInput: Uint8Array | undefined, compressed: boolean, network: Network): ECPairInterface;
|
|
10
|
+
/**
|
|
11
|
+
* Built-in ECPairAPI implementation using @noble/curves secp256k1.
|
|
12
|
+
*/
|
|
13
|
+
export declare const nobleECPair: ECPairAPI;
|
|
14
|
+
/**
|
|
15
|
+
* Wrap a @scure/bip32 HDKey in a BIP32Interface.
|
|
16
|
+
* Exported for advanced use cases where consumers need to wrap
|
|
17
|
+
* HDKey instances directly.
|
|
18
|
+
*/
|
|
19
|
+
export declare function wrapHDKey(hdkey: HDKey, network: Network): BIP32Interface;
|
|
20
|
+
/**
|
|
21
|
+
* Built-in BIP32API implementation using @scure/bip32.
|
|
22
|
+
*/
|
|
23
|
+
export declare const scureBIP32: BIP32API;
|
package/dist/adapters.js
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
// Copyright (c) 2025 Jose-Luis Landabaso - https://bitcoinerlab.com
|
|
2
|
+
// Distributed under the MIT software license
|
|
3
|
+
// Built-in adapters for ECPairAPI and BIP32API using
|
|
4
|
+
// @noble/curves, @scure/bip32, @noble/hashes, and @scure/base.
|
|
5
|
+
// These conform to the interfaces defined in ./types.ts.
|
|
6
|
+
import { secp256k1 } from '@noble/curves/secp256k1.js';
|
|
7
|
+
import { HDKey } from '@scure/bip32';
|
|
8
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
9
|
+
import { base58check, hex } from '@scure/base';
|
|
10
|
+
import { concatBytes } from '@scure/btc-signer/utils.js';
|
|
11
|
+
import { networks } from './networks.js';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Helpers
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
const bs58check = base58check(sha256);
|
|
16
|
+
const DEFAULT_NETWORK = networks.bitcoin;
|
|
17
|
+
/** Convert a bigint to a 32-byte big-endian Uint8Array. */
|
|
18
|
+
function bigintTo32Bytes(n) {
|
|
19
|
+
const hexStr = n.toString(16).padStart(64, '0');
|
|
20
|
+
return hex.decode(hexStr);
|
|
21
|
+
}
|
|
22
|
+
/** Write a 32-bit unsigned integer in big-endian format into buf at offset. */
|
|
23
|
+
function writeUInt32BE(buf, value, offset) {
|
|
24
|
+
buf[offset] = (value >>> 24) & 0xff;
|
|
25
|
+
buf[offset + 1] = (value >>> 16) & 0xff;
|
|
26
|
+
buf[offset + 2] = (value >>> 8) & 0xff;
|
|
27
|
+
buf[offset + 3] = value & 0xff;
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// WIF encode / decode
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
function encodeWIF(privateKey, compressed, network) {
|
|
33
|
+
const prefix = Uint8Array.from([network.wif]);
|
|
34
|
+
const payload = compressed
|
|
35
|
+
? concatBytes(prefix, privateKey, Uint8Array.from([0x01]))
|
|
36
|
+
: concatBytes(prefix, privateKey);
|
|
37
|
+
return bs58check.encode(payload);
|
|
38
|
+
}
|
|
39
|
+
function decodeWIF(wif, network) {
|
|
40
|
+
const decoded = bs58check.decode(wif);
|
|
41
|
+
const version = decoded[0];
|
|
42
|
+
// Determine matching network(s)
|
|
43
|
+
const candidateNetworks = network
|
|
44
|
+
? Array.isArray(network)
|
|
45
|
+
? network
|
|
46
|
+
: [network]
|
|
47
|
+
: [networks.bitcoin, networks.testnet, networks.regtest];
|
|
48
|
+
const matchedNetwork = candidateNetworks.find(n => n.wif === version);
|
|
49
|
+
if (!matchedNetwork) {
|
|
50
|
+
throw new Error(`Invalid network version`);
|
|
51
|
+
}
|
|
52
|
+
// Determine if compressed
|
|
53
|
+
if (decoded.length === 34 && decoded[33] === 0x01) {
|
|
54
|
+
return {
|
|
55
|
+
privateKey: decoded.subarray(1, 33),
|
|
56
|
+
compressed: true,
|
|
57
|
+
network: matchedNetwork
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
else if (decoded.length === 33) {
|
|
61
|
+
return {
|
|
62
|
+
privateKey: decoded.subarray(1, 33),
|
|
63
|
+
compressed: false,
|
|
64
|
+
network: matchedNetwork
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
throw new Error('Invalid WIF payload length');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// ECPair implementation
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
/**
|
|
75
|
+
* Create an ECPairInterface from a private key and/or public key.
|
|
76
|
+
* Exported for advanced use cases where consumers need to construct
|
|
77
|
+
* key pairs directly.
|
|
78
|
+
*/
|
|
79
|
+
export function createECPair(privKey, pubKeyInput, compressed, network) {
|
|
80
|
+
let pubKey;
|
|
81
|
+
if (privKey) {
|
|
82
|
+
pubKey = secp256k1.getPublicKey(privKey, compressed);
|
|
83
|
+
}
|
|
84
|
+
else if (pubKeyInput) {
|
|
85
|
+
// Normalise to the requested compression
|
|
86
|
+
const point = secp256k1.Point.fromHex(hex.encode(pubKeyInput));
|
|
87
|
+
pubKey = point.toBytes(compressed);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
throw new Error('Either privateKey or publicKey must be provided');
|
|
91
|
+
}
|
|
92
|
+
// Build the object conditionally so that `privateKey` is only present
|
|
93
|
+
// when defined (satisfies exactOptionalPropertyTypes).
|
|
94
|
+
const base = {
|
|
95
|
+
publicKey: pubKey,
|
|
96
|
+
compressed,
|
|
97
|
+
network,
|
|
98
|
+
sign(hash) {
|
|
99
|
+
if (!privKey)
|
|
100
|
+
throw new Error('Missing private key');
|
|
101
|
+
return secp256k1.sign(hash, privKey);
|
|
102
|
+
},
|
|
103
|
+
verify(hash, signature) {
|
|
104
|
+
return secp256k1.verify(signature, hash, pubKey);
|
|
105
|
+
},
|
|
106
|
+
toWIF() {
|
|
107
|
+
if (!privKey)
|
|
108
|
+
throw new Error('Missing private key');
|
|
109
|
+
return encodeWIF(privKey, compressed, network);
|
|
110
|
+
},
|
|
111
|
+
tweak(t) {
|
|
112
|
+
const tweakBigint = BigInt('0x' + hex.encode(t));
|
|
113
|
+
const n = secp256k1.Point.CURVE().n;
|
|
114
|
+
if (privKey) {
|
|
115
|
+
const privBigint = BigInt('0x' + hex.encode(privKey));
|
|
116
|
+
const newPrivBigint = (privBigint + tweakBigint) % n;
|
|
117
|
+
if (newPrivBigint === 0n) {
|
|
118
|
+
throw new Error('Tweaked private key is zero');
|
|
119
|
+
}
|
|
120
|
+
const newPrivKey = bigintTo32Bytes(newPrivBigint);
|
|
121
|
+
return createECPair(newPrivKey, undefined, compressed, network);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Public-key-only tweak: P' = P + t*G
|
|
125
|
+
const G = secp256k1.Point.BASE;
|
|
126
|
+
const tweakPoint = G.multiply(tweakBigint);
|
|
127
|
+
const pubPoint = secp256k1.Point.fromHex(hex.encode(pubKey));
|
|
128
|
+
const tweakedPoint = pubPoint.add(tweakPoint);
|
|
129
|
+
return createECPair(undefined, tweakedPoint.toBytes(compressed), compressed, network);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
if (privKey) {
|
|
134
|
+
return Object.assign(base, { privateKey: privKey });
|
|
135
|
+
}
|
|
136
|
+
return base;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Built-in ECPairAPI implementation using @noble/curves secp256k1.
|
|
140
|
+
*/
|
|
141
|
+
export const nobleECPair = {
|
|
142
|
+
fromPublicKey(publicKey, options) {
|
|
143
|
+
const compressed = options?.compressed !== false;
|
|
144
|
+
const network = options?.network ?? DEFAULT_NETWORK;
|
|
145
|
+
return createECPair(undefined, publicKey, compressed, network);
|
|
146
|
+
},
|
|
147
|
+
fromPrivateKey(privateKey, options) {
|
|
148
|
+
const compressed = options?.compressed !== false;
|
|
149
|
+
const network = options?.network ?? DEFAULT_NETWORK;
|
|
150
|
+
return createECPair(privateKey, undefined, compressed, network);
|
|
151
|
+
},
|
|
152
|
+
fromWIF(wif, network) {
|
|
153
|
+
const { privateKey, compressed, network: net } = decodeWIF(wif, network);
|
|
154
|
+
return createECPair(privateKey, undefined, compressed, net);
|
|
155
|
+
},
|
|
156
|
+
makeRandom(options) {
|
|
157
|
+
const privKey = secp256k1.utils.randomSecretKey();
|
|
158
|
+
const compressed = options?.compressed !== false;
|
|
159
|
+
const network = options?.network ?? DEFAULT_NETWORK;
|
|
160
|
+
return createECPair(privKey, undefined, compressed, network);
|
|
161
|
+
},
|
|
162
|
+
isPoint(p) {
|
|
163
|
+
try {
|
|
164
|
+
secp256k1.Point.fromHex(hex.encode(p));
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// BIP32 implementation
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
/** Map a Network to the versions object expected by @scure/bip32's HDKey. */
|
|
176
|
+
function networkToVersions(network) {
|
|
177
|
+
return { public: network.bip32.public, private: network.bip32.private };
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Wrap a @scure/bip32 HDKey in a BIP32Interface.
|
|
181
|
+
* Exported for advanced use cases where consumers need to wrap
|
|
182
|
+
* HDKey instances directly.
|
|
183
|
+
*/
|
|
184
|
+
export function wrapHDKey(hdkey, network) {
|
|
185
|
+
const versions = networkToVersions(network);
|
|
186
|
+
// Build the base object without privateKey, then conditionally add it.
|
|
187
|
+
// This satisfies exactOptionalPropertyTypes.
|
|
188
|
+
const base = {
|
|
189
|
+
get publicKey() {
|
|
190
|
+
if (!hdkey.publicKey)
|
|
191
|
+
throw new Error('Missing public key');
|
|
192
|
+
return hdkey.publicKey;
|
|
193
|
+
},
|
|
194
|
+
get chainCode() {
|
|
195
|
+
if (!hdkey.chainCode)
|
|
196
|
+
throw new Error('Missing chain code');
|
|
197
|
+
return hdkey.chainCode;
|
|
198
|
+
},
|
|
199
|
+
get fingerprint() {
|
|
200
|
+
// HDKey.fingerprint is a number (4-byte big-endian unsigned int)
|
|
201
|
+
const buf = new Uint8Array(4);
|
|
202
|
+
writeUInt32BE(buf, hdkey.fingerprint >>> 0, 0);
|
|
203
|
+
return buf;
|
|
204
|
+
},
|
|
205
|
+
get depth() {
|
|
206
|
+
return hdkey.depth;
|
|
207
|
+
},
|
|
208
|
+
get index() {
|
|
209
|
+
return hdkey.index;
|
|
210
|
+
},
|
|
211
|
+
get parentFingerprint() {
|
|
212
|
+
return hdkey.parentFingerprint;
|
|
213
|
+
},
|
|
214
|
+
network,
|
|
215
|
+
derivePath(path) {
|
|
216
|
+
// @scure/bip32 requires paths to start with "m" or "M"
|
|
217
|
+
// Old bip32 package accepted relative paths like "0'/1'/0'"
|
|
218
|
+
const normalizedPath = path.startsWith('m') || path.startsWith('M') ? path : `m/${path}`;
|
|
219
|
+
return wrapHDKey(hdkey.derive(normalizedPath), network);
|
|
220
|
+
},
|
|
221
|
+
derive(index) {
|
|
222
|
+
return wrapHDKey(hdkey.deriveChild(index), network);
|
|
223
|
+
},
|
|
224
|
+
deriveHardened(index) {
|
|
225
|
+
return wrapHDKey(hdkey.deriveChild(index + 0x80000000), network);
|
|
226
|
+
},
|
|
227
|
+
neutered() {
|
|
228
|
+
// Create a public-only HDKey via the public extended key
|
|
229
|
+
const xpub = hdkey.publicExtendedKey;
|
|
230
|
+
const neuteredKey = HDKey.fromExtendedKey(xpub, versions);
|
|
231
|
+
return wrapHDKey(neuteredKey, network);
|
|
232
|
+
},
|
|
233
|
+
toBase58() {
|
|
234
|
+
if (hdkey.privateKey) {
|
|
235
|
+
return hdkey.privateExtendedKey;
|
|
236
|
+
}
|
|
237
|
+
return hdkey.publicExtendedKey;
|
|
238
|
+
},
|
|
239
|
+
sign(hash) {
|
|
240
|
+
if (!hdkey.privateKey)
|
|
241
|
+
throw new Error('Missing private key');
|
|
242
|
+
return hdkey.sign(hash);
|
|
243
|
+
},
|
|
244
|
+
verify(hash, signature) {
|
|
245
|
+
return hdkey.verify(hash, signature);
|
|
246
|
+
},
|
|
247
|
+
isNeutered() {
|
|
248
|
+
return !hdkey.privateKey;
|
|
249
|
+
},
|
|
250
|
+
toWIF() {
|
|
251
|
+
if (!hdkey.privateKey) {
|
|
252
|
+
throw new Error('Missing private key');
|
|
253
|
+
}
|
|
254
|
+
return encodeWIF(hdkey.privateKey, true, network);
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
if (hdkey.privateKey) {
|
|
258
|
+
return Object.defineProperty(base, 'privateKey', {
|
|
259
|
+
get() {
|
|
260
|
+
return hdkey.privateKey;
|
|
261
|
+
},
|
|
262
|
+
enumerable: true,
|
|
263
|
+
configurable: true
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
return base;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Built-in BIP32API implementation using @scure/bip32.
|
|
270
|
+
*/
|
|
271
|
+
export const scureBIP32 = {
|
|
272
|
+
fromBase58(base58, network) {
|
|
273
|
+
const net = network ?? DEFAULT_NETWORK;
|
|
274
|
+
const versions = networkToVersions(net);
|
|
275
|
+
const hdkey = HDKey.fromExtendedKey(base58, versions);
|
|
276
|
+
return wrapHDKey(hdkey, net);
|
|
277
|
+
},
|
|
278
|
+
fromPublicKey(publicKey, chainCode, network) {
|
|
279
|
+
const net = network ?? DEFAULT_NETWORK;
|
|
280
|
+
const versions = networkToVersions(net);
|
|
281
|
+
// Manually serialise the public extended key in base58check format.
|
|
282
|
+
//
|
|
283
|
+
// xpub format (78 bytes):
|
|
284
|
+
// version (4) + depth (1) + parentFingerprint (4) + index (4) +
|
|
285
|
+
// chainCode (32) + publicKey (33)
|
|
286
|
+
const buf = new Uint8Array(78);
|
|
287
|
+
writeUInt32BE(buf, versions.public, 0); // version
|
|
288
|
+
buf[4] = 0; // depth
|
|
289
|
+
writeUInt32BE(buf, 0, 5); // parent fingerprint
|
|
290
|
+
writeUInt32BE(buf, 0, 9); // index
|
|
291
|
+
buf.set(chainCode, 13);
|
|
292
|
+
buf.set(publicKey, 45);
|
|
293
|
+
const xpub = bs58check.encode(buf);
|
|
294
|
+
const hdkey = HDKey.fromExtendedKey(xpub, versions);
|
|
295
|
+
return wrapHDKey(hdkey, net);
|
|
296
|
+
},
|
|
297
|
+
fromPrivateKey(privateKey, chainCode, network) {
|
|
298
|
+
const net = network ?? DEFAULT_NETWORK;
|
|
299
|
+
const versions = networkToVersions(net);
|
|
300
|
+
// xprv format (78 bytes):
|
|
301
|
+
// version (4) + depth (1) + parentFingerprint (4) + index (4) +
|
|
302
|
+
// chainCode (32) + 0x00 (1) + privateKey (32)
|
|
303
|
+
const buf = new Uint8Array(78);
|
|
304
|
+
writeUInt32BE(buf, versions.private, 0); // version
|
|
305
|
+
buf[4] = 0; // depth
|
|
306
|
+
writeUInt32BE(buf, 0, 5); // parent fingerprint
|
|
307
|
+
writeUInt32BE(buf, 0, 9); // index
|
|
308
|
+
buf.set(chainCode, 13);
|
|
309
|
+
buf[45] = 0x00; // padding byte before private key
|
|
310
|
+
buf.set(privateKey, 46);
|
|
311
|
+
const xprv = bs58check.encode(buf);
|
|
312
|
+
const hdkey = HDKey.fromExtendedKey(xprv, versions);
|
|
313
|
+
return wrapHDKey(hdkey, net);
|
|
314
|
+
},
|
|
315
|
+
fromSeed(seed, network) {
|
|
316
|
+
const net = network ?? DEFAULT_NETWORK;
|
|
317
|
+
const versions = networkToVersions(net);
|
|
318
|
+
const hdkey = HDKey.fromMasterSeed(seed, versions);
|
|
319
|
+
return wrapHDKey(hdkey, net);
|
|
320
|
+
}
|
|
321
|
+
};
|
package/dist/descriptors.d.ts
CHANGED
|
@@ -16,11 +16,12 @@ import type { PsbtLike } from './psbt.js';
|
|
|
16
16
|
* These are compatible interfaces for managing BIP32 keys and
|
|
17
17
|
* public/private key pairs respectively.
|
|
18
18
|
*
|
|
19
|
-
* @param {Object} params - An object with `ECPair` and `BIP32` factories.
|
|
19
|
+
* @param {Object} params - An object with optional `ECPair` and `BIP32` factories.
|
|
20
|
+
* When omitted, built-in adapters using @noble/curves and @scure/bip32 are used.
|
|
20
21
|
*/
|
|
21
|
-
export declare function DescriptorsFactory({ ECPair, BIP32 }
|
|
22
|
-
ECPair
|
|
23
|
-
BIP32
|
|
22
|
+
export declare function DescriptorsFactory({ ECPair, BIP32 }?: {
|
|
23
|
+
ECPair?: ECPairAPI;
|
|
24
|
+
BIP32?: BIP32API;
|
|
24
25
|
}): {
|
|
25
26
|
Output: {
|
|
26
27
|
new ({ descriptor, index, checksumRequired, allowMiniscriptInP2SH, network, preimages, signersPubKeys }: {
|
package/dist/descriptors.js
CHANGED
|
@@ -30,6 +30,7 @@ import { varintEncodingLength, decompileScript } from './scriptUtils.js';
|
|
|
30
30
|
import { hash160, compareBytes, equalBytes, concatBytes } from '@scure/btc-signer/utils.js';
|
|
31
31
|
import { hex } from '@scure/base';
|
|
32
32
|
import { sha256 } from '@noble/hashes/sha2.js';
|
|
33
|
+
import { nobleECPair, scureBIP32 } from './adapters.js';
|
|
33
34
|
import { computeFinalScripts, updatePsbt } from './psbt.js';
|
|
34
35
|
import { DescriptorChecksum } from './checksum.js';
|
|
35
36
|
import { parseKeyExpression as globalParseKeyExpression } from './keyExpressions.js';
|
|
@@ -178,9 +179,10 @@ function parseSortedMulti(inner) {
|
|
|
178
179
|
* These are compatible interfaces for managing BIP32 keys and
|
|
179
180
|
* public/private key pairs respectively.
|
|
180
181
|
*
|
|
181
|
-
* @param {Object} params - An object with `ECPair` and `BIP32` factories.
|
|
182
|
+
* @param {Object} params - An object with optional `ECPair` and `BIP32` factories.
|
|
183
|
+
* When omitted, built-in adapters using @noble/curves and @scure/bip32 are used.
|
|
182
184
|
*/
|
|
183
|
-
export function DescriptorsFactory({ ECPair, BIP32 }) {
|
|
185
|
+
export function DescriptorsFactory({ ECPair = nobleECPair, BIP32 = scureBIP32 } = {}) {
|
|
184
186
|
var _Output_instances, _Output_payment, _Output_preimages, _Output_signersPubKeys, _Output_miniscript, _Output_witnessScript, _Output_redeemScript, _Output_isSegwit, _Output_isTaproot, _Output_expandedExpression, _Output_expandedMiniscript, _Output_expansionMap, _Output_network, _Output_getTimeConstraints, _Output_assertPsbtInput;
|
|
185
187
|
/**
|
|
186
188
|
* Takes a string key expression (xpub, xprv, pubkey or wif) and parses it
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type { KeyInfo, Expansion } from './types.js';
|
|
2
|
+
export type { ECPairAPI, ECPairInterface, BIP32API, BIP32Interface } from './types.js';
|
|
2
3
|
export type { OutputInstance } from './descriptors.js';
|
|
3
4
|
export { DescriptorsFactory, OutputConstructor } from './descriptors.js';
|
|
4
5
|
export { DescriptorChecksum as checksum } from './checksum.js';
|
|
@@ -10,3 +11,91 @@ export { scriptExpressions };
|
|
|
10
11
|
export type { PsbtLike } from './psbt.js';
|
|
11
12
|
export { networks } from './networks.js';
|
|
12
13
|
export type { Network } from './networks.js';
|
|
14
|
+
export { nobleECPair, scureBIP32 } from './adapters.js';
|
|
15
|
+
export declare const defaultFactory: {
|
|
16
|
+
Output: {
|
|
17
|
+
new ({ descriptor, index, checksumRequired, allowMiniscriptInP2SH, network, preimages, signersPubKeys }: {
|
|
18
|
+
descriptor: string;
|
|
19
|
+
index?: number;
|
|
20
|
+
checksumRequired?: boolean;
|
|
21
|
+
allowMiniscriptInP2SH?: boolean;
|
|
22
|
+
network?: import("./networks.js").Network;
|
|
23
|
+
preimages?: import("./types.js").Preimage[];
|
|
24
|
+
signersPubKeys?: Uint8Array[];
|
|
25
|
+
}): {
|
|
26
|
+
readonly "__#private@#payment": import("@scure/btc-signer/payment.js").P2Ret;
|
|
27
|
+
readonly "__#private@#preimages": import("./types.js").Preimage[];
|
|
28
|
+
readonly "__#private@#signersPubKeys": Uint8Array[];
|
|
29
|
+
readonly "__#private@#miniscript"?: string;
|
|
30
|
+
readonly "__#private@#witnessScript"?: Uint8Array;
|
|
31
|
+
readonly "__#private@#redeemScript"?: Uint8Array;
|
|
32
|
+
readonly "__#private@#isSegwit"?: boolean;
|
|
33
|
+
readonly "__#private@#isTaproot"?: boolean;
|
|
34
|
+
readonly "__#private@#expandedExpression"?: string;
|
|
35
|
+
readonly "__#private@#expandedMiniscript"?: string;
|
|
36
|
+
readonly "__#private@#expansionMap"?: import("./types.js").ExpansionMap;
|
|
37
|
+
readonly "__#private@#network": import("./networks.js").Network;
|
|
38
|
+
"__#private@#getTimeConstraints"(): import("./types.js").TimeConstraints | undefined;
|
|
39
|
+
getPayment(): import("@scure/btc-signer/payment.js").P2Ret;
|
|
40
|
+
getAddress(): string;
|
|
41
|
+
getScriptPubKey(): Uint8Array;
|
|
42
|
+
getScriptSatisfaction(signatures: import("./types.js").PartialSig[] | "DANGEROUSLY_USE_FAKE_SIGNATURES"): Uint8Array;
|
|
43
|
+
getSequence(): number | undefined;
|
|
44
|
+
getLockTime(): number | undefined;
|
|
45
|
+
getWitnessScript(): Uint8Array | undefined;
|
|
46
|
+
getRedeemScript(): Uint8Array | undefined;
|
|
47
|
+
getNetwork(): import("./networks.js").Network;
|
|
48
|
+
isSegwit(): boolean | undefined;
|
|
49
|
+
isTaproot(): boolean | undefined;
|
|
50
|
+
guessOutput(): {
|
|
51
|
+
isPKH: boolean;
|
|
52
|
+
isWPKH: boolean;
|
|
53
|
+
isSH: boolean;
|
|
54
|
+
isWSH: boolean;
|
|
55
|
+
isTR: boolean;
|
|
56
|
+
};
|
|
57
|
+
inputWeight(isSegwitTx: boolean, signatures: import("./types.js").PartialSig[] | "DANGEROUSLY_USE_FAKE_SIGNATURES"): number;
|
|
58
|
+
outputWeight(): number;
|
|
59
|
+
updatePsbtAsInput({ psbt, txHex, txId, value, vout, rbf }: {
|
|
60
|
+
psbt: import("./psbt.js").PsbtLike;
|
|
61
|
+
txHex?: string;
|
|
62
|
+
txId?: string;
|
|
63
|
+
value?: number;
|
|
64
|
+
vout: number;
|
|
65
|
+
rbf?: boolean;
|
|
66
|
+
}): ({ psbt, validate }: {
|
|
67
|
+
psbt: import("./psbt.js").PsbtLike;
|
|
68
|
+
validate?: boolean | undefined;
|
|
69
|
+
}) => void;
|
|
70
|
+
updatePsbtAsOutput({ psbt, value }: {
|
|
71
|
+
psbt: import("./psbt.js").PsbtLike;
|
|
72
|
+
value: number | bigint;
|
|
73
|
+
}): void;
|
|
74
|
+
"__#private@#assertPsbtInput"({ psbt, index }: {
|
|
75
|
+
psbt: import("./psbt.js").PsbtLike;
|
|
76
|
+
index: number;
|
|
77
|
+
}): void;
|
|
78
|
+
finalizePsbtInput({ index, psbt, validate }: {
|
|
79
|
+
index: number;
|
|
80
|
+
psbt: import("./psbt.js").PsbtLike;
|
|
81
|
+
validate?: boolean | undefined;
|
|
82
|
+
}): void;
|
|
83
|
+
expand(): {
|
|
84
|
+
expansionMap?: import("./types.js").ExpansionMap;
|
|
85
|
+
expandedMiniscript?: string;
|
|
86
|
+
miniscript?: string;
|
|
87
|
+
expandedExpression?: string;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
parseKeyExpression: import("./types.js").ParseKeyExpression;
|
|
92
|
+
expand: ({ descriptor, index, checksumRequired, network, allowMiniscriptInP2SH }: {
|
|
93
|
+
descriptor: string;
|
|
94
|
+
index?: number;
|
|
95
|
+
checksumRequired?: boolean;
|
|
96
|
+
network?: import("./networks.js").Network;
|
|
97
|
+
allowMiniscriptInP2SH?: boolean;
|
|
98
|
+
}) => import("./types.js").Expansion;
|
|
99
|
+
ECPair: import("./types.js").ECPairAPI;
|
|
100
|
+
BIP32: import("./types.js").BIP32API;
|
|
101
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -8,3 +8,8 @@ export { keyExpressionBIP32 } from './keyExpressions.js';
|
|
|
8
8
|
import * as scriptExpressions from './scriptExpressions.js';
|
|
9
9
|
export { scriptExpressions };
|
|
10
10
|
export { networks } from './networks.js';
|
|
11
|
+
// Built-in adapters using @noble/curves and @scure/bip32
|
|
12
|
+
export { nobleECPair, scureBIP32 } from './adapters.js';
|
|
13
|
+
// Pre-built factory using built-in adapters (zero-config convenience)
|
|
14
|
+
import { DescriptorsFactory } from './descriptors.js';
|
|
15
|
+
export const defaultFactory = DescriptorsFactory();
|
package/dist/miniscript.js
CHANGED
|
@@ -6,7 +6,23 @@ import { hash160 } from '@scure/btc-signer/utils.js';
|
|
|
6
6
|
import { hex } from '@scure/base';
|
|
7
7
|
import { parseKeyExpression } from './keyExpressions.js';
|
|
8
8
|
import * as RE from './re.js';
|
|
9
|
-
import {
|
|
9
|
+
import { createRequire } from 'module';
|
|
10
|
+
// Lazy-load @bitcoinerlab/miniscript (optional peer dependency).
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
let _miniscriptLib;
|
|
13
|
+
function getMiniscriptLib() {
|
|
14
|
+
if (!_miniscriptLib) {
|
|
15
|
+
try {
|
|
16
|
+
const require = createRequire(import.meta.url);
|
|
17
|
+
_miniscriptLib = require('@bitcoinerlab/miniscript');
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
throw new Error('@bitcoinerlab/miniscript is required for miniscript descriptors. ' +
|
|
21
|
+
'Install it: npm install @bitcoinerlab/miniscript');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return _miniscriptLib;
|
|
25
|
+
}
|
|
10
26
|
/**
|
|
11
27
|
* Expand a miniscript to a generalized form using variables instead of key
|
|
12
28
|
* expressions. Variables will be of this form: @0, @1, ...
|
|
@@ -84,7 +100,7 @@ function substituteAsm({ expandedAsm, expansionMap }) {
|
|
|
84
100
|
return asm;
|
|
85
101
|
}
|
|
86
102
|
export function miniscript2Script({ expandedMiniscript, expansionMap }) {
|
|
87
|
-
const compiled = compileMiniscript(expandedMiniscript);
|
|
103
|
+
const compiled = getMiniscriptLib().compileMiniscript(expandedMiniscript);
|
|
88
104
|
if (compiled.issane !== true) {
|
|
89
105
|
throw new Error(`Error: Miniscript ${expandedMiniscript} is not sane`);
|
|
90
106
|
}
|
|
@@ -128,7 +144,7 @@ export function satisfyMiniscript({ expandedMiniscript, expansionMap, signatures
|
|
|
128
144
|
const expandedKnownsMap = { ...preimageMap, ...expandedSignatureMap };
|
|
129
145
|
const knowns = Object.keys(expandedKnownsMap);
|
|
130
146
|
//satisfier verifies again internally whether expandedKnownsMap with given knowns is sane
|
|
131
|
-
const { nonMalleableSats } = satisfier(expandedMiniscript, { knowns });
|
|
147
|
+
const { nonMalleableSats } = getMiniscriptLib().satisfier(expandedMiniscript, { knowns });
|
|
132
148
|
if (!Array.isArray(nonMalleableSats) || !nonMalleableSats[0])
|
|
133
149
|
throw new Error(`Error: unresolvable miniscript ${expandedMiniscript}`);
|
|
134
150
|
let sat;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@kukks/bitcoin-descriptors",
|
|
3
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.",
|
|
4
4
|
"homepage": "https://github.com/Kukks/descriptors",
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.2.1",
|
|
6
6
|
"author": "Jose-Luis Landabaso",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -51,14 +51,22 @@
|
|
|
51
51
|
],
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@bitcoinerlab/configs": "^2.0.0",
|
|
54
|
+
"@bitcoinerlab/miniscript": "^1.4.3",
|
|
54
55
|
"bip39": "^3.0.4",
|
|
55
56
|
"bip65": "^1.0.3",
|
|
56
57
|
"bip68": "^1.0.4",
|
|
57
58
|
"regtest-client": "^0.2.1",
|
|
58
59
|
"yargs": "^17.7.2"
|
|
59
60
|
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"@bitcoinerlab/miniscript": "^1.4.3"
|
|
63
|
+
},
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"@bitcoinerlab/miniscript": {
|
|
66
|
+
"optional": true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
60
69
|
"dependencies": {
|
|
61
|
-
"@bitcoinerlab/miniscript": "^1.4.3",
|
|
62
70
|
"@noble/curves": "^2.0.1",
|
|
63
71
|
"@noble/hashes": "^2.0.1",
|
|
64
72
|
"@scure/base": "^2.0.0",
|