@arkade-os/sdk 0.5.0-rc.3 → 0.5.0-rc.30
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 +223 -83
- package/dist/adapters/expo.cjs +5 -6
- package/dist/adapters/expo.d.cts +5 -5
- package/dist/adapters/expo.d.ts +5 -5
- package/dist/adapters/expo.js +3 -4
- package/dist/{asyncStorageTaskQueue-DAs_n1xr.d.ts → asyncStorageTaskQueue-DAVf4Fyy.d.ts} +2 -2
- package/dist/{asyncStorageTaskQueue-DqGRG66E.d.cts → asyncStorageTaskQueue-fkkUPrhz.d.cts} +2 -2
- package/dist/{chunk-FSF2PGTR.cjs → chunk-3SM7BMIE.cjs} +6736 -5189
- package/dist/chunk-3SM7BMIE.cjs.map +1 -0
- package/dist/{chunk-UCSTNXB4.cjs → chunk-4MCQZYH6.cjs} +501 -1153
- package/dist/chunk-4MCQZYH6.cjs.map +1 -0
- package/dist/{chunk-BCT7DT2J.cjs → chunk-6BTZ6KFI.cjs} +12 -10
- package/dist/chunk-6BTZ6KFI.cjs.map +1 -0
- package/dist/{chunk-L4HZK4KK.cjs → chunk-AICUNREA.cjs} +158 -263
- package/dist/chunk-AICUNREA.cjs.map +1 -0
- package/dist/{chunk-UJTYUYY4.cjs → chunk-ASKOHVGX.cjs} +596 -467
- package/dist/chunk-ASKOHVGX.cjs.map +1 -0
- package/dist/{chunk-43XGA362.cjs → chunk-DLHE4RCH.cjs} +40 -43
- package/dist/chunk-DLHE4RCH.cjs.map +1 -0
- package/dist/{chunk-7W6FHWYN.js → chunk-ESEHYZAY.js} +434 -1109
- package/dist/chunk-ESEHYZAY.js.map +1 -0
- package/dist/{chunk-HSG2GQTM.js → chunk-G6ZPX2GL.js} +586 -462
- package/dist/chunk-G6ZPX2GL.js.map +1 -0
- package/dist/{chunk-G4UPMCKW.js → chunk-KK6GXY4L.js} +33 -36
- package/dist/chunk-KK6GXY4L.js.map +1 -0
- package/dist/{chunk-ERUAQGYF.js → chunk-PY3YQNHP.js} +146 -252
- package/dist/chunk-PY3YQNHP.js.map +1 -0
- package/dist/{chunk-VQCDDGRW.js → chunk-XW72DWYO.js} +6350 -4816
- package/dist/chunk-XW72DWYO.js.map +1 -0
- package/dist/{chunk-ROD5H7RX.js → chunk-YML2N4SC.js} +7 -5
- package/dist/chunk-YML2N4SC.js.map +1 -0
- package/dist/contracts/handlers/index.cjs +9 -10
- package/dist/contracts/handlers/index.d.cts +5 -5
- package/dist/contracts/handlers/index.d.ts +5 -5
- package/dist/contracts/handlers/index.js +2 -3
- package/dist/{delegate-CZzIduW4.d.cts → delegate-BYoNu3lf.d.cts} +1 -1
- package/dist/{delegate-B9Bmrns7.d.ts → delegate-DsqzUVId.d.ts} +1 -1
- package/dist/index-CXNTURO_.d.cts +645 -0
- package/dist/{index-DnNIOqHS.d.ts → index-DhP68WBD.d.cts} +1698 -2402
- package/dist/{index-DnNIOqHS.d.cts → index-DhP68WBD.d.ts} +1698 -2402
- package/dist/index-pQr5y77P.d.ts +645 -0
- package/dist/index.cjs +407 -356
- package/dist/index.d.cts +1045 -1302
- package/dist/index.d.ts +1045 -1302
- package/dist/index.js +4 -5
- package/dist/repositories/realm/index.cjs +201 -106
- package/dist/repositories/realm/index.cjs.map +1 -1
- package/dist/repositories/realm/index.d.cts +28 -16
- package/dist/repositories/realm/index.d.ts +28 -16
- package/dist/repositories/realm/index.js +190 -95
- package/dist/repositories/realm/index.js.map +1 -1
- package/dist/repositories/sqlite/index.cjs +301 -189
- package/dist/repositories/sqlite/index.cjs.map +1 -1
- package/dist/repositories/sqlite/index.d.cts +32 -21
- package/dist/repositories/sqlite/index.d.ts +32 -21
- package/dist/repositories/sqlite/index.js +294 -182
- package/dist/repositories/sqlite/index.js.map +1 -1
- package/dist/{taskRunner-BDb5Ee2J.d.cts → taskRunner-C8H3bSsk.d.cts} +2 -2
- package/dist/{taskRunner-F7wNJcF3.d.ts → taskRunner-DKtBy8Yo.d.ts} +2 -2
- package/dist/wallet/expo/background.cjs +14 -15
- package/dist/wallet/expo/background.cjs.map +1 -1
- package/dist/wallet/expo/background.d.cts +10 -16
- package/dist/wallet/expo/background.d.ts +10 -16
- package/dist/wallet/expo/background.js +6 -7
- package/dist/wallet/expo/background.js.map +1 -1
- package/dist/wallet/expo/index.cjs +20 -23
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +8 -9
- package/dist/wallet/expo/index.d.ts +8 -9
- package/dist/wallet/expo/index.js +12 -15
- package/dist/wallet/expo/index.js.map +1 -1
- package/dist/wallet-BmAHDzK3.d.cts +1874 -0
- package/dist/wallet-C0W8EOnA.d.ts +1874 -0
- package/dist/worker/expo/index.cjs +9 -10
- package/dist/worker/expo/index.cjs.map +1 -1
- package/dist/worker/expo/index.d.cts +6 -6
- package/dist/worker/expo/index.d.ts +6 -6
- package/dist/worker/expo/index.js +5 -6
- package/dist/worker/expo/index.js.map +1 -1
- package/package.json +12 -51
- package/dist/adapters/asyncStorage.cjs +0 -48
- package/dist/adapters/asyncStorage.cjs.map +0 -1
- package/dist/adapters/asyncStorage.d.cts +0 -16
- package/dist/adapters/asyncStorage.d.ts +0 -16
- package/dist/adapters/asyncStorage.js +0 -46
- package/dist/adapters/asyncStorage.js.map +0 -1
- package/dist/adapters/fileSystem.cjs +0 -116
- package/dist/adapters/fileSystem.cjs.map +0 -1
- package/dist/adapters/fileSystem.d.cts +0 -17
- package/dist/adapters/fileSystem.d.ts +0 -17
- package/dist/adapters/fileSystem.js +0 -93
- package/dist/adapters/fileSystem.js.map +0 -1
- package/dist/adapters/indexedDB.cjs +0 -103
- package/dist/adapters/indexedDB.cjs.map +0 -1
- package/dist/adapters/indexedDB.d.cts +0 -18
- package/dist/adapters/indexedDB.d.ts +0 -18
- package/dist/adapters/indexedDB.js +0 -101
- package/dist/adapters/indexedDB.js.map +0 -1
- package/dist/adapters/localStorage.cjs +0 -50
- package/dist/adapters/localStorage.cjs.map +0 -1
- package/dist/adapters/localStorage.d.cts +0 -14
- package/dist/adapters/localStorage.d.ts +0 -14
- package/dist/adapters/localStorage.js +0 -48
- package/dist/adapters/localStorage.js.map +0 -1
- package/dist/chunk-43XGA362.cjs.map +0 -1
- package/dist/chunk-5BLDMQED.cjs +0 -18
- package/dist/chunk-5BLDMQED.cjs.map +0 -1
- package/dist/chunk-7W6FHWYN.js.map +0 -1
- package/dist/chunk-BCT7DT2J.cjs.map +0 -1
- package/dist/chunk-ERUAQGYF.js.map +0 -1
- package/dist/chunk-FSF2PGTR.cjs.map +0 -1
- package/dist/chunk-G4UPMCKW.js.map +0 -1
- package/dist/chunk-HSG2GQTM.js.map +0 -1
- package/dist/chunk-L4HZK4KK.cjs.map +0 -1
- package/dist/chunk-NSBPE2FW.js +0 -15
- package/dist/chunk-NSBPE2FW.js.map +0 -1
- package/dist/chunk-ROD5H7RX.js.map +0 -1
- package/dist/chunk-UCSTNXB4.cjs.map +0 -1
- package/dist/chunk-UJTYUYY4.cjs.map +0 -1
- package/dist/chunk-VQCDDGRW.js.map +0 -1
- package/dist/hdWalletCapable-BIl3yLVM.d.cts +0 -2232
- package/dist/hdWalletCapable-Cr5nGpK5.d.ts +0 -2232
- package/dist/index-C0IanN1m.d.cts +0 -11
- package/dist/index-C0IanN1m.d.ts +0 -11
- package/dist/index-Ci5MmNnK.d.cts +0 -850
- package/dist/index-DQ1Hb2w_.d.ts +0 -850
|
@@ -1,44 +1,48 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var chunk5BLDMQED_cjs = require('./chunk-5BLDMQED.cjs');
|
|
3
|
+
var chunkASKOHVGX_cjs = require('./chunk-ASKOHVGX.cjs');
|
|
5
4
|
var base = require('@scure/base');
|
|
6
5
|
var descriptorsScure = require('@bitcoinerlab/descriptors-scure');
|
|
7
6
|
var btcSigner = require('@scure/btc-signer');
|
|
7
|
+
var P = require('micro-packed');
|
|
8
8
|
var secp256k1_js = require('@noble/curves/secp256k1.js');
|
|
9
9
|
var utils_js = require('@noble/curves/utils.js');
|
|
10
|
+
var utils_js$1 = require('@scure/btc-signer/utils.js');
|
|
11
|
+
|
|
12
|
+
function _interopNamespace(e) {
|
|
13
|
+
if (e && e.__esModule) return e;
|
|
14
|
+
var n = Object.create(null);
|
|
15
|
+
if (e) {
|
|
16
|
+
Object.keys(e).forEach(function (k) {
|
|
17
|
+
if (k !== 'default') {
|
|
18
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
19
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return e[k]; }
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
n.default = e;
|
|
27
|
+
return Object.freeze(n);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var P__namespace = /*#__PURE__*/_interopNamespace(P);
|
|
10
31
|
|
|
11
32
|
// src/contracts/handlers/registry.ts
|
|
12
33
|
var ContractHandlerRegistry = class {
|
|
13
34
|
handlers = /* @__PURE__ */ new Map();
|
|
14
|
-
/**
|
|
15
|
-
* Register a contract handler.
|
|
16
|
-
*
|
|
17
|
-
* @param handler - The handler to register
|
|
18
|
-
* @throws If a handler for this type is already registered
|
|
19
|
-
*/
|
|
35
|
+
/** @throws If a handler for this type is already registered */
|
|
20
36
|
register(handler) {
|
|
21
37
|
if (this.handlers.has(handler.type)) {
|
|
22
38
|
throw new Error(`Contract handler for type '${handler.type}' is already registered`);
|
|
23
39
|
}
|
|
24
40
|
this.handlers.set(handler.type, handler);
|
|
25
41
|
}
|
|
26
|
-
/**
|
|
27
|
-
* Get a handler by type.
|
|
28
|
-
*
|
|
29
|
-
* @param type - The contract type
|
|
30
|
-
* @returns The handler, or undefined if not found
|
|
31
|
-
*/
|
|
32
42
|
get(type) {
|
|
33
43
|
return this.handlers.get(type);
|
|
34
44
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Get a handler by type, throwing if not found.
|
|
37
|
-
*
|
|
38
|
-
* @param type - The contract type
|
|
39
|
-
* @returns The handler
|
|
40
|
-
* @throws If no handler is registered for this type
|
|
41
|
-
*/
|
|
45
|
+
/** @throws If no handler is registered for this type */
|
|
42
46
|
getOrThrow(type) {
|
|
43
47
|
const handler = this.get(type);
|
|
44
48
|
if (!handler) {
|
|
@@ -46,29 +50,17 @@ var ContractHandlerRegistry = class {
|
|
|
46
50
|
}
|
|
47
51
|
return handler;
|
|
48
52
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Check if a handler is registered.
|
|
51
|
-
*
|
|
52
|
-
* @param type - The contract type
|
|
53
|
-
*/
|
|
54
53
|
has(type) {
|
|
55
54
|
return this.handlers.has(type);
|
|
56
55
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Get all registered types.
|
|
59
|
-
*/
|
|
60
56
|
getRegisteredTypes() {
|
|
61
57
|
return Array.from(this.handlers.keys());
|
|
62
58
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Unregister a handler (mainly for testing).
|
|
65
|
-
*/
|
|
59
|
+
/** Unregister a handler (mainly for testing). */
|
|
66
60
|
unregister(type) {
|
|
67
61
|
return this.handlers.delete(type);
|
|
68
62
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Clear all handlers (mainly for testing).
|
|
71
|
-
*/
|
|
63
|
+
/** Clear all handlers (mainly for testing). */
|
|
72
64
|
clear() {
|
|
73
65
|
this.handlers.clear();
|
|
74
66
|
}
|
|
@@ -76,14 +68,14 @@ var ContractHandlerRegistry = class {
|
|
|
76
68
|
var contractHandlers = new ContractHandlerRegistry();
|
|
77
69
|
exports.DefaultVtxo = void 0;
|
|
78
70
|
((DefaultVtxo2) => {
|
|
79
|
-
class Script3 extends
|
|
71
|
+
class Script3 extends chunkASKOHVGX_cjs.VtxoScript {
|
|
80
72
|
/** Create the default virtual output script with one forfeit path and one exit path. */
|
|
81
73
|
constructor(options) {
|
|
82
74
|
const { pubKey, serverPubKey, csvTimelock } = options;
|
|
83
|
-
const forfeitScript =
|
|
75
|
+
const forfeitScript = chunkASKOHVGX_cjs.MultisigTapscript.encode({
|
|
84
76
|
pubkeys: [pubKey, serverPubKey]
|
|
85
77
|
}).script;
|
|
86
|
-
const exitScript =
|
|
78
|
+
const exitScript = chunkASKOHVGX_cjs.CSVMultisigTapscript.encode({
|
|
87
79
|
timelock: csvTimelock,
|
|
88
80
|
pubkeys: [pubKey]
|
|
89
81
|
}).script;
|
|
@@ -268,27 +260,14 @@ function resolveRole(contract, context) {
|
|
|
268
260
|
}
|
|
269
261
|
return void 0;
|
|
270
262
|
};
|
|
271
|
-
if (context.walletDescriptor)
|
|
272
|
-
|
|
273
|
-
const matchedRole = matchRole(walletDescriptorKey);
|
|
274
|
-
if (matchedRole) {
|
|
275
|
-
return matchedRole;
|
|
276
|
-
}
|
|
277
|
-
if (!walletDescriptorKey && context.walletPubKey) {
|
|
278
|
-
return matchRole(extractRawPubKey(context.walletPubKey));
|
|
279
|
-
}
|
|
280
|
-
return void 0;
|
|
281
|
-
}
|
|
282
|
-
if (context.walletPubKey) {
|
|
283
|
-
return matchRole(extractRawPubKey(context.walletPubKey));
|
|
284
|
-
}
|
|
285
|
-
return void 0;
|
|
263
|
+
if (!context.walletDescriptor) return void 0;
|
|
264
|
+
return matchRole(extractRawPubKey(context.walletDescriptor));
|
|
286
265
|
}
|
|
287
266
|
function extractPubKeyBytes(value) {
|
|
288
267
|
return base.hex.decode(extractPubKey(normalizeToDescriptor(value)));
|
|
289
268
|
}
|
|
290
269
|
function deserializeCsvTimelock(value) {
|
|
291
|
-
return value !== void 0 && value !== "" ?
|
|
270
|
+
return value !== void 0 && value !== "" ? chunkASKOHVGX_cjs.sequenceToTimelock(Number(value)) : exports.DefaultVtxo.Script.DEFAULT_TIMELOCK;
|
|
292
271
|
}
|
|
293
272
|
var CLTV_HEIGHT_THRESHOLD = 500000000n;
|
|
294
273
|
function isCltvSatisfied(context, locktime) {
|
|
@@ -327,10 +306,139 @@ function assertVhtlcSpendableNow(contract, context) {
|
|
|
327
306
|
`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.`
|
|
328
307
|
);
|
|
329
308
|
}
|
|
309
|
+
function selectVhtlcPath(script, contract, context) {
|
|
310
|
+
const role = resolveRole(contract, context);
|
|
311
|
+
const preimage = contract.params?.preimage;
|
|
312
|
+
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
313
|
+
if (!role) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
if (context.collaborative) {
|
|
317
|
+
if (role === "receiver" && preimage) {
|
|
318
|
+
return {
|
|
319
|
+
leaf: script.claim(),
|
|
320
|
+
extraWitness: [base.hex.decode(preimage)]
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
324
|
+
return {
|
|
325
|
+
leaf: script.refundWithoutReceiver()
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
if (role === "receiver" && preimage) {
|
|
331
|
+
const sequence = Number(contract.params.claimDelay);
|
|
332
|
+
if (!isCsvSpendable(context, sequence)) return null;
|
|
333
|
+
return {
|
|
334
|
+
leaf: script.unilateralClaim(),
|
|
335
|
+
extraWitness: [base.hex.decode(preimage)],
|
|
336
|
+
sequence
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
if (role === "sender") {
|
|
340
|
+
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
341
|
+
if (!isCsvSpendable(context, sequence)) return null;
|
|
342
|
+
return {
|
|
343
|
+
leaf: script.unilateralRefundWithoutReceiver(),
|
|
344
|
+
sequence
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
function vhtlcAllSpendingPaths(script, contract, context) {
|
|
350
|
+
const role = resolveRole(contract, context);
|
|
351
|
+
const paths = [];
|
|
352
|
+
if (!role) {
|
|
353
|
+
return paths;
|
|
354
|
+
}
|
|
355
|
+
const preimage = contract.params?.preimage;
|
|
356
|
+
if (context.collaborative) {
|
|
357
|
+
if (role === "receiver" && preimage) {
|
|
358
|
+
paths.push({
|
|
359
|
+
leaf: script.claim(),
|
|
360
|
+
extraWitness: [base.hex.decode(preimage)]
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (role === "sender") {
|
|
364
|
+
paths.push({
|
|
365
|
+
leaf: script.refundWithoutReceiver()
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
} else {
|
|
369
|
+
if (role === "receiver" && preimage) {
|
|
370
|
+
const sequence = Number(contract.params.claimDelay);
|
|
371
|
+
paths.push({
|
|
372
|
+
leaf: script.unilateralClaim(),
|
|
373
|
+
extraWitness: [base.hex.decode(preimage)],
|
|
374
|
+
sequence
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
if (role === "sender") {
|
|
378
|
+
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
379
|
+
paths.push({
|
|
380
|
+
leaf: script.unilateralRefundWithoutReceiver(),
|
|
381
|
+
sequence
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return paths;
|
|
386
|
+
}
|
|
387
|
+
function vhtlcSpendablePaths(script, contract, context) {
|
|
388
|
+
const role = resolveRole(contract, context);
|
|
389
|
+
const paths = [];
|
|
390
|
+
if (!role) {
|
|
391
|
+
return paths;
|
|
392
|
+
}
|
|
393
|
+
const preimage = contract.params?.preimage;
|
|
394
|
+
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
395
|
+
if (context.collaborative) {
|
|
396
|
+
if (role === "receiver" && preimage) {
|
|
397
|
+
paths.push({
|
|
398
|
+
leaf: script.claim(),
|
|
399
|
+
extraWitness: [base.hex.decode(preimage)]
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
403
|
+
paths.push({
|
|
404
|
+
leaf: script.refundWithoutReceiver()
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
return paths;
|
|
408
|
+
}
|
|
409
|
+
if (role === "receiver" && preimage) {
|
|
410
|
+
const sequence = Number(contract.params.claimDelay);
|
|
411
|
+
if (isCsvSpendable(context, sequence)) {
|
|
412
|
+
paths.push({
|
|
413
|
+
leaf: script.unilateralClaim(),
|
|
414
|
+
extraWitness: [base.hex.decode(preimage)],
|
|
415
|
+
sequence
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (role === "sender") {
|
|
420
|
+
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
421
|
+
if (isCsvSpendable(context, sequence)) {
|
|
422
|
+
paths.push({
|
|
423
|
+
leaf: script.unilateralRefundWithoutReceiver(),
|
|
424
|
+
sequence
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return paths;
|
|
429
|
+
}
|
|
430
|
+
function deriveVhtlcTapscripts(script) {
|
|
431
|
+
const leaf = script.refundWithoutReceiver();
|
|
432
|
+
return {
|
|
433
|
+
forfeitTapLeafScript: leaf,
|
|
434
|
+
intentTapLeafScript: leaf,
|
|
435
|
+
tapTree: script.encode()
|
|
436
|
+
};
|
|
437
|
+
}
|
|
330
438
|
function isCsvSpendable(context, sequence) {
|
|
331
439
|
if (sequence === void 0) return true;
|
|
332
440
|
if (!context.vtxo) return false;
|
|
333
|
-
const timelock =
|
|
441
|
+
const timelock = chunkASKOHVGX_cjs.sequenceToTimelock(sequence);
|
|
334
442
|
if (timelock.type === "blocks") {
|
|
335
443
|
if (context.blockHeight === void 0 || context.vtxo.status.block_height === void 0) {
|
|
336
444
|
return false;
|
|
@@ -388,21 +496,21 @@ function forfeitExitSpendablePaths(script, contract, context) {
|
|
|
388
496
|
async function detectUsedScripts(indexerProvider, scriptHexes) {
|
|
389
497
|
const used = /* @__PURE__ */ new Set();
|
|
390
498
|
const unique = [...new Set(scriptHexes)];
|
|
391
|
-
for (let offset = 0; offset < unique.length; offset +=
|
|
392
|
-
const scripts = unique.slice(offset, offset +
|
|
499
|
+
for (let offset = 0; offset < unique.length; offset += chunkASKOHVGX_cjs.SCRIPT_QUERY_CHUNK_SIZE) {
|
|
500
|
+
const scripts = unique.slice(offset, offset + chunkASKOHVGX_cjs.SCRIPT_QUERY_CHUNK_SIZE);
|
|
393
501
|
const remaining = new Set(scripts);
|
|
394
502
|
let pageIndex = 0;
|
|
395
503
|
let hasMore = true;
|
|
396
504
|
while (hasMore && remaining.size > 0) {
|
|
397
|
-
const { vtxos, page } = await
|
|
505
|
+
const { vtxos, page } = await chunkASKOHVGX_cjs.getNormalizedVtxos(indexerProvider, {
|
|
398
506
|
scripts,
|
|
399
507
|
pageIndex,
|
|
400
|
-
pageSize:
|
|
508
|
+
pageSize: chunkASKOHVGX_cjs.DEFAULT_PAGE_SIZE
|
|
401
509
|
});
|
|
402
510
|
for (const vtxo of vtxos) {
|
|
403
511
|
if (remaining.delete(vtxo.script)) used.add(vtxo.script);
|
|
404
512
|
}
|
|
405
|
-
hasMore = page ? vtxos.length ===
|
|
513
|
+
hasMore = page ? vtxos.length === chunkASKOHVGX_cjs.DEFAULT_PAGE_SIZE : false;
|
|
406
514
|
pageIndex++;
|
|
407
515
|
}
|
|
408
516
|
}
|
|
@@ -463,7 +571,7 @@ var DefaultContractHandler = {
|
|
|
463
571
|
return {
|
|
464
572
|
pubKey: base.hex.encode(params.pubKey),
|
|
465
573
|
serverPubKey: base.hex.encode(params.serverPubKey),
|
|
466
|
-
csvTimelock:
|
|
574
|
+
csvTimelock: chunkASKOHVGX_cjs.timelockToSequence(params.csvTimelock).toString()
|
|
467
575
|
};
|
|
468
576
|
},
|
|
469
577
|
deserializeParams(params) {
|
|
@@ -495,11 +603,7 @@ function defaultCandidatesAt(_index, descriptor, deps) {
|
|
|
495
603
|
(opts) => new exports.DefaultVtxo.Script(opts)
|
|
496
604
|
).map((c) => ({
|
|
497
605
|
type: "default",
|
|
498
|
-
params:
|
|
499
|
-
pubKey: base.hex.encode(c.pubKey),
|
|
500
|
-
serverPubKey: base.hex.encode(c.serverPubKey),
|
|
501
|
-
csvTimelock: chunkUJTYUYY4_cjs.timelockToSequence(c.csvTimelock).toString()
|
|
502
|
-
},
|
|
606
|
+
params: DefaultContractHandler.serializeParams(c),
|
|
503
607
|
script: c.scriptHex,
|
|
504
608
|
address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
|
|
505
609
|
}));
|
|
@@ -514,12 +618,12 @@ function discoverDefaultRange(entries, deps) {
|
|
|
514
618
|
}
|
|
515
619
|
exports.DelegateVtxo = void 0;
|
|
516
620
|
((DelegateVtxo2) => {
|
|
517
|
-
class Script3 extends
|
|
621
|
+
class Script3 extends chunkASKOHVGX_cjs.VtxoScript {
|
|
518
622
|
/** Create a delegated virtual output script with forfeit, exit, and delegate paths. */
|
|
519
623
|
constructor(options) {
|
|
520
624
|
const defaultVtxo = new exports.DefaultVtxo.Script(options);
|
|
521
625
|
const { delegatePubKey, pubKey, serverPubKey } = options;
|
|
522
|
-
const delegateScript =
|
|
626
|
+
const delegateScript = chunkASKOHVGX_cjs.MultisigTapscript.encode({
|
|
523
627
|
pubkeys: [pubKey, delegatePubKey, serverPubKey]
|
|
524
628
|
}).script;
|
|
525
629
|
super([...defaultVtxo.scripts, delegateScript]);
|
|
@@ -558,7 +662,7 @@ var DelegateContractHandler = {
|
|
|
558
662
|
pubKey: base.hex.encode(params.pubKey),
|
|
559
663
|
serverPubKey: base.hex.encode(params.serverPubKey),
|
|
560
664
|
delegatePubKey: base.hex.encode(params.delegatePubKey),
|
|
561
|
-
csvTimelock:
|
|
665
|
+
csvTimelock: chunkASKOHVGX_cjs.timelockToSequence(params.csvTimelock).toString()
|
|
562
666
|
};
|
|
563
667
|
},
|
|
564
668
|
deserializeParams(params) {
|
|
@@ -598,12 +702,7 @@ function delegateCandidatesAt(_index, descriptor, deps) {
|
|
|
598
702
|
(opts) => new exports.DelegateVtxo.Script({ ...opts, delegatePubKey })
|
|
599
703
|
).map((c) => ({
|
|
600
704
|
type: "delegate",
|
|
601
|
-
params: {
|
|
602
|
-
pubKey: base.hex.encode(c.pubKey),
|
|
603
|
-
serverPubKey: base.hex.encode(c.serverPubKey),
|
|
604
|
-
delegatePubKey: base.hex.encode(delegatePubKey),
|
|
605
|
-
csvTimelock: chunkUJTYUYY4_cjs.timelockToSequence(c.csvTimelock).toString()
|
|
606
|
-
},
|
|
705
|
+
params: DelegateContractHandler.serializeParams({ ...c, delegatePubKey }),
|
|
607
706
|
script: c.scriptHex,
|
|
608
707
|
address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
|
|
609
708
|
}));
|
|
@@ -619,515 +718,10 @@ function discoverDelegateRange(entries, deps) {
|
|
|
619
718
|
(c, index, descriptor) => ({ ...c, ...rotatedReceiveMetadata(index, descriptor) })
|
|
620
719
|
);
|
|
621
720
|
}
|
|
622
|
-
function equalBytes(a, b) {
|
|
623
|
-
if (a.length !== b.length)
|
|
624
|
-
return false;
|
|
625
|
-
for (let i = 0; i < a.length; i++)
|
|
626
|
-
if (a[i] !== b[i])
|
|
627
|
-
return false;
|
|
628
|
-
return true;
|
|
629
|
-
}
|
|
630
|
-
function isBytes(a) {
|
|
631
|
-
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
632
|
-
}
|
|
633
|
-
var createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
634
|
-
function isPlainObject(obj) {
|
|
635
|
-
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
636
|
-
}
|
|
637
|
-
function isNum(num) {
|
|
638
|
-
return Number.isSafeInteger(num);
|
|
639
|
-
}
|
|
640
|
-
var Bitset = {
|
|
641
|
-
BITS: 32,
|
|
642
|
-
FULL_MASK: -1 >>> 0,
|
|
643
|
-
// 1<<32 will overflow
|
|
644
|
-
len: (len) => Math.ceil(len / 32),
|
|
645
|
-
create: (len) => new Uint32Array(Bitset.len(len)),
|
|
646
|
-
clean: (bs) => bs.fill(0),
|
|
647
|
-
debug: (bs) => Array.from(bs).map((i) => (i >>> 0).toString(2).padStart(32, "0")),
|
|
648
|
-
checkLen: (bs, len) => {
|
|
649
|
-
if (Bitset.len(len) === bs.length)
|
|
650
|
-
return;
|
|
651
|
-
throw new Error(`wrong length=${bs.length}. Expected: ${Bitset.len(len)}`);
|
|
652
|
-
},
|
|
653
|
-
chunkLen: (bsLen, pos, len) => {
|
|
654
|
-
if (pos < 0)
|
|
655
|
-
throw new Error(`wrong pos=${pos}`);
|
|
656
|
-
if (pos + len > bsLen)
|
|
657
|
-
throw new Error(`wrong range=${pos}/${len} of ${bsLen}`);
|
|
658
|
-
},
|
|
659
|
-
set: (bs, chunk, value, allowRewrite = true) => {
|
|
660
|
-
if (!allowRewrite && (bs[chunk] & value) !== 0)
|
|
661
|
-
return false;
|
|
662
|
-
bs[chunk] |= value;
|
|
663
|
-
return true;
|
|
664
|
-
},
|
|
665
|
-
pos: (pos, i) => ({
|
|
666
|
-
chunk: Math.floor((pos + i) / 32),
|
|
667
|
-
mask: 1 << 32 - (pos + i) % 32 - 1
|
|
668
|
-
}),
|
|
669
|
-
indices: (bs, len, invert = false) => {
|
|
670
|
-
Bitset.checkLen(bs, len);
|
|
671
|
-
const { FULL_MASK, BITS } = Bitset;
|
|
672
|
-
const left = BITS - len % BITS;
|
|
673
|
-
const lastMask = left ? FULL_MASK >>> left << left : FULL_MASK;
|
|
674
|
-
const res = [];
|
|
675
|
-
for (let i = 0; i < bs.length; i++) {
|
|
676
|
-
let c = bs[i];
|
|
677
|
-
if (invert)
|
|
678
|
-
c = ~c;
|
|
679
|
-
if (i === bs.length - 1)
|
|
680
|
-
c &= lastMask;
|
|
681
|
-
if (c === 0)
|
|
682
|
-
continue;
|
|
683
|
-
for (let j = 0; j < BITS; j++) {
|
|
684
|
-
const m = 1 << BITS - j - 1;
|
|
685
|
-
if (c & m)
|
|
686
|
-
res.push(i * BITS + j);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
return res;
|
|
690
|
-
},
|
|
691
|
-
range: (arr) => {
|
|
692
|
-
const res = [];
|
|
693
|
-
let cur;
|
|
694
|
-
for (const i of arr) {
|
|
695
|
-
if (cur === void 0 || i !== cur.pos + cur.length)
|
|
696
|
-
res.push(cur = { pos: i, length: 1 });
|
|
697
|
-
else
|
|
698
|
-
cur.length += 1;
|
|
699
|
-
}
|
|
700
|
-
return res;
|
|
701
|
-
},
|
|
702
|
-
rangeDebug: (bs, len, invert = false) => `[${Bitset.range(Bitset.indices(bs, len, invert)).map((i) => `(${i.pos}/${i.length})`).join(", ")}]`,
|
|
703
|
-
setRange: (bs, bsLen, pos, len, allowRewrite = true) => {
|
|
704
|
-
Bitset.chunkLen(bsLen, pos, len);
|
|
705
|
-
const { FULL_MASK, BITS } = Bitset;
|
|
706
|
-
const first = pos % BITS ? Math.floor(pos / BITS) : void 0;
|
|
707
|
-
const lastPos = pos + len;
|
|
708
|
-
const last = lastPos % BITS ? Math.floor(lastPos / BITS) : void 0;
|
|
709
|
-
if (first !== void 0 && first === last)
|
|
710
|
-
return Bitset.set(bs, first, FULL_MASK >>> BITS - len << BITS - len - pos, allowRewrite);
|
|
711
|
-
if (first !== void 0) {
|
|
712
|
-
if (!Bitset.set(bs, first, FULL_MASK >>> pos % BITS, allowRewrite))
|
|
713
|
-
return false;
|
|
714
|
-
}
|
|
715
|
-
const start = first !== void 0 ? first + 1 : pos / BITS;
|
|
716
|
-
const end = last !== void 0 ? last : lastPos / BITS;
|
|
717
|
-
for (let i = start; i < end; i++)
|
|
718
|
-
if (!Bitset.set(bs, i, FULL_MASK, allowRewrite))
|
|
719
|
-
return false;
|
|
720
|
-
if (last !== void 0 && first !== last) {
|
|
721
|
-
if (!Bitset.set(bs, last, FULL_MASK << BITS - lastPos % BITS, allowRewrite))
|
|
722
|
-
return false;
|
|
723
|
-
}
|
|
724
|
-
return true;
|
|
725
|
-
}
|
|
726
|
-
};
|
|
727
|
-
var Path = {
|
|
728
|
-
/**
|
|
729
|
-
* Internal method for handling stack of paths (debug, errors, dynamic fields via path)
|
|
730
|
-
* This is looks ugly (callback), but allows us to force stack cleaning by construction (.pop always after function).
|
|
731
|
-
* Also, this makes impossible:
|
|
732
|
-
* - pushing field when stack is empty
|
|
733
|
-
* - pushing field inside of field (real bug)
|
|
734
|
-
* NOTE: we don't want to do '.pop' on error!
|
|
735
|
-
*/
|
|
736
|
-
pushObj: (stack, obj, objFn) => {
|
|
737
|
-
const last = { obj };
|
|
738
|
-
stack.push(last);
|
|
739
|
-
objFn((field, fieldFn) => {
|
|
740
|
-
last.field = field;
|
|
741
|
-
fieldFn();
|
|
742
|
-
last.field = void 0;
|
|
743
|
-
});
|
|
744
|
-
stack.pop();
|
|
745
|
-
},
|
|
746
|
-
path: (stack) => {
|
|
747
|
-
const res = [];
|
|
748
|
-
for (const i of stack)
|
|
749
|
-
if (i.field !== void 0)
|
|
750
|
-
res.push(i.field);
|
|
751
|
-
return res.join("/");
|
|
752
|
-
},
|
|
753
|
-
err: (name, stack, msg) => {
|
|
754
|
-
const err = new Error(`${name}(${Path.path(stack)}): ${typeof msg === "string" ? msg : msg.message}`);
|
|
755
|
-
if (msg instanceof Error && msg.stack)
|
|
756
|
-
err.stack = msg.stack;
|
|
757
|
-
return err;
|
|
758
|
-
},
|
|
759
|
-
resolve: (stack, path) => {
|
|
760
|
-
const parts = path.split("/");
|
|
761
|
-
const objPath = stack.map((i2) => i2.obj);
|
|
762
|
-
let i = 0;
|
|
763
|
-
for (; i < parts.length; i++) {
|
|
764
|
-
if (parts[i] === "..")
|
|
765
|
-
objPath.pop();
|
|
766
|
-
else
|
|
767
|
-
break;
|
|
768
|
-
}
|
|
769
|
-
let cur = objPath.pop();
|
|
770
|
-
for (; i < parts.length; i++) {
|
|
771
|
-
if (!cur || cur[parts[i]] === void 0)
|
|
772
|
-
return void 0;
|
|
773
|
-
cur = cur[parts[i]];
|
|
774
|
-
}
|
|
775
|
-
return cur;
|
|
776
|
-
}
|
|
777
|
-
};
|
|
778
|
-
var _Reader = class __Reader {
|
|
779
|
-
pos = 0;
|
|
780
|
-
data;
|
|
781
|
-
opts;
|
|
782
|
-
stack;
|
|
783
|
-
parent;
|
|
784
|
-
parentOffset;
|
|
785
|
-
bitBuf = 0;
|
|
786
|
-
bitPos = 0;
|
|
787
|
-
bs;
|
|
788
|
-
// bitset
|
|
789
|
-
view;
|
|
790
|
-
constructor(data, opts = {}, stack = [], parent = void 0, parentOffset = 0) {
|
|
791
|
-
this.data = data;
|
|
792
|
-
this.opts = opts;
|
|
793
|
-
this.stack = stack;
|
|
794
|
-
this.parent = parent;
|
|
795
|
-
this.parentOffset = parentOffset;
|
|
796
|
-
this.view = createView(data);
|
|
797
|
-
}
|
|
798
|
-
/** Internal method for pointers. */
|
|
799
|
-
_enablePointers() {
|
|
800
|
-
if (this.parent)
|
|
801
|
-
return this.parent._enablePointers();
|
|
802
|
-
if (this.bs)
|
|
803
|
-
return;
|
|
804
|
-
this.bs = Bitset.create(this.data.length);
|
|
805
|
-
Bitset.setRange(this.bs, this.data.length, 0, this.pos, this.opts.allowMultipleReads);
|
|
806
|
-
}
|
|
807
|
-
markBytesBS(pos, len) {
|
|
808
|
-
if (this.parent)
|
|
809
|
-
return this.parent.markBytesBS(this.parentOffset + pos, len);
|
|
810
|
-
if (!len)
|
|
811
|
-
return true;
|
|
812
|
-
if (!this.bs)
|
|
813
|
-
return true;
|
|
814
|
-
return Bitset.setRange(this.bs, this.data.length, pos, len, false);
|
|
815
|
-
}
|
|
816
|
-
markBytes(len) {
|
|
817
|
-
const pos = this.pos;
|
|
818
|
-
this.pos += len;
|
|
819
|
-
const res = this.markBytesBS(pos, len);
|
|
820
|
-
if (!this.opts.allowMultipleReads && !res)
|
|
821
|
-
throw this.err(`multiple read pos=${this.pos} len=${len}`);
|
|
822
|
-
return res;
|
|
823
|
-
}
|
|
824
|
-
pushObj(obj, objFn) {
|
|
825
|
-
return Path.pushObj(this.stack, obj, objFn);
|
|
826
|
-
}
|
|
827
|
-
readView(n, fn) {
|
|
828
|
-
if (!Number.isFinite(n))
|
|
829
|
-
throw this.err(`readView: wrong length=${n}`);
|
|
830
|
-
if (this.pos + n > this.data.length)
|
|
831
|
-
throw this.err("readView: Unexpected end of buffer");
|
|
832
|
-
const res = fn(this.view, this.pos);
|
|
833
|
-
this.markBytes(n);
|
|
834
|
-
return res;
|
|
835
|
-
}
|
|
836
|
-
// read bytes by absolute offset
|
|
837
|
-
absBytes(n) {
|
|
838
|
-
if (n > this.data.length)
|
|
839
|
-
throw new Error("Unexpected end of buffer");
|
|
840
|
-
return this.data.subarray(n);
|
|
841
|
-
}
|
|
842
|
-
finish() {
|
|
843
|
-
if (this.opts.allowUnreadBytes)
|
|
844
|
-
return;
|
|
845
|
-
if (this.bitPos) {
|
|
846
|
-
throw this.err(`${this.bitPos} bits left after unpack: ${base.hex.encode(this.data.slice(this.pos))}`);
|
|
847
|
-
}
|
|
848
|
-
if (this.bs && !this.parent) {
|
|
849
|
-
const notRead = Bitset.indices(this.bs, this.data.length, true);
|
|
850
|
-
if (notRead.length) {
|
|
851
|
-
const formatted = Bitset.range(notRead).map(({ pos, length }) => `(${pos}/${length})[${base.hex.encode(this.data.subarray(pos, pos + length))}]`).join(", ");
|
|
852
|
-
throw this.err(`unread byte ranges: ${formatted} (total=${this.data.length})`);
|
|
853
|
-
} else
|
|
854
|
-
return;
|
|
855
|
-
}
|
|
856
|
-
if (!this.isEnd()) {
|
|
857
|
-
throw this.err(`${this.leftBytes} bytes ${this.bitPos} bits left after unpack: ${base.hex.encode(this.data.slice(this.pos))}`);
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
// User methods
|
|
861
|
-
err(msg) {
|
|
862
|
-
return Path.err("Reader", this.stack, msg);
|
|
863
|
-
}
|
|
864
|
-
offsetReader(n) {
|
|
865
|
-
if (n > this.data.length)
|
|
866
|
-
throw this.err("offsetReader: Unexpected end of buffer");
|
|
867
|
-
return new __Reader(this.absBytes(n), this.opts, this.stack, this, n);
|
|
868
|
-
}
|
|
869
|
-
bytes(n, peek = false) {
|
|
870
|
-
if (this.bitPos)
|
|
871
|
-
throw this.err("readBytes: bitPos not empty");
|
|
872
|
-
if (!Number.isFinite(n))
|
|
873
|
-
throw this.err(`readBytes: wrong length=${n}`);
|
|
874
|
-
if (this.pos + n > this.data.length)
|
|
875
|
-
throw this.err("readBytes: Unexpected end of buffer");
|
|
876
|
-
const slice = this.data.subarray(this.pos, this.pos + n);
|
|
877
|
-
if (!peek)
|
|
878
|
-
this.markBytes(n);
|
|
879
|
-
return slice;
|
|
880
|
-
}
|
|
881
|
-
byte(peek = false) {
|
|
882
|
-
if (this.bitPos)
|
|
883
|
-
throw this.err("readByte: bitPos not empty");
|
|
884
|
-
if (this.pos + 1 > this.data.length)
|
|
885
|
-
throw this.err("readBytes: Unexpected end of buffer");
|
|
886
|
-
const data = this.data[this.pos];
|
|
887
|
-
if (!peek)
|
|
888
|
-
this.markBytes(1);
|
|
889
|
-
return data;
|
|
890
|
-
}
|
|
891
|
-
get leftBytes() {
|
|
892
|
-
return this.data.length - this.pos;
|
|
893
|
-
}
|
|
894
|
-
get totalBytes() {
|
|
895
|
-
return this.data.length;
|
|
896
|
-
}
|
|
897
|
-
isEnd() {
|
|
898
|
-
return this.pos >= this.data.length && !this.bitPos;
|
|
899
|
-
}
|
|
900
|
-
// bits are read in BE mode (left to right): (0b1000_0000).readBits(1) == 1
|
|
901
|
-
bits(bits) {
|
|
902
|
-
if (bits > 32)
|
|
903
|
-
throw this.err("BitReader: cannot read more than 32 bits in single call");
|
|
904
|
-
let out = 0;
|
|
905
|
-
while (bits) {
|
|
906
|
-
if (!this.bitPos) {
|
|
907
|
-
this.bitBuf = this.byte();
|
|
908
|
-
this.bitPos = 8;
|
|
909
|
-
}
|
|
910
|
-
const take = Math.min(bits, this.bitPos);
|
|
911
|
-
this.bitPos -= take;
|
|
912
|
-
out = out << take | this.bitBuf >> this.bitPos & 2 ** take - 1;
|
|
913
|
-
this.bitBuf &= 2 ** this.bitPos - 1;
|
|
914
|
-
bits -= take;
|
|
915
|
-
}
|
|
916
|
-
return out >>> 0;
|
|
917
|
-
}
|
|
918
|
-
find(needle, pos = this.pos) {
|
|
919
|
-
if (!isBytes(needle))
|
|
920
|
-
throw this.err(`find: needle is not bytes! ${needle}`);
|
|
921
|
-
if (this.bitPos)
|
|
922
|
-
throw this.err("findByte: bitPos not empty");
|
|
923
|
-
if (!needle.length)
|
|
924
|
-
throw this.err(`find: needle is empty`);
|
|
925
|
-
for (let idx = pos; (idx = this.data.indexOf(needle[0], idx)) !== -1; idx++) {
|
|
926
|
-
if (idx === -1)
|
|
927
|
-
return;
|
|
928
|
-
const leftBytes = this.data.length - idx;
|
|
929
|
-
if (leftBytes < needle.length)
|
|
930
|
-
return;
|
|
931
|
-
if (equalBytes(needle, this.data.subarray(idx, idx + needle.length)))
|
|
932
|
-
return idx;
|
|
933
|
-
}
|
|
934
|
-
return;
|
|
935
|
-
}
|
|
936
|
-
};
|
|
937
|
-
var _Writer = class {
|
|
938
|
-
pos = 0;
|
|
939
|
-
stack;
|
|
940
|
-
// We could have a single buffer here and re-alloc it with
|
|
941
|
-
// x1.5-2 size each time it full, but it will be slower:
|
|
942
|
-
// basic/encode bench: 395ns -> 560ns
|
|
943
|
-
buffers = [];
|
|
944
|
-
ptrs = [];
|
|
945
|
-
bitBuf = 0;
|
|
946
|
-
bitPos = 0;
|
|
947
|
-
viewBuf = new Uint8Array(8);
|
|
948
|
-
view;
|
|
949
|
-
finished = false;
|
|
950
|
-
constructor(stack = []) {
|
|
951
|
-
this.stack = stack;
|
|
952
|
-
this.view = createView(this.viewBuf);
|
|
953
|
-
}
|
|
954
|
-
pushObj(obj, objFn) {
|
|
955
|
-
return Path.pushObj(this.stack, obj, objFn);
|
|
956
|
-
}
|
|
957
|
-
writeView(len, fn) {
|
|
958
|
-
if (this.finished)
|
|
959
|
-
throw this.err("buffer: finished");
|
|
960
|
-
if (!isNum(len) || len > 8)
|
|
961
|
-
throw new Error(`wrong writeView length=${len}`);
|
|
962
|
-
fn(this.view);
|
|
963
|
-
this.bytes(this.viewBuf.slice(0, len));
|
|
964
|
-
this.viewBuf.fill(0);
|
|
965
|
-
}
|
|
966
|
-
// User methods
|
|
967
|
-
err(msg) {
|
|
968
|
-
if (this.finished)
|
|
969
|
-
throw this.err("buffer: finished");
|
|
970
|
-
return Path.err("Reader", this.stack, msg);
|
|
971
|
-
}
|
|
972
|
-
bytes(b) {
|
|
973
|
-
if (this.finished)
|
|
974
|
-
throw this.err("buffer: finished");
|
|
975
|
-
if (this.bitPos)
|
|
976
|
-
throw this.err("writeBytes: ends with non-empty bit buffer");
|
|
977
|
-
this.buffers.push(b);
|
|
978
|
-
this.pos += b.length;
|
|
979
|
-
}
|
|
980
|
-
byte(b) {
|
|
981
|
-
if (this.finished)
|
|
982
|
-
throw this.err("buffer: finished");
|
|
983
|
-
if (this.bitPos)
|
|
984
|
-
throw this.err("writeByte: ends with non-empty bit buffer");
|
|
985
|
-
this.buffers.push(new Uint8Array([b]));
|
|
986
|
-
this.pos++;
|
|
987
|
-
}
|
|
988
|
-
finish(clean = true) {
|
|
989
|
-
if (this.finished)
|
|
990
|
-
throw this.err("buffer: finished");
|
|
991
|
-
if (this.bitPos)
|
|
992
|
-
throw this.err("buffer: ends with non-empty bit buffer");
|
|
993
|
-
const buffers = this.buffers.concat(this.ptrs.map((i) => i.buffer));
|
|
994
|
-
const sum = buffers.map((b) => b.length).reduce((a, b) => a + b, 0);
|
|
995
|
-
const buf = new Uint8Array(sum);
|
|
996
|
-
for (let i = 0, pad = 0; i < buffers.length; i++) {
|
|
997
|
-
const a = buffers[i];
|
|
998
|
-
buf.set(a, pad);
|
|
999
|
-
pad += a.length;
|
|
1000
|
-
}
|
|
1001
|
-
for (let pos = this.pos, i = 0; i < this.ptrs.length; i++) {
|
|
1002
|
-
const ptr = this.ptrs[i];
|
|
1003
|
-
buf.set(ptr.ptr.encode(pos), ptr.pos);
|
|
1004
|
-
pos += ptr.buffer.length;
|
|
1005
|
-
}
|
|
1006
|
-
if (clean) {
|
|
1007
|
-
this.buffers = [];
|
|
1008
|
-
for (const p of this.ptrs)
|
|
1009
|
-
p.buffer.fill(0);
|
|
1010
|
-
this.ptrs = [];
|
|
1011
|
-
this.finished = true;
|
|
1012
|
-
this.bitBuf = 0;
|
|
1013
|
-
}
|
|
1014
|
-
return buf;
|
|
1015
|
-
}
|
|
1016
|
-
bits(value, bits) {
|
|
1017
|
-
if (bits > 32)
|
|
1018
|
-
throw this.err("writeBits: cannot write more than 32 bits in single call");
|
|
1019
|
-
if (value >= 2 ** bits)
|
|
1020
|
-
throw this.err(`writeBits: value (${value}) >= 2**bits (${bits})`);
|
|
1021
|
-
while (bits) {
|
|
1022
|
-
const take = Math.min(bits, 8 - this.bitPos);
|
|
1023
|
-
this.bitBuf = this.bitBuf << take | value >> bits - take;
|
|
1024
|
-
this.bitPos += take;
|
|
1025
|
-
bits -= take;
|
|
1026
|
-
value &= 2 ** bits - 1;
|
|
1027
|
-
if (this.bitPos === 8) {
|
|
1028
|
-
this.bitPos = 0;
|
|
1029
|
-
this.buffers.push(new Uint8Array([this.bitBuf]));
|
|
1030
|
-
this.pos++;
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
function _wrap(inner) {
|
|
1036
|
-
return {
|
|
1037
|
-
// NOTE: we cannot export validate here, since it is likely mistake.
|
|
1038
|
-
encodeStream: inner.encodeStream,
|
|
1039
|
-
decodeStream: inner.decodeStream,
|
|
1040
|
-
size: inner.size,
|
|
1041
|
-
encode: (value) => {
|
|
1042
|
-
const w = new _Writer();
|
|
1043
|
-
inner.encodeStream(w, value);
|
|
1044
|
-
return w.finish();
|
|
1045
|
-
},
|
|
1046
|
-
decode: (data, opts = {}) => {
|
|
1047
|
-
const r = new _Reader(data, opts);
|
|
1048
|
-
const res = inner.decodeStream(r);
|
|
1049
|
-
r.finish();
|
|
1050
|
-
return res;
|
|
1051
|
-
}
|
|
1052
|
-
};
|
|
1053
|
-
}
|
|
1054
|
-
function validate(inner, fn) {
|
|
1055
|
-
if (!isCoder(inner))
|
|
1056
|
-
throw new Error(`validate: invalid inner value ${inner}`);
|
|
1057
|
-
if (typeof fn !== "function")
|
|
1058
|
-
throw new Error("validate: fn should be function");
|
|
1059
|
-
return _wrap({
|
|
1060
|
-
size: inner.size,
|
|
1061
|
-
encodeStream: (w, value) => {
|
|
1062
|
-
let res;
|
|
1063
|
-
try {
|
|
1064
|
-
res = fn(value);
|
|
1065
|
-
} catch (e) {
|
|
1066
|
-
throw w.err(e);
|
|
1067
|
-
}
|
|
1068
|
-
inner.encodeStream(w, res);
|
|
1069
|
-
},
|
|
1070
|
-
decodeStream: (r) => {
|
|
1071
|
-
const res = inner.decodeStream(r);
|
|
1072
|
-
try {
|
|
1073
|
-
return fn(res);
|
|
1074
|
-
} catch (e) {
|
|
1075
|
-
throw r.err(e);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
});
|
|
1079
|
-
}
|
|
1080
|
-
var wrap = (inner) => {
|
|
1081
|
-
const res = _wrap(inner);
|
|
1082
|
-
return inner.validate ? validate(res, inner.validate) : res;
|
|
1083
|
-
};
|
|
1084
|
-
var isBaseCoder = (elm) => isPlainObject(elm) && typeof elm.decode === "function" && typeof elm.encode === "function";
|
|
1085
|
-
function isCoder(elm) {
|
|
1086
|
-
return isPlainObject(elm) && isBaseCoder(elm) && typeof elm.encodeStream === "function" && typeof elm.decodeStream === "function" && (elm.size === void 0 || isNum(elm.size));
|
|
1087
|
-
}
|
|
1088
|
-
var view = (len, opts) => wrap({
|
|
1089
|
-
size: len,
|
|
1090
|
-
encodeStream: (w, value) => w.writeView(len, (view2) => opts.write(view2, value)),
|
|
1091
|
-
decodeStream: (r) => r.readView(len, opts.read),
|
|
1092
|
-
validate: (value) => {
|
|
1093
|
-
if (typeof value !== "number")
|
|
1094
|
-
throw new Error(`viewCoder: expected number, got ${typeof value}`);
|
|
1095
|
-
if (opts.validate)
|
|
1096
|
-
opts.validate(value);
|
|
1097
|
-
return value;
|
|
1098
|
-
}
|
|
1099
|
-
});
|
|
1100
|
-
var intView = (len, signed, opts) => {
|
|
1101
|
-
const bits = len * 8;
|
|
1102
|
-
const maxVal = 2 ** bits;
|
|
1103
|
-
const validateUnsigned = (value) => {
|
|
1104
|
-
if (!isNum(value))
|
|
1105
|
-
throw new Error(`uintView: value is not safe integer: ${value}`);
|
|
1106
|
-
if (0 > value || value >= maxVal) {
|
|
1107
|
-
throw new Error(`uintView: value out of bounds. Expected 0 <= ${value} < ${maxVal}`);
|
|
1108
|
-
}
|
|
1109
|
-
};
|
|
1110
|
-
return view(len, {
|
|
1111
|
-
write: opts.write,
|
|
1112
|
-
read: opts.read,
|
|
1113
|
-
validate: validateUnsigned
|
|
1114
|
-
});
|
|
1115
|
-
};
|
|
1116
|
-
var U32LE = /* @__PURE__ */ intView(4, false, {
|
|
1117
|
-
read: (view2, pos) => view2.getUint32(pos, true),
|
|
1118
|
-
write: (view2, value) => view2.setUint32(0, value, true)
|
|
1119
|
-
});
|
|
1120
|
-
var U16LE = /* @__PURE__ */ intView(2, false, {
|
|
1121
|
-
read: (view2, pos) => view2.getUint16(pos, true),
|
|
1122
|
-
write: (view2, value) => view2.setUint16(0, value, true)
|
|
1123
|
-
});
|
|
1124
|
-
var U8 = /* @__PURE__ */ intView(1, false, {
|
|
1125
|
-
read: (view2, pos) => view2.getUint8(pos),
|
|
1126
|
-
write: (view2, value) => view2.setUint8(0, value)
|
|
1127
|
-
});
|
|
1128
721
|
var ARKADE_OP = {
|
|
1129
722
|
// Merkle Branch Verification (0xb3 — repurposed NOP4 slot)
|
|
1130
723
|
MERKLEBRANCHVERIFY: 179,
|
|
724
|
+
PUT: 187,
|
|
1131
725
|
// Digest (0xc3)
|
|
1132
726
|
DIGEST: 195,
|
|
1133
727
|
// SHA256 Streaming (0xc4-0xc6)
|
|
@@ -1159,7 +753,10 @@ var ARKADE_OP = {
|
|
|
1159
753
|
BIN2NUM: 216,
|
|
1160
754
|
REVERSEBYTES: 217,
|
|
1161
755
|
MODEXP: 218,
|
|
1162
|
-
//
|
|
756
|
+
// VTXO Expiry & Emulator Clock (0xdb-0xdc)
|
|
757
|
+
PUSHEXPIRY: 219,
|
|
758
|
+
CHECKTIME: 220,
|
|
759
|
+
// 0xdd-0xdf are unassigned (OP_UNKNOWN221-223)
|
|
1163
760
|
// EC Operations (0xe0-0xe2)
|
|
1164
761
|
ECADD: 224,
|
|
1165
762
|
ECMUL: 225,
|
|
@@ -1188,7 +785,10 @@ var ARKADE_OP = {
|
|
|
1188
785
|
INSPECTPACKET: 244,
|
|
1189
786
|
INSPECTINPUTPACKET: 245,
|
|
1190
787
|
// Signature Hash (0xf6)
|
|
1191
|
-
SIGHASH: 246
|
|
788
|
+
SIGHASH: 246,
|
|
789
|
+
// Continuation & Intent Introspection (0xf7-0xf8)
|
|
790
|
+
TUNNEL: 247,
|
|
791
|
+
INSPECTINTENTMESSAGE: 248
|
|
1192
792
|
};
|
|
1193
793
|
var ARKADE_OPCODES = Object.values(ARKADE_OP);
|
|
1194
794
|
var ARKADE_OPCODE_NAMES = Object.fromEntries(
|
|
@@ -1256,7 +856,7 @@ function getOpcodeValue(name) {
|
|
|
1256
856
|
|
|
1257
857
|
// src/arkade/bignum.ts
|
|
1258
858
|
var bignum_exports = {};
|
|
1259
|
-
|
|
859
|
+
chunkASKOHVGX_cjs.__export(bignum_exports, {
|
|
1260
860
|
BIGNUM_MAX_BYTES: () => BIGNUM_MAX_BYTES,
|
|
1261
861
|
decode: () => decode,
|
|
1262
862
|
encode: () => encode
|
|
@@ -1284,7 +884,7 @@ var ArkadeOPNames = {};
|
|
|
1284
884
|
for (const [k, v] of Object.entries(ARKADE_OPS)) {
|
|
1285
885
|
if (typeof v === "number") ArkadeOPNames[v] = k;
|
|
1286
886
|
}
|
|
1287
|
-
var ArkadeScript = wrap({
|
|
887
|
+
var ArkadeScript = P__namespace.wrap({
|
|
1288
888
|
encodeStream: (w, value) => {
|
|
1289
889
|
for (let o of value) {
|
|
1290
890
|
if (typeof o === "string") {
|
|
@@ -1310,10 +910,10 @@ var ArkadeScript = wrap({
|
|
|
1310
910
|
w.byte(len);
|
|
1311
911
|
} else if (len <= 65535) {
|
|
1312
912
|
w.byte(btcSigner.OP.PUSHDATA2);
|
|
1313
|
-
w.bytes(U16LE.encode(len));
|
|
913
|
+
w.bytes(P__namespace.U16LE.encode(len));
|
|
1314
914
|
} else {
|
|
1315
915
|
w.byte(btcSigner.OP.PUSHDATA4);
|
|
1316
|
-
w.bytes(U32LE.encode(len));
|
|
916
|
+
w.bytes(P__namespace.U32LE.encode(len));
|
|
1317
917
|
}
|
|
1318
918
|
w.bytes(o);
|
|
1319
919
|
}
|
|
@@ -1325,9 +925,9 @@ var ArkadeScript = wrap({
|
|
|
1325
925
|
if (btcSigner.OP.OP_0 < cur && cur <= btcSigner.OP.PUSHDATA4) {
|
|
1326
926
|
let len;
|
|
1327
927
|
if (cur < btcSigner.OP.PUSHDATA1) len = cur;
|
|
1328
|
-
else if (cur === btcSigner.OP.PUSHDATA1) len = U8.decodeStream(r);
|
|
1329
|
-
else if (cur === btcSigner.OP.PUSHDATA2) len = U16LE.decodeStream(r);
|
|
1330
|
-
else if (cur === btcSigner.OP.PUSHDATA4) len = U32LE.decodeStream(r);
|
|
928
|
+
else if (cur === btcSigner.OP.PUSHDATA1) len = P__namespace.U8.decodeStream(r);
|
|
929
|
+
else if (cur === btcSigner.OP.PUSHDATA2) len = P__namespace.U16LE.decodeStream(r);
|
|
930
|
+
else if (cur === btcSigner.OP.PUSHDATA4) len = P__namespace.U32LE.decodeStream(r);
|
|
1331
931
|
else throw new Error("Should be not possible");
|
|
1332
932
|
out.push(r.bytes(len));
|
|
1333
933
|
} else if (cur === 0) {
|
|
@@ -1445,7 +1045,7 @@ function computeArkadeScriptPublicKey(pubKey, script) {
|
|
|
1445
1045
|
// src/script/vhtlc.ts
|
|
1446
1046
|
exports.VHTLC = void 0;
|
|
1447
1047
|
((VHTLC2) => {
|
|
1448
|
-
class BaseScript extends
|
|
1048
|
+
class BaseScript extends chunkASKOHVGX_cjs.VtxoScript {
|
|
1449
1049
|
options;
|
|
1450
1050
|
claimScript;
|
|
1451
1051
|
refundScript;
|
|
@@ -1472,27 +1072,27 @@ exports.VHTLC = void 0;
|
|
|
1472
1072
|
unilateralRefundWithoutReceiverDelay
|
|
1473
1073
|
} = options;
|
|
1474
1074
|
const conditionScript = preimageCondition(preimageHash);
|
|
1475
|
-
const claimScript =
|
|
1075
|
+
const claimScript = chunkASKOHVGX_cjs.ConditionMultisigTapscript.encode({
|
|
1476
1076
|
conditionScript,
|
|
1477
1077
|
pubkeys: [receiver, server]
|
|
1478
1078
|
}).script;
|
|
1479
|
-
const refundScript =
|
|
1079
|
+
const refundScript = chunkASKOHVGX_cjs.MultisigTapscript.encode({
|
|
1480
1080
|
pubkeys: [sender, receiver, server]
|
|
1481
1081
|
}).script;
|
|
1482
|
-
const refundWithoutReceiverScript =
|
|
1082
|
+
const refundWithoutReceiverScript = chunkASKOHVGX_cjs.CLTVMultisigTapscript.encode({
|
|
1483
1083
|
absoluteTimelock: refundLocktime,
|
|
1484
1084
|
pubkeys: [sender, server]
|
|
1485
1085
|
}).script;
|
|
1486
|
-
const unilateralClaimScript =
|
|
1086
|
+
const unilateralClaimScript = chunkASKOHVGX_cjs.ConditionCSVMultisigTapscript.encode({
|
|
1487
1087
|
conditionScript,
|
|
1488
1088
|
timelock: unilateralClaimDelay,
|
|
1489
1089
|
pubkeys: [receiver]
|
|
1490
1090
|
}).script;
|
|
1491
|
-
const unilateralRefundScript =
|
|
1091
|
+
const unilateralRefundScript = chunkASKOHVGX_cjs.CSVMultisigTapscript.encode({
|
|
1492
1092
|
timelock: unilateralRefundDelay,
|
|
1493
1093
|
pubkeys: [sender, receiver]
|
|
1494
1094
|
}).script;
|
|
1495
|
-
const unilateralRefundWithoutReceiverScript =
|
|
1095
|
+
const unilateralRefundWithoutReceiverScript = chunkASKOHVGX_cjs.CSVMultisigTapscript.encode({
|
|
1496
1096
|
timelock: unilateralRefundWithoutReceiverDelay,
|
|
1497
1097
|
pubkeys: [sender]
|
|
1498
1098
|
}).script;
|
|
@@ -1512,7 +1112,7 @@ exports.VHTLC = void 0;
|
|
|
1512
1112
|
const covenants = options.nonInteractiveParameters;
|
|
1513
1113
|
if (covenants) {
|
|
1514
1114
|
arkadeScriptNic = enforcePayToMaybeAsset(covenants.receiverPkScript, options.asset);
|
|
1515
|
-
nonInteractiveClaimScript =
|
|
1115
|
+
nonInteractiveClaimScript = chunkASKOHVGX_cjs.ConditionMultisigTapscript.encode({
|
|
1516
1116
|
conditionScript,
|
|
1517
1117
|
pubkeys: [
|
|
1518
1118
|
server,
|
|
@@ -1525,12 +1125,12 @@ exports.VHTLC = void 0;
|
|
|
1525
1125
|
covenants.emulatorPubkey,
|
|
1526
1126
|
arkadeScriptNir
|
|
1527
1127
|
);
|
|
1528
|
-
nonInteractiveRefundScript =
|
|
1128
|
+
nonInteractiveRefundScript = chunkASKOHVGX_cjs.MultisigTapscript.encode({
|
|
1529
1129
|
pubkeys: [server, receiver, nirCosigner]
|
|
1530
1130
|
}).script;
|
|
1531
1131
|
scripts.push(nonInteractiveRefundScript);
|
|
1532
1132
|
if (covenants.legacy !== "preTimelockedRefund") {
|
|
1533
|
-
nonInteractiveRefundWithoutReceiverScript =
|
|
1133
|
+
nonInteractiveRefundWithoutReceiverScript = chunkASKOHVGX_cjs.CLTVMultisigTapscript.encode({
|
|
1534
1134
|
absoluteTimelock: refundLocktime,
|
|
1535
1135
|
pubkeys: [server, nirCosigner]
|
|
1536
1136
|
}).script;
|
|
@@ -1609,54 +1209,19 @@ exports.VHTLC = void 0;
|
|
|
1609
1209
|
/**
|
|
1610
1210
|
* Return the timelocked non-interactive refund tapleaf and its ArkadeScript.
|
|
1611
1211
|
*
|
|
1612
|
-
*
|
|
1613
|
-
*
|
|
1614
|
-
*
|
|
1615
|
-
*
|
|
1616
|
-
* the
|
|
1617
|
-
*
|
|
1618
|
-
*
|
|
1619
|
-
*
|
|
1620
|
-
* TapLeafScript} as `tapLeafScript`, this script's {@link
|
|
1621
|
-
* VtxoScript.encode} as `tapTree`), plus its checkpoint tx.
|
|
1622
|
-
* 2. Attach the ArkadeScript this method returns to the spent
|
|
1623
|
-
* input via an `EmulatorPacket` (type 1) — `{ vin, script:
|
|
1624
|
-
* <this ArkadeScript>, witness: <empty> }`, empty because the
|
|
1625
|
-
* script pushes its own input/output index with
|
|
1626
|
-
* `PUSHCURRENTINPUTINDEX` rather than reading one from the
|
|
1627
|
-
* witness — wrapped in an `Extension` OP_RETURN output on the
|
|
1628
|
-
* ark tx.
|
|
1629
|
-
* 3. Attach the spent input's OWN creating ark tx as `PrevArkTx` on
|
|
1630
|
-
* input 0 — required so the emulator can resolve that input's
|
|
1631
|
-
* prevout pkScript/value; it does not otherwise have them.
|
|
1632
|
-
* 4. POST the (base64-PSBT) ark tx and checkpoint(s) as `{ arkTx,
|
|
1633
|
-
* checkpointTxs }` to the emulator's `POST /v1/tx`.
|
|
1212
|
+
* Spent through the generic covenant path ({@link EmulatorProvider},
|
|
1213
|
+
* {@link ArkadeTransactionBuilder}): build the ark tx on this leaf plus its checkpoint;
|
|
1214
|
+
* attach this ArkadeScript to the input in an `EmulatorPacket` (type 1, empty witness:
|
|
1215
|
+
* the script pushes its own index with `PUSHCURRENTINPUTINDEX`) inside an `Extension`
|
|
1216
|
+
* OP_RETURN; attach the input's creating ark tx as `PrevArkTx` (the emulator can't
|
|
1217
|
+
* otherwise resolve its prevout); POST to the emulator's `/v1/tx`. The emulator co-signs
|
|
1218
|
+
* for `nirCosigner` only if `enforcePayTo(senderPkScript)` holds, and finalizes with arkd.
|
|
1219
|
+
* `server`'s signature is still required at consensus level, outside the covenant.
|
|
1634
1220
|
*
|
|
1635
|
-
*
|
|
1636
|
-
*
|
|
1637
|
-
*
|
|
1638
|
-
*
|
|
1639
|
-
* check passing does the emulator sign for `nirCosigner` (the
|
|
1640
|
-
* `emulatorPubkey` tweaked by this ArkadeScript's hash); the
|
|
1641
|
-
* response carries the fully co-signed `signedArkTx` and
|
|
1642
|
-
* `signedCheckpointTxs` — `ArkadeTransactionBuilder.send()`'s own
|
|
1643
|
-
* comment on this path: "the emulator executes the arkade script
|
|
1644
|
-
* and finalizes with arkd" — no separate call to arkd is made by
|
|
1645
|
-
* this SDK for a covenant spend.
|
|
1646
|
-
* Neither `server` nor `receiver` play any part in that check: this
|
|
1647
|
-
* leaf's tapscript still requires `server`'s own signature
|
|
1648
|
-
* alongside `nirCosigner`'s (see the class doc above), but that is
|
|
1649
|
-
* consensus-level multisig, not something the covenant enforces.
|
|
1650
|
-
*
|
|
1651
|
-
* NOT SPENDABLE UNTIL `refundLocktime` MATURES — the tapscript's
|
|
1652
|
-
* `OP_CHECKLOCKTIMEVERIFY` is arkd's concern, not the emulator's;
|
|
1653
|
-
* the emulator will happily co-sign an immature spend and arkd will
|
|
1654
|
-
* then refuse it. A block-height-typed `refundLocktime` (below the
|
|
1655
|
-
* standard height/timestamp boundary this SDK names
|
|
1656
|
-
* `CLTV_HEIGHT_THRESHOLD`, 500,000,000, in
|
|
1657
|
-
* `src/contracts/handlers/helpers.ts`) is refused by arkd for a
|
|
1658
|
-
* forfeit-eligible leaf independent of maturity — use a
|
|
1659
|
-
* seconds-typed (absolute Unix timestamp) value.
|
|
1221
|
+
* The emulator does not check `refundLocktime`: it co-signs an immature spend and arkd's
|
|
1222
|
+
* CLTV refuses it. arkd also refuses a block-height `refundLocktime`
|
|
1223
|
+
* (< `CLTV_HEIGHT_THRESHOLD`, 500,000,000) on a forfeit-eligible leaf regardless of
|
|
1224
|
+
* maturity: use a seconds-typed (Unix timestamp) value.
|
|
1660
1225
|
*/
|
|
1661
1226
|
nonInteractiveRefundWithoutReceiver() {
|
|
1662
1227
|
if (!this.nonInteractiveRefundWithoutReceiverScript || !this.nonInteractiveRefundWithoutReceiverArkadeScript) {
|
|
@@ -1799,10 +1364,7 @@ function enforcePayToAsset(destinationPkScript, asset) {
|
|
|
1799
1364
|
}
|
|
1800
1365
|
const inspectionTxid = Uint8Array.from(asset.txid).reverse();
|
|
1801
1366
|
return ArkadeScript.encode([
|
|
1802
|
-
// The output carries at least
|
|
1803
|
-
// Output index is the input's -- the same index alignment the sat
|
|
1804
|
-
// covenant relies on, and the same liveness obligation on whoever
|
|
1805
|
-
// assembles the spend.
|
|
1367
|
+
// The output at the input's index carries at least the input's amount of the asset.
|
|
1806
1368
|
"PUSHCURRENTINPUTINDEX",
|
|
1807
1369
|
inspectionTxid,
|
|
1808
1370
|
asset.groupIndex,
|
|
@@ -1844,9 +1406,9 @@ var VHTLCContractHandler = {
|
|
|
1844
1406
|
server: base.hex.encode(params.server),
|
|
1845
1407
|
hash: base.hex.encode(params.preimageHash),
|
|
1846
1408
|
refundLocktime: params.refundLocktime.toString(),
|
|
1847
|
-
claimDelay:
|
|
1848
|
-
refundDelay:
|
|
1849
|
-
refundNoReceiverDelay:
|
|
1409
|
+
claimDelay: chunkASKOHVGX_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
|
|
1410
|
+
refundDelay: chunkASKOHVGX_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
|
|
1411
|
+
refundNoReceiverDelay: chunkASKOHVGX_cjs.timelockToSequence(
|
|
1850
1412
|
params.unilateralRefundWithoutReceiverDelay
|
|
1851
1413
|
).toString()
|
|
1852
1414
|
};
|
|
@@ -1858,147 +1420,26 @@ var VHTLCContractHandler = {
|
|
|
1858
1420
|
server: base.hex.decode(params.server),
|
|
1859
1421
|
preimageHash: base.hex.decode(params.hash),
|
|
1860
1422
|
refundLocktime: BigInt(params.refundLocktime),
|
|
1861
|
-
unilateralClaimDelay:
|
|
1862
|
-
unilateralRefundDelay:
|
|
1863
|
-
unilateralRefundWithoutReceiverDelay:
|
|
1423
|
+
unilateralClaimDelay: chunkASKOHVGX_cjs.sequenceToTimelock(Number(params.claimDelay)),
|
|
1424
|
+
unilateralRefundDelay: chunkASKOHVGX_cjs.sequenceToTimelock(Number(params.refundDelay)),
|
|
1425
|
+
unilateralRefundWithoutReceiverDelay: chunkASKOHVGX_cjs.sequenceToTimelock(
|
|
1864
1426
|
Number(params.refundNoReceiverDelay)
|
|
1865
1427
|
)
|
|
1866
1428
|
};
|
|
1867
1429
|
},
|
|
1868
1430
|
/**
|
|
1869
|
-
* Select spending path based on context.
|
|
1870
|
-
*
|
|
1871
|
-
* Role is determined from `context.role` or by matching
|
|
1872
|
-
* `context.walletDescriptor` (preferred) / `context.walletPubKey`
|
|
1873
|
-
* against sender/receiver in contract params.
|
|
1431
|
+
* Select spending path based on context. Role comes from `context.role` or from matching
|
|
1432
|
+
* `context.walletDescriptor` against sender/receiver.
|
|
1874
1433
|
*/
|
|
1875
1434
|
selectPath(script, contract, context) {
|
|
1876
|
-
|
|
1877
|
-
const preimage = contract.params?.preimage;
|
|
1878
|
-
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
1879
|
-
if (!role) {
|
|
1880
|
-
return null;
|
|
1881
|
-
}
|
|
1882
|
-
if (context.collaborative) {
|
|
1883
|
-
if (role === "receiver" && preimage) {
|
|
1884
|
-
return {
|
|
1885
|
-
leaf: script.claim(),
|
|
1886
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
1887
|
-
};
|
|
1888
|
-
}
|
|
1889
|
-
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
1890
|
-
return {
|
|
1891
|
-
leaf: script.refundWithoutReceiver()
|
|
1892
|
-
};
|
|
1893
|
-
}
|
|
1894
|
-
return null;
|
|
1895
|
-
}
|
|
1896
|
-
if (role === "receiver" && preimage) {
|
|
1897
|
-
const sequence = Number(contract.params.claimDelay);
|
|
1898
|
-
if (!isCsvSpendable(context, sequence)) return null;
|
|
1899
|
-
return {
|
|
1900
|
-
leaf: script.unilateralClaim(),
|
|
1901
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
1902
|
-
sequence
|
|
1903
|
-
};
|
|
1904
|
-
}
|
|
1905
|
-
if (role === "sender") {
|
|
1906
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
1907
|
-
if (!isCsvSpendable(context, sequence)) return null;
|
|
1908
|
-
return {
|
|
1909
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
1910
|
-
sequence
|
|
1911
|
-
};
|
|
1912
|
-
}
|
|
1913
|
-
return null;
|
|
1435
|
+
return selectVhtlcPath(script, contract, context);
|
|
1914
1436
|
},
|
|
1915
|
-
/**
|
|
1916
|
-
* Get all possible spending paths (no timelock checks).
|
|
1917
|
-
*
|
|
1918
|
-
* Role is determined from `context.role` or by matching
|
|
1919
|
-
* `context.walletDescriptor` (preferred) / `context.walletPubKey`
|
|
1920
|
-
* against sender/receiver in contract params.
|
|
1921
|
-
*/
|
|
1437
|
+
/** All possible spending paths (no timelock checks); role as in {@link selectPath}. */
|
|
1922
1438
|
getAllSpendingPaths(script, contract, context) {
|
|
1923
|
-
|
|
1924
|
-
const paths = [];
|
|
1925
|
-
if (!role) {
|
|
1926
|
-
return paths;
|
|
1927
|
-
}
|
|
1928
|
-
const preimage = contract.params?.preimage;
|
|
1929
|
-
if (context.collaborative) {
|
|
1930
|
-
if (role === "receiver" && preimage) {
|
|
1931
|
-
paths.push({
|
|
1932
|
-
leaf: script.claim(),
|
|
1933
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
1934
|
-
});
|
|
1935
|
-
}
|
|
1936
|
-
if (role === "sender") {
|
|
1937
|
-
paths.push({
|
|
1938
|
-
leaf: script.refundWithoutReceiver()
|
|
1939
|
-
});
|
|
1940
|
-
}
|
|
1941
|
-
} else {
|
|
1942
|
-
if (role === "receiver" && preimage) {
|
|
1943
|
-
const sequence = Number(contract.params.claimDelay);
|
|
1944
|
-
paths.push({
|
|
1945
|
-
leaf: script.unilateralClaim(),
|
|
1946
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
1947
|
-
sequence
|
|
1948
|
-
});
|
|
1949
|
-
}
|
|
1950
|
-
if (role === "sender") {
|
|
1951
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
1952
|
-
paths.push({
|
|
1953
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
1954
|
-
sequence
|
|
1955
|
-
});
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
return paths;
|
|
1439
|
+
return vhtlcAllSpendingPaths(script, contract, context);
|
|
1959
1440
|
},
|
|
1960
1441
|
getSpendablePaths(script, contract, context) {
|
|
1961
|
-
|
|
1962
|
-
const paths = [];
|
|
1963
|
-
if (!role) {
|
|
1964
|
-
return paths;
|
|
1965
|
-
}
|
|
1966
|
-
const preimage = contract.params?.preimage;
|
|
1967
|
-
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
1968
|
-
if (context.collaborative) {
|
|
1969
|
-
if (role === "receiver" && preimage) {
|
|
1970
|
-
paths.push({
|
|
1971
|
-
leaf: script.claim(),
|
|
1972
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
1973
|
-
});
|
|
1974
|
-
}
|
|
1975
|
-
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
1976
|
-
paths.push({
|
|
1977
|
-
leaf: script.refundWithoutReceiver()
|
|
1978
|
-
});
|
|
1979
|
-
}
|
|
1980
|
-
return paths;
|
|
1981
|
-
}
|
|
1982
|
-
if (role === "receiver" && preimage) {
|
|
1983
|
-
const sequence = Number(contract.params.claimDelay);
|
|
1984
|
-
if (isCsvSpendable(context, sequence)) {
|
|
1985
|
-
paths.push({
|
|
1986
|
-
leaf: script.unilateralClaim(),
|
|
1987
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
1988
|
-
sequence
|
|
1989
|
-
});
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
if (role === "sender") {
|
|
1993
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
1994
|
-
if (isCsvSpendable(context, sequence)) {
|
|
1995
|
-
paths.push({
|
|
1996
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
1997
|
-
sequence
|
|
1998
|
-
});
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
return paths;
|
|
1442
|
+
return vhtlcSpendablePaths(script, contract, context);
|
|
2002
1443
|
},
|
|
2003
1444
|
/**
|
|
2004
1445
|
* Refuse an explicit spend of a lockup whose refund path has not opened.
|
|
@@ -2009,70 +1450,38 @@ var VHTLCContractHandler = {
|
|
|
2009
1450
|
assertVhtlcSpendableNow(contract, context);
|
|
2010
1451
|
},
|
|
2011
1452
|
/**
|
|
2012
|
-
* Never. A live VHTLC is escrow:
|
|
2013
|
-
*
|
|
2014
|
-
* lockup out from under a swap the counterparty is still entitled to
|
|
2015
|
-
* complete, or race a claim already in flight.
|
|
1453
|
+
* Never. A live VHTLC is escrow: generic selection (send, settle, renewal, offboard) would
|
|
1454
|
+
* move the lockup out from under a swap the counterparty may still complete, or race a claim.
|
|
2016
1455
|
*
|
|
2017
|
-
*
|
|
2018
|
-
* VTXO
|
|
2019
|
-
* `
|
|
2020
|
-
*
|
|
2021
|
-
* reasons are that an escrowed lockup must not count toward the
|
|
2022
|
-
* `available` balance bucket, and that generic RENEWAL must not silently
|
|
2023
|
-
* execute a refund the caller never asked for — `runPeriodicSettle` selects
|
|
2024
|
-
* through `getSpendableVtxos`, which this gate filters, and it runs
|
|
2025
|
-
* unprompted whenever a wallet is built without an explicit
|
|
2026
|
-
* `settlementConfig`.
|
|
1456
|
+
* The stamped leaf is the sender's own CLTV refund, so this is not about destroying the
|
|
1457
|
+
* VTXO: an escrowed lockup must not count toward the `available` balance, and generic
|
|
1458
|
+
* renewal (`runPeriodicSettle`, unprompted without an explicit `settlementConfig`) must not
|
|
1459
|
+
* silently execute a refund nobody asked for.
|
|
2027
1460
|
*
|
|
2028
|
-
* **Inseparable from {@link deriveTapscripts}
|
|
2029
|
-
*
|
|
2030
|
-
*
|
|
2031
|
-
* unobservable, so the two only ever made sense together.
|
|
2032
|
-
*
|
|
2033
|
-
* Recovery is filtered on {@link assertSpendableNow}, not on this: the gate
|
|
2034
|
-
* is permanent, and applying it there would strand a matured lockup.
|
|
1461
|
+
* **Inseparable from {@link deriveTapscripts}**: deriving the leaf without closing this gate
|
|
1462
|
+
* hands renewal an escrow. Recovery filters on {@link assertSpendableNow} instead; this
|
|
1463
|
+
* permanent gate would strand a matured lockup.
|
|
2035
1464
|
*/
|
|
2036
1465
|
isGenericallySpendable: () => false,
|
|
2037
1466
|
/**
|
|
2038
1467
|
* The annotation leaf stamped onto every VTXO locked to this contract.
|
|
2039
1468
|
*
|
|
2040
|
-
* **
|
|
2041
|
-
* `
|
|
2042
|
-
*
|
|
2043
|
-
* script version has a `forfeit()` — `VtxoScript` does not define one and
|
|
2044
|
-
* `VHTLC.BaseScript` does not add one. The fallback therefore threw
|
|
2045
|
-
* `legacy.forfeit is not a function`, `annotatableIn` caught it, and
|
|
2046
|
-
* `fetchContractVtxosBulk` dropped this contract's VTXOs before they were
|
|
2047
|
-
* persisted. The row existed and was watched while its balance stayed
|
|
2048
|
-
* permanently invisible, and `getSyncState()` reported `degraded` forever.
|
|
2049
|
-
*
|
|
2050
|
-
* `refundWithoutReceiver` is the leaf, for both roles the annotation
|
|
2051
|
-
* serves, because it is the only collaborative path this wallet can
|
|
2052
|
-
* actually satisfy as the sender — the same conclusion `selectPath`
|
|
2053
|
-
* reaches, kept in step with it deliberately. The claim leaves belong to
|
|
2054
|
-
* the receiver and need a preimage the sender does not have; `refund` and
|
|
2055
|
-
* `unilateralRefund` both need the counterparty's signature, which this
|
|
2056
|
-
* protocol has no message to ask for. V1 has no covenant leaves at all.
|
|
1469
|
+
* **Required, not an optimization.** Without it `deriveContractTapscripts` falls back to
|
|
1470
|
+
* `script.forfeit()`, which no VHTLC script has, so the contract's VTXOs are dropped before
|
|
1471
|
+
* persisting: balance invisible, `getSyncState()` degraded forever.
|
|
2057
1472
|
*
|
|
2058
|
-
*
|
|
2059
|
-
*
|
|
2060
|
-
*
|
|
2061
|
-
*
|
|
2062
|
-
* derived per contract and knows no clock; `recoverVtxos` filters on
|
|
2063
|
-
* {@link assertSpendableNow} for it.
|
|
1473
|
+
* `refundWithoutReceiver` is the only collaborative path this wallet can satisfy as sender
|
|
1474
|
+
* (kept in step with `selectPath`): the claim leaves need the preimage, and `refund` /
|
|
1475
|
+
* `unilateralRefund` need a counterparty signature the protocol can't request. V1 has no
|
|
1476
|
+
* covenant leaves.
|
|
2064
1477
|
*
|
|
2065
|
-
* **
|
|
2066
|
-
*
|
|
2067
|
-
*
|
|
1478
|
+
* **It carries a CLTV**: a settlement on it is rejected until `refundLocktime` matures, and
|
|
1479
|
+
* the per-contract annotation knows no clock, so `recoverVtxos` filters on
|
|
1480
|
+
* {@link assertSpendableNow}. **Role-blind**: a receiver's row gets the same leaf, satisfiable
|
|
1481
|
+
* only by the `sender` key holder; anyone else fails at intent registration.
|
|
2068
1482
|
*/
|
|
2069
1483
|
deriveTapscripts(script) {
|
|
2070
|
-
|
|
2071
|
-
return {
|
|
2072
|
-
forfeitTapLeafScript: leaf,
|
|
2073
|
-
intentTapLeafScript: leaf,
|
|
2074
|
-
tapTree: script.encode()
|
|
2075
|
-
};
|
|
1484
|
+
return deriveVhtlcTapscripts(script);
|
|
2076
1485
|
}
|
|
2077
1486
|
};
|
|
2078
1487
|
var parseGroupIndex = (raw) => {
|
|
@@ -2106,48 +1515,26 @@ var VHTLCV2ContractHandler = {
|
|
|
2106
1515
|
server: base.hex.encode(params.server),
|
|
2107
1516
|
hash: base.hex.encode(params.preimageHash),
|
|
2108
1517
|
refundLocktime: params.refundLocktime.toString(),
|
|
2109
|
-
claimDelay:
|
|
2110
|
-
refundDelay:
|
|
2111
|
-
refundNoReceiverDelay:
|
|
1518
|
+
claimDelay: chunkASKOHVGX_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
|
|
1519
|
+
refundDelay: chunkASKOHVGX_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
|
|
1520
|
+
refundNoReceiverDelay: chunkASKOHVGX_cjs.timelockToSequence(
|
|
2112
1521
|
params.unilateralRefundWithoutReceiverDelay
|
|
2113
1522
|
).toString(),
|
|
2114
|
-
//
|
|
2115
|
-
//
|
|
2116
|
-
//
|
|
2117
|
-
// The group maps onto them without loss — one emulator key serves
|
|
2118
|
-
// both covenant destinations by construction (see the option's doc
|
|
2119
|
-
// on VHTLC.Options), so the two emulator-key columns always hold
|
|
2120
|
-
// the same value on a row written from here.
|
|
2121
|
-
//
|
|
2122
|
-
// Spread rather than written as `undefined`: a `Record<string,
|
|
2123
|
-
// string>` round-tripped through a repository must not gain keys
|
|
2124
|
-
// whose value is the string "undefined".
|
|
1523
|
+
// Per-leaf on-disk keys predate the grouped param and older rows carry exactly these;
|
|
1524
|
+
// both emulator columns hold the same key. Spread, not `undefined`, so a repository
|
|
1525
|
+
// round-trip never gains "undefined" string values.
|
|
2125
1526
|
...covenants && {
|
|
2126
1527
|
nonInteractiveClaimReceiverPkScript: base.hex.encode(covenants.receiverPkScript),
|
|
2127
1528
|
nonInteractiveClaimEmulatorPubkey: base.hex.encode(covenants.emulatorPubkey),
|
|
2128
1529
|
nonInteractiveRefundSenderPkScript: base.hex.encode(covenants.senderPkScript),
|
|
2129
1530
|
nonInteractiveRefundEmulatorPubkey: base.hex.encode(covenants.emulatorPubkey),
|
|
2130
|
-
// The legacy marker is
|
|
2131
|
-
// row carrying it re-derives the full suite (nine leaves), a
|
|
2132
|
-
// row lacking it the pre-timelocked-refund eight — the same
|
|
2133
|
-
// encoding older SDKs wrote for eight-leaf rows, so those rows
|
|
2134
|
-
// read back unchanged. Spread rather than a "false"/"undefined"
|
|
2135
|
-
// string: a dropped flag re-derives the EIGHT-leaf script, a
|
|
2136
|
-
// different pkScript, and registration dies at
|
|
2137
|
-
// `upsertContractRow` with an opaque `Script mismatch`.
|
|
1531
|
+
// The legacy (eight-leaf) marker is this key's ABSENCE, as older SDKs wrote it.
|
|
2138
1532
|
...covenants.legacy === void 0 && {
|
|
2139
1533
|
nonInteractiveRefundWithoutReceiver: "1"
|
|
2140
1534
|
}
|
|
2141
1535
|
},
|
|
2142
|
-
//
|
|
2143
|
-
//
|
|
2144
|
-
// these params; dropping the asset derives the SAT-ONLY script, so
|
|
2145
|
-
// registration died at `upsertContractRow` with a `Script mismatch`
|
|
2146
|
-
// naming two hex strings and no cause. Same silent-drop class
|
|
2147
|
-
// `validateOptions` refuses one layer up.
|
|
2148
|
-
//
|
|
2149
|
-
// Two keys rather than one blob, mirroring the script's own view of
|
|
2150
|
-
// an Asset ID as a (txid, groupIndex) pair.
|
|
1536
|
+
// Must round-trip: dropping the asset re-derives the sat-only script and registration
|
|
1537
|
+
// dies at `upsertContractRow` with an opaque `Script mismatch`.
|
|
2151
1538
|
...params.asset && {
|
|
2152
1539
|
assetTxid: base.hex.encode(params.asset.txid),
|
|
2153
1540
|
assetGroupIndex: params.asset.groupIndex.toString()
|
|
@@ -2208,9 +1595,9 @@ var VHTLCV2ContractHandler = {
|
|
|
2208
1595
|
preimageHash: base.hex.decode(params.hash),
|
|
2209
1596
|
refundLocktime: BigInt(params.refundLocktime),
|
|
2210
1597
|
...asset && { asset },
|
|
2211
|
-
unilateralClaimDelay:
|
|
2212
|
-
unilateralRefundDelay:
|
|
2213
|
-
unilateralRefundWithoutReceiverDelay:
|
|
1598
|
+
unilateralClaimDelay: chunkASKOHVGX_cjs.sequenceToTimelock(Number(params.claimDelay)),
|
|
1599
|
+
unilateralRefundDelay: chunkASKOHVGX_cjs.sequenceToTimelock(Number(params.refundDelay)),
|
|
1600
|
+
unilateralRefundWithoutReceiverDelay: chunkASKOHVGX_cjs.sequenceToTimelock(
|
|
2214
1601
|
Number(params.refundNoReceiverDelay)
|
|
2215
1602
|
),
|
|
2216
1603
|
...claim && refund && {
|
|
@@ -2218,8 +1605,6 @@ var VHTLCV2ContractHandler = {
|
|
|
2218
1605
|
receiverPkScript: claim.destination,
|
|
2219
1606
|
senderPkScript: refund.destination,
|
|
2220
1607
|
emulatorPubkey: claim.emulatorPubkey,
|
|
2221
|
-
// Absence of the flag IS the legacy marker — the same
|
|
2222
|
-
// encoding older SDKs wrote for eight-leaf rows.
|
|
2223
1608
|
...params.nonInteractiveRefundWithoutReceiver !== "1" && {
|
|
2224
1609
|
legacy: "preTimelockedRefund"
|
|
2225
1610
|
}
|
|
@@ -2228,139 +1613,18 @@ var VHTLCV2ContractHandler = {
|
|
|
2228
1613
|
};
|
|
2229
1614
|
},
|
|
2230
1615
|
/**
|
|
2231
|
-
* Select spending path based on context.
|
|
2232
|
-
*
|
|
2233
|
-
* Role is determined from `context.role` or by matching
|
|
2234
|
-
* `context.walletDescriptor` (preferred) / `context.walletPubKey`
|
|
2235
|
-
* against sender/receiver in contract params.
|
|
1616
|
+
* Select spending path based on context. Role comes from `context.role` or by matching
|
|
1617
|
+
* `context.walletDescriptor` against sender/receiver.
|
|
2236
1618
|
*/
|
|
2237
1619
|
selectPath(script, contract, context) {
|
|
2238
|
-
|
|
2239
|
-
const preimage = contract.params?.preimage;
|
|
2240
|
-
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
2241
|
-
if (!role) {
|
|
2242
|
-
return null;
|
|
2243
|
-
}
|
|
2244
|
-
if (context.collaborative) {
|
|
2245
|
-
if (role === "receiver" && preimage) {
|
|
2246
|
-
return {
|
|
2247
|
-
leaf: script.claim(),
|
|
2248
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
2249
|
-
};
|
|
2250
|
-
}
|
|
2251
|
-
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
2252
|
-
return {
|
|
2253
|
-
leaf: script.refundWithoutReceiver()
|
|
2254
|
-
};
|
|
2255
|
-
}
|
|
2256
|
-
return null;
|
|
2257
|
-
}
|
|
2258
|
-
if (role === "receiver" && preimage) {
|
|
2259
|
-
const sequence = Number(contract.params.claimDelay);
|
|
2260
|
-
if (!isCsvSpendable(context, sequence)) return null;
|
|
2261
|
-
return {
|
|
2262
|
-
leaf: script.unilateralClaim(),
|
|
2263
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
2264
|
-
sequence
|
|
2265
|
-
};
|
|
2266
|
-
}
|
|
2267
|
-
if (role === "sender") {
|
|
2268
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
2269
|
-
if (!isCsvSpendable(context, sequence)) return null;
|
|
2270
|
-
return {
|
|
2271
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
2272
|
-
sequence
|
|
2273
|
-
};
|
|
2274
|
-
}
|
|
2275
|
-
return null;
|
|
1620
|
+
return selectVhtlcPath(script, contract, context);
|
|
2276
1621
|
},
|
|
2277
|
-
/**
|
|
2278
|
-
* Get all possible spending paths (no timelock checks).
|
|
2279
|
-
*
|
|
2280
|
-
* Role is determined from `context.role` or by matching
|
|
2281
|
-
* `context.walletDescriptor` (preferred) / `context.walletPubKey`
|
|
2282
|
-
* against sender/receiver in contract params.
|
|
2283
|
-
*/
|
|
1622
|
+
/** Get all possible spending paths (no timelock checks); role resolved as in `selectPath`. */
|
|
2284
1623
|
getAllSpendingPaths(script, contract, context) {
|
|
2285
|
-
|
|
2286
|
-
const paths = [];
|
|
2287
|
-
if (!role) {
|
|
2288
|
-
return paths;
|
|
2289
|
-
}
|
|
2290
|
-
const preimage = contract.params?.preimage;
|
|
2291
|
-
if (context.collaborative) {
|
|
2292
|
-
if (role === "receiver" && preimage) {
|
|
2293
|
-
paths.push({
|
|
2294
|
-
leaf: script.claim(),
|
|
2295
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
2296
|
-
});
|
|
2297
|
-
}
|
|
2298
|
-
if (role === "sender") {
|
|
2299
|
-
paths.push({
|
|
2300
|
-
leaf: script.refundWithoutReceiver()
|
|
2301
|
-
});
|
|
2302
|
-
}
|
|
2303
|
-
} else {
|
|
2304
|
-
if (role === "receiver" && preimage) {
|
|
2305
|
-
const sequence = Number(contract.params.claimDelay);
|
|
2306
|
-
paths.push({
|
|
2307
|
-
leaf: script.unilateralClaim(),
|
|
2308
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
2309
|
-
sequence
|
|
2310
|
-
});
|
|
2311
|
-
}
|
|
2312
|
-
if (role === "sender") {
|
|
2313
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
2314
|
-
paths.push({
|
|
2315
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
2316
|
-
sequence
|
|
2317
|
-
});
|
|
2318
|
-
}
|
|
2319
|
-
}
|
|
2320
|
-
return paths;
|
|
1624
|
+
return vhtlcAllSpendingPaths(script, contract, context);
|
|
2321
1625
|
},
|
|
2322
1626
|
getSpendablePaths(script, contract, context) {
|
|
2323
|
-
|
|
2324
|
-
const paths = [];
|
|
2325
|
-
if (!role) {
|
|
2326
|
-
return paths;
|
|
2327
|
-
}
|
|
2328
|
-
const preimage = contract.params?.preimage;
|
|
2329
|
-
const refundLocktime = BigInt(contract.params.refundLocktime);
|
|
2330
|
-
if (context.collaborative) {
|
|
2331
|
-
if (role === "receiver" && preimage) {
|
|
2332
|
-
paths.push({
|
|
2333
|
-
leaf: script.claim(),
|
|
2334
|
-
extraWitness: [base.hex.decode(preimage)]
|
|
2335
|
-
});
|
|
2336
|
-
}
|
|
2337
|
-
if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
|
|
2338
|
-
paths.push({
|
|
2339
|
-
leaf: script.refundWithoutReceiver()
|
|
2340
|
-
});
|
|
2341
|
-
}
|
|
2342
|
-
return paths;
|
|
2343
|
-
}
|
|
2344
|
-
if (role === "receiver" && preimage) {
|
|
2345
|
-
const sequence = Number(contract.params.claimDelay);
|
|
2346
|
-
if (isCsvSpendable(context, sequence)) {
|
|
2347
|
-
paths.push({
|
|
2348
|
-
leaf: script.unilateralClaim(),
|
|
2349
|
-
extraWitness: [base.hex.decode(preimage)],
|
|
2350
|
-
sequence
|
|
2351
|
-
});
|
|
2352
|
-
}
|
|
2353
|
-
}
|
|
2354
|
-
if (role === "sender") {
|
|
2355
|
-
const sequence = Number(contract.params.refundNoReceiverDelay);
|
|
2356
|
-
if (isCsvSpendable(context, sequence)) {
|
|
2357
|
-
paths.push({
|
|
2358
|
-
leaf: script.unilateralRefundWithoutReceiver(),
|
|
2359
|
-
sequence
|
|
2360
|
-
});
|
|
2361
|
-
}
|
|
2362
|
-
}
|
|
2363
|
-
return paths;
|
|
1627
|
+
return vhtlcSpendablePaths(script, contract, context);
|
|
2364
1628
|
},
|
|
2365
1629
|
/**
|
|
2366
1630
|
* Refuse an explicit spend of a lockup whose refund path has not opened.
|
|
@@ -2370,62 +1634,28 @@ var VHTLCV2ContractHandler = {
|
|
|
2370
1634
|
assertVhtlcSpendableNow(contract, context);
|
|
2371
1635
|
},
|
|
2372
1636
|
/**
|
|
2373
|
-
* Never. A live VHTLC is escrow
|
|
2374
|
-
*
|
|
2375
|
-
*
|
|
2376
|
-
*
|
|
2377
|
-
*
|
|
2378
|
-
*
|
|
2379
|
-
* The gate covers `available` and renewal. Recovery is generic and names
|
|
2380
|
-
* nothing, so it is not covered here: `recoverVtxos` filters on
|
|
2381
|
-
* {@link assertSpendableNow} instead, which drops a lockup only while its
|
|
2382
|
-
* refund path is shut rather than forever. The explicit routes out —
|
|
2383
|
-
* `settle({ inputs })`, or `@arkade-os/swap`'s `pushRefundWithoutReceiver`
|
|
2384
|
-
* over `findLockupVtxos`' outpoints — are unaffected either way.
|
|
1637
|
+
* Never. A live VHTLC is escrow with the counterparty's claim leaf armed; generic selection
|
|
1638
|
+
* (send, settle, renewal, offboard) would move it out from under the swap or race a claim.
|
|
1639
|
+
* Recovery isn't covered by this gate: `recoverVtxos` filters on {@link assertSpendableNow},
|
|
1640
|
+
* dropping a lockup only while its refund path is shut. Explicit routes (`settle({ inputs })`,
|
|
1641
|
+
* `pushRefundWithoutReceiver`) are unaffected.
|
|
2385
1642
|
*/
|
|
2386
1643
|
isGenericallySpendable: () => false,
|
|
2387
1644
|
/**
|
|
2388
1645
|
* The annotation leaf stamped onto every VTXO locked to this contract.
|
|
2389
1646
|
*
|
|
2390
|
-
*
|
|
2391
|
-
* `
|
|
2392
|
-
*
|
|
2393
|
-
* script version has a `forfeit()` — `VtxoScript` does not define one and
|
|
2394
|
-
* `VHTLC.BaseScript` does not add one. The fallback therefore throws
|
|
2395
|
-
* `legacy.forfeit is not a function`, `annotatableIn` catches it, and
|
|
2396
|
-
* `fetchContractVtxosBulk` drops this contract's VTXOs before they are
|
|
2397
|
-
* persisted. The row would exist and be watched while its balance stayed
|
|
2398
|
-
* permanently invisible, and `getSyncState()` would report `degraded`
|
|
2399
|
-
* forever. (The `vhtlc` handler had the same gap and now closes it the same
|
|
2400
|
-
* way; nothing registers V1 rows through `ContractManager` in this repo, so
|
|
2401
|
-
* it was never hit here.)
|
|
2402
|
-
*
|
|
2403
|
-
* `refundWithoutReceiver` is the leaf, for both roles the annotation
|
|
2404
|
-
* serves, because it is the only collaborative path this wallet can
|
|
2405
|
-
* actually satisfy as the sender — the same conclusion `selectPath`
|
|
2406
|
-
* reaches, kept in step with it deliberately. The claim leaves belong to
|
|
2407
|
-
* the receiver and need a preimage the sender does not have; `refund` and
|
|
2408
|
-
* `unilateralRefund` need the counterparty; the covenant leaves are the
|
|
2409
|
-
* emulator's.
|
|
1647
|
+
* Required, not an optimization: without {@link TapscriptDeriving} the fallback calls
|
|
1648
|
+
* `script.forfeit()`, which no VHTLC version has, so the VTXOs are silently dropped before
|
|
1649
|
+
* persisting and `getSyncState()` stays `degraded`.
|
|
2410
1650
|
*
|
|
2411
|
-
*
|
|
2412
|
-
*
|
|
2413
|
-
*
|
|
2414
|
-
*
|
|
2415
|
-
*
|
|
2416
|
-
* {@link assertSpendableNow} for it.
|
|
2417
|
-
*
|
|
2418
|
-
* **Role-blind.** A receiver's row gets the same leaf, which names keys that
|
|
2419
|
-
* wallet does not hold, so it is satisfiable only by the wallet holding the
|
|
2420
|
-
* lockup's `sender` key and fails at intent registration for anyone else.
|
|
1651
|
+
* `refundWithoutReceiver` is used (in step with `selectPath`) as the only collaborative leaf
|
|
1652
|
+
* the sender can satisfy. It carries a CLTV: settling on it before `refundLocktime` matures is
|
|
1653
|
+
* rejected, and this handler has no clock, so `recoverVtxos` filters on
|
|
1654
|
+
* {@link assertSpendableNow}. Role-blind: a receiver's row gets the same leaf and fails at
|
|
1655
|
+
* intent registration.
|
|
2421
1656
|
*/
|
|
2422
1657
|
deriveTapscripts(script) {
|
|
2423
|
-
|
|
2424
|
-
return {
|
|
2425
|
-
forfeitTapLeafScript: leaf,
|
|
2426
|
-
intentTapLeafScript: leaf,
|
|
2427
|
-
tapTree: script.encode()
|
|
2428
|
-
};
|
|
1658
|
+
return deriveVhtlcTapscripts(script);
|
|
2429
1659
|
}
|
|
2430
1660
|
};
|
|
2431
1661
|
var BoardingContractHandler = {
|
|
@@ -2451,24 +1681,10 @@ var BoardingContractHandler = {
|
|
|
2451
1681
|
/** Preserves today's settle/board behaviour. */
|
|
2452
1682
|
isGenericallySpendable: () => true,
|
|
2453
1683
|
/**
|
|
2454
|
-
* Probe the on-chain
|
|
2455
|
-
*
|
|
2456
|
-
*
|
|
2457
|
-
*
|
|
2458
|
-
* boarding output becomes an L2 VTXO at the receive index, so the
|
|
2459
|
-
* indexer probe already keeps the gap window open for it; only an
|
|
2460
|
-
* *unspent* boarding output needs the on-chain probe (see plan §2).
|
|
2461
|
-
*
|
|
2462
|
-
* No-ops (returns `[]`) when boarding discovery is not plumbed — i.e.
|
|
2463
|
-
* `deps.boardingTimelock` or `deps.onchainNetwork` is absent — so the
|
|
2464
|
-
* scanner unit harness (which sets neither) is unaffected.
|
|
2465
|
-
*
|
|
2466
|
-
* Always emits `type: "boarding"`, even in the degenerate equal-delay case
|
|
2467
|
-
* where the boarding script is byte-identical to a `default` script at this
|
|
2468
|
-
* index (`boardingExitDelay === unilateralExitDelay`). The collision is no
|
|
2469
|
-
* longer pre-judged in discovery; it is tolerated FIRST-WINS at the
|
|
2470
|
-
* persistence layer ({@link ContractManager.upsertContract}). `deps.csvTimelocks`
|
|
2471
|
-
* is intentionally not read here.
|
|
1684
|
+
* Probe the **current** on-chain coin set for a boarding output at this HD index. Only an
|
|
1685
|
+
* unspent boarding output needs this: a boarded one became an L2 VTXO at the receive index,
|
|
1686
|
+
* which the indexer probe already covers. Always emits `type: "boarding"` (see the handler
|
|
1687
|
+
* doc on collisions); `deps.csvTimelocks` is intentionally not read.
|
|
2472
1688
|
*/
|
|
2473
1689
|
async discoverAt(index, descriptor, deps) {
|
|
2474
1690
|
if (!deps.boardingTimelock || !deps.onchainNetwork) return [];
|
|
@@ -2482,38 +1698,49 @@ var BoardingContractHandler = {
|
|
|
2482
1698
|
const coins = await deps.onchainProvider.getCoins(onchainAddress);
|
|
2483
1699
|
if (coins.length === 0) return [];
|
|
2484
1700
|
const scriptHex = base.hex.encode(script.pkScript);
|
|
2485
|
-
const boardingSeq = chunkUJTYUYY4_cjs.timelockToSequence(deps.boardingTimelock);
|
|
2486
1701
|
return [
|
|
2487
1702
|
{
|
|
2488
1703
|
type: "boarding",
|
|
2489
|
-
params: {
|
|
2490
|
-
pubKey
|
|
2491
|
-
serverPubKey:
|
|
2492
|
-
csvTimelock:
|
|
2493
|
-
},
|
|
1704
|
+
params: BoardingContractHandler.serializeParams({
|
|
1705
|
+
pubKey,
|
|
1706
|
+
serverPubKey: deps.serverPubKey,
|
|
1707
|
+
csvTimelock: deps.boardingTimelock
|
|
1708
|
+
}),
|
|
2494
1709
|
script: scriptHex,
|
|
2495
|
-
// The
|
|
2496
|
-
//
|
|
2497
|
-
// ContractWatcher keeps monitoring the same L2 script and the
|
|
2498
|
-
// VTXO repository bucket lines up (plan §6-I.4). The P2TR is
|
|
2499
|
-
// recomputed from params only for the `getCoins` probe.
|
|
1710
|
+
// The Ark address, not the P2TR: must match the row registered at init so the
|
|
1711
|
+
// watcher monitors the same L2 script and the VTXO repository bucket lines up.
|
|
2500
1712
|
address: script.address(deps.network.hrp, deps.serverPubKey).encode(),
|
|
2501
|
-
// Tag rotated rows (index > 0)
|
|
2502
|
-
// newest boarding address and descriptor-aware signing can
|
|
2503
|
-
// recover the per-index key (plan §6-II/§6-III.3). The index-0
|
|
2504
|
-
// baseline stays untagged, matching `default`/`delegate`.
|
|
1713
|
+
// Tag rotated rows (index > 0) for boot resolution and per-index signing.
|
|
2505
1714
|
...rotatedReceiveMetadata(index, descriptor)
|
|
2506
1715
|
}
|
|
2507
1716
|
];
|
|
2508
1717
|
}
|
|
2509
1718
|
};
|
|
2510
1719
|
var MinimalScriptNum = btcSigner.ScriptNum(void 0, true);
|
|
2511
|
-
var
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
1720
|
+
var ARKADE_TYPE_ENCODINGS = {
|
|
1721
|
+
pubkey: "raw",
|
|
1722
|
+
signature: "schnorr-64",
|
|
1723
|
+
bytes: "raw",
|
|
1724
|
+
bytes20: "raw-20",
|
|
1725
|
+
bytes32: "raw-32",
|
|
1726
|
+
asset: "raw-32",
|
|
1727
|
+
int: "scriptnum",
|
|
1728
|
+
bool: "scriptnum",
|
|
1729
|
+
AssetGroup: "scriptnum"
|
|
1730
|
+
};
|
|
1731
|
+
var SUPPORTED_PROGRAM_VERSION = 1;
|
|
1732
|
+
var UnsupportedProgramVersionError = class extends Error {
|
|
1733
|
+
constructor(version, context) {
|
|
1734
|
+
super(
|
|
1735
|
+
`${context}: unsupported program version ${String(version)}; this SDK supports version ${SUPPORTED_PROGRAM_VERSION}. Recover it with an SDK that reads version ${String(version)}, re-create it with current params, or delete it.`
|
|
1736
|
+
);
|
|
1737
|
+
this.version = version;
|
|
1738
|
+
}
|
|
1739
|
+
version;
|
|
1740
|
+
name = "UnsupportedProgramVersionError";
|
|
1741
|
+
};
|
|
2515
1742
|
function bindValue(bind, name) {
|
|
2516
|
-
const v = bind[name];
|
|
1743
|
+
const v = Object.hasOwn(bind, name) ? bind[name] : void 0;
|
|
2517
1744
|
if (v === void 0) throw new Error(`unbound parameter '${name}'`);
|
|
2518
1745
|
return v;
|
|
2519
1746
|
}
|
|
@@ -2528,6 +1755,17 @@ function resolveTimelockValue(value, args) {
|
|
|
2528
1755
|
`invalid timelock value '${value}' \u2014 expected a bigint or a '$param' reference`
|
|
2529
1756
|
);
|
|
2530
1757
|
}
|
|
1758
|
+
function resolveCsvTimelock(csv, args) {
|
|
1759
|
+
const value = resolveTimelockValue(csv.value, args);
|
|
1760
|
+
if (csv.type !== "sequence") return { type: csv.type, value };
|
|
1761
|
+
const timelock = chunkASKOHVGX_cjs.sequenceToCanonicalTimelock(value);
|
|
1762
|
+
if (!timelock) {
|
|
1763
|
+
throw new Error(
|
|
1764
|
+
`csv '${csv.value}' resolved to ${value}, which is not a canonical BIP68 sequence`
|
|
1765
|
+
);
|
|
1766
|
+
}
|
|
1767
|
+
return timelock;
|
|
1768
|
+
}
|
|
2531
1769
|
function resolveAsm(asm, bind) {
|
|
2532
1770
|
const tokens = asm.map((t) => {
|
|
2533
1771
|
if (typeof t === "string" && t.startsWith("$")) {
|
|
@@ -2576,6 +1814,7 @@ function collectParamRefs(program) {
|
|
|
2576
1814
|
const collect = (items) => {
|
|
2577
1815
|
for (const t of items ?? []) {
|
|
2578
1816
|
if (typeof t === "string" && t.startsWith("$")) refs.add(t.slice(1));
|
|
1817
|
+
else if (isTweakedSigner(t) && t.tweak.startsWith("$")) refs.add(t.tweak.slice(1));
|
|
2579
1818
|
}
|
|
2580
1819
|
};
|
|
2581
1820
|
for (const fn of Object.values(program.functions)) {
|
|
@@ -2590,11 +1829,28 @@ function collectParamRefs(program) {
|
|
|
2590
1829
|
}
|
|
2591
1830
|
return refs;
|
|
2592
1831
|
}
|
|
2593
|
-
var TYPED_BYTE_LENGTHS = {
|
|
1832
|
+
var TYPED_BYTE_LENGTHS = {
|
|
1833
|
+
pubkey: 32,
|
|
1834
|
+
signature: 64,
|
|
1835
|
+
bytes20: 20,
|
|
1836
|
+
bytes32: 32,
|
|
1837
|
+
asset: 32
|
|
1838
|
+
};
|
|
2594
1839
|
function validateParamValue(def, value) {
|
|
2595
|
-
if (def.type
|
|
1840
|
+
if (typeof def.type !== "string" || !Object.hasOwn(ARKADE_TYPE_ENCODINGS, def.type)) {
|
|
1841
|
+
throw new Error(`program parameter '${def.name}': unknown type '${def.type}'`);
|
|
1842
|
+
}
|
|
1843
|
+
if (ARKADE_TYPE_ENCODINGS[def.type] === "scriptnum") {
|
|
2596
1844
|
if (typeof value !== "bigint" && typeof value !== "number") {
|
|
2597
|
-
throw new Error(`program parameter '${def.name}' expects
|
|
1845
|
+
throw new Error(`program parameter '${def.name}' expects ${def.type}, got bytes`);
|
|
1846
|
+
}
|
|
1847
|
+
if (typeof value === "number" && !Number.isSafeInteger(value)) {
|
|
1848
|
+
throw new Error(
|
|
1849
|
+
`program parameter '${def.name}' expects a safe integer; use bigint for larger values`
|
|
1850
|
+
);
|
|
1851
|
+
}
|
|
1852
|
+
if (def.type === "bool" && value !== 0 && value !== 1 && value !== 0n && value !== 1n) {
|
|
1853
|
+
throw new Error(`program parameter '${def.name}' expects a boolean encoded as 0 or 1`);
|
|
2598
1854
|
}
|
|
2599
1855
|
return;
|
|
2600
1856
|
}
|
|
@@ -2611,11 +1867,10 @@ function validateParamValue(def, value) {
|
|
|
2611
1867
|
}
|
|
2612
1868
|
}
|
|
2613
1869
|
function validateProgram(program, args) {
|
|
2614
|
-
const params = program.params;
|
|
2615
|
-
|
|
2616
|
-
const declared = new Set(params.map(inputName));
|
|
1870
|
+
const params = program.params ?? [];
|
|
1871
|
+
const declared = new Set(params.map((p) => p.name));
|
|
2617
1872
|
for (const name of declared) {
|
|
2618
|
-
if (args[name] === void 0) {
|
|
1873
|
+
if (!Object.hasOwn(args, name) || args[name] === void 0) {
|
|
2619
1874
|
throw new Error(`program parameter '${name}' is declared but not bound in args`);
|
|
2620
1875
|
}
|
|
2621
1876
|
}
|
|
@@ -2625,13 +1880,21 @@ function validateProgram(program, args) {
|
|
|
2625
1880
|
}
|
|
2626
1881
|
}
|
|
2627
1882
|
for (const p of params) {
|
|
2628
|
-
|
|
1883
|
+
validateParamValue(p, args[p.name]);
|
|
1884
|
+
}
|
|
1885
|
+
for (const name of Object.keys(args)) {
|
|
1886
|
+
if (!declared.has(name)) throw new Error(`program: undeclared argument '${name}'`);
|
|
2629
1887
|
}
|
|
2630
1888
|
}
|
|
1889
|
+
function isTweakedSigner(ref) {
|
|
1890
|
+
if (typeof ref !== "object" || ref === null || ref instanceof Uint8Array) return false;
|
|
1891
|
+
const { tweak, fn } = ref;
|
|
1892
|
+
return typeof tweak === "string" && typeof fn === "string";
|
|
1893
|
+
}
|
|
2631
1894
|
function resolveSigner(ref, args) {
|
|
2632
1895
|
if (ref instanceof Uint8Array) return ref;
|
|
2633
|
-
if (!ref.startsWith("$")) {
|
|
2634
|
-
throw new Error(`unknown signer reference '${ref}' \u2014 use '
|
|
1896
|
+
if (typeof ref !== "string" || !ref.startsWith("$")) {
|
|
1897
|
+
throw new Error(`unknown signer reference '${ref}' \u2014 use a '$param' or key bytes`);
|
|
2635
1898
|
}
|
|
2636
1899
|
const v = bindValue(args, ref.slice(1));
|
|
2637
1900
|
if (!(v instanceof Uint8Array)) {
|
|
@@ -2641,35 +1904,33 @@ function resolveSigner(ref, args) {
|
|
|
2641
1904
|
}
|
|
2642
1905
|
function encodeTapscriptSegment(seg, pubkeys, args) {
|
|
2643
1906
|
if (seg.csv) {
|
|
2644
|
-
const timelock =
|
|
1907
|
+
const timelock = resolveCsvTimelock(seg.csv, args);
|
|
2645
1908
|
if (seg.asm) {
|
|
2646
|
-
return
|
|
1909
|
+
return chunkASKOHVGX_cjs.ConditionCSVMultisigTapscript.encode({
|
|
2647
1910
|
conditionScript: resolveAsm(seg.asm, args),
|
|
2648
1911
|
timelock,
|
|
2649
1912
|
pubkeys
|
|
2650
1913
|
});
|
|
2651
1914
|
}
|
|
2652
|
-
return
|
|
1915
|
+
return chunkASKOHVGX_cjs.CSVMultisigTapscript.encode({ timelock, pubkeys });
|
|
2653
1916
|
}
|
|
2654
1917
|
if (seg.cltv !== void 0) {
|
|
2655
|
-
return
|
|
1918
|
+
return chunkASKOHVGX_cjs.CLTVMultisigTapscript.encode({
|
|
2656
1919
|
absoluteTimelock: resolveTimelockValue(seg.cltv, args),
|
|
2657
1920
|
pubkeys
|
|
2658
1921
|
});
|
|
2659
1922
|
}
|
|
2660
1923
|
if (seg.asm) {
|
|
2661
|
-
return
|
|
1924
|
+
return chunkASKOHVGX_cjs.ConditionMultisigTapscript.encode({
|
|
2662
1925
|
conditionScript: resolveAsm(seg.asm, args),
|
|
2663
1926
|
pubkeys
|
|
2664
1927
|
});
|
|
2665
1928
|
}
|
|
2666
|
-
return
|
|
1929
|
+
return chunkASKOHVGX_cjs.MultisigTapscript.encode({ pubkeys });
|
|
2667
1930
|
}
|
|
2668
1931
|
function compileFunctions(program, args, keys) {
|
|
2669
1932
|
if (program.version !== SUPPORTED_PROGRAM_VERSION) {
|
|
2670
|
-
throw new
|
|
2671
|
-
`ArkadeContract: unsupported program version ${program.version} \u2014 this SDK supports version ${SUPPORTED_PROGRAM_VERSION}`
|
|
2672
|
-
);
|
|
1933
|
+
throw new UnsupportedProgramVersionError(program.version, "ArkadeContract");
|
|
2673
1934
|
}
|
|
2674
1935
|
const functions = program.functions;
|
|
2675
1936
|
const names = Object.keys(functions);
|
|
@@ -2677,23 +1938,74 @@ function compileFunctions(program, args, keys) {
|
|
|
2677
1938
|
throw new Error("ArkadeContract: program has no functions");
|
|
2678
1939
|
}
|
|
2679
1940
|
validateProgram(program, args);
|
|
1941
|
+
if (args.server !== void 0 && (!(args.server instanceof Uint8Array) || !utils_js$1.equalBytes(args.server, keys.serverKey))) {
|
|
1942
|
+
throw new Error(
|
|
1943
|
+
"ArkadeContract: reserved server parameter must match the contract server key"
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
2680
1946
|
const defs = names.map((n) => functions[n]);
|
|
2681
|
-
const
|
|
1947
|
+
const covenants = /* @__PURE__ */ new Map();
|
|
1948
|
+
for (const [name, def] of Object.entries(functions)) {
|
|
1949
|
+
if (!def.arkadeScript) continue;
|
|
1950
|
+
const script = resolveAsm(def.arkadeScript.asm, args);
|
|
1951
|
+
for (const target of [name, ...def.group ? [def.group] : []]) {
|
|
1952
|
+
const previous = covenants.get(target);
|
|
1953
|
+
if (previous && !utils_js$1.equalBytes(previous, script)) {
|
|
1954
|
+
throw new Error(`ArkadeContract: ambiguous covenant '${target}'`);
|
|
1955
|
+
}
|
|
1956
|
+
covenants.set(target, script);
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
const covenant = names.find(
|
|
1960
|
+
(_, i) => defs[i].arkadeScript && defs[i].tapscript.emulator !== null
|
|
1961
|
+
);
|
|
2682
1962
|
if (covenant && !keys.emulatorKey) {
|
|
2683
1963
|
throw new Error(
|
|
2684
1964
|
`ArkadeContract: function '${covenant}' has an arkadeScript but no emulator is configured \u2014 pass an \`emulator\` to Arkade.connect`
|
|
2685
1965
|
);
|
|
2686
1966
|
}
|
|
2687
1967
|
return defs.map((def, i) => {
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
1968
|
+
const pubkeys = def.tapscript.signers.map((signer) => {
|
|
1969
|
+
if (!isTweakedSigner(signer)) return resolveSigner(signer, args);
|
|
1970
|
+
const script = covenants.get(signer.fn);
|
|
1971
|
+
if (!script) {
|
|
1972
|
+
throw new Error(
|
|
1973
|
+
`ArkadeContract: function '${names[i]}' tweaks '${signer.fn}', which has no arkade script`
|
|
1974
|
+
);
|
|
1975
|
+
}
|
|
1976
|
+
return computeArkadeScriptPublicKey(resolveSigner(signer.tweak, args), script);
|
|
1977
|
+
});
|
|
1978
|
+
const arkadeScript = def.arkadeScript ? covenants.get(names[i]) : void 0;
|
|
1979
|
+
const leafPubkeys = [...pubkeys];
|
|
1980
|
+
if (arkadeScript && def.tapscript.emulator !== null) {
|
|
1981
|
+
const position = def.tapscript.emulatorIndex ?? pubkeys.length;
|
|
1982
|
+
if (!Number.isInteger(position) || position < 0 || position > pubkeys.length) {
|
|
1983
|
+
throw new Error(
|
|
1984
|
+
`ArkadeContract: function '${names[i]}' has an invalid emulator position ${position}`
|
|
1985
|
+
);
|
|
1986
|
+
}
|
|
1987
|
+
const target = def.group ? covenants.get(def.tapscript.emulator ?? def.group) : arkadeScript;
|
|
1988
|
+
if (!target || !utils_js$1.equalBytes(target, arkadeScript)) {
|
|
1989
|
+
throw new Error(
|
|
1990
|
+
`ArkadeContract: function '${names[i]}' has an invalid emulator covenant '${def.tapscript.emulator}'`
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
leafPubkeys.splice(
|
|
1994
|
+
position,
|
|
1995
|
+
0,
|
|
1996
|
+
computeArkadeScriptPublicKey(keys.emulatorKey, target)
|
|
1997
|
+
);
|
|
1998
|
+
} else if (def.tapscript.emulatorIndex !== void 0) {
|
|
1999
|
+
throw new Error(
|
|
2000
|
+
`ArkadeContract: function '${names[i]}' specifies an emulator position without an emulator`
|
|
2001
|
+
);
|
|
2002
|
+
}
|
|
2003
|
+
validateTapscript({ ...def.tapscript, signers: leafPubkeys });
|
|
2692
2004
|
const leafScript = encodeTapscriptSegment(def.tapscript, leafPubkeys, args).script;
|
|
2693
2005
|
return { name: names[i], def, leafScript, arkadeScript, signerKeys: pubkeys };
|
|
2694
2006
|
});
|
|
2695
2007
|
}
|
|
2696
|
-
var ArkadeProgramScript = class extends
|
|
2008
|
+
var ArkadeProgramScript = class extends chunkASKOHVGX_cjs.VtxoScript {
|
|
2697
2009
|
constructor(program, args, keys) {
|
|
2698
2010
|
const partial = compileFunctions(program, args, keys);
|
|
2699
2011
|
super(partial.map((p) => p.leafScript));
|
|
@@ -2716,23 +2028,72 @@ var ArkadeProgramScript = class extends chunkUJTYUYY4_cjs.VtxoScript {
|
|
|
2716
2028
|
}
|
|
2717
2029
|
};
|
|
2718
2030
|
function parseArtifact(artifact) {
|
|
2031
|
+
if (Array.isArray(artifact.functions)) {
|
|
2032
|
+
throw new Error(
|
|
2033
|
+
"parseArtifact: `functions` is an array, which is the arkadec artifact shape, not an SDK program \u2014 read it with programFromArtifact instead"
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
if (typeof artifact.functions !== "object" || artifact.functions === null) {
|
|
2037
|
+
throw new Error("parseArtifact: `functions` must be an object keyed by function name");
|
|
2038
|
+
}
|
|
2719
2039
|
const hexToken = (t) => typeof t === "string" && t.startsWith("0x") ? base.hex.decode(t.slice(2)) : t;
|
|
2040
|
+
const signerRef = (s) => {
|
|
2041
|
+
if (s instanceof Uint8Array || typeof s === "string") return hexToken(s);
|
|
2042
|
+
if (isTweakedSigner(s)) return { tweak: s.tweak, fn: s.fn };
|
|
2043
|
+
throw new Error("parseArtifact: a tweaked signer needs string `tweak` and `fn`");
|
|
2044
|
+
};
|
|
2720
2045
|
const timelockValue = (v) => typeof v === "string" && v.startsWith("$") ? v : BigInt(v);
|
|
2721
|
-
|
|
2046
|
+
if (artifact.version !== void 0 && artifact.version !== SUPPORTED_PROGRAM_VERSION) {
|
|
2047
|
+
throw new UnsupportedProgramVersionError(artifact.version, "parseArtifact");
|
|
2048
|
+
}
|
|
2049
|
+
const declarations = [artifact.params];
|
|
2050
|
+
for (const [name, fn] of Object.entries(artifact.functions)) {
|
|
2051
|
+
if (!fn || typeof fn !== "object" || Array.isArray(fn)) {
|
|
2052
|
+
throw new Error(`parseArtifact: function '${name}' must be an object`);
|
|
2053
|
+
}
|
|
2054
|
+
const tap = fn.tapscript;
|
|
2055
|
+
if (tap !== void 0 && (!tap || typeof tap !== "object" || Array.isArray(tap))) {
|
|
2056
|
+
throw new Error(`parseArtifact: function '${name}' tapscript must be an object`);
|
|
2057
|
+
}
|
|
2058
|
+
declarations.push(fn.inputs, tap?.signatures);
|
|
2059
|
+
if (tap?.emulatorIndex !== void 0 && (!Number.isInteger(tap.emulatorIndex) || tap.emulatorIndex < 0)) {
|
|
2060
|
+
throw new Error(`parseArtifact: function '${name}' has an invalid emulator position`);
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
for (const defs of declarations) {
|
|
2064
|
+
if (defs === void 0) continue;
|
|
2065
|
+
if (!Array.isArray(defs)) {
|
|
2066
|
+
throw new Error(
|
|
2067
|
+
"parseArtifact: parameters, inputs and signatures require arrays of typed declarations"
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
for (const def of defs) {
|
|
2071
|
+
if (!def || typeof def.name !== "string" || def.name.length === 0 || typeof def.type !== "string" || !Object.hasOwn(ARKADE_TYPE_ENCODINGS, def.type)) {
|
|
2072
|
+
throw new Error(
|
|
2073
|
+
"parseArtifact: parameters, inputs and signatures require typed { name, type } declarations"
|
|
2074
|
+
);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
const functions = /* @__PURE__ */ Object.create(null);
|
|
2722
2079
|
for (const [name, fn] of Object.entries(artifact.functions)) {
|
|
2723
2080
|
const tap = fn.tapscript ?? {};
|
|
2724
2081
|
const tapscript = {
|
|
2725
|
-
signers: (tap.signers ?? []).map(
|
|
2082
|
+
signers: (tap.signers ?? []).map(signerRef),
|
|
2083
|
+
...tap.signatures ? { signatures: tap.signatures } : {},
|
|
2726
2084
|
...tap.asm ? { asm: tap.asm.map(hexToken) } : {},
|
|
2727
2085
|
...tap.witness ? { witness: tap.witness.map(hexToken) } : {},
|
|
2728
2086
|
...tap.csv ? { csv: { type: tap.csv.type, value: timelockValue(tap.csv.value) } } : {},
|
|
2729
|
-
...tap.cltv !== void 0 ? { cltv: timelockValue(tap.cltv) } : {}
|
|
2087
|
+
...tap.cltv !== void 0 ? { cltv: timelockValue(tap.cltv) } : {},
|
|
2088
|
+
..."emulator" in tap ? { emulator: tap.emulator } : {},
|
|
2089
|
+
...tap.emulatorIndex !== void 0 ? { emulatorIndex: tap.emulatorIndex } : {}
|
|
2730
2090
|
};
|
|
2731
2091
|
const arkadeScript = fn.arkadeScript ? {
|
|
2732
2092
|
asm: fn.arkadeScript.asm.map(hexToken),
|
|
2733
2093
|
...fn.arkadeScript.witness ? { witness: fn.arkadeScript.witness.map(hexToken) } : {}
|
|
2734
2094
|
} : void 0;
|
|
2735
2095
|
functions[name] = {
|
|
2096
|
+
...fn.group !== void 0 ? { group: fn.group } : {},
|
|
2736
2097
|
...fn.inputs ? { inputs: fn.inputs } : {},
|
|
2737
2098
|
tapscript,
|
|
2738
2099
|
...arkadeScript ? { arkadeScript } : {}
|
|
@@ -2756,17 +2117,21 @@ function stringifyArtifact(program) {
|
|
|
2756
2117
|
}
|
|
2757
2118
|
return t;
|
|
2758
2119
|
};
|
|
2759
|
-
const functions =
|
|
2120
|
+
const functions = /* @__PURE__ */ Object.create(null);
|
|
2760
2121
|
for (const [name, fn] of Object.entries(program.functions)) {
|
|
2761
2122
|
const tap = fn.tapscript;
|
|
2762
2123
|
functions[name] = {
|
|
2124
|
+
...fn.group !== void 0 ? { group: fn.group } : {},
|
|
2763
2125
|
...fn.inputs ? { inputs: fn.inputs } : {},
|
|
2764
2126
|
tapscript: {
|
|
2765
2127
|
signers: tap.signers.map(token),
|
|
2128
|
+
...tap.signatures ? { signatures: tap.signatures } : {},
|
|
2766
2129
|
...tap.asm ? { asm: tap.asm.map(token) } : {},
|
|
2767
2130
|
...tap.witness ? { witness: tap.witness.map(token) } : {},
|
|
2768
2131
|
...tap.csv ? { csv: { type: tap.csv.type, value: tap.csv.value.toString() } } : {},
|
|
2769
|
-
...tap.cltv !== void 0 ? { cltv: tap.cltv.toString() } : {}
|
|
2132
|
+
...tap.cltv !== void 0 ? { cltv: tap.cltv.toString() } : {},
|
|
2133
|
+
...tap.emulator !== void 0 ? { emulator: tap.emulator } : {},
|
|
2134
|
+
...tap.emulatorIndex !== void 0 ? { emulatorIndex: tap.emulatorIndex } : {}
|
|
2770
2135
|
},
|
|
2771
2136
|
...fn.arkadeScript ? {
|
|
2772
2137
|
arkadeScript: {
|
|
@@ -2788,20 +2153,12 @@ function serializeArgValue(v) {
|
|
|
2788
2153
|
if (typeof v === "bigint") return v.toString();
|
|
2789
2154
|
return v;
|
|
2790
2155
|
}
|
|
2791
|
-
function parseArgValue(v) {
|
|
2792
|
-
if (typeof v === "number") return v;
|
|
2793
|
-
if (typeof v === "string") {
|
|
2794
|
-
if (v.startsWith("0x")) return base.hex.decode(v.slice(2));
|
|
2795
|
-
return BigInt(v);
|
|
2796
|
-
}
|
|
2797
|
-
throw new Error(`invalid arkade arg value: ${JSON.stringify(v)}`);
|
|
2798
|
-
}
|
|
2799
2156
|
function parseTypedArgValue(name, type, v) {
|
|
2800
|
-
if (type === "
|
|
2157
|
+
if (ARKADE_TYPE_ENCODINGS[type] === "scriptnum") {
|
|
2801
2158
|
if (typeof v === "number") return v;
|
|
2802
2159
|
if (typeof v === "string") return BigInt(v);
|
|
2803
2160
|
throw new Error(
|
|
2804
|
-
`arkade contract params: '${name}' expects
|
|
2161
|
+
`arkade contract params: '${name}' expects ${type}, got ${JSON.stringify(v)}`
|
|
2805
2162
|
);
|
|
2806
2163
|
}
|
|
2807
2164
|
if (typeof v === "string" && v.startsWith("0x")) return base.hex.decode(v.slice(2));
|
|
@@ -2810,7 +2167,7 @@ function parseTypedArgValue(name, type, v) {
|
|
|
2810
2167
|
);
|
|
2811
2168
|
}
|
|
2812
2169
|
function serializeArkadeContractParams(typed) {
|
|
2813
|
-
const args =
|
|
2170
|
+
const args = /* @__PURE__ */ Object.create(null);
|
|
2814
2171
|
for (const [k, v] of Object.entries(typed.args)) {
|
|
2815
2172
|
args[k] = serializeArgValue(v);
|
|
2816
2173
|
}
|
|
@@ -2830,15 +2187,13 @@ function deserializeArkadeContractParams(params) {
|
|
|
2830
2187
|
throw new Error("arkade contract params: missing 'serverKey'");
|
|
2831
2188
|
}
|
|
2832
2189
|
const program = parseArtifact(JSON.parse(params.program));
|
|
2833
|
-
const paramTypes =
|
|
2834
|
-
|
|
2835
|
-
if (typeof p !== "string") paramTypes.set(p.name, p.type);
|
|
2836
|
-
}
|
|
2837
|
-
const args = {};
|
|
2190
|
+
const paramTypes = new Map((program.params ?? []).map((p) => [p.name, p.type]));
|
|
2191
|
+
const args = /* @__PURE__ */ Object.create(null);
|
|
2838
2192
|
if (params.args) {
|
|
2839
2193
|
for (const [k, v] of Object.entries(JSON.parse(params.args))) {
|
|
2840
2194
|
const type = paramTypes.get(k);
|
|
2841
|
-
|
|
2195
|
+
if (!type) throw new Error(`arkade contract params: undeclared argument '${k}'`);
|
|
2196
|
+
args[k] = parseTypedArgValue(k, type, v);
|
|
2842
2197
|
}
|
|
2843
2198
|
}
|
|
2844
2199
|
return {
|
|
@@ -2852,22 +2207,12 @@ function deserializeArkadeContractParams(params) {
|
|
|
2852
2207
|
|
|
2853
2208
|
// src/contracts/handlers/arkade.ts
|
|
2854
2209
|
function walletKeyFrom(context) {
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
return void 0;
|
|
2861
|
-
}
|
|
2862
|
-
};
|
|
2863
|
-
if (context.walletDescriptor) {
|
|
2864
|
-
const key = extract(context.walletDescriptor);
|
|
2865
|
-
if (key) return key;
|
|
2866
|
-
}
|
|
2867
|
-
if (context.walletPubKey) {
|
|
2868
|
-
return extract(context.walletPubKey);
|
|
2210
|
+
if (!context.walletDescriptor) return void 0;
|
|
2211
|
+
try {
|
|
2212
|
+
return extractPubKey(context.walletDescriptor).toLowerCase();
|
|
2213
|
+
} catch {
|
|
2214
|
+
return void 0;
|
|
2869
2215
|
}
|
|
2870
|
-
return void 0;
|
|
2871
2216
|
}
|
|
2872
2217
|
function staticWitness(fn, script) {
|
|
2873
2218
|
const refs = fn.def.tapscript.witness ?? [];
|
|
@@ -2892,7 +2237,7 @@ function pathsFor(script, context, opts) {
|
|
|
2892
2237
|
continue;
|
|
2893
2238
|
}
|
|
2894
2239
|
const csvDef = fn.def.tapscript.csv;
|
|
2895
|
-
const csv = csvDef ?
|
|
2240
|
+
const csv = csvDef ? resolveCsvTimelock(csvDef, script.args) : void 0;
|
|
2896
2241
|
const cltv = fn.def.tapscript.cltv !== void 0 ? resolveTimelockValue(fn.def.tapscript.cltv, script.args) : void 0;
|
|
2897
2242
|
if (context.collaborative) {
|
|
2898
2243
|
if (csv) continue;
|
|
@@ -2906,7 +2251,7 @@ function pathsFor(script, context, opts) {
|
|
|
2906
2251
|
continue;
|
|
2907
2252
|
}
|
|
2908
2253
|
if (requiresServer) continue;
|
|
2909
|
-
const sequence = csv ? Number(
|
|
2254
|
+
const sequence = csv ? Number(chunkASKOHVGX_cjs.timelockToSequence(csv)) : void 0;
|
|
2910
2255
|
if (opts.checkTimelocks && csv && !isCsvSpendable(context, sequence)) continue;
|
|
2911
2256
|
if (opts.checkTimelocks && cltv !== void 0 && !isCltvSatisfied(context, cltv)) {
|
|
2912
2257
|
continue;
|
|
@@ -2993,6 +2338,7 @@ exports.ARKADE_OPCODES = ARKADE_OPCODES;
|
|
|
2993
2338
|
exports.ARKADE_OPCODE_NAMES = ARKADE_OPCODE_NAMES;
|
|
2994
2339
|
exports.ARKADE_OPCODE_VALUES = ARKADE_OPCODE_VALUES;
|
|
2995
2340
|
exports.ARKADE_OPS = ARKADE_OPS;
|
|
2341
|
+
exports.ARKADE_TYPE_ENCODINGS = ARKADE_TYPE_ENCODINGS;
|
|
2996
2342
|
exports.ArkadeContractHandler = ArkadeContractHandler;
|
|
2997
2343
|
exports.ArkadeProgramScript = ArkadeProgramScript;
|
|
2998
2344
|
exports.ArkadeScript = ArkadeScript;
|
|
@@ -3002,6 +2348,7 @@ exports.DelegateContractHandler = DelegateContractHandler;
|
|
|
3002
2348
|
exports.OPCODE_NAMES = OPCODE_NAMES;
|
|
3003
2349
|
exports.OPCODE_VALUES = OPCODE_VALUES;
|
|
3004
2350
|
exports.SUPPORTED_PROGRAM_VERSION = SUPPORTED_PROGRAM_VERSION;
|
|
2351
|
+
exports.UnsupportedProgramVersionError = UnsupportedProgramVersionError;
|
|
3005
2352
|
exports.VHTLCContractHandler = VHTLCContractHandler;
|
|
3006
2353
|
exports.VHTLCV2ContractHandler = VHTLCV2ContractHandler;
|
|
3007
2354
|
exports.WALLET_RECEIVE_SOURCE = WALLET_RECEIVE_SOURCE;
|
|
@@ -3016,11 +2363,11 @@ exports.deriveDescriptorLeafCompressedPubKey = deriveDescriptorLeafCompressedPub
|
|
|
3016
2363
|
exports.deriveDescriptorLeafPubKey = deriveDescriptorLeafPubKey;
|
|
3017
2364
|
exports.descriptorIsOurs = descriptorIsOurs;
|
|
3018
2365
|
exports.deserializeArkadeContractParams = deserializeArkadeContractParams;
|
|
2366
|
+
exports.extractPubKey = extractPubKey;
|
|
3019
2367
|
exports.fromASM = fromASM;
|
|
3020
2368
|
exports.getOpcodeName = getOpcodeName;
|
|
3021
2369
|
exports.getOpcodeValue = getOpcodeValue;
|
|
3022
2370
|
exports.identityDescriptor = identityDescriptor;
|
|
3023
|
-
exports.inputName = inputName;
|
|
3024
2371
|
exports.isCltvSatisfied = isCltvSatisfied;
|
|
3025
2372
|
exports.isCsvSpendable = isCsvSpendable;
|
|
3026
2373
|
exports.isMainnetDescriptor = isMainnetDescriptor;
|
|
@@ -3033,7 +2380,8 @@ exports.speculativeReceiveMetadata = speculativeReceiveMetadata;
|
|
|
3033
2380
|
exports.stringifyArtifact = stringifyArtifact;
|
|
3034
2381
|
exports.toASM = toASM;
|
|
3035
2382
|
exports.toXOnly = toXOnly;
|
|
2383
|
+
exports.validateParamValue = validateParamValue;
|
|
3036
2384
|
exports.validateProgram = validateProgram;
|
|
3037
2385
|
exports.witnessRefToBytes = witnessRefToBytes;
|
|
3038
|
-
//# sourceMappingURL=chunk-
|
|
3039
|
-
//# sourceMappingURL=chunk-
|
|
2386
|
+
//# sourceMappingURL=chunk-4MCQZYH6.cjs.map
|
|
2387
|
+
//# sourceMappingURL=chunk-4MCQZYH6.cjs.map
|