@arkade-os/sdk 0.4.22 → 0.4.23
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 +95 -12
- package/dist/cjs/contracts/arkcontract.js +2 -1
- package/dist/cjs/identity/descriptor.js +75 -4
- package/dist/cjs/identity/hdCapableIdentity.js +2 -0
- package/dist/cjs/identity/seedIdentity.js +225 -103
- package/dist/cjs/identity/serialize.js +5 -0
- package/dist/cjs/identity/staticDescriptorProvider.js +1 -1
- package/dist/cjs/index.js +12 -3
- package/dist/cjs/providers/electrum.js +285 -79
- package/dist/cjs/providers/expoIndexer.js +1 -1
- package/dist/cjs/providers/indexer.js +2 -2
- package/dist/cjs/providers/onchain.js +9 -3
- package/dist/cjs/repositories/migrations/walletRepositoryImpl.js +6 -2
- package/dist/cjs/repositories/realm/walletRepository.js +2 -2
- package/dist/cjs/repositories/serialization.js +34 -1
- package/dist/cjs/repositories/sqlite/walletRepository.js +4 -2
- package/dist/cjs/script/address.js +2 -1
- package/dist/cjs/utils/transactionHistory.js +4 -4
- package/dist/cjs/wallet/asset-manager.js +18 -18
- package/dist/cjs/wallet/asset.js +10 -8
- package/dist/cjs/wallet/delegator.js +2 -2
- package/dist/cjs/wallet/hdDescriptorProvider.js +159 -0
- package/dist/cjs/wallet/index.js +5 -1
- package/dist/cjs/wallet/onchain.js +2 -1
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +1 -1
- package/dist/cjs/wallet/serviceWorker/wallet.js +5 -4
- package/dist/cjs/wallet/validation.js +2 -3
- package/dist/cjs/wallet/wallet.js +13 -14
- package/dist/esm/contracts/arkcontract.js +2 -1
- package/dist/esm/identity/descriptor.js +74 -5
- package/dist/esm/identity/hdCapableIdentity.js +1 -0
- package/dist/esm/identity/seedIdentity.js +225 -103
- package/dist/esm/identity/serialize.js +5 -0
- package/dist/esm/identity/staticDescriptorProvider.js +1 -1
- package/dist/esm/index.js +7 -4
- package/dist/esm/providers/electrum.js +284 -78
- package/dist/esm/providers/expoIndexer.js +1 -1
- package/dist/esm/providers/indexer.js +2 -2
- package/dist/esm/providers/onchain.js +9 -3
- package/dist/esm/repositories/migrations/walletRepositoryImpl.js +6 -2
- package/dist/esm/repositories/realm/walletRepository.js +3 -3
- package/dist/esm/repositories/serialization.js +27 -0
- package/dist/esm/repositories/sqlite/walletRepository.js +5 -3
- package/dist/esm/script/address.js +2 -1
- package/dist/esm/utils/transactionHistory.js +4 -4
- package/dist/esm/wallet/asset-manager.js +18 -18
- package/dist/esm/wallet/asset.js +10 -8
- package/dist/esm/wallet/delegator.js +2 -2
- package/dist/esm/wallet/hdDescriptorProvider.js +155 -0
- package/dist/esm/wallet/index.js +4 -0
- package/dist/esm/wallet/onchain.js +2 -1
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +1 -1
- package/dist/esm/wallet/serviceWorker/wallet.js +5 -4
- package/dist/esm/wallet/validation.js +2 -3
- package/dist/esm/wallet/wallet.js +12 -14
- package/dist/types/contracts/arkcontract.d.ts +1 -1
- package/dist/types/identity/descriptor.d.ts +26 -0
- package/dist/types/identity/descriptorProvider.d.ts +11 -4
- package/dist/types/identity/hdCapableIdentity.d.ts +44 -0
- package/dist/types/identity/index.d.ts +1 -0
- package/dist/types/identity/seedIdentity.d.ts +113 -29
- package/dist/types/identity/serialize.d.ts +12 -0
- package/dist/types/identity/staticDescriptorProvider.d.ts +1 -1
- package/dist/types/index.d.ts +6 -3
- package/dist/types/providers/electrum.d.ts +115 -15
- package/dist/types/providers/onchain.d.ts +6 -0
- package/dist/types/repositories/serialization.d.ts +26 -2
- package/dist/types/script/address.d.ts +1 -1
- package/dist/types/wallet/hdDescriptorProvider.d.ts +93 -0
- package/dist/types/wallet/index.d.ts +19 -10
- package/dist/types/wallet/onchain.d.ts +1 -1
- package/dist/types/wallet/serviceWorker/wallet.d.ts +1 -1
- package/dist/types/wallet/wallet.d.ts +4 -1
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ const base_1 = require("@scure/base");
|
|
|
11
11
|
const signingSession_1 = require("../tree/signingSession");
|
|
12
12
|
const secp256k1_1 = require("@noble/secp256k1");
|
|
13
13
|
const descriptors_scure_1 = require("@bitcoinerlab/descriptors-scure");
|
|
14
|
+
const descriptor_1 = require("./descriptor");
|
|
14
15
|
const ALL_SIGHASH = Object.values(btc_signer_1.SigHash).filter((x) => typeof x === "number");
|
|
15
16
|
/**
|
|
16
17
|
* Secret-bearing state for seed-backed identities, held off the public
|
|
@@ -24,85 +25,117 @@ const ALL_SIGHASH = Object.values(btc_signer_1.SigHash).filter((x) => typeof x =
|
|
|
24
25
|
*/
|
|
25
26
|
const seedBytes = new WeakMap();
|
|
26
27
|
const mnemonicMeta = new WeakMap();
|
|
27
|
-
// ── Helpers ──────────────────────────────────────────────────────
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* @internal
|
|
32
|
-
*/
|
|
33
|
-
function detectNetwork(descriptor) {
|
|
34
|
-
return descriptor.includes("tpub") ? descriptors_scure_1.networks.testnet : descriptors_scure_1.networks.bitcoin;
|
|
35
|
-
}
|
|
36
|
-
function hasDescriptor(opts = {}) {
|
|
37
|
-
return "descriptor" in opts && typeof opts.descriptor === "string";
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Builds a BIP86 Taproot output descriptor from a seed and network flag.
|
|
41
|
-
* @internal
|
|
42
|
-
*/
|
|
43
|
-
function buildDescriptor(seed, isMainnet) {
|
|
44
|
-
const network = isMainnet ? descriptors_scure_1.networks.bitcoin : descriptors_scure_1.networks.testnet;
|
|
45
|
-
const masterNode = descriptors_scure_1.HDKey.fromMasterSeed(seed, network.bip32);
|
|
46
|
-
return descriptors_scure_1.scriptExpressions.trBIP32({
|
|
47
|
-
masterNode,
|
|
48
|
-
network,
|
|
49
|
-
account: 0,
|
|
50
|
-
change: 0,
|
|
51
|
-
index: 0,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Seed-based identity derived from a raw seed and an output descriptor.
|
|
29
|
+
* Seed-based identity derived from a raw seed and an account descriptor
|
|
30
|
+
* *template*.
|
|
56
31
|
*
|
|
57
32
|
* This is the recommended identity type for most applications. It uses
|
|
58
|
-
* standard BIP86 (Taproot) derivation by default
|
|
59
|
-
*
|
|
33
|
+
* standard BIP86 (Taproot) derivation by default; callers that need a
|
|
34
|
+
* different path supply the wildcard template directly.
|
|
60
35
|
*
|
|
61
36
|
* Prefer this (or @see MnemonicIdentity) over `SingleKey` for new
|
|
62
37
|
* integrations — `SingleKey` exists for backward compatibility with
|
|
63
38
|
* raw nsec-style keys.
|
|
64
39
|
*
|
|
65
|
-
*
|
|
40
|
+
* The identity holds the wildcard *template* (e.g.
|
|
41
|
+
* `tr([fp/86'/0'/0']xpub/0/*)`) on its public {@link descriptor}
|
|
42
|
+
* field. HD rotation reads it directly; consumers that need a
|
|
43
|
+
* concrete descriptor at a specific index materialize it themselves
|
|
44
|
+
* (see `HDDescriptorProvider` in the wallet layer).
|
|
45
|
+
*
|
|
46
|
+
* Exposes seed-level primitives (signing, derivation, the template)
|
|
47
|
+
* but is deliberately NOT a `DescriptorProvider`. Wrap it explicitly
|
|
48
|
+
* to get one:
|
|
49
|
+
* - `HDDescriptorProvider` for rotating receive addresses.
|
|
50
|
+
* - {@link StaticDescriptorProvider} for legacy, single-key behaviour.
|
|
51
|
+
*
|
|
52
|
+
* The split prevents a SeedIdentity from being silently used as a
|
|
53
|
+
* concrete descriptor source, which would defeat HD rotation without
|
|
54
|
+
* any compile-time signal that something was wrong.
|
|
66
55
|
*
|
|
67
56
|
* @example
|
|
68
57
|
* ```typescript
|
|
69
58
|
* const seed = mnemonicToSeedSync(mnemonic);
|
|
70
59
|
*
|
|
71
|
-
* // Testnet (BIP86
|
|
60
|
+
* // Testnet (BIP86 wildcard descriptor m/86'/1'/0'/0/*)
|
|
72
61
|
* const identity = SeedIdentity.fromSeed(seed, { isMainnet: false });
|
|
73
62
|
*
|
|
74
|
-
* // Mainnet (BIP86
|
|
63
|
+
* // Mainnet (BIP86 wildcard descriptor m/86'/0'/0'/0/*)
|
|
75
64
|
* const identity = SeedIdentity.fromSeed(seed, { isMainnet: true });
|
|
76
65
|
*
|
|
77
|
-
* //
|
|
66
|
+
* // Caller-supplied wildcard descriptor (must end in `/*)`).
|
|
78
67
|
* const identity = SeedIdentity.fromSeed(seed, { descriptor });
|
|
79
68
|
* ```
|
|
80
69
|
*/
|
|
81
70
|
class SeedIdentity {
|
|
82
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Constructs a SeedIdentity from a 64-byte seed and either a
|
|
73
|
+
* caller-supplied wildcard descriptor (`{ descriptor }`) or the
|
|
74
|
+
* default BIP86 path at the requested network (`{ isMainnet }`).
|
|
75
|
+
* Prefer the {@link fromSeed} factory for symmetry with
|
|
76
|
+
* {@link MnemonicIdentity.fromMnemonic}.
|
|
77
|
+
*
|
|
78
|
+
* Throws on a non-wildcard descriptor, an xpub mismatch with the
|
|
79
|
+
* seed, or a missing derivation path.
|
|
80
|
+
*/
|
|
81
|
+
constructor(seed, opts = {}) {
|
|
83
82
|
if (seed.length !== 64) {
|
|
84
83
|
throw new Error("Seed must be 64 bytes");
|
|
85
84
|
}
|
|
85
|
+
// Resolve the descriptor: caller-supplied wins; otherwise build
|
|
86
|
+
// the BIP86 default at the requested network via the library.
|
|
87
|
+
let descriptor;
|
|
88
|
+
let network;
|
|
89
|
+
if ("descriptor" in opts && typeof opts.descriptor === "string") {
|
|
90
|
+
descriptor = opts.descriptor;
|
|
91
|
+
network = (0, descriptor_1.isMainnetDescriptor)(descriptor)
|
|
92
|
+
? descriptors_scure_1.networks.bitcoin
|
|
93
|
+
: descriptors_scure_1.networks.testnet;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
network =
|
|
97
|
+
(opts.isMainnet ?? true)
|
|
98
|
+
? descriptors_scure_1.networks.bitcoin
|
|
99
|
+
: descriptors_scure_1.networks.testnet;
|
|
100
|
+
descriptor = descriptors_scure_1.scriptExpressions.trBIP32({
|
|
101
|
+
masterNode: descriptors_scure_1.HDKey.fromMasterSeed(seed, network.bip32),
|
|
102
|
+
network,
|
|
103
|
+
account: 0,
|
|
104
|
+
change: 0,
|
|
105
|
+
index: "*",
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Parse the descriptor, substituting the wildcard at index 0.
|
|
109
|
+
// The library raises "index passed for non-ranged descriptor"
|
|
110
|
+
// if the input isn't a wildcard template, which we re-wrap so
|
|
111
|
+
// the caller sees what they actually got wrong.
|
|
112
|
+
let expansion;
|
|
113
|
+
try {
|
|
114
|
+
expansion = (0, descriptors_scure_1.expand)({ descriptor, network, index: 0 });
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
throw new Error(`SeedIdentity requires a wildcard descriptor template (must end in "/*)"); ${e instanceof Error ? e.message : String(e)}`);
|
|
118
|
+
}
|
|
119
|
+
const keyInfo = expansion.expansionMap?.["@0"];
|
|
86
120
|
// Defensive copy: `derivedKey` and `descriptor` are computed eagerly
|
|
87
121
|
// from the bytes we're about to stash, so a later mutation of the
|
|
88
122
|
// caller's buffer must not drift the serialized `seed` out of sync
|
|
89
123
|
// with the live identity state.
|
|
90
124
|
seedBytes.set(this, new Uint8Array(seed));
|
|
91
125
|
this.descriptor = descriptor;
|
|
92
|
-
const network = detectNetwork(descriptor);
|
|
93
|
-
// Parse and validate the descriptor using the library
|
|
94
|
-
const expansion = (0, descriptors_scure_1.expand)({ descriptor, network });
|
|
95
|
-
const keyInfo = expansion.expansionMap?.["@0"];
|
|
96
126
|
if (!keyInfo?.originPath) {
|
|
97
127
|
throw new Error("Descriptor must include a key origin path");
|
|
98
128
|
}
|
|
99
|
-
// Verify the xpub in the descriptor matches our seed
|
|
129
|
+
// Verify the xpub in the descriptor matches our seed (validates
|
|
130
|
+
// that the descriptor was generated from this seed; we don't
|
|
131
|
+
// need to keep the xpub around afterwards — `isOurs` re-derives
|
|
132
|
+
// it from `this.descriptor` on demand).
|
|
100
133
|
const masterNode = descriptors_scure_1.HDKey.fromMasterSeed(seed, network.bip32);
|
|
101
134
|
const accountNode = masterNode.derive(`m${keyInfo.originPath}`);
|
|
102
135
|
if (accountNode.publicExtendedKey !== keyInfo.bip32?.toBase58()) {
|
|
103
136
|
throw new Error("xpub mismatch: derived key does not match descriptor");
|
|
104
137
|
}
|
|
105
|
-
// Derive the private key using the full path
|
|
138
|
+
// Derive the private key for index 0 using the full path
|
|
106
139
|
if (!keyInfo.path) {
|
|
107
140
|
throw new Error("Descriptor must specify a full derivation path");
|
|
108
141
|
}
|
|
@@ -116,16 +149,14 @@ class SeedIdentity {
|
|
|
116
149
|
* Creates a SeedIdentity from a raw 64-byte seed.
|
|
117
150
|
*
|
|
118
151
|
* Pass `{ isMainnet }` for default BIP86 derivation, or
|
|
119
|
-
* `{ descriptor }` for a
|
|
152
|
+
* `{ descriptor }` for a caller-supplied account-descriptor
|
|
153
|
+
* template (the option's value must end with `/*)`).
|
|
120
154
|
*
|
|
121
155
|
* @param seed - 64-byte seed (typically from mnemonicToSeedSync)
|
|
122
|
-
* @param opts - Network selection or
|
|
156
|
+
* @param opts - Network selection or descriptor template.
|
|
123
157
|
*/
|
|
124
158
|
static fromSeed(seed, opts = {}) {
|
|
125
|
-
|
|
126
|
-
? opts.descriptor
|
|
127
|
-
: buildDescriptor(seed, opts.isMainnet ?? true);
|
|
128
|
-
return new SeedIdentity(seed, descriptor);
|
|
159
|
+
return new SeedIdentity(seed, opts);
|
|
129
160
|
}
|
|
130
161
|
async xOnlyPublicKey() {
|
|
131
162
|
return (0, utils_js_1.pubSchnorr)(this.derivedKey);
|
|
@@ -134,10 +165,82 @@ class SeedIdentity {
|
|
|
134
165
|
return (0, utils_js_1.pubECDSA)(this.derivedKey, true);
|
|
135
166
|
}
|
|
136
167
|
async sign(tx, inputIndexes) {
|
|
168
|
+
return this.signTxWithKey(tx, this.derivedKey, inputIndexes);
|
|
169
|
+
}
|
|
170
|
+
async signMessage(message, signatureType = "schnorr") {
|
|
171
|
+
return this.signMessageWithKey(this.derivedKey, message, signatureType);
|
|
172
|
+
}
|
|
173
|
+
signerSession() {
|
|
174
|
+
return signingSession_1.TreeSignerSession.random();
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Converts to a watch-only identity that cannot sign. Carries the
|
|
178
|
+
* template forward, so the readonly side stays HD-capable (can
|
|
179
|
+
* derive descriptors at any index without seed access).
|
|
180
|
+
*/
|
|
181
|
+
async toReadonly() {
|
|
182
|
+
return ReadonlyDescriptorIdentity.fromDescriptor(this.descriptor);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Returns true when `descriptor` is derived from this identity's seed.
|
|
186
|
+
* HD descriptors match by account xpub; bare `tr(pubkey)` descriptors
|
|
187
|
+
* match by raw pubkey. See {@link descriptorIsOurs}.
|
|
188
|
+
*/
|
|
189
|
+
isOurs(descriptor) {
|
|
190
|
+
return (0, descriptor_1.descriptorIsOurs)(descriptor, this.descriptor, (0, utils_js_1.pubSchnorr)(this.derivedKey));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Signs each request with the key derived from its descriptor.
|
|
194
|
+
* Each descriptor must share this identity's seed ({@link isOurs}).
|
|
195
|
+
*/
|
|
196
|
+
async signWithDescriptor(requests) {
|
|
197
|
+
return requests.map((request) => {
|
|
198
|
+
if (!this.isOurs(request.descriptor)) {
|
|
199
|
+
throw new Error(`Descriptor ${request.descriptor} does not belong to this identity`);
|
|
200
|
+
}
|
|
201
|
+
const key = this.derivePrivateKeyForDescriptor(request.descriptor);
|
|
202
|
+
return this.signTxWithKey(request.tx, key, request.inputIndexes);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Signs a message with the key derived from `descriptor`.
|
|
207
|
+
*/
|
|
208
|
+
async signMessageWithDescriptor(descriptor, message, signatureType = "schnorr") {
|
|
209
|
+
if (!this.isOurs(descriptor)) {
|
|
210
|
+
throw new Error(`Descriptor ${descriptor} does not belong to this identity`);
|
|
211
|
+
}
|
|
212
|
+
const key = this.derivePrivateKeyForDescriptor(descriptor);
|
|
213
|
+
return this.signMessageWithKey(key, message, signatureType);
|
|
214
|
+
}
|
|
215
|
+
// ── internal helpers ─────────────────────────────────────────────
|
|
216
|
+
derivePrivateKeyForDescriptor(descriptor) {
|
|
217
|
+
const network = (0, descriptor_1.isMainnetDescriptor)(descriptor)
|
|
218
|
+
? descriptors_scure_1.networks.bitcoin
|
|
219
|
+
: descriptors_scure_1.networks.testnet;
|
|
220
|
+
const expansion = (0, descriptors_scure_1.expand)({ descriptor, network });
|
|
221
|
+
if (expansion.isRanged) {
|
|
222
|
+
throw new Error("Cannot sign with a wildcard descriptor; derive a concrete index first");
|
|
223
|
+
}
|
|
224
|
+
const keyInfo = expansion.expansionMap?.["@0"];
|
|
225
|
+
if (!keyInfo?.path) {
|
|
226
|
+
throw new Error("Descriptor must specify a full derivation path for signing");
|
|
227
|
+
}
|
|
228
|
+
const seed = seedBytes.get(this);
|
|
229
|
+
if (!seed) {
|
|
230
|
+
throw new Error("Seed bytes not available for descriptor signing");
|
|
231
|
+
}
|
|
232
|
+
const masterNode = descriptors_scure_1.HDKey.fromMasterSeed(seed, network.bip32);
|
|
233
|
+
const node = masterNode.derive(keyInfo.path);
|
|
234
|
+
if (!node.privateKey) {
|
|
235
|
+
throw new Error("Failed to derive private key for descriptor");
|
|
236
|
+
}
|
|
237
|
+
return node.privateKey;
|
|
238
|
+
}
|
|
239
|
+
signTxWithKey(tx, key, inputIndexes) {
|
|
137
240
|
const txCpy = tx.clone();
|
|
138
241
|
if (!inputIndexes) {
|
|
139
242
|
try {
|
|
140
|
-
if (!txCpy.sign(
|
|
243
|
+
if (!txCpy.sign(key, ALL_SIGHASH)) {
|
|
141
244
|
throw new Error("Failed to sign transaction");
|
|
142
245
|
}
|
|
143
246
|
}
|
|
@@ -150,29 +253,20 @@ class SeedIdentity {
|
|
|
150
253
|
throw e;
|
|
151
254
|
}
|
|
152
255
|
}
|
|
153
|
-
return txCpy;
|
|
154
256
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
257
|
+
else {
|
|
258
|
+
for (const idx of inputIndexes) {
|
|
259
|
+
if (!txCpy.signIdx(key, idx, ALL_SIGHASH)) {
|
|
260
|
+
throw new Error(`Failed to sign input #${idx}`);
|
|
261
|
+
}
|
|
158
262
|
}
|
|
159
263
|
}
|
|
160
264
|
return txCpy;
|
|
161
265
|
}
|
|
162
|
-
|
|
163
|
-
if (signatureType === "ecdsa")
|
|
164
|
-
return (0, secp256k1_1.signAsync)(message,
|
|
165
|
-
|
|
166
|
-
return secp256k1_1.schnorr.signAsync(message, this.derivedKey);
|
|
167
|
-
}
|
|
168
|
-
signerSession() {
|
|
169
|
-
return signingSession_1.TreeSignerSession.random();
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Converts to a watch-only identity that cannot sign.
|
|
173
|
-
*/
|
|
174
|
-
async toReadonly() {
|
|
175
|
-
return ReadonlyDescriptorIdentity.fromDescriptor(this.descriptor);
|
|
266
|
+
signMessageWithKey(key, message, signatureType) {
|
|
267
|
+
if (signatureType === "ecdsa")
|
|
268
|
+
return (0, secp256k1_1.signAsync)(message, key, { prehash: false });
|
|
269
|
+
return secp256k1_1.schnorr.signAsync(message, key);
|
|
176
270
|
}
|
|
177
271
|
}
|
|
178
272
|
exports.SeedIdentity = SeedIdentity;
|
|
@@ -193,83 +287,108 @@ exports.SeedIdentity = SeedIdentity;
|
|
|
193
287
|
* ```
|
|
194
288
|
*/
|
|
195
289
|
class MnemonicIdentity extends SeedIdentity {
|
|
196
|
-
constructor(
|
|
197
|
-
|
|
198
|
-
|
|
290
|
+
constructor(phrase, opts) {
|
|
291
|
+
const { passphrase } = opts;
|
|
292
|
+
super((0, bip39_1.mnemonicToSeedSync)(phrase, passphrase), opts);
|
|
293
|
+
mnemonicMeta.set(this, { mnemonic: phrase, passphrase });
|
|
199
294
|
}
|
|
200
295
|
/**
|
|
201
296
|
* Creates a MnemonicIdentity from a BIP39 mnemonic phrase.
|
|
202
297
|
*
|
|
203
298
|
* Pass `{ isMainnet }` for default BIP86 derivation, or
|
|
204
|
-
* `{ descriptor }` for a
|
|
299
|
+
* `{ descriptor }` for a caller-supplied account-descriptor
|
|
300
|
+
* template (the option's value must end with `/*)`).
|
|
205
301
|
*
|
|
206
302
|
* @param phrase - BIP39 mnemonic phrase (12 or 24 words)
|
|
207
|
-
* @param opts - Network selection or
|
|
303
|
+
* @param opts - Network selection or descriptor template, plus optional passphrase
|
|
208
304
|
*/
|
|
209
305
|
static fromMnemonic(phrase, opts = {}) {
|
|
210
306
|
if (!(0, bip39_1.validateMnemonic)(phrase, english_js_1.wordlist)) {
|
|
211
307
|
throw new Error("Invalid mnemonic");
|
|
212
308
|
}
|
|
213
|
-
|
|
214
|
-
const seed = (0, bip39_1.mnemonicToSeedSync)(phrase, passphrase);
|
|
215
|
-
const descriptor = hasDescriptor(opts)
|
|
216
|
-
? opts.descriptor
|
|
217
|
-
: buildDescriptor(seed, opts.isMainnet ?? true);
|
|
218
|
-
return new MnemonicIdentity(seed, descriptor, phrase, passphrase);
|
|
309
|
+
return new MnemonicIdentity(phrase, opts);
|
|
219
310
|
}
|
|
220
311
|
}
|
|
221
312
|
exports.MnemonicIdentity = MnemonicIdentity;
|
|
222
313
|
/**
|
|
223
|
-
* Watch-only identity from
|
|
314
|
+
* Watch-only HD identity from a descriptor *template*.
|
|
224
315
|
*
|
|
225
316
|
* Can derive public keys but cannot sign transactions. Use this for
|
|
226
|
-
* watch-only wallets
|
|
227
|
-
*
|
|
317
|
+
* watch-only wallets — given just an xpub-based template, the readonly
|
|
318
|
+
* side still rotates through HD indices.
|
|
319
|
+
*
|
|
320
|
+
* Constructed from a wildcard template (e.g.
|
|
321
|
+
* `tr([fp/86'/0'/0']xpub.../0/*)`); the {@link descriptor} field
|
|
322
|
+
* holds it for HD providers to consume.
|
|
228
323
|
*
|
|
229
324
|
* @example
|
|
230
325
|
* ```typescript
|
|
231
|
-
* const
|
|
232
|
-
*
|
|
233
|
-
*
|
|
326
|
+
* const ro = ReadonlyDescriptorIdentity.fromDescriptor(
|
|
327
|
+
* "tr([fp/86'/0'/0']xpub.../0/*)"
|
|
328
|
+
* );
|
|
329
|
+
* ro.descriptor;
|
|
330
|
+
* // => "tr([fp/86'/0'/0']xpub.../0/*)" — the template
|
|
234
331
|
* ```
|
|
235
332
|
*/
|
|
236
333
|
class ReadonlyDescriptorIdentity {
|
|
237
334
|
constructor(descriptor) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
335
|
+
const network = (0, descriptor_1.isMainnetDescriptor)(descriptor)
|
|
336
|
+
? descriptors_scure_1.networks.bitcoin
|
|
337
|
+
: descriptors_scure_1.networks.testnet;
|
|
338
|
+
// Library substitutes the wildcard at index 0 and raises
|
|
339
|
+
// "index passed for non-ranged descriptor" if `descriptor` isn't
|
|
340
|
+
// actually a wildcard template — re-wrap so the caller sees
|
|
341
|
+
// the higher-level invariant they violated.
|
|
342
|
+
let expansion;
|
|
343
|
+
try {
|
|
344
|
+
expansion = (0, descriptors_scure_1.expand)({ descriptor, network, index: 0 });
|
|
345
|
+
}
|
|
346
|
+
catch (e) {
|
|
347
|
+
throw new Error(`ReadonlyDescriptorIdentity requires a wildcard descriptor template (must end in "/*)"); ${e instanceof Error ? e.message : String(e)}`);
|
|
348
|
+
}
|
|
241
349
|
const keyInfo = expansion.expansionMap?.["@0"];
|
|
242
350
|
if (!keyInfo?.pubkey) {
|
|
243
351
|
throw new Error("Failed to derive public key from descriptor");
|
|
244
352
|
}
|
|
245
|
-
|
|
246
|
-
this.xOnlyPubKey = keyInfo.pubkey;
|
|
247
|
-
// Get 33-byte compressed key with correct parity from the bip32 node
|
|
248
|
-
if (keyInfo.bip32 && keyInfo.keyPath) {
|
|
249
|
-
// Strip leading "/" — the library's derivePath prepends "m/" itself
|
|
250
|
-
const relPath = keyInfo.keyPath.replace(/^\//, "");
|
|
251
|
-
this.compressedPubKey = keyInfo.bip32.derivePath(relPath).publicKey;
|
|
252
|
-
}
|
|
253
|
-
else if (keyInfo.bip32) {
|
|
254
|
-
this.compressedPubKey = keyInfo.bip32.publicKey;
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
353
|
+
if (!keyInfo.bip32) {
|
|
257
354
|
throw new Error("Cannot determine compressed public key parity from descriptor");
|
|
258
355
|
}
|
|
356
|
+
this.descriptor = descriptor;
|
|
357
|
+
this.indexZero = keyInfo;
|
|
259
358
|
}
|
|
260
359
|
/**
|
|
261
|
-
* Creates a ReadonlyDescriptorIdentity from an
|
|
360
|
+
* Creates a ReadonlyDescriptorIdentity from an account-descriptor
|
|
361
|
+
* *template* (must end with the BIP-32 wildcard suffix `/*)`).
|
|
262
362
|
*
|
|
263
|
-
* @param descriptor - Taproot
|
|
363
|
+
* @param descriptor - Wildcard-suffixed Taproot template
|
|
364
|
+
* (`tr([fp/path']xpub.../child/*)`).
|
|
264
365
|
*/
|
|
265
366
|
static fromDescriptor(descriptor) {
|
|
266
367
|
return new ReadonlyDescriptorIdentity(descriptor);
|
|
267
368
|
}
|
|
268
369
|
async xOnlyPublicKey() {
|
|
269
|
-
|
|
370
|
+
// Validated non-null in the constructor.
|
|
371
|
+
return this.indexZero.pubkey;
|
|
270
372
|
}
|
|
271
373
|
async compressedPublicKey() {
|
|
272
|
-
|
|
374
|
+
const { bip32, keyPath } = this.indexZero;
|
|
375
|
+
// bip32 validated non-null in the constructor; derivePath
|
|
376
|
+
// returns a fresh node so this is a read of the index-0
|
|
377
|
+
// compressed pubkey, not a mutation of the stored one.
|
|
378
|
+
if (keyPath) {
|
|
379
|
+
// Strip leading "/" — the library's derivePath prepends "m/" itself
|
|
380
|
+
return bip32.derivePath(keyPath.replace(/^\//, "")).publicKey;
|
|
381
|
+
}
|
|
382
|
+
return bip32.publicKey;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Returns true when `descriptor` derives from this identity's xpub.
|
|
386
|
+
* HD descriptors match by account xpub; bare `tr(pubkey)` descriptors
|
|
387
|
+
* fall back to comparing against the index-0 x-only pubkey. See
|
|
388
|
+
* {@link descriptorIsOurs}.
|
|
389
|
+
*/
|
|
390
|
+
isOurs(descriptor) {
|
|
391
|
+
return (0, descriptor_1.descriptorIsOurs)(descriptor, this.descriptor, this.indexZero.pubkey);
|
|
273
392
|
}
|
|
274
393
|
}
|
|
275
394
|
exports.ReadonlyDescriptorIdentity = ReadonlyDescriptorIdentity;
|
|
@@ -335,5 +454,8 @@ function serializeSeedOwnedSigningIdentity(identity) {
|
|
|
335
454
|
* @internal
|
|
336
455
|
*/
|
|
337
456
|
function serializeSeedOwnedReadonlyIdentity(identity) {
|
|
338
|
-
return {
|
|
457
|
+
return {
|
|
458
|
+
type: "readonly-descriptor",
|
|
459
|
+
descriptor: identity.descriptor,
|
|
460
|
+
};
|
|
339
461
|
}
|
|
@@ -61,6 +61,11 @@ async function serializeReadonlyIdentity(identity) {
|
|
|
61
61
|
* The return type is the union of signing and readonly; use
|
|
62
62
|
* {@link isSigningSerialized} on the envelope before hydration if the caller
|
|
63
63
|
* needs to know which side it ends up on.
|
|
64
|
+
*
|
|
65
|
+
* Envelopes store the wildcard template directly (see
|
|
66
|
+
* `serializeSeedOwnedSigningIdentity` / `serializeSeedOwnedReadonlyIdentity`),
|
|
67
|
+
* so the `descriptor` field is passed straight through to the
|
|
68
|
+
* template-only factories.
|
|
64
69
|
*/
|
|
65
70
|
function hydrateIdentity(s) {
|
|
66
71
|
switch (s.type) {
|
|
@@ -18,7 +18,7 @@ class StaticDescriptorProvider {
|
|
|
18
18
|
const pubKey = await identity.xOnlyPublicKey();
|
|
19
19
|
return new StaticDescriptorProvider(identity, base_1.hex.encode(pubKey));
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
async getNextSigningDescriptor() {
|
|
22
22
|
return this.descriptor;
|
|
23
23
|
}
|
|
24
24
|
isOurs(descriptor) {
|
package/dist/cjs/index.js
CHANGED
|
@@ -36,9 +36,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
36
36
|
};
|
|
37
37
|
})();
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
40
|
-
exports.
|
|
41
|
-
exports.isArkContract = exports.contractFromArkContractWithAddress = exports.contractFromArkContract = exports.decodeArkContract = exports.encodeArkContract = exports.VHTLCContractHandler = void 0;
|
|
39
|
+
exports.CLTVMultisigTapscript = exports.ConditionMultisigTapscript = exports.ConditionCSVMultisigTapscript = exports.CSVMultisigTapscript = exports.MultisigTapscript = exports.decodeTapscript = exports.DEFAULT_MESSAGE_TIMEOUTS = exports.ServiceWorkerReadonlyWallet = exports.ServiceWorkerWallet = exports.ServiceWorkerTimeoutError = exports.MessageBusNotInitializedError = exports.MESSAGE_BUS_NOT_INITIALIZED = exports.DelegatorNotConfiguredError = exports.ReadonlyWalletError = exports.WalletNotInitializedError = exports.WalletMessageHandler = exports.MessageBus = exports.setupServiceWorker = exports.SettlementEventType = exports.ChainTxType = exports.IndexerTxType = exports.TxType = exports.VHTLC = exports.VtxoScript = exports.DelegateVtxo = exports.DefaultVtxo = exports.ArkAddress = exports.RestIndexerProvider = exports.RestArkProvider = exports.WsElectrumChainSource = exports.ElectrumOnchainProvider = exports.ELECTRUM_TCP_HOST = exports.ELECTRUM_WS_URL = exports.EsploraProvider = exports.ESPLORA_URL = exports.RestDelegatorProvider = exports.DelegatorManagerImpl = exports.HDDescriptorProvider = exports.VtxoManager = exports.Ramps = exports.OnchainWallet = exports.isBatchSignable = exports.ReadonlyDescriptorIdentity = exports.MnemonicIdentity = exports.SeedIdentity = exports.ReadonlySingleKey = exports.SingleKey = exports.ReadonlyWallet = exports.Wallet = exports.asset = void 0;
|
|
40
|
+
exports.isExpired = exports.isSubdust = exports.isSpendable = exports.isRecoverable = exports.buildForfeitTx = exports.validateConnectorsTxGraph = exports.validateVtxoTxGraph = exports.Batch = exports.maybeArkError = exports.ArkError = exports.sequenceToTimelock = exports.timelockToSequence = exports.TxWeightEstimator = exports.Transaction = exports.Unroll = exports.P2A = exports.TxTree = exports.BIP322 = exports.Intent = exports.ContractRepositoryImpl = exports.WalletRepositoryImpl = exports.rollbackMigration = exports.getMigrationStatus = exports.requiresMigration = exports.migrateWalletRepository = exports.MIGRATION_KEY = exports.InMemoryContractRepository = exports.InMemoryWalletRepository = exports.IndexedDBContractRepository = exports.IndexedDBWalletRepository = exports.openDatabase = exports.closeDatabase = exports.networks = exports.ArkNote = exports.isValidArkAddress = exports.isVtxoExpiringSoon = exports.combineTapscriptSigs = exports.hasBoardingTxExpired = exports.waitForIncomingFunds = exports.verifyTapscriptSignatures = exports.buildOffchainTx = exports.ConditionWitness = exports.VtxoTaprootTree = exports.VtxoTreeExpiry = exports.CosignerPublicKey = exports.getArkPsbtFields = exports.setArkPsbtField = exports.ArkPsbtFieldKeyType = exports.ArkPsbtFieldKey = exports.TapTreeCoder = void 0;
|
|
41
|
+
exports.isArkContract = exports.contractFromArkContractWithAddress = exports.contractFromArkContract = exports.decodeArkContract = exports.encodeArkContract = exports.VHTLCContractHandler = exports.DelegateContractHandler = exports.DefaultContractHandler = exports.contractHandlers = exports.ContractWatcher = exports.ContractManager = exports.getSequence = void 0;
|
|
42
42
|
const transaction_1 = require("./utils/transaction");
|
|
43
43
|
Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { return transaction_1.Transaction; } });
|
|
44
44
|
const singleKey_1 = require("./identity/singleKey");
|
|
@@ -80,6 +80,8 @@ const txTree_1 = require("./tree/txTree");
|
|
|
80
80
|
Object.defineProperty(exports, "TxTree", { enumerable: true, get: function () { return txTree_1.TxTree; } });
|
|
81
81
|
const ramps_1 = require("./wallet/ramps");
|
|
82
82
|
Object.defineProperty(exports, "Ramps", { enumerable: true, get: function () { return ramps_1.Ramps; } });
|
|
83
|
+
const hdDescriptorProvider_1 = require("./wallet/hdDescriptorProvider");
|
|
84
|
+
Object.defineProperty(exports, "HDDescriptorProvider", { enumerable: true, get: function () { return hdDescriptorProvider_1.HDDescriptorProvider; } });
|
|
83
85
|
const vtxo_manager_1 = require("./wallet/vtxo-manager");
|
|
84
86
|
Object.defineProperty(exports, "isVtxoExpiringSoon", { enumerable: true, get: function () { return vtxo_manager_1.isVtxoExpiringSoon; } });
|
|
85
87
|
Object.defineProperty(exports, "VtxoManager", { enumerable: true, get: function () { return vtxo_manager_1.VtxoManager; } });
|
|
@@ -95,6 +97,8 @@ const onchain_2 = require("./providers/onchain");
|
|
|
95
97
|
Object.defineProperty(exports, "ESPLORA_URL", { enumerable: true, get: function () { return onchain_2.ESPLORA_URL; } });
|
|
96
98
|
Object.defineProperty(exports, "EsploraProvider", { enumerable: true, get: function () { return onchain_2.EsploraProvider; } });
|
|
97
99
|
const electrum_1 = require("./providers/electrum");
|
|
100
|
+
Object.defineProperty(exports, "ELECTRUM_TCP_HOST", { enumerable: true, get: function () { return electrum_1.ELECTRUM_TCP_HOST; } });
|
|
101
|
+
Object.defineProperty(exports, "ELECTRUM_WS_URL", { enumerable: true, get: function () { return electrum_1.ELECTRUM_WS_URL; } });
|
|
98
102
|
Object.defineProperty(exports, "ElectrumOnchainProvider", { enumerable: true, get: function () { return electrum_1.ElectrumOnchainProvider; } });
|
|
99
103
|
Object.defineProperty(exports, "WsElectrumChainSource", { enumerable: true, get: function () { return electrum_1.WsElectrumChainSource; } });
|
|
100
104
|
const ark_1 = require("./providers/ark");
|
|
@@ -138,6 +142,8 @@ Object.defineProperty(exports, "IndexerTxType", { enumerable: true, get: functio
|
|
|
138
142
|
Object.defineProperty(exports, "ChainTxType", { enumerable: true, get: function () { return indexer_1.ChainTxType; } });
|
|
139
143
|
const anchor_1 = require("./utils/anchor");
|
|
140
144
|
Object.defineProperty(exports, "P2A", { enumerable: true, get: function () { return anchor_1.P2A; } });
|
|
145
|
+
const txSizeEstimator_1 = require("./utils/txSizeEstimator");
|
|
146
|
+
Object.defineProperty(exports, "TxWeightEstimator", { enumerable: true, get: function () { return txSizeEstimator_1.TxWeightEstimator; } });
|
|
141
147
|
const unroll_1 = require("./wallet/unroll");
|
|
142
148
|
Object.defineProperty(exports, "Unroll", { enumerable: true, get: function () { return unroll_1.Unroll; } });
|
|
143
149
|
const errors_1 = require("./providers/errors");
|
|
@@ -177,6 +183,9 @@ Object.defineProperty(exports, "decodeArkContract", { enumerable: true, get: fun
|
|
|
177
183
|
Object.defineProperty(exports, "contractFromArkContract", { enumerable: true, get: function () { return contracts_1.contractFromArkContract; } });
|
|
178
184
|
Object.defineProperty(exports, "contractFromArkContractWithAddress", { enumerable: true, get: function () { return contracts_1.contractFromArkContractWithAddress; } });
|
|
179
185
|
Object.defineProperty(exports, "isArkContract", { enumerable: true, get: function () { return contracts_1.isArkContract; } });
|
|
186
|
+
const helpers_1 = require("./contracts/handlers/helpers");
|
|
187
|
+
Object.defineProperty(exports, "timelockToSequence", { enumerable: true, get: function () { return helpers_1.timelockToSequence; } });
|
|
188
|
+
Object.defineProperty(exports, "sequenceToTimelock", { enumerable: true, get: function () { return helpers_1.sequenceToTimelock; } });
|
|
180
189
|
const manager_1 = require("./repositories/indexedDB/manager");
|
|
181
190
|
Object.defineProperty(exports, "closeDatabase", { enumerable: true, get: function () { return manager_1.closeDatabase; } });
|
|
182
191
|
Object.defineProperty(exports, "openDatabase", { enumerable: true, get: function () { return manager_1.openDatabase; } });
|