@arkade-os/sdk 0.5.0-rc.11 → 0.5.0-rc.13
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 +43 -12
- package/dist/adapters/expo.cjs +5 -5
- package/dist/adapters/expo.d.cts +2 -2
- package/dist/adapters/expo.d.ts +2 -2
- package/dist/adapters/expo.js +3 -3
- package/dist/{asyncStorageTaskQueue-DBaZsltv.d.cts → asyncStorageTaskQueue-0EeSeCAt.d.cts} +1 -1
- package/dist/{asyncStorageTaskQueue-uAG3XLyg.d.ts → asyncStorageTaskQueue-DV94jhwq.d.ts} +1 -1
- package/dist/{chunk-WSQAWSEH.js → chunk-3JLYJ5KZ.js} +75 -237
- package/dist/chunk-3JLYJ5KZ.js.map +1 -0
- package/dist/{chunk-VMLLYEYM.js → chunk-4EU2Q6YT.js} +12 -14
- package/dist/chunk-4EU2Q6YT.js.map +1 -0
- package/dist/{chunk-IA32YGLH.cjs → chunk-7BACS4XK.cjs} +10 -10
- package/dist/chunk-7BACS4XK.cjs.map +1 -0
- package/dist/{chunk-5OBGYL6U.cjs → chunk-7NK6XFC3.cjs} +120 -194
- package/dist/chunk-7NK6XFC3.cjs.map +1 -0
- package/dist/{chunk-CQPQ7D4U.cjs → chunk-BFQX2KS3.cjs} +87 -248
- package/dist/chunk-BFQX2KS3.cjs.map +1 -0
- package/dist/{chunk-DD6MTNAS.js → chunk-D7JLTHSZ.js} +5 -5
- package/dist/chunk-D7JLTHSZ.js.map +1 -0
- package/dist/{chunk-CMLSTGOC.js → chunk-EJYWGTZ7.js} +119 -194
- package/dist/chunk-EJYWGTZ7.js.map +1 -0
- package/dist/{chunk-T2ILYGWE.cjs → chunk-FDQQOF3F.cjs} +327 -1080
- package/dist/chunk-FDQQOF3F.cjs.map +1 -0
- package/dist/{chunk-MGDXN74N.cjs → chunk-I4YBVHAK.cjs} +2357 -3374
- package/dist/chunk-I4YBVHAK.cjs.map +1 -0
- package/dist/{chunk-M2ZUPLKQ.js → chunk-IV2252XM.js} +1946 -2977
- package/dist/chunk-IV2252XM.js.map +1 -0
- package/dist/{chunk-OMJRW2D5.js → chunk-JOUPIZ32.js} +263 -1036
- package/dist/chunk-JOUPIZ32.js.map +1 -0
- package/dist/{chunk-PWEBQNIE.cjs → chunk-RDQSVIXD.cjs} +22 -24
- package/dist/chunk-RDQSVIXD.cjs.map +1 -0
- package/dist/contracts/handlers/index.cjs +9 -9
- package/dist/contracts/handlers/index.d.cts +3 -3
- package/dist/contracts/handlers/index.d.ts +3 -3
- package/dist/contracts/handlers/index.js +2 -2
- package/dist/{delegate-DFwlkVYR.d.cts → delegate-BgpUJW5B.d.cts} +1 -1
- package/dist/{delegate-D3YHDERL.d.ts → delegate-BuagcGnG.d.ts} +1 -1
- package/dist/{index-DTvUv5lD.d.cts → index-CKmB14Yu.d.cts} +1145 -2263
- package/dist/{index-DTvUv5lD.d.ts → index-CKmB14Yu.d.ts} +1145 -2263
- package/dist/index-D0BuYwhF.d.cts +637 -0
- package/dist/index-DbzyrqK7.d.ts +637 -0
- package/dist/index.cjs +341 -297
- package/dist/index.d.cts +379 -788
- package/dist/index.d.ts +379 -788
- package/dist/index.js +4 -4
- package/dist/repositories/realm/index.cjs +142 -101
- package/dist/repositories/realm/index.cjs.map +1 -1
- package/dist/repositories/realm/index.d.cts +13 -11
- package/dist/repositories/realm/index.d.ts +13 -11
- package/dist/repositories/realm/index.js +130 -89
- package/dist/repositories/realm/index.js.map +1 -1
- package/dist/repositories/sqlite/index.cjs +158 -118
- package/dist/repositories/sqlite/index.cjs.map +1 -1
- package/dist/repositories/sqlite/index.d.cts +14 -13
- package/dist/repositories/sqlite/index.d.ts +14 -13
- package/dist/repositories/sqlite/index.js +147 -107
- package/dist/repositories/sqlite/index.js.map +1 -1
- package/dist/{taskRunner-B5bl0YRt.d.ts → taskRunner-BX-pB0sv.d.ts} +1 -1
- package/dist/{taskRunner--sKy9Inv.d.cts → taskRunner-DJrFFyus.d.cts} +1 -1
- package/dist/wallet/expo/background.cjs +14 -14
- package/dist/wallet/expo/background.cjs.map +1 -1
- package/dist/wallet/expo/background.d.cts +8 -14
- package/dist/wallet/expo/background.d.ts +8 -14
- package/dist/wallet/expo/background.js +6 -6
- package/dist/wallet/expo/background.js.map +1 -1
- package/dist/wallet/expo/index.cjs +14 -14
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +5 -5
- package/dist/wallet/expo/index.d.ts +5 -5
- package/dist/wallet/expo/index.js +5 -5
- package/dist/wallet/expo/index.js.map +1 -1
- package/dist/wallet-BsL2G3Qb.d.cts +1542 -0
- package/dist/wallet-DXNiCmq8.d.ts +1542 -0
- package/dist/worker/expo/index.cjs +9 -9
- package/dist/worker/expo/index.d.cts +4 -4
- package/dist/worker/expo/index.d.ts +4 -4
- package/dist/worker/expo/index.js +5 -5
- package/package.json +3 -2
- package/dist/chunk-5OBGYL6U.cjs.map +0 -1
- package/dist/chunk-CMLSTGOC.js.map +0 -1
- package/dist/chunk-CQPQ7D4U.cjs.map +0 -1
- package/dist/chunk-DD6MTNAS.js.map +0 -1
- package/dist/chunk-IA32YGLH.cjs.map +0 -1
- package/dist/chunk-M2ZUPLKQ.js.map +0 -1
- package/dist/chunk-MGDXN74N.cjs.map +0 -1
- package/dist/chunk-OMJRW2D5.js.map +0 -1
- package/dist/chunk-PWEBQNIE.cjs.map +0 -1
- package/dist/chunk-T2ILYGWE.cjs.map +0 -1
- package/dist/chunk-VMLLYEYM.js.map +0 -1
- package/dist/chunk-WSQAWSEH.js.map +0 -1
- package/dist/hdWalletCapable-C350s3bP.d.ts +0 -2206
- package/dist/hdWalletCapable-rrOmXcbT.d.cts +0 -2206
- package/dist/index-C0ZyGoyP.d.cts +0 -850
- package/dist/index-DASN1cVk.d.ts +0 -850
|
@@ -1,43 +1,47 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk7NK6XFC3_cjs = require('./chunk-7NK6XFC3.cjs');
|
|
4
4
|
var base = require('@scure/base');
|
|
5
5
|
var descriptorsScure = require('@bitcoinerlab/descriptors-scure');
|
|
6
6
|
var btcSigner = require('@scure/btc-signer');
|
|
7
|
+
var P = require('micro-packed');
|
|
7
8
|
var secp256k1_js = require('@noble/curves/secp256k1.js');
|
|
8
9
|
var utils_js = require('@noble/curves/utils.js');
|
|
9
10
|
|
|
11
|
+
function _interopNamespace(e) {
|
|
12
|
+
if (e && e.__esModule) return e;
|
|
13
|
+
var n = Object.create(null);
|
|
14
|
+
if (e) {
|
|
15
|
+
Object.keys(e).forEach(function (k) {
|
|
16
|
+
if (k !== 'default') {
|
|
17
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
18
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () { return e[k]; }
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
n.default = e;
|
|
26
|
+
return Object.freeze(n);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var P__namespace = /*#__PURE__*/_interopNamespace(P);
|
|
30
|
+
|
|
10
31
|
// src/contracts/handlers/registry.ts
|
|
11
32
|
var ContractHandlerRegistry = class {
|
|
12
33
|
handlers = /* @__PURE__ */ new Map();
|
|
13
|
-
/**
|
|
14
|
-
* Register a contract handler.
|
|
15
|
-
*
|
|
16
|
-
* @param handler - The handler to register
|
|
17
|
-
* @throws If a handler for this type is already registered
|
|
18
|
-
*/
|
|
34
|
+
/** @throws If a handler for this type is already registered */
|
|
19
35
|
register(handler) {
|
|
20
36
|
if (this.handlers.has(handler.type)) {
|
|
21
37
|
throw new Error(`Contract handler for type '${handler.type}' is already registered`);
|
|
22
38
|
}
|
|
23
39
|
this.handlers.set(handler.type, handler);
|
|
24
40
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Get a handler by type.
|
|
27
|
-
*
|
|
28
|
-
* @param type - The contract type
|
|
29
|
-
* @returns The handler, or undefined if not found
|
|
30
|
-
*/
|
|
31
41
|
get(type) {
|
|
32
42
|
return this.handlers.get(type);
|
|
33
43
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Get a handler by type, throwing if not found.
|
|
36
|
-
*
|
|
37
|
-
* @param type - The contract type
|
|
38
|
-
* @returns The handler
|
|
39
|
-
* @throws If no handler is registered for this type
|
|
40
|
-
*/
|
|
44
|
+
/** @throws If no handler is registered for this type */
|
|
41
45
|
getOrThrow(type) {
|
|
42
46
|
const handler = this.get(type);
|
|
43
47
|
if (!handler) {
|
|
@@ -45,29 +49,17 @@ var ContractHandlerRegistry = class {
|
|
|
45
49
|
}
|
|
46
50
|
return handler;
|
|
47
51
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Check if a handler is registered.
|
|
50
|
-
*
|
|
51
|
-
* @param type - The contract type
|
|
52
|
-
*/
|
|
53
52
|
has(type) {
|
|
54
53
|
return this.handlers.has(type);
|
|
55
54
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Get all registered types.
|
|
58
|
-
*/
|
|
59
55
|
getRegisteredTypes() {
|
|
60
56
|
return Array.from(this.handlers.keys());
|
|
61
57
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Unregister a handler (mainly for testing).
|
|
64
|
-
*/
|
|
58
|
+
/** Unregister a handler (mainly for testing). */
|
|
65
59
|
unregister(type) {
|
|
66
60
|
return this.handlers.delete(type);
|
|
67
61
|
}
|
|
68
|
-
/**
|
|
69
|
-
* Clear all handlers (mainly for testing).
|
|
70
|
-
*/
|
|
62
|
+
/** Clear all handlers (mainly for testing). */
|
|
71
63
|
clear() {
|
|
72
64
|
this.handlers.clear();
|
|
73
65
|
}
|
|
@@ -75,14 +67,14 @@ var ContractHandlerRegistry = class {
|
|
|
75
67
|
var contractHandlers = new ContractHandlerRegistry();
|
|
76
68
|
exports.DefaultVtxo = void 0;
|
|
77
69
|
((DefaultVtxo2) => {
|
|
78
|
-
class Script3 extends
|
|
70
|
+
class Script3 extends chunk7NK6XFC3_cjs.VtxoScript {
|
|
79
71
|
/** Create the default virtual output script with one forfeit path and one exit path. */
|
|
80
72
|
constructor(options) {
|
|
81
73
|
const { pubKey, serverPubKey, csvTimelock } = options;
|
|
82
|
-
const forfeitScript =
|
|
74
|
+
const forfeitScript = chunk7NK6XFC3_cjs.MultisigTapscript.encode({
|
|
83
75
|
pubkeys: [pubKey, serverPubKey]
|
|
84
76
|
}).script;
|
|
85
|
-
const exitScript =
|
|
77
|
+
const exitScript = chunk7NK6XFC3_cjs.CSVMultisigTapscript.encode({
|
|
86
78
|
timelock: csvTimelock,
|
|
87
79
|
pubkeys: [pubKey]
|
|
88
80
|
}).script;
|
|
@@ -274,7 +266,7 @@ function extractPubKeyBytes(value) {
|
|
|
274
266
|
return base.hex.decode(extractPubKey(normalizeToDescriptor(value)));
|
|
275
267
|
}
|
|
276
268
|
function deserializeCsvTimelock(value) {
|
|
277
|
-
return value !== void 0 && value !== "" ?
|
|
269
|
+
return value !== void 0 && value !== "" ? chunk7NK6XFC3_cjs.sequenceToTimelock(Number(value)) : exports.DefaultVtxo.Script.DEFAULT_TIMELOCK;
|
|
278
270
|
}
|
|
279
271
|
var CLTV_HEIGHT_THRESHOLD = 500000000n;
|
|
280
272
|
function isCltvSatisfied(context, locktime) {
|
|
@@ -313,10 +305,139 @@ function assertVhtlcSpendableNow(contract, context) {
|
|
|
313
305
|
`vhtlc ${contract.script} cannot be spent yet: its refund path opens at ${matures}, now ${now}. Until then the lockup is the receiver's to claim, and the server rejects a spend of it. Retry after ${matures}, or wait for the receiver to claim it with the preimage.`
|
|
314
306
|
);
|
|
315
307
|
}
|
|
308
|
+
function selectVhtlcPath(script, contract, context) {
|
|
309
|
+
const role = resolveRole(contract, context);
|
|
310
|
+
const preimage = contract.params?.preimage;
|
|
311
|
+
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
312
|
+
if (!role) {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
if (context.collaborative) {
|
|
316
|
+
if (role === "receiver" && preimage) {
|
|
317
|
+
return {
|
|
318
|
+
leaf: script.claim(),
|
|
319
|
+
extraWitness: [base.hex.decode(preimage)]
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
323
|
+
return {
|
|
324
|
+
leaf: script.refundWithoutReceiver()
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
if (role === "receiver" && preimage) {
|
|
330
|
+
const sequence = Number(contract.params.claimDelay);
|
|
331
|
+
if (!isCsvSpendable(context, sequence)) return null;
|
|
332
|
+
return {
|
|
333
|
+
leaf: script.unilateralClaim(),
|
|
334
|
+
extraWitness: [base.hex.decode(preimage)],
|
|
335
|
+
sequence
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
if (role === "sender") {
|
|
339
|
+
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
340
|
+
if (!isCsvSpendable(context, sequence)) return null;
|
|
341
|
+
return {
|
|
342
|
+
leaf: script.unilateralRefundWithoutReceiver(),
|
|
343
|
+
sequence
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
function vhtlcAllSpendingPaths(script, contract, context) {
|
|
349
|
+
const role = resolveRole(contract, context);
|
|
350
|
+
const paths = [];
|
|
351
|
+
if (!role) {
|
|
352
|
+
return paths;
|
|
353
|
+
}
|
|
354
|
+
const preimage = contract.params?.preimage;
|
|
355
|
+
if (context.collaborative) {
|
|
356
|
+
if (role === "receiver" && preimage) {
|
|
357
|
+
paths.push({
|
|
358
|
+
leaf: script.claim(),
|
|
359
|
+
extraWitness: [base.hex.decode(preimage)]
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (role === "sender") {
|
|
363
|
+
paths.push({
|
|
364
|
+
leaf: script.refundWithoutReceiver()
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
if (role === "receiver" && preimage) {
|
|
369
|
+
const sequence = Number(contract.params.claimDelay);
|
|
370
|
+
paths.push({
|
|
371
|
+
leaf: script.unilateralClaim(),
|
|
372
|
+
extraWitness: [base.hex.decode(preimage)],
|
|
373
|
+
sequence
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
if (role === "sender") {
|
|
377
|
+
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
378
|
+
paths.push({
|
|
379
|
+
leaf: script.unilateralRefundWithoutReceiver(),
|
|
380
|
+
sequence
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return paths;
|
|
385
|
+
}
|
|
386
|
+
function vhtlcSpendablePaths(script, contract, context) {
|
|
387
|
+
const role = resolveRole(contract, context);
|
|
388
|
+
const paths = [];
|
|
389
|
+
if (!role) {
|
|
390
|
+
return paths;
|
|
391
|
+
}
|
|
392
|
+
const preimage = contract.params?.preimage;
|
|
393
|
+
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
394
|
+
if (context.collaborative) {
|
|
395
|
+
if (role === "receiver" && preimage) {
|
|
396
|
+
paths.push({
|
|
397
|
+
leaf: script.claim(),
|
|
398
|
+
extraWitness: [base.hex.decode(preimage)]
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
402
|
+
paths.push({
|
|
403
|
+
leaf: script.refundWithoutReceiver()
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
return paths;
|
|
407
|
+
}
|
|
408
|
+
if (role === "receiver" && preimage) {
|
|
409
|
+
const sequence = Number(contract.params.claimDelay);
|
|
410
|
+
if (isCsvSpendable(context, sequence)) {
|
|
411
|
+
paths.push({
|
|
412
|
+
leaf: script.unilateralClaim(),
|
|
413
|
+
extraWitness: [base.hex.decode(preimage)],
|
|
414
|
+
sequence
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (role === "sender") {
|
|
419
|
+
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
420
|
+
if (isCsvSpendable(context, sequence)) {
|
|
421
|
+
paths.push({
|
|
422
|
+
leaf: script.unilateralRefundWithoutReceiver(),
|
|
423
|
+
sequence
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return paths;
|
|
428
|
+
}
|
|
429
|
+
function deriveVhtlcTapscripts(script) {
|
|
430
|
+
const leaf = script.refundWithoutReceiver();
|
|
431
|
+
return {
|
|
432
|
+
forfeitTapLeafScript: leaf,
|
|
433
|
+
intentTapLeafScript: leaf,
|
|
434
|
+
tapTree: script.encode()
|
|
435
|
+
};
|
|
436
|
+
}
|
|
316
437
|
function isCsvSpendable(context, sequence) {
|
|
317
438
|
if (sequence === void 0) return true;
|
|
318
439
|
if (!context.vtxo) return false;
|
|
319
|
-
const timelock =
|
|
440
|
+
const timelock = chunk7NK6XFC3_cjs.sequenceToTimelock(sequence);
|
|
320
441
|
if (timelock.type === "blocks") {
|
|
321
442
|
if (context.blockHeight === void 0 || context.vtxo.status.block_height === void 0) {
|
|
322
443
|
return false;
|
|
@@ -374,21 +495,21 @@ function forfeitExitSpendablePaths(script, contract, context) {
|
|
|
374
495
|
async function detectUsedScripts(indexerProvider, scriptHexes) {
|
|
375
496
|
const used = /* @__PURE__ */ new Set();
|
|
376
497
|
const unique = [...new Set(scriptHexes)];
|
|
377
|
-
for (let offset = 0; offset < unique.length; offset +=
|
|
378
|
-
const scripts = unique.slice(offset, offset +
|
|
498
|
+
for (let offset = 0; offset < unique.length; offset += chunk7NK6XFC3_cjs.SCRIPT_QUERY_CHUNK_SIZE) {
|
|
499
|
+
const scripts = unique.slice(offset, offset + chunk7NK6XFC3_cjs.SCRIPT_QUERY_CHUNK_SIZE);
|
|
379
500
|
const remaining = new Set(scripts);
|
|
380
501
|
let pageIndex = 0;
|
|
381
502
|
let hasMore = true;
|
|
382
503
|
while (hasMore && remaining.size > 0) {
|
|
383
|
-
const { vtxos, page } = await
|
|
504
|
+
const { vtxos, page } = await chunk7NK6XFC3_cjs.getNormalizedVtxos(indexerProvider, {
|
|
384
505
|
scripts,
|
|
385
506
|
pageIndex,
|
|
386
|
-
pageSize:
|
|
507
|
+
pageSize: chunk7NK6XFC3_cjs.DEFAULT_PAGE_SIZE
|
|
387
508
|
});
|
|
388
509
|
for (const vtxo of vtxos) {
|
|
389
510
|
if (remaining.delete(vtxo.script)) used.add(vtxo.script);
|
|
390
511
|
}
|
|
391
|
-
hasMore = page ? vtxos.length ===
|
|
512
|
+
hasMore = page ? vtxos.length === chunk7NK6XFC3_cjs.DEFAULT_PAGE_SIZE : false;
|
|
392
513
|
pageIndex++;
|
|
393
514
|
}
|
|
394
515
|
}
|
|
@@ -449,7 +570,7 @@ var DefaultContractHandler = {
|
|
|
449
570
|
return {
|
|
450
571
|
pubKey: base.hex.encode(params.pubKey),
|
|
451
572
|
serverPubKey: base.hex.encode(params.serverPubKey),
|
|
452
|
-
csvTimelock:
|
|
573
|
+
csvTimelock: chunk7NK6XFC3_cjs.timelockToSequence(params.csvTimelock).toString()
|
|
453
574
|
};
|
|
454
575
|
},
|
|
455
576
|
deserializeParams(params) {
|
|
@@ -481,11 +602,7 @@ function defaultCandidatesAt(_index, descriptor, deps) {
|
|
|
481
602
|
(opts) => new exports.DefaultVtxo.Script(opts)
|
|
482
603
|
).map((c) => ({
|
|
483
604
|
type: "default",
|
|
484
|
-
params:
|
|
485
|
-
pubKey: base.hex.encode(c.pubKey),
|
|
486
|
-
serverPubKey: base.hex.encode(c.serverPubKey),
|
|
487
|
-
csvTimelock: chunk5OBGYL6U_cjs.timelockToSequence(c.csvTimelock).toString()
|
|
488
|
-
},
|
|
605
|
+
params: DefaultContractHandler.serializeParams(c),
|
|
489
606
|
script: c.scriptHex,
|
|
490
607
|
address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
|
|
491
608
|
}));
|
|
@@ -500,12 +617,12 @@ function discoverDefaultRange(entries, deps) {
|
|
|
500
617
|
}
|
|
501
618
|
exports.DelegateVtxo = void 0;
|
|
502
619
|
((DelegateVtxo2) => {
|
|
503
|
-
class Script3 extends
|
|
620
|
+
class Script3 extends chunk7NK6XFC3_cjs.VtxoScript {
|
|
504
621
|
/** Create a delegated virtual output script with forfeit, exit, and delegate paths. */
|
|
505
622
|
constructor(options) {
|
|
506
623
|
const defaultVtxo = new exports.DefaultVtxo.Script(options);
|
|
507
624
|
const { delegatePubKey, pubKey, serverPubKey } = options;
|
|
508
|
-
const delegateScript =
|
|
625
|
+
const delegateScript = chunk7NK6XFC3_cjs.MultisigTapscript.encode({
|
|
509
626
|
pubkeys: [pubKey, delegatePubKey, serverPubKey]
|
|
510
627
|
}).script;
|
|
511
628
|
super([...defaultVtxo.scripts, delegateScript]);
|
|
@@ -544,7 +661,7 @@ var DelegateContractHandler = {
|
|
|
544
661
|
pubKey: base.hex.encode(params.pubKey),
|
|
545
662
|
serverPubKey: base.hex.encode(params.serverPubKey),
|
|
546
663
|
delegatePubKey: base.hex.encode(params.delegatePubKey),
|
|
547
|
-
csvTimelock:
|
|
664
|
+
csvTimelock: chunk7NK6XFC3_cjs.timelockToSequence(params.csvTimelock).toString()
|
|
548
665
|
};
|
|
549
666
|
},
|
|
550
667
|
deserializeParams(params) {
|
|
@@ -584,12 +701,7 @@ function delegateCandidatesAt(_index, descriptor, deps) {
|
|
|
584
701
|
(opts) => new exports.DelegateVtxo.Script({ ...opts, delegatePubKey })
|
|
585
702
|
).map((c) => ({
|
|
586
703
|
type: "delegate",
|
|
587
|
-
params: {
|
|
588
|
-
pubKey: base.hex.encode(c.pubKey),
|
|
589
|
-
serverPubKey: base.hex.encode(c.serverPubKey),
|
|
590
|
-
delegatePubKey: base.hex.encode(delegatePubKey),
|
|
591
|
-
csvTimelock: chunk5OBGYL6U_cjs.timelockToSequence(c.csvTimelock).toString()
|
|
592
|
-
},
|
|
704
|
+
params: DelegateContractHandler.serializeParams({ ...c, delegatePubKey }),
|
|
593
705
|
script: c.scriptHex,
|
|
594
706
|
address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
|
|
595
707
|
}));
|
|
@@ -605,512 +717,6 @@ function discoverDelegateRange(entries, deps) {
|
|
|
605
717
|
(c, index, descriptor) => ({ ...c, ...rotatedReceiveMetadata(index, descriptor) })
|
|
606
718
|
);
|
|
607
719
|
}
|
|
608
|
-
function equalBytes(a, b) {
|
|
609
|
-
if (a.length !== b.length)
|
|
610
|
-
return false;
|
|
611
|
-
for (let i = 0; i < a.length; i++)
|
|
612
|
-
if (a[i] !== b[i])
|
|
613
|
-
return false;
|
|
614
|
-
return true;
|
|
615
|
-
}
|
|
616
|
-
function isBytes(a) {
|
|
617
|
-
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
618
|
-
}
|
|
619
|
-
var createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
620
|
-
function isPlainObject(obj) {
|
|
621
|
-
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
622
|
-
}
|
|
623
|
-
function isNum(num) {
|
|
624
|
-
return Number.isSafeInteger(num);
|
|
625
|
-
}
|
|
626
|
-
var Bitset = {
|
|
627
|
-
BITS: 32,
|
|
628
|
-
FULL_MASK: -1 >>> 0,
|
|
629
|
-
// 1<<32 will overflow
|
|
630
|
-
len: (len) => Math.ceil(len / 32),
|
|
631
|
-
create: (len) => new Uint32Array(Bitset.len(len)),
|
|
632
|
-
clean: (bs) => bs.fill(0),
|
|
633
|
-
debug: (bs) => Array.from(bs).map((i) => (i >>> 0).toString(2).padStart(32, "0")),
|
|
634
|
-
checkLen: (bs, len) => {
|
|
635
|
-
if (Bitset.len(len) === bs.length)
|
|
636
|
-
return;
|
|
637
|
-
throw new Error(`wrong length=${bs.length}. Expected: ${Bitset.len(len)}`);
|
|
638
|
-
},
|
|
639
|
-
chunkLen: (bsLen, pos, len) => {
|
|
640
|
-
if (pos < 0)
|
|
641
|
-
throw new Error(`wrong pos=${pos}`);
|
|
642
|
-
if (pos + len > bsLen)
|
|
643
|
-
throw new Error(`wrong range=${pos}/${len} of ${bsLen}`);
|
|
644
|
-
},
|
|
645
|
-
set: (bs, chunk, value, allowRewrite = true) => {
|
|
646
|
-
if (!allowRewrite && (bs[chunk] & value) !== 0)
|
|
647
|
-
return false;
|
|
648
|
-
bs[chunk] |= value;
|
|
649
|
-
return true;
|
|
650
|
-
},
|
|
651
|
-
pos: (pos, i) => ({
|
|
652
|
-
chunk: Math.floor((pos + i) / 32),
|
|
653
|
-
mask: 1 << 32 - (pos + i) % 32 - 1
|
|
654
|
-
}),
|
|
655
|
-
indices: (bs, len, invert = false) => {
|
|
656
|
-
Bitset.checkLen(bs, len);
|
|
657
|
-
const { FULL_MASK, BITS } = Bitset;
|
|
658
|
-
const left = BITS - len % BITS;
|
|
659
|
-
const lastMask = left ? FULL_MASK >>> left << left : FULL_MASK;
|
|
660
|
-
const res = [];
|
|
661
|
-
for (let i = 0; i < bs.length; i++) {
|
|
662
|
-
let c = bs[i];
|
|
663
|
-
if (invert)
|
|
664
|
-
c = ~c;
|
|
665
|
-
if (i === bs.length - 1)
|
|
666
|
-
c &= lastMask;
|
|
667
|
-
if (c === 0)
|
|
668
|
-
continue;
|
|
669
|
-
for (let j = 0; j < BITS; j++) {
|
|
670
|
-
const m = 1 << BITS - j - 1;
|
|
671
|
-
if (c & m)
|
|
672
|
-
res.push(i * BITS + j);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
return res;
|
|
676
|
-
},
|
|
677
|
-
range: (arr) => {
|
|
678
|
-
const res = [];
|
|
679
|
-
let cur;
|
|
680
|
-
for (const i of arr) {
|
|
681
|
-
if (cur === void 0 || i !== cur.pos + cur.length)
|
|
682
|
-
res.push(cur = { pos: i, length: 1 });
|
|
683
|
-
else
|
|
684
|
-
cur.length += 1;
|
|
685
|
-
}
|
|
686
|
-
return res;
|
|
687
|
-
},
|
|
688
|
-
rangeDebug: (bs, len, invert = false) => `[${Bitset.range(Bitset.indices(bs, len, invert)).map((i) => `(${i.pos}/${i.length})`).join(", ")}]`,
|
|
689
|
-
setRange: (bs, bsLen, pos, len, allowRewrite = true) => {
|
|
690
|
-
Bitset.chunkLen(bsLen, pos, len);
|
|
691
|
-
const { FULL_MASK, BITS } = Bitset;
|
|
692
|
-
const first = pos % BITS ? Math.floor(pos / BITS) : void 0;
|
|
693
|
-
const lastPos = pos + len;
|
|
694
|
-
const last = lastPos % BITS ? Math.floor(lastPos / BITS) : void 0;
|
|
695
|
-
if (first !== void 0 && first === last)
|
|
696
|
-
return Bitset.set(bs, first, FULL_MASK >>> BITS - len << BITS - len - pos, allowRewrite);
|
|
697
|
-
if (first !== void 0) {
|
|
698
|
-
if (!Bitset.set(bs, first, FULL_MASK >>> pos % BITS, allowRewrite))
|
|
699
|
-
return false;
|
|
700
|
-
}
|
|
701
|
-
const start = first !== void 0 ? first + 1 : pos / BITS;
|
|
702
|
-
const end = last !== void 0 ? last : lastPos / BITS;
|
|
703
|
-
for (let i = start; i < end; i++)
|
|
704
|
-
if (!Bitset.set(bs, i, FULL_MASK, allowRewrite))
|
|
705
|
-
return false;
|
|
706
|
-
if (last !== void 0 && first !== last) {
|
|
707
|
-
if (!Bitset.set(bs, last, FULL_MASK << BITS - lastPos % BITS, allowRewrite))
|
|
708
|
-
return false;
|
|
709
|
-
}
|
|
710
|
-
return true;
|
|
711
|
-
}
|
|
712
|
-
};
|
|
713
|
-
var Path = {
|
|
714
|
-
/**
|
|
715
|
-
* Internal method for handling stack of paths (debug, errors, dynamic fields via path)
|
|
716
|
-
* This is looks ugly (callback), but allows us to force stack cleaning by construction (.pop always after function).
|
|
717
|
-
* Also, this makes impossible:
|
|
718
|
-
* - pushing field when stack is empty
|
|
719
|
-
* - pushing field inside of field (real bug)
|
|
720
|
-
* NOTE: we don't want to do '.pop' on error!
|
|
721
|
-
*/
|
|
722
|
-
pushObj: (stack, obj, objFn) => {
|
|
723
|
-
const last = { obj };
|
|
724
|
-
stack.push(last);
|
|
725
|
-
objFn((field, fieldFn) => {
|
|
726
|
-
last.field = field;
|
|
727
|
-
fieldFn();
|
|
728
|
-
last.field = void 0;
|
|
729
|
-
});
|
|
730
|
-
stack.pop();
|
|
731
|
-
},
|
|
732
|
-
path: (stack) => {
|
|
733
|
-
const res = [];
|
|
734
|
-
for (const i of stack)
|
|
735
|
-
if (i.field !== void 0)
|
|
736
|
-
res.push(i.field);
|
|
737
|
-
return res.join("/");
|
|
738
|
-
},
|
|
739
|
-
err: (name, stack, msg) => {
|
|
740
|
-
const err = new Error(`${name}(${Path.path(stack)}): ${typeof msg === "string" ? msg : msg.message}`);
|
|
741
|
-
if (msg instanceof Error && msg.stack)
|
|
742
|
-
err.stack = msg.stack;
|
|
743
|
-
return err;
|
|
744
|
-
},
|
|
745
|
-
resolve: (stack, path) => {
|
|
746
|
-
const parts = path.split("/");
|
|
747
|
-
const objPath = stack.map((i2) => i2.obj);
|
|
748
|
-
let i = 0;
|
|
749
|
-
for (; i < parts.length; i++) {
|
|
750
|
-
if (parts[i] === "..")
|
|
751
|
-
objPath.pop();
|
|
752
|
-
else
|
|
753
|
-
break;
|
|
754
|
-
}
|
|
755
|
-
let cur = objPath.pop();
|
|
756
|
-
for (; i < parts.length; i++) {
|
|
757
|
-
if (!cur || cur[parts[i]] === void 0)
|
|
758
|
-
return void 0;
|
|
759
|
-
cur = cur[parts[i]];
|
|
760
|
-
}
|
|
761
|
-
return cur;
|
|
762
|
-
}
|
|
763
|
-
};
|
|
764
|
-
var _Reader = class __Reader {
|
|
765
|
-
pos = 0;
|
|
766
|
-
data;
|
|
767
|
-
opts;
|
|
768
|
-
stack;
|
|
769
|
-
parent;
|
|
770
|
-
parentOffset;
|
|
771
|
-
bitBuf = 0;
|
|
772
|
-
bitPos = 0;
|
|
773
|
-
bs;
|
|
774
|
-
// bitset
|
|
775
|
-
view;
|
|
776
|
-
constructor(data, opts = {}, stack = [], parent = void 0, parentOffset = 0) {
|
|
777
|
-
this.data = data;
|
|
778
|
-
this.opts = opts;
|
|
779
|
-
this.stack = stack;
|
|
780
|
-
this.parent = parent;
|
|
781
|
-
this.parentOffset = parentOffset;
|
|
782
|
-
this.view = createView(data);
|
|
783
|
-
}
|
|
784
|
-
/** Internal method for pointers. */
|
|
785
|
-
_enablePointers() {
|
|
786
|
-
if (this.parent)
|
|
787
|
-
return this.parent._enablePointers();
|
|
788
|
-
if (this.bs)
|
|
789
|
-
return;
|
|
790
|
-
this.bs = Bitset.create(this.data.length);
|
|
791
|
-
Bitset.setRange(this.bs, this.data.length, 0, this.pos, this.opts.allowMultipleReads);
|
|
792
|
-
}
|
|
793
|
-
markBytesBS(pos, len) {
|
|
794
|
-
if (this.parent)
|
|
795
|
-
return this.parent.markBytesBS(this.parentOffset + pos, len);
|
|
796
|
-
if (!len)
|
|
797
|
-
return true;
|
|
798
|
-
if (!this.bs)
|
|
799
|
-
return true;
|
|
800
|
-
return Bitset.setRange(this.bs, this.data.length, pos, len, false);
|
|
801
|
-
}
|
|
802
|
-
markBytes(len) {
|
|
803
|
-
const pos = this.pos;
|
|
804
|
-
this.pos += len;
|
|
805
|
-
const res = this.markBytesBS(pos, len);
|
|
806
|
-
if (!this.opts.allowMultipleReads && !res)
|
|
807
|
-
throw this.err(`multiple read pos=${this.pos} len=${len}`);
|
|
808
|
-
return res;
|
|
809
|
-
}
|
|
810
|
-
pushObj(obj, objFn) {
|
|
811
|
-
return Path.pushObj(this.stack, obj, objFn);
|
|
812
|
-
}
|
|
813
|
-
readView(n, fn) {
|
|
814
|
-
if (!Number.isFinite(n))
|
|
815
|
-
throw this.err(`readView: wrong length=${n}`);
|
|
816
|
-
if (this.pos + n > this.data.length)
|
|
817
|
-
throw this.err("readView: Unexpected end of buffer");
|
|
818
|
-
const res = fn(this.view, this.pos);
|
|
819
|
-
this.markBytes(n);
|
|
820
|
-
return res;
|
|
821
|
-
}
|
|
822
|
-
// read bytes by absolute offset
|
|
823
|
-
absBytes(n) {
|
|
824
|
-
if (n > this.data.length)
|
|
825
|
-
throw new Error("Unexpected end of buffer");
|
|
826
|
-
return this.data.subarray(n);
|
|
827
|
-
}
|
|
828
|
-
finish() {
|
|
829
|
-
if (this.opts.allowUnreadBytes)
|
|
830
|
-
return;
|
|
831
|
-
if (this.bitPos) {
|
|
832
|
-
throw this.err(`${this.bitPos} bits left after unpack: ${base.hex.encode(this.data.slice(this.pos))}`);
|
|
833
|
-
}
|
|
834
|
-
if (this.bs && !this.parent) {
|
|
835
|
-
const notRead = Bitset.indices(this.bs, this.data.length, true);
|
|
836
|
-
if (notRead.length) {
|
|
837
|
-
const formatted = Bitset.range(notRead).map(({ pos, length }) => `(${pos}/${length})[${base.hex.encode(this.data.subarray(pos, pos + length))}]`).join(", ");
|
|
838
|
-
throw this.err(`unread byte ranges: ${formatted} (total=${this.data.length})`);
|
|
839
|
-
} else
|
|
840
|
-
return;
|
|
841
|
-
}
|
|
842
|
-
if (!this.isEnd()) {
|
|
843
|
-
throw this.err(`${this.leftBytes} bytes ${this.bitPos} bits left after unpack: ${base.hex.encode(this.data.slice(this.pos))}`);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
// User methods
|
|
847
|
-
err(msg) {
|
|
848
|
-
return Path.err("Reader", this.stack, msg);
|
|
849
|
-
}
|
|
850
|
-
offsetReader(n) {
|
|
851
|
-
if (n > this.data.length)
|
|
852
|
-
throw this.err("offsetReader: Unexpected end of buffer");
|
|
853
|
-
return new __Reader(this.absBytes(n), this.opts, this.stack, this, n);
|
|
854
|
-
}
|
|
855
|
-
bytes(n, peek = false) {
|
|
856
|
-
if (this.bitPos)
|
|
857
|
-
throw this.err("readBytes: bitPos not empty");
|
|
858
|
-
if (!Number.isFinite(n))
|
|
859
|
-
throw this.err(`readBytes: wrong length=${n}`);
|
|
860
|
-
if (this.pos + n > this.data.length)
|
|
861
|
-
throw this.err("readBytes: Unexpected end of buffer");
|
|
862
|
-
const slice = this.data.subarray(this.pos, this.pos + n);
|
|
863
|
-
if (!peek)
|
|
864
|
-
this.markBytes(n);
|
|
865
|
-
return slice;
|
|
866
|
-
}
|
|
867
|
-
byte(peek = false) {
|
|
868
|
-
if (this.bitPos)
|
|
869
|
-
throw this.err("readByte: bitPos not empty");
|
|
870
|
-
if (this.pos + 1 > this.data.length)
|
|
871
|
-
throw this.err("readBytes: Unexpected end of buffer");
|
|
872
|
-
const data = this.data[this.pos];
|
|
873
|
-
if (!peek)
|
|
874
|
-
this.markBytes(1);
|
|
875
|
-
return data;
|
|
876
|
-
}
|
|
877
|
-
get leftBytes() {
|
|
878
|
-
return this.data.length - this.pos;
|
|
879
|
-
}
|
|
880
|
-
get totalBytes() {
|
|
881
|
-
return this.data.length;
|
|
882
|
-
}
|
|
883
|
-
isEnd() {
|
|
884
|
-
return this.pos >= this.data.length && !this.bitPos;
|
|
885
|
-
}
|
|
886
|
-
// bits are read in BE mode (left to right): (0b1000_0000).readBits(1) == 1
|
|
887
|
-
bits(bits) {
|
|
888
|
-
if (bits > 32)
|
|
889
|
-
throw this.err("BitReader: cannot read more than 32 bits in single call");
|
|
890
|
-
let out = 0;
|
|
891
|
-
while (bits) {
|
|
892
|
-
if (!this.bitPos) {
|
|
893
|
-
this.bitBuf = this.byte();
|
|
894
|
-
this.bitPos = 8;
|
|
895
|
-
}
|
|
896
|
-
const take = Math.min(bits, this.bitPos);
|
|
897
|
-
this.bitPos -= take;
|
|
898
|
-
out = out << take | this.bitBuf >> this.bitPos & 2 ** take - 1;
|
|
899
|
-
this.bitBuf &= 2 ** this.bitPos - 1;
|
|
900
|
-
bits -= take;
|
|
901
|
-
}
|
|
902
|
-
return out >>> 0;
|
|
903
|
-
}
|
|
904
|
-
find(needle, pos = this.pos) {
|
|
905
|
-
if (!isBytes(needle))
|
|
906
|
-
throw this.err(`find: needle is not bytes! ${needle}`);
|
|
907
|
-
if (this.bitPos)
|
|
908
|
-
throw this.err("findByte: bitPos not empty");
|
|
909
|
-
if (!needle.length)
|
|
910
|
-
throw this.err(`find: needle is empty`);
|
|
911
|
-
for (let idx = pos; (idx = this.data.indexOf(needle[0], idx)) !== -1; idx++) {
|
|
912
|
-
if (idx === -1)
|
|
913
|
-
return;
|
|
914
|
-
const leftBytes = this.data.length - idx;
|
|
915
|
-
if (leftBytes < needle.length)
|
|
916
|
-
return;
|
|
917
|
-
if (equalBytes(needle, this.data.subarray(idx, idx + needle.length)))
|
|
918
|
-
return idx;
|
|
919
|
-
}
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
};
|
|
923
|
-
var _Writer = class {
|
|
924
|
-
pos = 0;
|
|
925
|
-
stack;
|
|
926
|
-
// We could have a single buffer here and re-alloc it with
|
|
927
|
-
// x1.5-2 size each time it full, but it will be slower:
|
|
928
|
-
// basic/encode bench: 395ns -> 560ns
|
|
929
|
-
buffers = [];
|
|
930
|
-
ptrs = [];
|
|
931
|
-
bitBuf = 0;
|
|
932
|
-
bitPos = 0;
|
|
933
|
-
viewBuf = new Uint8Array(8);
|
|
934
|
-
view;
|
|
935
|
-
finished = false;
|
|
936
|
-
constructor(stack = []) {
|
|
937
|
-
this.stack = stack;
|
|
938
|
-
this.view = createView(this.viewBuf);
|
|
939
|
-
}
|
|
940
|
-
pushObj(obj, objFn) {
|
|
941
|
-
return Path.pushObj(this.stack, obj, objFn);
|
|
942
|
-
}
|
|
943
|
-
writeView(len, fn) {
|
|
944
|
-
if (this.finished)
|
|
945
|
-
throw this.err("buffer: finished");
|
|
946
|
-
if (!isNum(len) || len > 8)
|
|
947
|
-
throw new Error(`wrong writeView length=${len}`);
|
|
948
|
-
fn(this.view);
|
|
949
|
-
this.bytes(this.viewBuf.slice(0, len));
|
|
950
|
-
this.viewBuf.fill(0);
|
|
951
|
-
}
|
|
952
|
-
// User methods
|
|
953
|
-
err(msg) {
|
|
954
|
-
if (this.finished)
|
|
955
|
-
throw this.err("buffer: finished");
|
|
956
|
-
return Path.err("Reader", this.stack, msg);
|
|
957
|
-
}
|
|
958
|
-
bytes(b) {
|
|
959
|
-
if (this.finished)
|
|
960
|
-
throw this.err("buffer: finished");
|
|
961
|
-
if (this.bitPos)
|
|
962
|
-
throw this.err("writeBytes: ends with non-empty bit buffer");
|
|
963
|
-
this.buffers.push(b);
|
|
964
|
-
this.pos += b.length;
|
|
965
|
-
}
|
|
966
|
-
byte(b) {
|
|
967
|
-
if (this.finished)
|
|
968
|
-
throw this.err("buffer: finished");
|
|
969
|
-
if (this.bitPos)
|
|
970
|
-
throw this.err("writeByte: ends with non-empty bit buffer");
|
|
971
|
-
this.buffers.push(new Uint8Array([b]));
|
|
972
|
-
this.pos++;
|
|
973
|
-
}
|
|
974
|
-
finish(clean = true) {
|
|
975
|
-
if (this.finished)
|
|
976
|
-
throw this.err("buffer: finished");
|
|
977
|
-
if (this.bitPos)
|
|
978
|
-
throw this.err("buffer: ends with non-empty bit buffer");
|
|
979
|
-
const buffers = this.buffers.concat(this.ptrs.map((i) => i.buffer));
|
|
980
|
-
const sum = buffers.map((b) => b.length).reduce((a, b) => a + b, 0);
|
|
981
|
-
const buf = new Uint8Array(sum);
|
|
982
|
-
for (let i = 0, pad = 0; i < buffers.length; i++) {
|
|
983
|
-
const a = buffers[i];
|
|
984
|
-
buf.set(a, pad);
|
|
985
|
-
pad += a.length;
|
|
986
|
-
}
|
|
987
|
-
for (let pos = this.pos, i = 0; i < this.ptrs.length; i++) {
|
|
988
|
-
const ptr = this.ptrs[i];
|
|
989
|
-
buf.set(ptr.ptr.encode(pos), ptr.pos);
|
|
990
|
-
pos += ptr.buffer.length;
|
|
991
|
-
}
|
|
992
|
-
if (clean) {
|
|
993
|
-
this.buffers = [];
|
|
994
|
-
for (const p of this.ptrs)
|
|
995
|
-
p.buffer.fill(0);
|
|
996
|
-
this.ptrs = [];
|
|
997
|
-
this.finished = true;
|
|
998
|
-
this.bitBuf = 0;
|
|
999
|
-
}
|
|
1000
|
-
return buf;
|
|
1001
|
-
}
|
|
1002
|
-
bits(value, bits) {
|
|
1003
|
-
if (bits > 32)
|
|
1004
|
-
throw this.err("writeBits: cannot write more than 32 bits in single call");
|
|
1005
|
-
if (value >= 2 ** bits)
|
|
1006
|
-
throw this.err(`writeBits: value (${value}) >= 2**bits (${bits})`);
|
|
1007
|
-
while (bits) {
|
|
1008
|
-
const take = Math.min(bits, 8 - this.bitPos);
|
|
1009
|
-
this.bitBuf = this.bitBuf << take | value >> bits - take;
|
|
1010
|
-
this.bitPos += take;
|
|
1011
|
-
bits -= take;
|
|
1012
|
-
value &= 2 ** bits - 1;
|
|
1013
|
-
if (this.bitPos === 8) {
|
|
1014
|
-
this.bitPos = 0;
|
|
1015
|
-
this.buffers.push(new Uint8Array([this.bitBuf]));
|
|
1016
|
-
this.pos++;
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
};
|
|
1021
|
-
function _wrap(inner) {
|
|
1022
|
-
return {
|
|
1023
|
-
// NOTE: we cannot export validate here, since it is likely mistake.
|
|
1024
|
-
encodeStream: inner.encodeStream,
|
|
1025
|
-
decodeStream: inner.decodeStream,
|
|
1026
|
-
size: inner.size,
|
|
1027
|
-
encode: (value) => {
|
|
1028
|
-
const w = new _Writer();
|
|
1029
|
-
inner.encodeStream(w, value);
|
|
1030
|
-
return w.finish();
|
|
1031
|
-
},
|
|
1032
|
-
decode: (data, opts = {}) => {
|
|
1033
|
-
const r = new _Reader(data, opts);
|
|
1034
|
-
const res = inner.decodeStream(r);
|
|
1035
|
-
r.finish();
|
|
1036
|
-
return res;
|
|
1037
|
-
}
|
|
1038
|
-
};
|
|
1039
|
-
}
|
|
1040
|
-
function validate(inner, fn) {
|
|
1041
|
-
if (!isCoder(inner))
|
|
1042
|
-
throw new Error(`validate: invalid inner value ${inner}`);
|
|
1043
|
-
if (typeof fn !== "function")
|
|
1044
|
-
throw new Error("validate: fn should be function");
|
|
1045
|
-
return _wrap({
|
|
1046
|
-
size: inner.size,
|
|
1047
|
-
encodeStream: (w, value) => {
|
|
1048
|
-
let res;
|
|
1049
|
-
try {
|
|
1050
|
-
res = fn(value);
|
|
1051
|
-
} catch (e) {
|
|
1052
|
-
throw w.err(e);
|
|
1053
|
-
}
|
|
1054
|
-
inner.encodeStream(w, res);
|
|
1055
|
-
},
|
|
1056
|
-
decodeStream: (r) => {
|
|
1057
|
-
const res = inner.decodeStream(r);
|
|
1058
|
-
try {
|
|
1059
|
-
return fn(res);
|
|
1060
|
-
} catch (e) {
|
|
1061
|
-
throw r.err(e);
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
});
|
|
1065
|
-
}
|
|
1066
|
-
var wrap = (inner) => {
|
|
1067
|
-
const res = _wrap(inner);
|
|
1068
|
-
return inner.validate ? validate(res, inner.validate) : res;
|
|
1069
|
-
};
|
|
1070
|
-
var isBaseCoder = (elm) => isPlainObject(elm) && typeof elm.decode === "function" && typeof elm.encode === "function";
|
|
1071
|
-
function isCoder(elm) {
|
|
1072
|
-
return isPlainObject(elm) && isBaseCoder(elm) && typeof elm.encodeStream === "function" && typeof elm.decodeStream === "function" && (elm.size === void 0 || isNum(elm.size));
|
|
1073
|
-
}
|
|
1074
|
-
var view = (len, opts) => wrap({
|
|
1075
|
-
size: len,
|
|
1076
|
-
encodeStream: (w, value) => w.writeView(len, (view2) => opts.write(view2, value)),
|
|
1077
|
-
decodeStream: (r) => r.readView(len, opts.read),
|
|
1078
|
-
validate: (value) => {
|
|
1079
|
-
if (typeof value !== "number")
|
|
1080
|
-
throw new Error(`viewCoder: expected number, got ${typeof value}`);
|
|
1081
|
-
if (opts.validate)
|
|
1082
|
-
opts.validate(value);
|
|
1083
|
-
return value;
|
|
1084
|
-
}
|
|
1085
|
-
});
|
|
1086
|
-
var intView = (len, signed, opts) => {
|
|
1087
|
-
const bits = len * 8;
|
|
1088
|
-
const maxVal = 2 ** bits;
|
|
1089
|
-
const validateUnsigned = (value) => {
|
|
1090
|
-
if (!isNum(value))
|
|
1091
|
-
throw new Error(`uintView: value is not safe integer: ${value}`);
|
|
1092
|
-
if (0 > value || value >= maxVal) {
|
|
1093
|
-
throw new Error(`uintView: value out of bounds. Expected 0 <= ${value} < ${maxVal}`);
|
|
1094
|
-
}
|
|
1095
|
-
};
|
|
1096
|
-
return view(len, {
|
|
1097
|
-
write: opts.write,
|
|
1098
|
-
read: opts.read,
|
|
1099
|
-
validate: validateUnsigned
|
|
1100
|
-
});
|
|
1101
|
-
};
|
|
1102
|
-
var U32LE = /* @__PURE__ */ intView(4, false, {
|
|
1103
|
-
read: (view2, pos) => view2.getUint32(pos, true),
|
|
1104
|
-
write: (view2, value) => view2.setUint32(0, value, true)
|
|
1105
|
-
});
|
|
1106
|
-
var U16LE = /* @__PURE__ */ intView(2, false, {
|
|
1107
|
-
read: (view2, pos) => view2.getUint16(pos, true),
|
|
1108
|
-
write: (view2, value) => view2.setUint16(0, value, true)
|
|
1109
|
-
});
|
|
1110
|
-
var U8 = /* @__PURE__ */ intView(1, false, {
|
|
1111
|
-
read: (view2, pos) => view2.getUint8(pos),
|
|
1112
|
-
write: (view2, value) => view2.setUint8(0, value)
|
|
1113
|
-
});
|
|
1114
720
|
var ARKADE_OP = {
|
|
1115
721
|
// Merkle Branch Verification (0xb3 — repurposed NOP4 slot)
|
|
1116
722
|
MERKLEBRANCHVERIFY: 179,
|
|
@@ -1147,7 +753,6 @@ var ARKADE_OP = {
|
|
|
1147
753
|
MODEXP: 218,
|
|
1148
754
|
// VTXO Expiry & Emulator Clock (0xdb-0xdc)
|
|
1149
755
|
PUSHEXPIRY: 219,
|
|
1150
|
-
// compiler artifacts use OP_CHECKTIME.
|
|
1151
756
|
CHECKTIME: 220,
|
|
1152
757
|
// 0xdd-0xdf are unassigned (OP_UNKNOWN221-223)
|
|
1153
758
|
// EC Operations (0xe0-0xe2)
|
|
@@ -1249,7 +854,7 @@ function getOpcodeValue(name) {
|
|
|
1249
854
|
|
|
1250
855
|
// src/arkade/bignum.ts
|
|
1251
856
|
var bignum_exports = {};
|
|
1252
|
-
|
|
857
|
+
chunk7NK6XFC3_cjs.__export(bignum_exports, {
|
|
1253
858
|
BIGNUM_MAX_BYTES: () => BIGNUM_MAX_BYTES,
|
|
1254
859
|
decode: () => decode,
|
|
1255
860
|
encode: () => encode
|
|
@@ -1277,7 +882,7 @@ var ArkadeOPNames = {};
|
|
|
1277
882
|
for (const [k, v] of Object.entries(ARKADE_OPS)) {
|
|
1278
883
|
if (typeof v === "number") ArkadeOPNames[v] = k;
|
|
1279
884
|
}
|
|
1280
|
-
var ArkadeScript = wrap({
|
|
885
|
+
var ArkadeScript = P__namespace.wrap({
|
|
1281
886
|
encodeStream: (w, value) => {
|
|
1282
887
|
for (let o of value) {
|
|
1283
888
|
if (typeof o === "string") {
|
|
@@ -1303,10 +908,10 @@ var ArkadeScript = wrap({
|
|
|
1303
908
|
w.byte(len);
|
|
1304
909
|
} else if (len <= 65535) {
|
|
1305
910
|
w.byte(btcSigner.OP.PUSHDATA2);
|
|
1306
|
-
w.bytes(U16LE.encode(len));
|
|
911
|
+
w.bytes(P__namespace.U16LE.encode(len));
|
|
1307
912
|
} else {
|
|
1308
913
|
w.byte(btcSigner.OP.PUSHDATA4);
|
|
1309
|
-
w.bytes(U32LE.encode(len));
|
|
914
|
+
w.bytes(P__namespace.U32LE.encode(len));
|
|
1310
915
|
}
|
|
1311
916
|
w.bytes(o);
|
|
1312
917
|
}
|
|
@@ -1318,9 +923,9 @@ var ArkadeScript = wrap({
|
|
|
1318
923
|
if (btcSigner.OP.OP_0 < cur && cur <= btcSigner.OP.PUSHDATA4) {
|
|
1319
924
|
let len;
|
|
1320
925
|
if (cur < btcSigner.OP.PUSHDATA1) len = cur;
|
|
1321
|
-
else if (cur === btcSigner.OP.PUSHDATA1) len = U8.decodeStream(r);
|
|
1322
|
-
else if (cur === btcSigner.OP.PUSHDATA2) len = U16LE.decodeStream(r);
|
|
1323
|
-
else if (cur === btcSigner.OP.PUSHDATA4) len = U32LE.decodeStream(r);
|
|
926
|
+
else if (cur === btcSigner.OP.PUSHDATA1) len = P__namespace.U8.decodeStream(r);
|
|
927
|
+
else if (cur === btcSigner.OP.PUSHDATA2) len = P__namespace.U16LE.decodeStream(r);
|
|
928
|
+
else if (cur === btcSigner.OP.PUSHDATA4) len = P__namespace.U32LE.decodeStream(r);
|
|
1324
929
|
else throw new Error("Should be not possible");
|
|
1325
930
|
out.push(r.bytes(len));
|
|
1326
931
|
} else if (cur === 0) {
|
|
@@ -1438,7 +1043,7 @@ function computeArkadeScriptPublicKey(pubKey, script) {
|
|
|
1438
1043
|
// src/script/vhtlc.ts
|
|
1439
1044
|
exports.VHTLC = void 0;
|
|
1440
1045
|
((VHTLC2) => {
|
|
1441
|
-
class BaseScript extends
|
|
1046
|
+
class BaseScript extends chunk7NK6XFC3_cjs.VtxoScript {
|
|
1442
1047
|
options;
|
|
1443
1048
|
claimScript;
|
|
1444
1049
|
refundScript;
|
|
@@ -1465,27 +1070,27 @@ exports.VHTLC = void 0;
|
|
|
1465
1070
|
unilateralRefundWithoutReceiverDelay
|
|
1466
1071
|
} = options;
|
|
1467
1072
|
const conditionScript = preimageCondition(preimageHash);
|
|
1468
|
-
const claimScript =
|
|
1073
|
+
const claimScript = chunk7NK6XFC3_cjs.ConditionMultisigTapscript.encode({
|
|
1469
1074
|
conditionScript,
|
|
1470
1075
|
pubkeys: [receiver, server]
|
|
1471
1076
|
}).script;
|
|
1472
|
-
const refundScript =
|
|
1077
|
+
const refundScript = chunk7NK6XFC3_cjs.MultisigTapscript.encode({
|
|
1473
1078
|
pubkeys: [sender, receiver, server]
|
|
1474
1079
|
}).script;
|
|
1475
|
-
const refundWithoutReceiverScript =
|
|
1080
|
+
const refundWithoutReceiverScript = chunk7NK6XFC3_cjs.CLTVMultisigTapscript.encode({
|
|
1476
1081
|
absoluteTimelock: refundLocktime,
|
|
1477
1082
|
pubkeys: [sender, server]
|
|
1478
1083
|
}).script;
|
|
1479
|
-
const unilateralClaimScript =
|
|
1084
|
+
const unilateralClaimScript = chunk7NK6XFC3_cjs.ConditionCSVMultisigTapscript.encode({
|
|
1480
1085
|
conditionScript,
|
|
1481
1086
|
timelock: unilateralClaimDelay,
|
|
1482
1087
|
pubkeys: [receiver]
|
|
1483
1088
|
}).script;
|
|
1484
|
-
const unilateralRefundScript =
|
|
1089
|
+
const unilateralRefundScript = chunk7NK6XFC3_cjs.CSVMultisigTapscript.encode({
|
|
1485
1090
|
timelock: unilateralRefundDelay,
|
|
1486
1091
|
pubkeys: [sender, receiver]
|
|
1487
1092
|
}).script;
|
|
1488
|
-
const unilateralRefundWithoutReceiverScript =
|
|
1093
|
+
const unilateralRefundWithoutReceiverScript = chunk7NK6XFC3_cjs.CSVMultisigTapscript.encode({
|
|
1489
1094
|
timelock: unilateralRefundWithoutReceiverDelay,
|
|
1490
1095
|
pubkeys: [sender]
|
|
1491
1096
|
}).script;
|
|
@@ -1505,7 +1110,7 @@ exports.VHTLC = void 0;
|
|
|
1505
1110
|
const covenants = options.nonInteractiveParameters;
|
|
1506
1111
|
if (covenants) {
|
|
1507
1112
|
arkadeScriptNic = enforcePayToMaybeAsset(covenants.receiverPkScript, options.asset);
|
|
1508
|
-
nonInteractiveClaimScript =
|
|
1113
|
+
nonInteractiveClaimScript = chunk7NK6XFC3_cjs.ConditionMultisigTapscript.encode({
|
|
1509
1114
|
conditionScript,
|
|
1510
1115
|
pubkeys: [
|
|
1511
1116
|
server,
|
|
@@ -1518,12 +1123,12 @@ exports.VHTLC = void 0;
|
|
|
1518
1123
|
covenants.emulatorPubkey,
|
|
1519
1124
|
arkadeScriptNir
|
|
1520
1125
|
);
|
|
1521
|
-
nonInteractiveRefundScript =
|
|
1126
|
+
nonInteractiveRefundScript = chunk7NK6XFC3_cjs.MultisigTapscript.encode({
|
|
1522
1127
|
pubkeys: [server, receiver, nirCosigner]
|
|
1523
1128
|
}).script;
|
|
1524
1129
|
scripts.push(nonInteractiveRefundScript);
|
|
1525
1130
|
if (covenants.legacy !== "preTimelockedRefund") {
|
|
1526
|
-
nonInteractiveRefundWithoutReceiverScript =
|
|
1131
|
+
nonInteractiveRefundWithoutReceiverScript = chunk7NK6XFC3_cjs.CLTVMultisigTapscript.encode({
|
|
1527
1132
|
absoluteTimelock: refundLocktime,
|
|
1528
1133
|
pubkeys: [server, nirCosigner]
|
|
1529
1134
|
}).script;
|
|
@@ -1602,54 +1207,19 @@ exports.VHTLC = void 0;
|
|
|
1602
1207
|
/**
|
|
1603
1208
|
* Return the timelocked non-interactive refund tapleaf and its ArkadeScript.
|
|
1604
1209
|
*
|
|
1605
|
-
*
|
|
1606
|
-
*
|
|
1607
|
-
*
|
|
1608
|
-
*
|
|
1609
|
-
* the
|
|
1610
|
-
*
|
|
1611
|
-
*
|
|
1612
|
-
*
|
|
1613
|
-
* TapLeafScript} as `tapLeafScript`, this script's {@link
|
|
1614
|
-
* VtxoScript.encode} as `tapTree`), plus its checkpoint tx.
|
|
1615
|
-
* 2. Attach the ArkadeScript this method returns to the spent
|
|
1616
|
-
* input via an `EmulatorPacket` (type 1) — `{ vin, script:
|
|
1617
|
-
* <this ArkadeScript>, witness: <empty> }`, empty because the
|
|
1618
|
-
* script pushes its own input/output index with
|
|
1619
|
-
* `PUSHCURRENTINPUTINDEX` rather than reading one from the
|
|
1620
|
-
* witness — wrapped in an `Extension` OP_RETURN output on the
|
|
1621
|
-
* ark tx.
|
|
1622
|
-
* 3. Attach the spent input's OWN creating ark tx as `PrevArkTx` on
|
|
1623
|
-
* input 0 — required so the emulator can resolve that input's
|
|
1624
|
-
* prevout pkScript/value; it does not otherwise have them.
|
|
1625
|
-
* 4. POST the (base64-PSBT) ark tx and checkpoint(s) as `{ arkTx,
|
|
1626
|
-
* checkpointTxs }` to the emulator's `POST /v1/tx`.
|
|
1210
|
+
* Spent through the generic covenant path ({@link EmulatorProvider},
|
|
1211
|
+
* {@link ArkadeTransactionBuilder}): build the ark tx on this leaf plus its checkpoint;
|
|
1212
|
+
* attach this ArkadeScript to the input in an `EmulatorPacket` (type 1, empty witness:
|
|
1213
|
+
* the script pushes its own index with `PUSHCURRENTINPUTINDEX`) inside an `Extension`
|
|
1214
|
+
* OP_RETURN; attach the input's creating ark tx as `PrevArkTx` (the emulator can't
|
|
1215
|
+
* otherwise resolve its prevout); POST to the emulator's `/v1/tx`. The emulator co-signs
|
|
1216
|
+
* for `nirCosigner` only if `enforcePayTo(senderPkScript)` holds, and finalizes with arkd.
|
|
1217
|
+
* `server`'s signature is still required at consensus level, outside the covenant.
|
|
1627
1218
|
*
|
|
1628
|
-
*
|
|
1629
|
-
*
|
|
1630
|
-
*
|
|
1631
|
-
*
|
|
1632
|
-
* check passing does the emulator sign for `nirCosigner` (the
|
|
1633
|
-
* `emulatorPubkey` tweaked by this ArkadeScript's hash); the
|
|
1634
|
-
* response carries the fully co-signed `signedArkTx` and
|
|
1635
|
-
* `signedCheckpointTxs` — `ArkadeTransactionBuilder.send()`'s own
|
|
1636
|
-
* comment on this path: "the emulator executes the arkade script
|
|
1637
|
-
* and finalizes with arkd" — no separate call to arkd is made by
|
|
1638
|
-
* this SDK for a covenant spend.
|
|
1639
|
-
* Neither `server` nor `receiver` play any part in that check: this
|
|
1640
|
-
* leaf's tapscript still requires `server`'s own signature
|
|
1641
|
-
* alongside `nirCosigner`'s (see the class doc above), but that is
|
|
1642
|
-
* consensus-level multisig, not something the covenant enforces.
|
|
1643
|
-
*
|
|
1644
|
-
* NOT SPENDABLE UNTIL `refundLocktime` MATURES — the tapscript's
|
|
1645
|
-
* `OP_CHECKLOCKTIMEVERIFY` is arkd's concern, not the emulator's;
|
|
1646
|
-
* the emulator will happily co-sign an immature spend and arkd will
|
|
1647
|
-
* then refuse it. A block-height-typed `refundLocktime` (below the
|
|
1648
|
-
* standard height/timestamp boundary this SDK names
|
|
1649
|
-
* `CLTV_HEIGHT_THRESHOLD`, 500,000,000, in
|
|
1650
|
-
* `src/contracts/handlers/helpers.ts`) is refused by arkd for a
|
|
1651
|
-
* forfeit-eligible leaf independent of maturity — use a
|
|
1652
|
-
* seconds-typed (absolute Unix timestamp) value.
|
|
1219
|
+
* The emulator does not check `refundLocktime`: it co-signs an immature spend and arkd's
|
|
1220
|
+
* CLTV refuses it. arkd also refuses a block-height `refundLocktime`
|
|
1221
|
+
* (< `CLTV_HEIGHT_THRESHOLD`, 500,000,000) on a forfeit-eligible leaf regardless of
|
|
1222
|
+
* maturity: use a seconds-typed (Unix timestamp) value.
|
|
1653
1223
|
*/
|
|
1654
1224
|
nonInteractiveRefundWithoutReceiver() {
|
|
1655
1225
|
if (!this.nonInteractiveRefundWithoutReceiverScript || !this.nonInteractiveRefundWithoutReceiverArkadeScript) {
|
|
@@ -1792,10 +1362,7 @@ function enforcePayToAsset(destinationPkScript, asset) {
|
|
|
1792
1362
|
}
|
|
1793
1363
|
const inspectionTxid = Uint8Array.from(asset.txid).reverse();
|
|
1794
1364
|
return ArkadeScript.encode([
|
|
1795
|
-
// The output carries at least
|
|
1796
|
-
// Output index is the input's -- the same index alignment the sat
|
|
1797
|
-
// covenant relies on, and the same liveness obligation on whoever
|
|
1798
|
-
// assembles the spend.
|
|
1365
|
+
// The output at the input's index carries at least the input's amount of the asset.
|
|
1799
1366
|
"PUSHCURRENTINPUTINDEX",
|
|
1800
1367
|
inspectionTxid,
|
|
1801
1368
|
asset.groupIndex,
|
|
@@ -1837,9 +1404,9 @@ var VHTLCContractHandler = {
|
|
|
1837
1404
|
server: base.hex.encode(params.server),
|
|
1838
1405
|
hash: base.hex.encode(params.preimageHash),
|
|
1839
1406
|
refundLocktime: params.refundLocktime.toString(),
|
|
1840
|
-
claimDelay:
|
|
1841
|
-
refundDelay:
|
|
1842
|
-
refundNoReceiverDelay:
|
|
1407
|
+
claimDelay: chunk7NK6XFC3_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
|
|
1408
|
+
refundDelay: chunk7NK6XFC3_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
|
|
1409
|
+
refundNoReceiverDelay: chunk7NK6XFC3_cjs.timelockToSequence(
|
|
1843
1410
|
params.unilateralRefundWithoutReceiverDelay
|
|
1844
1411
|
).toString()
|
|
1845
1412
|
};
|
|
@@ -1851,147 +1418,26 @@ var VHTLCContractHandler = {
|
|
|
1851
1418
|
server: base.hex.decode(params.server),
|
|
1852
1419
|
preimageHash: base.hex.decode(params.hash),
|
|
1853
1420
|
refundLocktime: BigInt(params.refundLocktime),
|
|
1854
|
-
unilateralClaimDelay:
|
|
1855
|
-
unilateralRefundDelay:
|
|
1856
|
-
unilateralRefundWithoutReceiverDelay:
|
|
1421
|
+
unilateralClaimDelay: chunk7NK6XFC3_cjs.sequenceToTimelock(Number(params.claimDelay)),
|
|
1422
|
+
unilateralRefundDelay: chunk7NK6XFC3_cjs.sequenceToTimelock(Number(params.refundDelay)),
|
|
1423
|
+
unilateralRefundWithoutReceiverDelay: chunk7NK6XFC3_cjs.sequenceToTimelock(
|
|
1857
1424
|
Number(params.refundNoReceiverDelay)
|
|
1858
1425
|
)
|
|
1859
1426
|
};
|
|
1860
1427
|
},
|
|
1861
1428
|
/**
|
|
1862
|
-
* Select spending path based on context.
|
|
1863
|
-
*
|
|
1864
|
-
* Role is determined from `context.role` or by matching
|
|
1865
|
-
* `context.walletDescriptor`
|
|
1866
|
-
* against sender/receiver in contract params.
|
|
1429
|
+
* Select spending path based on context. Role comes from `context.role` or from matching
|
|
1430
|
+
* `context.walletDescriptor` against sender/receiver.
|
|
1867
1431
|
*/
|
|
1868
1432
|
selectPath(script, contract, context) {
|
|
1869
|
-
|
|
1870
|
-
const preimage = contract.params?.preimage;
|
|
1871
|
-
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
1872
|
-
if (!role) {
|
|
1873
|
-
return null;
|
|
1874
|
-
}
|
|
1875
|
-
if (context.collaborative) {
|
|
1876
|
-
if (role === "receiver" && preimage) {
|
|
1877
|
-
return {
|
|
1878
|
-
leaf: script.claim(),
|
|
1879
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
1880
|
-
};
|
|
1881
|
-
}
|
|
1882
|
-
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
1883
|
-
return {
|
|
1884
|
-
leaf: script.refundWithoutReceiver()
|
|
1885
|
-
};
|
|
1886
|
-
}
|
|
1887
|
-
return null;
|
|
1888
|
-
}
|
|
1889
|
-
if (role === "receiver" && preimage) {
|
|
1890
|
-
const sequence = Number(contract.params.claimDelay);
|
|
1891
|
-
if (!isCsvSpendable(context, sequence)) return null;
|
|
1892
|
-
return {
|
|
1893
|
-
leaf: script.unilateralClaim(),
|
|
1894
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
1895
|
-
sequence
|
|
1896
|
-
};
|
|
1897
|
-
}
|
|
1898
|
-
if (role === "sender") {
|
|
1899
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
1900
|
-
if (!isCsvSpendable(context, sequence)) return null;
|
|
1901
|
-
return {
|
|
1902
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
1903
|
-
sequence
|
|
1904
|
-
};
|
|
1905
|
-
}
|
|
1906
|
-
return null;
|
|
1433
|
+
return selectVhtlcPath(script, contract, context);
|
|
1907
1434
|
},
|
|
1908
|
-
/**
|
|
1909
|
-
* Get all possible spending paths (no timelock checks).
|
|
1910
|
-
*
|
|
1911
|
-
* Role is determined from `context.role` or by matching
|
|
1912
|
-
* `context.walletDescriptor`
|
|
1913
|
-
* against sender/receiver in contract params.
|
|
1914
|
-
*/
|
|
1435
|
+
/** All possible spending paths (no timelock checks); role as in {@link selectPath}. */
|
|
1915
1436
|
getAllSpendingPaths(script, contract, context) {
|
|
1916
|
-
|
|
1917
|
-
const paths = [];
|
|
1918
|
-
if (!role) {
|
|
1919
|
-
return paths;
|
|
1920
|
-
}
|
|
1921
|
-
const preimage = contract.params?.preimage;
|
|
1922
|
-
if (context.collaborative) {
|
|
1923
|
-
if (role === "receiver" && preimage) {
|
|
1924
|
-
paths.push({
|
|
1925
|
-
leaf: script.claim(),
|
|
1926
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
1927
|
-
});
|
|
1928
|
-
}
|
|
1929
|
-
if (role === "sender") {
|
|
1930
|
-
paths.push({
|
|
1931
|
-
leaf: script.refundWithoutReceiver()
|
|
1932
|
-
});
|
|
1933
|
-
}
|
|
1934
|
-
} else {
|
|
1935
|
-
if (role === "receiver" && preimage) {
|
|
1936
|
-
const sequence = Number(contract.params.claimDelay);
|
|
1937
|
-
paths.push({
|
|
1938
|
-
leaf: script.unilateralClaim(),
|
|
1939
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
1940
|
-
sequence
|
|
1941
|
-
});
|
|
1942
|
-
}
|
|
1943
|
-
if (role === "sender") {
|
|
1944
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
1945
|
-
paths.push({
|
|
1946
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
1947
|
-
sequence
|
|
1948
|
-
});
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
return paths;
|
|
1437
|
+
return vhtlcAllSpendingPaths(script, contract, context);
|
|
1952
1438
|
},
|
|
1953
1439
|
getSpendablePaths(script, contract, context) {
|
|
1954
|
-
|
|
1955
|
-
const paths = [];
|
|
1956
|
-
if (!role) {
|
|
1957
|
-
return paths;
|
|
1958
|
-
}
|
|
1959
|
-
const preimage = contract.params?.preimage;
|
|
1960
|
-
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
1961
|
-
if (context.collaborative) {
|
|
1962
|
-
if (role === "receiver" && preimage) {
|
|
1963
|
-
paths.push({
|
|
1964
|
-
leaf: script.claim(),
|
|
1965
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
1966
|
-
});
|
|
1967
|
-
}
|
|
1968
|
-
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
1969
|
-
paths.push({
|
|
1970
|
-
leaf: script.refundWithoutReceiver()
|
|
1971
|
-
});
|
|
1972
|
-
}
|
|
1973
|
-
return paths;
|
|
1974
|
-
}
|
|
1975
|
-
if (role === "receiver" && preimage) {
|
|
1976
|
-
const sequence = Number(contract.params.claimDelay);
|
|
1977
|
-
if (isCsvSpendable(context, sequence)) {
|
|
1978
|
-
paths.push({
|
|
1979
|
-
leaf: script.unilateralClaim(),
|
|
1980
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
1981
|
-
sequence
|
|
1982
|
-
});
|
|
1983
|
-
}
|
|
1984
|
-
}
|
|
1985
|
-
if (role === "sender") {
|
|
1986
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
1987
|
-
if (isCsvSpendable(context, sequence)) {
|
|
1988
|
-
paths.push({
|
|
1989
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
1990
|
-
sequence
|
|
1991
|
-
});
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
return paths;
|
|
1440
|
+
return vhtlcSpendablePaths(script, contract, context);
|
|
1995
1441
|
},
|
|
1996
1442
|
/**
|
|
1997
1443
|
* Refuse an explicit spend of a lockup whose refund path has not opened.
|
|
@@ -2002,70 +1448,38 @@ var VHTLCContractHandler = {
|
|
|
2002
1448
|
assertVhtlcSpendableNow(contract, context);
|
|
2003
1449
|
},
|
|
2004
1450
|
/**
|
|
2005
|
-
* Never. A live VHTLC is escrow:
|
|
2006
|
-
*
|
|
2007
|
-
* lockup out from under a swap the counterparty is still entitled to
|
|
2008
|
-
* complete, or race a claim already in flight.
|
|
2009
|
-
*
|
|
2010
|
-
* Two narrow reasons, and neither is "spending this would destroy the
|
|
2011
|
-
* VTXO". It would not: the leaf {@link deriveTapscripts} stamps is
|
|
2012
|
-
* `refundWithoutReceiver` — `CLTV[sender, server]`, the sender's OWN
|
|
2013
|
-
* refund, which the server rejects until `refundLocktime` matures. The
|
|
2014
|
-
* reasons are that an escrowed lockup must not count toward the
|
|
2015
|
-
* `available` balance bucket, and that generic RENEWAL must not silently
|
|
2016
|
-
* execute a refund the caller never asked for — `runPeriodicSettle` selects
|
|
2017
|
-
* through `getSpendableVtxos`, which this gate filters, and it runs
|
|
2018
|
-
* unprompted whenever a wallet is built without an explicit
|
|
2019
|
-
* `settlementConfig`.
|
|
1451
|
+
* Never. A live VHTLC is escrow: generic selection (send, settle, renewal, offboard) would
|
|
1452
|
+
* move the lockup out from under a swap the counterparty may still complete, or race a claim.
|
|
2020
1453
|
*
|
|
2021
|
-
*
|
|
2022
|
-
*
|
|
2023
|
-
*
|
|
2024
|
-
*
|
|
1454
|
+
* The stamped leaf is the sender's own CLTV refund, so this is not about destroying the
|
|
1455
|
+
* VTXO: an escrowed lockup must not count toward the `available` balance, and generic
|
|
1456
|
+
* renewal (`runPeriodicSettle`, unprompted without an explicit `settlementConfig`) must not
|
|
1457
|
+
* silently execute a refund nobody asked for.
|
|
2025
1458
|
*
|
|
2026
|
-
*
|
|
2027
|
-
*
|
|
1459
|
+
* **Inseparable from {@link deriveTapscripts}**: deriving the leaf without closing this gate
|
|
1460
|
+
* hands renewal an escrow. Recovery filters on {@link assertSpendableNow} instead; this
|
|
1461
|
+
* permanent gate would strand a matured lockup.
|
|
2028
1462
|
*/
|
|
2029
1463
|
isGenericallySpendable: () => false,
|
|
2030
1464
|
/**
|
|
2031
1465
|
* The annotation leaf stamped onto every VTXO locked to this contract.
|
|
2032
1466
|
*
|
|
2033
|
-
* **
|
|
2034
|
-
* `
|
|
2035
|
-
*
|
|
2036
|
-
* script version has a `forfeit()` — `VtxoScript` does not define one and
|
|
2037
|
-
* `VHTLC.BaseScript` does not add one. The fallback therefore threw
|
|
2038
|
-
* `legacy.forfeit is not a function`, `annotatableIn` caught it, and
|
|
2039
|
-
* `fetchContractVtxosBulk` dropped this contract's VTXOs before they were
|
|
2040
|
-
* persisted. The row existed and was watched while its balance stayed
|
|
2041
|
-
* permanently invisible, and `getSyncState()` reported `degraded` forever.
|
|
1467
|
+
* **Required, not an optimization.** Without it `deriveContractTapscripts` falls back to
|
|
1468
|
+
* `script.forfeit()`, which no VHTLC script has, so the contract's VTXOs are dropped before
|
|
1469
|
+
* persisting: balance invisible, `getSyncState()` degraded forever.
|
|
2042
1470
|
*
|
|
2043
|
-
* `refundWithoutReceiver` is the
|
|
2044
|
-
*
|
|
2045
|
-
*
|
|
2046
|
-
*
|
|
2047
|
-
* the receiver and need a preimage the sender does not have; `refund` and
|
|
2048
|
-
* `unilateralRefund` both need the counterparty's signature, which this
|
|
2049
|
-
* protocol has no message to ask for. V1 has no covenant leaves at all.
|
|
1471
|
+
* `refundWithoutReceiver` is the only collaborative path this wallet can satisfy as sender
|
|
1472
|
+
* (kept in step with `selectPath`): the claim leaves need the preimage, and `refund` /
|
|
1473
|
+
* `unilateralRefund` need a counterparty signature the protocol can't request. V1 has no
|
|
1474
|
+
* covenant leaves.
|
|
2050
1475
|
*
|
|
2051
|
-
* **It carries a CLTV
|
|
2052
|
-
*
|
|
2053
|
-
*
|
|
2054
|
-
*
|
|
2055
|
-
* derived per contract and knows no clock; `recoverVtxos` filters on
|
|
2056
|
-
* {@link assertSpendableNow} for it.
|
|
2057
|
-
*
|
|
2058
|
-
* **Role-blind.** A receiver's row gets the same leaf, which names keys that
|
|
2059
|
-
* wallet does not hold, so it is satisfiable only by the wallet holding the
|
|
2060
|
-
* lockup's `sender` key and fails at intent registration for anyone else.
|
|
1476
|
+
* **It carries a CLTV**: a settlement on it is rejected until `refundLocktime` matures, and
|
|
1477
|
+
* the per-contract annotation knows no clock, so `recoverVtxos` filters on
|
|
1478
|
+
* {@link assertSpendableNow}. **Role-blind**: a receiver's row gets the same leaf, satisfiable
|
|
1479
|
+
* only by the `sender` key holder; anyone else fails at intent registration.
|
|
2061
1480
|
*/
|
|
2062
1481
|
deriveTapscripts(script) {
|
|
2063
|
-
|
|
2064
|
-
return {
|
|
2065
|
-
forfeitTapLeafScript: leaf,
|
|
2066
|
-
intentTapLeafScript: leaf,
|
|
2067
|
-
tapTree: script.encode()
|
|
2068
|
-
};
|
|
1482
|
+
return deriveVhtlcTapscripts(script);
|
|
2069
1483
|
}
|
|
2070
1484
|
};
|
|
2071
1485
|
var parseGroupIndex = (raw) => {
|
|
@@ -2099,48 +1513,26 @@ var VHTLCV2ContractHandler = {
|
|
|
2099
1513
|
server: base.hex.encode(params.server),
|
|
2100
1514
|
hash: base.hex.encode(params.preimageHash),
|
|
2101
1515
|
refundLocktime: params.refundLocktime.toString(),
|
|
2102
|
-
claimDelay:
|
|
2103
|
-
refundDelay:
|
|
2104
|
-
refundNoReceiverDelay:
|
|
1516
|
+
claimDelay: chunk7NK6XFC3_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
|
|
1517
|
+
refundDelay: chunk7NK6XFC3_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
|
|
1518
|
+
refundNoReceiverDelay: chunk7NK6XFC3_cjs.timelockToSequence(
|
|
2105
1519
|
params.unilateralRefundWithoutReceiverDelay
|
|
2106
1520
|
).toString(),
|
|
2107
|
-
//
|
|
2108
|
-
//
|
|
2109
|
-
//
|
|
2110
|
-
// The group maps onto them without loss — one emulator key serves
|
|
2111
|
-
// both covenant destinations by construction (see the option's doc
|
|
2112
|
-
// on VHTLC.Options), so the two emulator-key columns always hold
|
|
2113
|
-
// the same value on a row written from here.
|
|
2114
|
-
//
|
|
2115
|
-
// Spread rather than written as `undefined`: a `Record<string,
|
|
2116
|
-
// string>` round-tripped through a repository must not gain keys
|
|
2117
|
-
// whose value is the string "undefined".
|
|
1521
|
+
// Per-leaf on-disk keys predate the grouped param and older rows carry exactly these;
|
|
1522
|
+
// both emulator columns hold the same key. Spread, not `undefined`, so a repository
|
|
1523
|
+
// round-trip never gains "undefined" string values.
|
|
2118
1524
|
...covenants && {
|
|
2119
1525
|
nonInteractiveClaimReceiverPkScript: base.hex.encode(covenants.receiverPkScript),
|
|
2120
1526
|
nonInteractiveClaimEmulatorPubkey: base.hex.encode(covenants.emulatorPubkey),
|
|
2121
1527
|
nonInteractiveRefundSenderPkScript: base.hex.encode(covenants.senderPkScript),
|
|
2122
1528
|
nonInteractiveRefundEmulatorPubkey: base.hex.encode(covenants.emulatorPubkey),
|
|
2123
|
-
// The legacy marker is
|
|
2124
|
-
// row carrying it re-derives the full suite (nine leaves), a
|
|
2125
|
-
// row lacking it the pre-timelocked-refund eight — the same
|
|
2126
|
-
// encoding older SDKs wrote for eight-leaf rows, so those rows
|
|
2127
|
-
// read back unchanged. Spread rather than a "false"/"undefined"
|
|
2128
|
-
// string: a dropped flag re-derives the EIGHT-leaf script, a
|
|
2129
|
-
// different pkScript, and registration dies at
|
|
2130
|
-
// `upsertContractRow` with an opaque `Script mismatch`.
|
|
1529
|
+
// The legacy (eight-leaf) marker is this key's ABSENCE, as older SDKs wrote it.
|
|
2131
1530
|
...covenants.legacy === void 0 && {
|
|
2132
1531
|
nonInteractiveRefundWithoutReceiver: "1"
|
|
2133
1532
|
}
|
|
2134
1533
|
},
|
|
2135
|
-
//
|
|
2136
|
-
//
|
|
2137
|
-
// these params; dropping the asset derives the SAT-ONLY script, so
|
|
2138
|
-
// registration died at `upsertContractRow` with a `Script mismatch`
|
|
2139
|
-
// naming two hex strings and no cause. Same silent-drop class
|
|
2140
|
-
// `validateOptions` refuses one layer up.
|
|
2141
|
-
//
|
|
2142
|
-
// Two keys rather than one blob, mirroring the script's own view of
|
|
2143
|
-
// an Asset ID as a (txid, groupIndex) pair.
|
|
1534
|
+
// Must round-trip: dropping the asset re-derives the sat-only script and registration
|
|
1535
|
+
// dies at `upsertContractRow` with an opaque `Script mismatch`.
|
|
2144
1536
|
...params.asset && {
|
|
2145
1537
|
assetTxid: base.hex.encode(params.asset.txid),
|
|
2146
1538
|
assetGroupIndex: params.asset.groupIndex.toString()
|
|
@@ -2201,9 +1593,9 @@ var VHTLCV2ContractHandler = {
|
|
|
2201
1593
|
preimageHash: base.hex.decode(params.hash),
|
|
2202
1594
|
refundLocktime: BigInt(params.refundLocktime),
|
|
2203
1595
|
...asset && { asset },
|
|
2204
|
-
unilateralClaimDelay:
|
|
2205
|
-
unilateralRefundDelay:
|
|
2206
|
-
unilateralRefundWithoutReceiverDelay:
|
|
1596
|
+
unilateralClaimDelay: chunk7NK6XFC3_cjs.sequenceToTimelock(Number(params.claimDelay)),
|
|
1597
|
+
unilateralRefundDelay: chunk7NK6XFC3_cjs.sequenceToTimelock(Number(params.refundDelay)),
|
|
1598
|
+
unilateralRefundWithoutReceiverDelay: chunk7NK6XFC3_cjs.sequenceToTimelock(
|
|
2207
1599
|
Number(params.refundNoReceiverDelay)
|
|
2208
1600
|
),
|
|
2209
1601
|
...claim && refund && {
|
|
@@ -2211,8 +1603,6 @@ var VHTLCV2ContractHandler = {
|
|
|
2211
1603
|
receiverPkScript: claim.destination,
|
|
2212
1604
|
senderPkScript: refund.destination,
|
|
2213
1605
|
emulatorPubkey: claim.emulatorPubkey,
|
|
2214
|
-
// Absence of the flag IS the legacy marker — the same
|
|
2215
|
-
// encoding older SDKs wrote for eight-leaf rows.
|
|
2216
1606
|
...params.nonInteractiveRefundWithoutReceiver !== "1" && {
|
|
2217
1607
|
legacy: "preTimelockedRefund"
|
|
2218
1608
|
}
|
|
@@ -2221,139 +1611,18 @@ var VHTLCV2ContractHandler = {
|
|
|
2221
1611
|
};
|
|
2222
1612
|
},
|
|
2223
1613
|
/**
|
|
2224
|
-
* Select spending path based on context.
|
|
2225
|
-
*
|
|
2226
|
-
* Role is determined from `context.role` or by matching
|
|
2227
|
-
* `context.walletDescriptor`
|
|
2228
|
-
* against sender/receiver in contract params.
|
|
1614
|
+
* Select spending path based on context. Role comes from `context.role` or by matching
|
|
1615
|
+
* `context.walletDescriptor` against sender/receiver.
|
|
2229
1616
|
*/
|
|
2230
1617
|
selectPath(script, contract, context) {
|
|
2231
|
-
|
|
2232
|
-
const preimage = contract.params?.preimage;
|
|
2233
|
-
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
2234
|
-
if (!role) {
|
|
2235
|
-
return null;
|
|
2236
|
-
}
|
|
2237
|
-
if (context.collaborative) {
|
|
2238
|
-
if (role === "receiver" && preimage) {
|
|
2239
|
-
return {
|
|
2240
|
-
leaf: script.claim(),
|
|
2241
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
2242
|
-
};
|
|
2243
|
-
}
|
|
2244
|
-
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
2245
|
-
return {
|
|
2246
|
-
leaf: script.refundWithoutReceiver()
|
|
2247
|
-
};
|
|
2248
|
-
}
|
|
2249
|
-
return null;
|
|
2250
|
-
}
|
|
2251
|
-
if (role === "receiver" && preimage) {
|
|
2252
|
-
const sequence = Number(contract.params.claimDelay);
|
|
2253
|
-
if (!isCsvSpendable(context, sequence)) return null;
|
|
2254
|
-
return {
|
|
2255
|
-
leaf: script.unilateralClaim(),
|
|
2256
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
2257
|
-
sequence
|
|
2258
|
-
};
|
|
2259
|
-
}
|
|
2260
|
-
if (role === "sender") {
|
|
2261
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
2262
|
-
if (!isCsvSpendable(context, sequence)) return null;
|
|
2263
|
-
return {
|
|
2264
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
2265
|
-
sequence
|
|
2266
|
-
};
|
|
2267
|
-
}
|
|
2268
|
-
return null;
|
|
1618
|
+
return selectVhtlcPath(script, contract, context);
|
|
2269
1619
|
},
|
|
2270
|
-
/**
|
|
2271
|
-
* Get all possible spending paths (no timelock checks).
|
|
2272
|
-
*
|
|
2273
|
-
* Role is determined from `context.role` or by matching
|
|
2274
|
-
* `context.walletDescriptor`
|
|
2275
|
-
* against sender/receiver in contract params.
|
|
2276
|
-
*/
|
|
1620
|
+
/** Get all possible spending paths (no timelock checks); role resolved as in `selectPath`. */
|
|
2277
1621
|
getAllSpendingPaths(script, contract, context) {
|
|
2278
|
-
|
|
2279
|
-
const paths = [];
|
|
2280
|
-
if (!role) {
|
|
2281
|
-
return paths;
|
|
2282
|
-
}
|
|
2283
|
-
const preimage = contract.params?.preimage;
|
|
2284
|
-
if (context.collaborative) {
|
|
2285
|
-
if (role === "receiver" && preimage) {
|
|
2286
|
-
paths.push({
|
|
2287
|
-
leaf: script.claim(),
|
|
2288
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
2289
|
-
});
|
|
2290
|
-
}
|
|
2291
|
-
if (role === "sender") {
|
|
2292
|
-
paths.push({
|
|
2293
|
-
leaf: script.refundWithoutReceiver()
|
|
2294
|
-
});
|
|
2295
|
-
}
|
|
2296
|
-
} else {
|
|
2297
|
-
if (role === "receiver" && preimage) {
|
|
2298
|
-
const sequence = Number(contract.params.claimDelay);
|
|
2299
|
-
paths.push({
|
|
2300
|
-
leaf: script.unilateralClaim(),
|
|
2301
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
2302
|
-
sequence
|
|
2303
|
-
});
|
|
2304
|
-
}
|
|
2305
|
-
if (role === "sender") {
|
|
2306
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
2307
|
-
paths.push({
|
|
2308
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
2309
|
-
sequence
|
|
2310
|
-
});
|
|
2311
|
-
}
|
|
2312
|
-
}
|
|
2313
|
-
return paths;
|
|
1622
|
+
return vhtlcAllSpendingPaths(script, contract, context);
|
|
2314
1623
|
},
|
|
2315
1624
|
getSpendablePaths(script, contract, context) {
|
|
2316
|
-
|
|
2317
|
-
const paths = [];
|
|
2318
|
-
if (!role) {
|
|
2319
|
-
return paths;
|
|
2320
|
-
}
|
|
2321
|
-
const preimage = contract.params?.preimage;
|
|
2322
|
-
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
2323
|
-
if (context.collaborative) {
|
|
2324
|
-
if (role === "receiver" && preimage) {
|
|
2325
|
-
paths.push({
|
|
2326
|
-
leaf: script.claim(),
|
|
2327
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
2328
|
-
});
|
|
2329
|
-
}
|
|
2330
|
-
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
2331
|
-
paths.push({
|
|
2332
|
-
leaf: script.refundWithoutReceiver()
|
|
2333
|
-
});
|
|
2334
|
-
}
|
|
2335
|
-
return paths;
|
|
2336
|
-
}
|
|
2337
|
-
if (role === "receiver" && preimage) {
|
|
2338
|
-
const sequence = Number(contract.params.claimDelay);
|
|
2339
|
-
if (isCsvSpendable(context, sequence)) {
|
|
2340
|
-
paths.push({
|
|
2341
|
-
leaf: script.unilateralClaim(),
|
|
2342
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
2343
|
-
sequence
|
|
2344
|
-
});
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
if (role === "sender") {
|
|
2348
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
2349
|
-
if (isCsvSpendable(context, sequence)) {
|
|
2350
|
-
paths.push({
|
|
2351
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
2352
|
-
sequence
|
|
2353
|
-
});
|
|
2354
|
-
}
|
|
2355
|
-
}
|
|
2356
|
-
return paths;
|
|
1625
|
+
return vhtlcSpendablePaths(script, contract, context);
|
|
2357
1626
|
},
|
|
2358
1627
|
/**
|
|
2359
1628
|
* Refuse an explicit spend of a lockup whose refund path has not opened.
|
|
@@ -2363,62 +1632,28 @@ var VHTLCV2ContractHandler = {
|
|
|
2363
1632
|
assertVhtlcSpendableNow(contract, context);
|
|
2364
1633
|
},
|
|
2365
1634
|
/**
|
|
2366
|
-
* Never. A live VHTLC is escrow
|
|
2367
|
-
*
|
|
2368
|
-
*
|
|
2369
|
-
*
|
|
2370
|
-
*
|
|
2371
|
-
*
|
|
2372
|
-
* The gate covers `available` and renewal. Recovery is generic and names
|
|
2373
|
-
* nothing, so it is not covered here: `recoverVtxos` filters on
|
|
2374
|
-
* {@link assertSpendableNow} instead, which drops a lockup only while its
|
|
2375
|
-
* refund path is shut rather than forever. The explicit routes out —
|
|
2376
|
-
* `settle({ inputs })`, or `@arkade-os/swap`'s `pushRefundWithoutReceiver`
|
|
2377
|
-
* over `findLockupVtxos`' outpoints — are unaffected either way.
|
|
1635
|
+
* Never. A live VHTLC is escrow with the counterparty's claim leaf armed; generic selection
|
|
1636
|
+
* (send, settle, renewal, offboard) would move it out from under the swap or race a claim.
|
|
1637
|
+
* Recovery isn't covered by this gate: `recoverVtxos` filters on {@link assertSpendableNow},
|
|
1638
|
+
* dropping a lockup only while its refund path is shut. Explicit routes (`settle({ inputs })`,
|
|
1639
|
+
* `pushRefundWithoutReceiver`) are unaffected.
|
|
2378
1640
|
*/
|
|
2379
1641
|
isGenericallySpendable: () => false,
|
|
2380
1642
|
/**
|
|
2381
1643
|
* The annotation leaf stamped onto every VTXO locked to this contract.
|
|
2382
1644
|
*
|
|
2383
|
-
*
|
|
2384
|
-
* `
|
|
2385
|
-
*
|
|
2386
|
-
* script version has a `forfeit()` — `VtxoScript` does not define one and
|
|
2387
|
-
* `VHTLC.BaseScript` does not add one. The fallback therefore throws
|
|
2388
|
-
* `legacy.forfeit is not a function`, `annotatableIn` catches it, and
|
|
2389
|
-
* `fetchContractVtxosBulk` drops this contract's VTXOs before they are
|
|
2390
|
-
* persisted. The row would exist and be watched while its balance stayed
|
|
2391
|
-
* permanently invisible, and `getSyncState()` would report `degraded`
|
|
2392
|
-
* forever. (The `vhtlc` handler had the same gap and now closes it the same
|
|
2393
|
-
* way; nothing registers V1 rows through `ContractManager` in this repo, so
|
|
2394
|
-
* it was never hit here.)
|
|
2395
|
-
*
|
|
2396
|
-
* `refundWithoutReceiver` is the leaf, for both roles the annotation
|
|
2397
|
-
* serves, because it is the only collaborative path this wallet can
|
|
2398
|
-
* actually satisfy as the sender — the same conclusion `selectPath`
|
|
2399
|
-
* reaches, kept in step with it deliberately. The claim leaves belong to
|
|
2400
|
-
* the receiver and need a preimage the sender does not have; `refund` and
|
|
2401
|
-
* `unilateralRefund` need the counterparty; the covenant leaves are the
|
|
2402
|
-
* emulator's.
|
|
1645
|
+
* Required, not an optimization: without {@link TapscriptDeriving} the fallback calls
|
|
1646
|
+
* `script.forfeit()`, which no VHTLC version has, so the VTXOs are silently dropped before
|
|
1647
|
+
* persisting and `getSyncState()` stays `degraded`.
|
|
2403
1648
|
*
|
|
2404
|
-
*
|
|
2405
|
-
*
|
|
2406
|
-
*
|
|
2407
|
-
*
|
|
2408
|
-
*
|
|
2409
|
-
* {@link assertSpendableNow} for it.
|
|
2410
|
-
*
|
|
2411
|
-
* **Role-blind.** A receiver's row gets the same leaf, which names keys that
|
|
2412
|
-
* wallet does not hold, so it is satisfiable only by the wallet holding the
|
|
2413
|
-
* lockup's `sender` key and fails at intent registration for anyone else.
|
|
1649
|
+
* `refundWithoutReceiver` is used (in step with `selectPath`) as the only collaborative leaf
|
|
1650
|
+
* the sender can satisfy. It carries a CLTV: settling on it before `refundLocktime` matures is
|
|
1651
|
+
* rejected, and this handler has no clock, so `recoverVtxos` filters on
|
|
1652
|
+
* {@link assertSpendableNow}. Role-blind: a receiver's row gets the same leaf and fails at
|
|
1653
|
+
* intent registration.
|
|
2414
1654
|
*/
|
|
2415
1655
|
deriveTapscripts(script) {
|
|
2416
|
-
|
|
2417
|
-
return {
|
|
2418
|
-
forfeitTapLeafScript: leaf,
|
|
2419
|
-
intentTapLeafScript: leaf,
|
|
2420
|
-
tapTree: script.encode()
|
|
2421
|
-
};
|
|
1656
|
+
return deriveVhtlcTapscripts(script);
|
|
2422
1657
|
}
|
|
2423
1658
|
};
|
|
2424
1659
|
var BoardingContractHandler = {
|
|
@@ -2444,24 +1679,10 @@ var BoardingContractHandler = {
|
|
|
2444
1679
|
/** Preserves today's settle/board behaviour. */
|
|
2445
1680
|
isGenericallySpendable: () => true,
|
|
2446
1681
|
/**
|
|
2447
|
-
* Probe the on-chain
|
|
2448
|
-
*
|
|
2449
|
-
*
|
|
2450
|
-
*
|
|
2451
|
-
* boarding output becomes an L2 VTXO at the receive index, so the
|
|
2452
|
-
* indexer probe already keeps the gap window open for it; only an
|
|
2453
|
-
* *unspent* boarding output needs the on-chain probe (see plan §2).
|
|
2454
|
-
*
|
|
2455
|
-
* No-ops (returns `[]`) when boarding discovery is not plumbed — i.e.
|
|
2456
|
-
* `deps.boardingTimelock` or `deps.onchainNetwork` is absent — so the
|
|
2457
|
-
* scanner unit harness (which sets neither) is unaffected.
|
|
2458
|
-
*
|
|
2459
|
-
* Always emits `type: "boarding"`, even in the degenerate equal-delay case
|
|
2460
|
-
* where the boarding script is byte-identical to a `default` script at this
|
|
2461
|
-
* index (`boardingExitDelay === unilateralExitDelay`). The collision is no
|
|
2462
|
-
* longer pre-judged in discovery; it is tolerated FIRST-WINS at the
|
|
2463
|
-
* persistence layer ({@link ContractManager.upsertContract}). `deps.csvTimelocks`
|
|
2464
|
-
* is intentionally not read here.
|
|
1682
|
+
* Probe the **current** on-chain coin set for a boarding output at this HD index. Only an
|
|
1683
|
+
* unspent boarding output needs this: a boarded one became an L2 VTXO at the receive index,
|
|
1684
|
+
* which the indexer probe already covers. Always emits `type: "boarding"` (see the handler
|
|
1685
|
+
* doc on collisions); `deps.csvTimelocks` is intentionally not read.
|
|
2465
1686
|
*/
|
|
2466
1687
|
async discoverAt(index, descriptor, deps) {
|
|
2467
1688
|
if (!deps.boardingTimelock || !deps.onchainNetwork) return [];
|
|
@@ -2475,26 +1696,19 @@ var BoardingContractHandler = {
|
|
|
2475
1696
|
const coins = await deps.onchainProvider.getCoins(onchainAddress);
|
|
2476
1697
|
if (coins.length === 0) return [];
|
|
2477
1698
|
const scriptHex = base.hex.encode(script.pkScript);
|
|
2478
|
-
const boardingSeq = chunk5OBGYL6U_cjs.timelockToSequence(deps.boardingTimelock);
|
|
2479
1699
|
return [
|
|
2480
1700
|
{
|
|
2481
1701
|
type: "boarding",
|
|
2482
|
-
params: {
|
|
2483
|
-
pubKey
|
|
2484
|
-
serverPubKey:
|
|
2485
|
-
csvTimelock:
|
|
2486
|
-
},
|
|
1702
|
+
params: BoardingContractHandler.serializeParams({
|
|
1703
|
+
pubKey,
|
|
1704
|
+
serverPubKey: deps.serverPubKey,
|
|
1705
|
+
csvTimelock: deps.boardingTimelock
|
|
1706
|
+
}),
|
|
2487
1707
|
script: scriptHex,
|
|
2488
|
-
// The
|
|
2489
|
-
//
|
|
2490
|
-
// ContractWatcher keeps monitoring the same L2 script and the
|
|
2491
|
-
// VTXO repository bucket lines up (plan §6-I.4). The P2TR is
|
|
2492
|
-
// recomputed from params only for the `getCoins` probe.
|
|
1708
|
+
// The Ark address, not the P2TR: must match the row registered at init so the
|
|
1709
|
+
// watcher monitors the same L2 script and the VTXO repository bucket lines up.
|
|
2493
1710
|
address: script.address(deps.network.hrp, deps.serverPubKey).encode(),
|
|
2494
|
-
// Tag rotated rows (index > 0)
|
|
2495
|
-
// newest boarding address and descriptor-aware signing can
|
|
2496
|
-
// recover the per-index key (plan §6-II/§6-III.3). The index-0
|
|
2497
|
-
// baseline stays untagged, matching `default`/`delegate`.
|
|
1711
|
+
// Tag rotated rows (index > 0) for boot resolution and per-index signing.
|
|
2498
1712
|
...rotatedReceiveMetadata(index, descriptor)
|
|
2499
1713
|
}
|
|
2500
1714
|
];
|
|
@@ -2569,6 +1783,7 @@ function collectParamRefs(program) {
|
|
|
2569
1783
|
const collect = (items) => {
|
|
2570
1784
|
for (const t of items ?? []) {
|
|
2571
1785
|
if (typeof t === "string" && t.startsWith("$")) refs.add(t.slice(1));
|
|
1786
|
+
else if (isTweakedSigner(t) && t.tweak.startsWith("$")) refs.add(t.tweak.slice(1));
|
|
2572
1787
|
}
|
|
2573
1788
|
};
|
|
2574
1789
|
for (const fn of Object.values(program.functions)) {
|
|
@@ -2621,10 +1836,15 @@ function validateProgram(program, args) {
|
|
|
2621
1836
|
if (typeof p !== "string") validateParamValue(p, args[p.name]);
|
|
2622
1837
|
}
|
|
2623
1838
|
}
|
|
1839
|
+
function isTweakedSigner(ref) {
|
|
1840
|
+
if (typeof ref !== "object" || ref === null || ref instanceof Uint8Array) return false;
|
|
1841
|
+
const { tweak, fn } = ref;
|
|
1842
|
+
return typeof tweak === "string" && typeof fn === "string";
|
|
1843
|
+
}
|
|
2624
1844
|
function resolveSigner(ref, args) {
|
|
2625
1845
|
if (ref instanceof Uint8Array) return ref;
|
|
2626
|
-
if (!ref.startsWith("$")) {
|
|
2627
|
-
throw new Error(`unknown signer reference '${ref}' \u2014 use '
|
|
1846
|
+
if (typeof ref !== "string" || !ref.startsWith("$")) {
|
|
1847
|
+
throw new Error(`unknown signer reference '${ref}' \u2014 use a '$param' or key bytes`);
|
|
2628
1848
|
}
|
|
2629
1849
|
const v = bindValue(args, ref.slice(1));
|
|
2630
1850
|
if (!(v instanceof Uint8Array)) {
|
|
@@ -2636,27 +1856,27 @@ function encodeTapscriptSegment(seg, pubkeys, args) {
|
|
|
2636
1856
|
if (seg.csv) {
|
|
2637
1857
|
const timelock = { type: seg.csv.type, value: resolveTimelockValue(seg.csv.value, args) };
|
|
2638
1858
|
if (seg.asm) {
|
|
2639
|
-
return
|
|
1859
|
+
return chunk7NK6XFC3_cjs.ConditionCSVMultisigTapscript.encode({
|
|
2640
1860
|
conditionScript: resolveAsm(seg.asm, args),
|
|
2641
1861
|
timelock,
|
|
2642
1862
|
pubkeys
|
|
2643
1863
|
});
|
|
2644
1864
|
}
|
|
2645
|
-
return
|
|
1865
|
+
return chunk7NK6XFC3_cjs.CSVMultisigTapscript.encode({ timelock, pubkeys });
|
|
2646
1866
|
}
|
|
2647
1867
|
if (seg.cltv !== void 0) {
|
|
2648
|
-
return
|
|
1868
|
+
return chunk7NK6XFC3_cjs.CLTVMultisigTapscript.encode({
|
|
2649
1869
|
absoluteTimelock: resolveTimelockValue(seg.cltv, args),
|
|
2650
1870
|
pubkeys
|
|
2651
1871
|
});
|
|
2652
1872
|
}
|
|
2653
1873
|
if (seg.asm) {
|
|
2654
|
-
return
|
|
1874
|
+
return chunk7NK6XFC3_cjs.ConditionMultisigTapscript.encode({
|
|
2655
1875
|
conditionScript: resolveAsm(seg.asm, args),
|
|
2656
1876
|
pubkeys
|
|
2657
1877
|
});
|
|
2658
1878
|
}
|
|
2659
|
-
return
|
|
1879
|
+
return chunk7NK6XFC3_cjs.MultisigTapscript.encode({ pubkeys });
|
|
2660
1880
|
}
|
|
2661
1881
|
function compileFunctions(program, args, keys) {
|
|
2662
1882
|
if (program.version !== SUPPORTED_PROGRAM_VERSION) {
|
|
@@ -2679,14 +1899,26 @@ function compileFunctions(program, args, keys) {
|
|
|
2679
1899
|
}
|
|
2680
1900
|
return defs.map((def, i) => {
|
|
2681
1901
|
validateTapscript(def.tapscript);
|
|
2682
|
-
const pubkeys = def.tapscript.signers.map((
|
|
1902
|
+
const pubkeys = def.tapscript.signers.map((signer) => {
|
|
1903
|
+
if (!isTweakedSigner(signer)) return resolveSigner(signer, args);
|
|
1904
|
+
const asm = functions[signer.fn]?.arkadeScript?.asm;
|
|
1905
|
+
if (!asm) {
|
|
1906
|
+
throw new Error(
|
|
1907
|
+
`ArkadeContract: function '${names[i]}' tweaks '${signer.fn}', which has no arkade script`
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
return computeArkadeScriptPublicKey(
|
|
1911
|
+
resolveSigner(signer.tweak, args),
|
|
1912
|
+
resolveAsm(asm, args)
|
|
1913
|
+
);
|
|
1914
|
+
});
|
|
2683
1915
|
const arkadeScript = def.arkadeScript ? resolveAsm(def.arkadeScript.asm, args) : void 0;
|
|
2684
|
-
const leafPubkeys = arkadeScript ? [...pubkeys, computeArkadeScriptPublicKey(keys.emulatorKey, arkadeScript)] : pubkeys;
|
|
1916
|
+
const leafPubkeys = arkadeScript && def.tapscript.emulator !== null ? [...pubkeys, computeArkadeScriptPublicKey(keys.emulatorKey, arkadeScript)] : pubkeys;
|
|
2685
1917
|
const leafScript = encodeTapscriptSegment(def.tapscript, leafPubkeys, args).script;
|
|
2686
1918
|
return { name: names[i], def, leafScript, arkadeScript, signerKeys: pubkeys };
|
|
2687
1919
|
});
|
|
2688
1920
|
}
|
|
2689
|
-
var ArkadeProgramScript = class extends
|
|
1921
|
+
var ArkadeProgramScript = class extends chunk7NK6XFC3_cjs.VtxoScript {
|
|
2690
1922
|
constructor(program, args, keys) {
|
|
2691
1923
|
const partial = compileFunctions(program, args, keys);
|
|
2692
1924
|
super(partial.map((p) => p.leafScript));
|
|
@@ -2709,17 +1941,31 @@ var ArkadeProgramScript = class extends chunk5OBGYL6U_cjs.VtxoScript {
|
|
|
2709
1941
|
}
|
|
2710
1942
|
};
|
|
2711
1943
|
function parseArtifact(artifact) {
|
|
1944
|
+
if (Array.isArray(artifact.functions)) {
|
|
1945
|
+
throw new Error(
|
|
1946
|
+
"parseArtifact: `functions` is an array, which is the arkadec artifact shape, not an SDK program \u2014 read it with programFromArtifact instead"
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1949
|
+
if (typeof artifact.functions !== "object" || artifact.functions === null) {
|
|
1950
|
+
throw new Error("parseArtifact: `functions` must be an object keyed by function name");
|
|
1951
|
+
}
|
|
2712
1952
|
const hexToken = (t) => typeof t === "string" && t.startsWith("0x") ? base.hex.decode(t.slice(2)) : t;
|
|
1953
|
+
const signerRef = (s) => {
|
|
1954
|
+
if (s instanceof Uint8Array || typeof s === "string") return hexToken(s);
|
|
1955
|
+
if (isTweakedSigner(s)) return { tweak: s.tweak, fn: s.fn };
|
|
1956
|
+
throw new Error("parseArtifact: a tweaked signer needs string `tweak` and `fn`");
|
|
1957
|
+
};
|
|
2713
1958
|
const timelockValue = (v) => typeof v === "string" && v.startsWith("$") ? v : BigInt(v);
|
|
2714
1959
|
const functions = {};
|
|
2715
1960
|
for (const [name, fn] of Object.entries(artifact.functions)) {
|
|
2716
1961
|
const tap = fn.tapscript ?? {};
|
|
2717
1962
|
const tapscript = {
|
|
2718
|
-
signers: (tap.signers ?? []).map(
|
|
1963
|
+
signers: (tap.signers ?? []).map(signerRef),
|
|
2719
1964
|
...tap.asm ? { asm: tap.asm.map(hexToken) } : {},
|
|
2720
1965
|
...tap.witness ? { witness: tap.witness.map(hexToken) } : {},
|
|
2721
1966
|
...tap.csv ? { csv: { type: tap.csv.type, value: timelockValue(tap.csv.value) } } : {},
|
|
2722
|
-
...tap.cltv !== void 0 ? { cltv: timelockValue(tap.cltv) } : {}
|
|
1967
|
+
...tap.cltv !== void 0 ? { cltv: timelockValue(tap.cltv) } : {},
|
|
1968
|
+
..."emulator" in tap ? { emulator: tap.emulator } : {}
|
|
2723
1969
|
};
|
|
2724
1970
|
const arkadeScript = fn.arkadeScript ? {
|
|
2725
1971
|
asm: fn.arkadeScript.asm.map(hexToken),
|
|
@@ -2759,7 +2005,8 @@ function stringifyArtifact(program) {
|
|
|
2759
2005
|
...tap.asm ? { asm: tap.asm.map(token) } : {},
|
|
2760
2006
|
...tap.witness ? { witness: tap.witness.map(token) } : {},
|
|
2761
2007
|
...tap.csv ? { csv: { type: tap.csv.type, value: tap.csv.value.toString() } } : {},
|
|
2762
|
-
...tap.cltv !== void 0 ? { cltv: tap.cltv.toString() } : {}
|
|
2008
|
+
...tap.cltv !== void 0 ? { cltv: tap.cltv.toString() } : {},
|
|
2009
|
+
...tap.emulator !== void 0 ? { emulator: tap.emulator } : {}
|
|
2763
2010
|
},
|
|
2764
2011
|
...fn.arkadeScript ? {
|
|
2765
2012
|
arkadeScript: {
|
|
@@ -2889,7 +2136,7 @@ function pathsFor(script, context, opts) {
|
|
|
2889
2136
|
continue;
|
|
2890
2137
|
}
|
|
2891
2138
|
if (requiresServer) continue;
|
|
2892
|
-
const sequence = csv ? Number(
|
|
2139
|
+
const sequence = csv ? Number(chunk7NK6XFC3_cjs.timelockToSequence(csv)) : void 0;
|
|
2893
2140
|
if (opts.checkTimelocks && csv && !isCsvSpendable(context, sequence)) continue;
|
|
2894
2141
|
if (opts.checkTimelocks && cltv !== void 0 && !isCltvSatisfied(context, cltv)) {
|
|
2895
2142
|
continue;
|
|
@@ -3018,5 +2265,5 @@ exports.toASM = toASM;
|
|
|
3018
2265
|
exports.toXOnly = toXOnly;
|
|
3019
2266
|
exports.validateProgram = validateProgram;
|
|
3020
2267
|
exports.witnessRefToBytes = witnessRefToBytes;
|
|
3021
|
-
//# sourceMappingURL=chunk-
|
|
3022
|
-
//# sourceMappingURL=chunk-
|
|
2268
|
+
//# sourceMappingURL=chunk-FDQQOF3F.cjs.map
|
|
2269
|
+
//# sourceMappingURL=chunk-FDQQOF3F.cjs.map
|