@arkade-os/sdk 0.3.0-alpha.8 → 0.3.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +64 -14
  2. package/dist/cjs/arknote/index.js +3 -3
  3. package/dist/cjs/forfeit.js +5 -2
  4. package/dist/cjs/identity/singleKey.js +5 -4
  5. package/dist/cjs/index.js +6 -3
  6. package/dist/cjs/{bip322 → intent}/index.js +37 -55
  7. package/dist/cjs/providers/ark.js +62 -23
  8. package/dist/cjs/providers/expoArk.js +15 -170
  9. package/dist/cjs/providers/expoIndexer.js +22 -111
  10. package/dist/cjs/providers/expoUtils.js +124 -0
  11. package/dist/cjs/script/base.js +1 -2
  12. package/dist/cjs/script/tapscript.js +20 -21
  13. package/dist/cjs/script/vhtlc.js +2 -2
  14. package/dist/cjs/tree/signingSession.js +7 -8
  15. package/dist/cjs/tree/txTree.js +3 -4
  16. package/dist/cjs/tree/validation.js +2 -3
  17. package/dist/cjs/utils/arkTransaction.js +104 -12
  18. package/dist/cjs/utils/unknownFields.js +5 -5
  19. package/dist/cjs/wallet/onchain.js +4 -5
  20. package/dist/cjs/wallet/serviceWorker/utils.js +2 -0
  21. package/dist/cjs/wallet/serviceWorker/wallet.js +4 -8
  22. package/dist/cjs/wallet/serviceWorker/worker.js +23 -18
  23. package/dist/cjs/wallet/unroll.js +6 -7
  24. package/dist/cjs/wallet/vtxo-manager.js +381 -0
  25. package/dist/cjs/wallet/wallet.js +63 -94
  26. package/dist/esm/arknote/index.js +2 -2
  27. package/dist/esm/forfeit.js +4 -1
  28. package/dist/esm/identity/singleKey.js +7 -6
  29. package/dist/esm/index.js +7 -6
  30. package/dist/esm/{bip322 → intent}/index.js +31 -48
  31. package/dist/esm/providers/ark.js +62 -23
  32. package/dist/esm/providers/expoArk.js +15 -137
  33. package/dist/esm/providers/expoIndexer.js +22 -78
  34. package/dist/esm/providers/expoUtils.js +87 -0
  35. package/dist/esm/script/base.js +1 -2
  36. package/dist/esm/script/tapscript.js +1 -2
  37. package/dist/esm/script/vhtlc.js +1 -1
  38. package/dist/esm/tree/signingSession.js +8 -9
  39. package/dist/esm/tree/txTree.js +3 -4
  40. package/dist/esm/tree/validation.js +2 -3
  41. package/dist/esm/utils/arkTransaction.js +95 -4
  42. package/dist/esm/utils/unknownFields.js +1 -1
  43. package/dist/esm/wallet/onchain.js +1 -2
  44. package/dist/esm/wallet/serviceWorker/utils.js +1 -0
  45. package/dist/esm/wallet/serviceWorker/wallet.js +5 -9
  46. package/dist/esm/wallet/serviceWorker/worker.js +23 -18
  47. package/dist/esm/wallet/unroll.js +2 -3
  48. package/dist/esm/wallet/vtxo-manager.js +372 -0
  49. package/dist/esm/wallet/wallet.js +56 -87
  50. package/dist/types/arknote/index.d.ts +1 -1
  51. package/dist/types/forfeit.d.ts +2 -2
  52. package/dist/types/identity/index.d.ts +1 -1
  53. package/dist/types/identity/singleKey.d.ts +1 -1
  54. package/dist/types/index.d.ts +6 -5
  55. package/dist/types/intent/index.d.ts +41 -0
  56. package/dist/types/providers/ark.d.ts +55 -21
  57. package/dist/types/providers/expoIndexer.d.ts +2 -10
  58. package/dist/types/providers/expoUtils.d.ts +18 -0
  59. package/dist/types/providers/indexer.d.ts +1 -9
  60. package/dist/types/script/base.d.ts +3 -2
  61. package/dist/types/tree/signingSession.d.ts +10 -10
  62. package/dist/types/utils/anchor.d.ts +2 -2
  63. package/dist/types/utils/arkTransaction.d.ts +13 -3
  64. package/dist/types/utils/unknownFields.d.ts +2 -2
  65. package/dist/types/wallet/index.d.ts +6 -4
  66. package/dist/types/wallet/onchain.d.ts +1 -1
  67. package/dist/types/wallet/serviceWorker/utils.d.ts +1 -0
  68. package/dist/types/wallet/serviceWorker/wallet.d.ts +2 -2
  69. package/dist/types/wallet/serviceWorker/worker.d.ts +3 -1
  70. package/dist/types/wallet/unroll.d.ts +1 -1
  71. package/dist/types/wallet/vtxo-manager.d.ts +207 -0
  72. package/dist/types/wallet/wallet.d.ts +7 -3
  73. package/package.json +1 -2
  74. package/dist/cjs/bip322/errors.js +0 -13
  75. package/dist/esm/bip322/errors.js +0 -9
  76. package/dist/types/bip322/errors.d.ts +0 -6
  77. package/dist/types/bip322/index.d.ts +0 -57
@@ -36,10 +36,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.CLTVMultisigTapscript = exports.ConditionMultisigTapscript = exports.ConditionCSVMultisigTapscript = exports.CSVMultisigTapscript = exports.MultisigTapscript = exports.TapscriptType = void 0;
37
37
  exports.decodeTapscript = decodeTapscript;
38
38
  const bip68 = __importStar(require("bip68"));
39
- const script_js_1 = require("@scure/btc-signer/script.js");
40
- const payment_js_1 = require("@scure/btc-signer/payment.js");
39
+ const btc_signer_1 = require("@scure/btc-signer");
41
40
  const base_1 = require("@scure/base");
42
- const MinimalScriptNum = (0, script_js_1.ScriptNum)(undefined, true);
41
+ const MinimalScriptNum = (0, btc_signer_1.ScriptNum)(undefined, true);
43
42
  var TapscriptType;
44
43
  (function (TapscriptType) {
45
44
  TapscriptType["Multisig"] = "multisig";
@@ -109,7 +108,7 @@ var MultisigTapscript;
109
108
  return {
110
109
  type: TapscriptType.Multisig,
111
110
  params,
112
- script: (0, payment_js_1.p2tr_ms)(params.pubkeys.length, params.pubkeys).script,
111
+ script: (0, btc_signer_1.p2tr_ms)(params.pubkeys.length, params.pubkeys).script,
113
112
  };
114
113
  }
115
114
  const asm = [];
@@ -126,7 +125,7 @@ var MultisigTapscript;
126
125
  return {
127
126
  type: TapscriptType.Multisig,
128
127
  params,
129
- script: script_js_1.Script.encode(asm),
128
+ script: btc_signer_1.Script.encode(asm),
130
129
  };
131
130
  }
132
131
  MultisigTapscript.encode = encode;
@@ -151,7 +150,7 @@ var MultisigTapscript;
151
150
  MultisigTapscript.decode = decode;
152
151
  // <pubkey> CHECKSIG <pubkey> CHECKSIGADD <len_keys> NUMEQUAL
153
152
  function decodeChecksigAdd(script) {
154
- const asm = script_js_1.Script.decode(script);
153
+ const asm = btc_signer_1.Script.decode(script);
155
154
  const pubkeys = [];
156
155
  let foundNumEqual = false;
157
156
  // Parse through ASM operations
@@ -201,7 +200,7 @@ var MultisigTapscript;
201
200
  }
202
201
  // <pubkey> CHECKSIGVERIFY <pubkey> CHECKSIG
203
202
  function decodeChecksig(script) {
204
- const asm = script_js_1.Script.decode(script);
203
+ const asm = btc_signer_1.Script.decode(script);
205
204
  const pubkeys = [];
206
205
  // Parse through ASM operations
207
206
  for (let i = 0; i < asm.length; i++) {
@@ -278,7 +277,7 @@ var CSVMultisigTapscript;
278
277
  ];
279
278
  const multisigScript = MultisigTapscript.encode(params);
280
279
  const script = new Uint8Array([
281
- ...script_js_1.Script.encode(asm),
280
+ ...btc_signer_1.Script.encode(asm),
282
281
  ...multisigScript.script,
283
282
  ]);
284
283
  return {
@@ -292,7 +291,7 @@ var CSVMultisigTapscript;
292
291
  if (script.length === 0) {
293
292
  throw new Error("Failed to decode: script is empty");
294
293
  }
295
- const asm = script_js_1.Script.decode(script);
294
+ const asm = btc_signer_1.Script.decode(script);
296
295
  if (asm.length < 3) {
297
296
  throw new Error(`Invalid script: too short (expected at least 3)`);
298
297
  }
@@ -303,7 +302,7 @@ var CSVMultisigTapscript;
303
302
  if (asm[1] !== "CHECKSEQUENCEVERIFY" || asm[2] !== "DROP") {
304
303
  throw new Error("Invalid script: expected CHECKSEQUENCEVERIFY DROP");
305
304
  }
306
- const multisigScript = new Uint8Array(script_js_1.Script.encode(asm.slice(3)));
305
+ const multisigScript = new Uint8Array(btc_signer_1.Script.encode(asm.slice(3)));
307
306
  let multisig;
308
307
  try {
309
308
  multisig = MultisigTapscript.decode(multisigScript);
@@ -361,7 +360,7 @@ var ConditionCSVMultisigTapscript;
361
360
  function encode(params) {
362
361
  const script = new Uint8Array([
363
362
  ...params.conditionScript,
364
- ...script_js_1.Script.encode(["VERIFY"]),
363
+ ...btc_signer_1.Script.encode(["VERIFY"]),
365
364
  ...CSVMultisigTapscript.encode(params).script,
366
365
  ]);
367
366
  return {
@@ -375,7 +374,7 @@ var ConditionCSVMultisigTapscript;
375
374
  if (script.length === 0) {
376
375
  throw new Error("Failed to decode: script is empty");
377
376
  }
378
- const asm = script_js_1.Script.decode(script);
377
+ const asm = btc_signer_1.Script.decode(script);
379
378
  if (asm.length < 1) {
380
379
  throw new Error(`Invalid script: too short (expected at least 1)`);
381
380
  }
@@ -388,8 +387,8 @@ var ConditionCSVMultisigTapscript;
388
387
  if (verifyIndex === -1) {
389
388
  throw new Error("Invalid script: missing VERIFY operation");
390
389
  }
391
- const conditionScript = new Uint8Array(script_js_1.Script.encode(asm.slice(0, verifyIndex)));
392
- const csvMultisigScript = new Uint8Array(script_js_1.Script.encode(asm.slice(verifyIndex + 1)));
390
+ const conditionScript = new Uint8Array(btc_signer_1.Script.encode(asm.slice(0, verifyIndex)));
391
+ const csvMultisigScript = new Uint8Array(btc_signer_1.Script.encode(asm.slice(verifyIndex + 1)));
393
392
  let csvMultisig;
394
393
  try {
395
394
  csvMultisig = CSVMultisigTapscript.decode(csvMultisigScript);
@@ -436,7 +435,7 @@ var ConditionMultisigTapscript;
436
435
  function encode(params) {
437
436
  const script = new Uint8Array([
438
437
  ...params.conditionScript,
439
- ...script_js_1.Script.encode(["VERIFY"]),
438
+ ...btc_signer_1.Script.encode(["VERIFY"]),
440
439
  ...MultisigTapscript.encode(params).script,
441
440
  ]);
442
441
  return {
@@ -450,7 +449,7 @@ var ConditionMultisigTapscript;
450
449
  if (script.length === 0) {
451
450
  throw new Error("Failed to decode: script is empty");
452
451
  }
453
- const asm = script_js_1.Script.decode(script);
452
+ const asm = btc_signer_1.Script.decode(script);
454
453
  if (asm.length < 1) {
455
454
  throw new Error(`Invalid script: too short (expected at least 1)`);
456
455
  }
@@ -463,8 +462,8 @@ var ConditionMultisigTapscript;
463
462
  if (verifyIndex === -1) {
464
463
  throw new Error("Invalid script: missing VERIFY operation");
465
464
  }
466
- const conditionScript = new Uint8Array(script_js_1.Script.encode(asm.slice(0, verifyIndex)));
467
- const multisigScript = new Uint8Array(script_js_1.Script.encode(asm.slice(verifyIndex + 1)));
465
+ const conditionScript = new Uint8Array(btc_signer_1.Script.encode(asm.slice(0, verifyIndex)));
466
+ const multisigScript = new Uint8Array(btc_signer_1.Script.encode(asm.slice(verifyIndex + 1)));
468
467
  let multisig;
469
468
  try {
470
469
  multisig = MultisigTapscript.decode(multisigScript);
@@ -515,7 +514,7 @@ var CLTVMultisigTapscript;
515
514
  "CHECKLOCKTIMEVERIFY",
516
515
  "DROP",
517
516
  ];
518
- const timelockedScript = script_js_1.Script.encode(asm);
517
+ const timelockedScript = btc_signer_1.Script.encode(asm);
519
518
  const script = new Uint8Array([
520
519
  ...timelockedScript,
521
520
  ...MultisigTapscript.encode(params).script,
@@ -531,7 +530,7 @@ var CLTVMultisigTapscript;
531
530
  if (script.length === 0) {
532
531
  throw new Error("Failed to decode: script is empty");
533
532
  }
534
- const asm = script_js_1.Script.decode(script);
533
+ const asm = btc_signer_1.Script.decode(script);
535
534
  if (asm.length < 3) {
536
535
  throw new Error(`Invalid script: too short (expected at least 3)`);
537
536
  }
@@ -542,7 +541,7 @@ var CLTVMultisigTapscript;
542
541
  if (asm[1] !== "CHECKLOCKTIMEVERIFY" || asm[2] !== "DROP") {
543
542
  throw new Error("Invalid script: expected CHECKLOCKTIMEVERIFY DROP");
544
543
  }
545
- const multisigScript = new Uint8Array(script_js_1.Script.encode(asm.slice(3)));
544
+ const multisigScript = new Uint8Array(btc_signer_1.Script.encode(asm.slice(3)));
546
545
  let multisig;
547
546
  try {
548
547
  multisig = MultisigTapscript.decode(multisigScript);
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VHTLC = void 0;
4
- const script_js_1 = require("@scure/btc-signer/script.js");
4
+ const btc_signer_1 = require("@scure/btc-signer");
5
5
  const tapscript_1 = require("./tapscript");
6
6
  const base_1 = require("@scure/base");
7
7
  const base_2 = require("./base");
@@ -158,5 +158,5 @@ var VHTLC;
158
158
  }
159
159
  })(VHTLC || (exports.VHTLC = VHTLC = {}));
160
160
  function preimageConditionScript(preimageHash) {
161
- return script_js_1.Script.encode(["HASH160", preimageHash, "EQUAL"]);
161
+ return btc_signer_1.Script.encode(["HASH160", preimageHash, "EQUAL"]);
162
162
  }
@@ -57,15 +57,15 @@ class TreeSignerSession {
57
57
  const secretKey = (0, utils_js_1.randomPrivateKeyBytes)();
58
58
  return new TreeSignerSession(secretKey);
59
59
  }
60
- init(tree, scriptRoot, rootInputAmount) {
60
+ async init(tree, scriptRoot, rootInputAmount) {
61
61
  this.graph = tree;
62
62
  this.scriptRoot = scriptRoot;
63
63
  this.rootSharedOutputAmount = rootInputAmount;
64
64
  }
65
- getPublicKey() {
65
+ async getPublicKey() {
66
66
  return secp256k1_js_1.secp256k1.getPublicKey(this.secretKey);
67
67
  }
68
- getNonces() {
68
+ async getNonces() {
69
69
  if (!this.graph)
70
70
  throw exports.ErrMissingVtxoGraph;
71
71
  if (!this.myNonces) {
@@ -77,12 +77,12 @@ class TreeSignerSession {
77
77
  }
78
78
  return publicNonces;
79
79
  }
80
- setAggregatedNonces(nonces) {
80
+ async setAggregatedNonces(nonces) {
81
81
  if (this.aggregateNonces)
82
82
  throw new Error("nonces already set");
83
83
  this.aggregateNonces = nonces;
84
84
  }
85
- sign() {
85
+ async sign() {
86
86
  if (!this.graph)
87
87
  throw exports.ErrMissingVtxoGraph;
88
88
  if (!this.aggregateNonces)
@@ -166,9 +166,8 @@ async function validateTreeSigs(finalAggregatedKey, sharedOutputAmount, vtxoTree
166
166
  function getPrevOutput(finalKey, graph, sharedOutputAmount, tx) {
167
167
  // generate P2TR script from musig2 final key
168
168
  const pkScript = script_js_1.Script.encode(["OP_1", finalKey.slice(1)]);
169
- const txid = base_1.hex.encode((0, utils_js_1.sha256x2)(tx.toBytes(true)).reverse());
170
169
  // if the input is the root input, return the shared output amount
171
- if (txid === graph.txid) {
170
+ if (tx.id === graph.txid) {
172
171
  return {
173
172
  amount: sharedOutputAmount,
174
173
  script: pkScript,
@@ -178,7 +177,7 @@ function getPrevOutput(finalKey, graph, sharedOutputAmount, tx) {
178
177
  const parentInput = tx.getInput(0);
179
178
  if (!parentInput.txid)
180
179
  throw new Error("missing parent input txid");
181
- const parentTxid = base_1.hex.encode(new Uint8Array(parentInput.txid));
180
+ const parentTxid = base_1.hex.encode(parentInput.txid);
182
181
  const parent = graph.find(parentTxid);
183
182
  if (!parent)
184
183
  throw new Error("parent tx not found");
@@ -4,7 +4,6 @@ exports.TxTree = void 0;
4
4
  const transaction_js_1 = require("@scure/btc-signer/transaction.js");
5
5
  const base_1 = require("@scure/base");
6
6
  const base_2 = require("@scure/base");
7
- const utils_js_1 = require("@scure/btc-signer/utils.js");
8
7
  /**
9
8
  * TxTree is a graph of bitcoin transactions.
10
9
  * It is used to represent batch tree created during settlement session
@@ -22,7 +21,7 @@ class TxTree {
22
21
  const chunksByTxid = new Map();
23
22
  for (const chunk of chunks) {
24
23
  const decodedChunk = decodeNode(chunk);
25
- const txid = base_2.hex.encode((0, utils_js_1.sha256x2)(decodedChunk.tx.toBytes(true)).reverse());
24
+ const txid = decodedChunk.tx.id;
26
25
  chunksByTxid.set(txid, decodedChunk);
27
26
  }
28
27
  // Find the root chunks (the ones that aren't referenced as a child)
@@ -91,7 +90,7 @@ class TxTree {
91
90
  }
92
91
  child.validate();
93
92
  const childInput = child.root.getInput(0);
94
- const parentTxid = base_2.hex.encode((0, utils_js_1.sha256x2)(this.root.toBytes(true)).reverse());
93
+ const parentTxid = this.root.id;
95
94
  // verify the input of the child is the output of the parent
96
95
  if (!childInput.txid ||
97
96
  base_2.hex.encode(childInput.txid) !== parentTxid ||
@@ -126,7 +125,7 @@ class TxTree {
126
125
  return leaves;
127
126
  }
128
127
  get txid() {
129
- return base_2.hex.encode((0, utils_js_1.sha256x2)(this.root.toBytes(true)).reverse());
128
+ return this.root.id;
130
129
  }
131
130
  find(txid) {
132
131
  if (txid === this.txid) {
@@ -6,7 +6,6 @@ exports.validateVtxoTxGraph = validateVtxoTxGraph;
6
6
  const base_1 = require("@scure/base");
7
7
  const transaction_js_1 = require("@scure/btc-signer/transaction.js");
8
8
  const base_2 = require("@scure/base");
9
- const utils_js_1 = require("@scure/btc-signer/utils.js");
10
9
  const musig2_1 = require("../musig2");
11
10
  const unknownFields_1 = require("../utils/unknownFields");
12
11
  const ErrInvalidSettlementTx = (tx) => new Error(`invalid settlement transaction: ${tx}`);
@@ -31,7 +30,7 @@ function validateConnectorsTxGraph(settlementTxB64, connectorsGraph) {
31
30
  const settlementTx = transaction_js_1.Transaction.fromPSBT(base_2.base64.decode(settlementTxB64));
32
31
  if (settlementTx.outputsLength <= BATCH_OUTPUT_CONNECTORS_INDEX)
33
32
  throw exports.ErrInvalidSettlementTxOutputs;
34
- const expectedRootTxid = base_1.hex.encode((0, utils_js_1.sha256x2)(settlementTx.toBytes(true)).reverse());
33
+ const expectedRootTxid = settlementTx.id;
35
34
  if (!rootInput.txid)
36
35
  throw exports.ErrWrongSettlementTxid;
37
36
  if (base_1.hex.encode(rootInput.txid) !== expectedRootTxid)
@@ -58,7 +57,7 @@ function validateVtxoTxGraph(graph, roundTransaction, sweepTapTreeRoot) {
58
57
  throw exports.ErrEmptyTree;
59
58
  }
60
59
  const rootInput = graph.root.getInput(0);
61
- const commitmentTxid = base_1.hex.encode((0, utils_js_1.sha256x2)(roundTransaction.toBytes(true)).reverse());
60
+ const commitmentTxid = roundTransaction.id;
62
61
  if (!rootInput.txid ||
63
62
  base_1.hex.encode(rootInput.txid) !== commitmentTxid ||
64
63
  rootInput.index !== BATCH_OUTPUT_VTXO_INDEX) {
@@ -2,12 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildOffchainTx = buildOffchainTx;
4
4
  exports.hasBoardingTxExpired = hasBoardingTxExpired;
5
- const transaction_js_1 = require("@scure/btc-signer/transaction.js");
5
+ exports.verifyTapscriptSignatures = verifyTapscriptSignatures;
6
+ const secp256k1_js_1 = require("@noble/curves/secp256k1.js");
7
+ const base_1 = require("@scure/base");
8
+ const btc_signer_1 = require("@scure/btc-signer");
9
+ const payment_js_1 = require("@scure/btc-signer/payment.js");
6
10
  const tapscript_1 = require("../script/tapscript");
7
- const base_1 = require("../script/base");
11
+ const base_2 = require("../script/base");
8
12
  const anchor_1 = require("./anchor");
9
- const base_2 = require("@scure/base");
10
- const utils_js_1 = require("@scure/btc-signer/utils.js");
11
13
  const unknownFields_1 = require("./unknownFields");
12
14
  /**
13
15
  * Builds an offchain transaction with checkpoint transactions.
@@ -32,7 +34,7 @@ function buildOffchainTx(inputs, outputs, serverUnrollScript) {
32
34
  function buildVirtualTx(inputs, outputs) {
33
35
  let lockTime = 0n;
34
36
  for (const input of inputs) {
35
- const tapscript = (0, tapscript_1.decodeTapscript)((0, base_1.scriptFromTapLeafScript)(input.tapLeafScript));
37
+ const tapscript = (0, tapscript_1.decodeTapscript)((0, base_2.scriptFromTapLeafScript)(input.tapLeafScript));
36
38
  if (tapscript_1.CLTVMultisigTapscript.is(tapscript)) {
37
39
  if (lockTime !== 0n) {
38
40
  // if a locktime is already set, check if the new locktime is in the same unit
@@ -46,7 +48,7 @@ function buildVirtualTx(inputs, outputs) {
46
48
  }
47
49
  }
48
50
  }
49
- const tx = new transaction_js_1.Transaction({
51
+ const tx = new btc_signer_1.Transaction({
50
52
  version: 3,
51
53
  allowUnknown: true,
52
54
  allowUnknownOutputs: true,
@@ -56,9 +58,9 @@ function buildVirtualTx(inputs, outputs) {
56
58
  tx.addInput({
57
59
  txid: input.txid,
58
60
  index: input.vout,
59
- sequence: lockTime ? transaction_js_1.DEFAULT_SEQUENCE - 1 : undefined,
61
+ sequence: lockTime ? btc_signer_1.DEFAULT_SEQUENCE - 1 : undefined,
60
62
  witnessUtxo: {
61
- script: base_1.VtxoScript.decode(input.tapTree).pkScript,
63
+ script: base_2.VtxoScript.decode(input.tapTree).pkScript,
62
64
  amount: BigInt(input.value),
63
65
  },
64
66
  tapLeafScript: [input.tapLeafScript],
@@ -75,9 +77,9 @@ function buildVirtualTx(inputs, outputs) {
75
77
  function buildCheckpointTx(vtxo, serverUnrollScript) {
76
78
  // create the checkpoint vtxo script from collaborative closure
77
79
  const collaborativeClosure = (0, tapscript_1.decodeTapscript)(vtxo.checkpointTapLeafScript ??
78
- (0, base_1.scriptFromTapLeafScript)(vtxo.tapLeafScript));
80
+ (0, base_2.scriptFromTapLeafScript)(vtxo.tapLeafScript));
79
81
  // create the checkpoint vtxo script combining collaborative closure and server unroll script
80
- const checkpointVtxoScript = new base_1.VtxoScript([
82
+ const checkpointVtxoScript = new base_2.VtxoScript([
81
83
  serverUnrollScript.script,
82
84
  collaborativeClosure.script,
83
85
  ]);
@@ -89,10 +91,10 @@ function buildCheckpointTx(vtxo, serverUnrollScript) {
89
91
  },
90
92
  ]);
91
93
  // get the collaborative leaf proof
92
- const collaborativeLeafProof = checkpointVtxoScript.findLeaf(base_2.hex.encode(collaborativeClosure.script));
94
+ const collaborativeLeafProof = checkpointVtxoScript.findLeaf(base_1.hex.encode(collaborativeClosure.script));
93
95
  // create the checkpoint input that will be used as input of the virtual tx
94
96
  const checkpointInput = {
95
- txid: base_2.hex.encode((0, utils_js_1.sha256x2)(checkpointTx.toBytes(true)).reverse()),
97
+ txid: checkpointTx.id,
96
98
  vout: 0,
97
99
  value: vtxo.value,
98
100
  tapLeafScript: collaborativeLeafProof,
@@ -119,3 +121,93 @@ function hasBoardingTxExpired(coin, boardingTimelock) {
119
121
  const blockTime = BigInt(Math.floor(coin.status.block_time));
120
122
  return blockTime + boardingTimelock.value <= now;
121
123
  }
124
+ /**
125
+ * Formats a sighash type as a hex string (e.g., 0x01)
126
+ */
127
+ function formatSighash(type) {
128
+ return `0x${type.toString(16).padStart(2, "0")}`;
129
+ }
130
+ /**
131
+ * Verify tapscript signatures on a transaction input
132
+ * @param tx Transaction to verify
133
+ * @param inputIndex Index of the input to verify
134
+ * @param requiredSigners List of required signer pubkeys (hex encoded)
135
+ * @param excludePubkeys List of pubkeys to exclude from verification (hex encoded, e.g., server key not yet signed)
136
+ * @param allowedSighashTypes List of allowed sighash types (defaults to [SigHash.DEFAULT])
137
+ * @throws Error if verification fails
138
+ */
139
+ function verifyTapscriptSignatures(tx, inputIndex, requiredSigners, excludePubkeys = [], allowedSighashTypes = [btc_signer_1.SigHash.DEFAULT]) {
140
+ const input = tx.getInput(inputIndex);
141
+ // Collect prevout scripts and amounts for ALL inputs (required for preimageWitnessV1)
142
+ const prevoutScripts = [];
143
+ const prevoutAmounts = [];
144
+ for (let i = 0; i < tx.inputsLength; i++) {
145
+ const inp = tx.getInput(i);
146
+ if (!inp.witnessUtxo) {
147
+ throw new Error(`Input ${i} is missing witnessUtxo`);
148
+ }
149
+ prevoutScripts.push(inp.witnessUtxo.script);
150
+ prevoutAmounts.push(inp.witnessUtxo.amount);
151
+ }
152
+ // Verify tapScriptSig signatures
153
+ if (!input.tapScriptSig || input.tapScriptSig.length === 0) {
154
+ throw new Error(`Input ${inputIndex} is missing tapScriptSig`);
155
+ }
156
+ // Verify each signature in tapScriptSig
157
+ for (const [tapScriptSigData, signature] of input.tapScriptSig) {
158
+ const pubKey = tapScriptSigData.pubKey;
159
+ const pubKeyHex = base_1.hex.encode(pubKey);
160
+ // Skip verification for excluded pubkeys
161
+ if (excludePubkeys.includes(pubKeyHex)) {
162
+ continue;
163
+ }
164
+ // Extract sighash type from signature
165
+ // Schnorr signatures are 64 bytes, with optional 1-byte sighash appended
166
+ const sighashType = signature.length === 65 ? signature[64] : btc_signer_1.SigHash.DEFAULT;
167
+ const sig = signature.subarray(0, 64);
168
+ // Verify sighash type is allowed
169
+ if (!allowedSighashTypes.includes(sighashType)) {
170
+ const sighashName = formatSighash(sighashType);
171
+ throw new Error(`Unallowed sighash type ${sighashName} for input ${inputIndex}, pubkey ${pubKeyHex}.`);
172
+ }
173
+ // Find the tapLeafScript that matches this signature's leafHash
174
+ if (!input.tapLeafScript || input.tapLeafScript.length === 0) {
175
+ throw new Error();
176
+ }
177
+ // Search for the leaf that matches the leafHash in tapScriptSigData
178
+ const leafHash = tapScriptSigData.leafHash;
179
+ const leafHashHex = base_1.hex.encode(leafHash);
180
+ let matchingScript;
181
+ let matchingVersion;
182
+ for (const [_, scriptWithVersion] of input.tapLeafScript) {
183
+ const script = scriptWithVersion.subarray(0, -1);
184
+ const version = scriptWithVersion[scriptWithVersion.length - 1];
185
+ // Compute the leaf hash for this script and compare as hex strings
186
+ const computedLeafHash = (0, payment_js_1.tapLeafHash)(script, version);
187
+ const computedHex = base_1.hex.encode(computedLeafHash);
188
+ if (computedHex === leafHashHex) {
189
+ matchingScript = script;
190
+ matchingVersion = version;
191
+ break;
192
+ }
193
+ }
194
+ if (!matchingScript || matchingVersion === undefined) {
195
+ throw new Error(`Input ${inputIndex}: No tapLeafScript found matching leafHash ${base_1.hex.encode(leafHash)}`);
196
+ }
197
+ // Reconstruct the message that was signed
198
+ // Note: preimageWitnessV1 requires ALL input prevout scripts and amounts
199
+ const message = tx.preimageWitnessV1(inputIndex, prevoutScripts, sighashType, prevoutAmounts, undefined, matchingScript, matchingVersion);
200
+ // Verify the schnorr signature
201
+ const isValid = secp256k1_js_1.schnorr.verify(sig, message, pubKey);
202
+ if (!isValid) {
203
+ throw new Error(`Invalid signature for input ${inputIndex}, pubkey ${pubKeyHex}`);
204
+ }
205
+ }
206
+ // Verify we have signatures from all required signers (excluding those we're skipping)
207
+ const signedPubkeys = input.tapScriptSig.map(([data]) => base_1.hex.encode(data.pubKey));
208
+ const requiredNotExcluded = requiredSigners.filter((pk) => !excludePubkeys.includes(pk));
209
+ const missingSigners = requiredNotExcluded.filter((pk) => !signedPubkeys.includes(pk));
210
+ if (missingSigners.length > 0) {
211
+ throw new Error(`Missing signatures from: ${missingSigners.map((pk) => pk.slice(0, 16)).join(", ")}...`);
212
+ }
213
+ }
@@ -37,7 +37,7 @@ exports.VtxoTreeExpiry = exports.CosignerPublicKey = exports.ConditionWitness =
37
37
  exports.setArkPsbtField = setArkPsbtField;
38
38
  exports.getArkPsbtFields = getArkPsbtFields;
39
39
  const bip68 = __importStar(require("bip68"));
40
- const script_js_1 = require("@scure/btc-signer/script.js");
40
+ const btc_signer_1 = require("@scure/btc-signer");
41
41
  const base_1 = require("@scure/base");
42
42
  /**
43
43
  * ArkPsbtFieldKey is the key values for ark psbt fields.
@@ -126,12 +126,12 @@ exports.ConditionWitness = {
126
126
  type: exports.ArkPsbtFieldKeyType,
127
127
  key: encodedPsbtFieldKey[ArkPsbtFieldKey.ConditionWitness],
128
128
  },
129
- script_js_1.RawWitness.encode(value),
129
+ btc_signer_1.RawWitness.encode(value),
130
130
  ],
131
131
  decode: (value) => nullIfCatch(() => {
132
132
  if (!checkKeyIncludes(value[0], ArkPsbtFieldKey.ConditionWitness))
133
133
  return null;
134
- return script_js_1.RawWitness.decode(value[1]);
134
+ return btc_signer_1.RawWitness.decode(value[1]);
135
135
  }),
136
136
  };
137
137
  /**
@@ -176,12 +176,12 @@ exports.VtxoTreeExpiry = {
176
176
  type: exports.ArkPsbtFieldKeyType,
177
177
  key: encodedPsbtFieldKey[ArkPsbtFieldKey.VtxoTreeExpiry],
178
178
  },
179
- (0, script_js_1.ScriptNum)(6, true).encode(value.value === 0n ? 0n : value.value),
179
+ (0, btc_signer_1.ScriptNum)(6, true).encode(value.value === 0n ? 0n : value.value),
180
180
  ],
181
181
  decode: (unknown) => nullIfCatch(() => {
182
182
  if (!checkKeyIncludes(unknown[0], ArkPsbtFieldKey.VtxoTreeExpiry))
183
183
  return null;
184
- const v = (0, script_js_1.ScriptNum)(6, true).decode(unknown[1]);
184
+ const v = (0, btc_signer_1.ScriptNum)(6, true).decode(unknown[1]);
185
185
  if (!v)
186
186
  return null;
187
187
  const { blocks, seconds } = bip68.decode(Number(v));
@@ -2,10 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OnchainWallet = void 0;
4
4
  exports.selectCoins = selectCoins;
5
- const payment_js_1 = require("@scure/btc-signer/payment.js");
5
+ const btc_signer_1 = require("@scure/btc-signer");
6
6
  const networks_1 = require("../networks");
7
7
  const onchain_1 = require("../providers/onchain");
8
- const transaction_js_1 = require("@scure/btc-signer/transaction.js");
9
8
  const anchor_1 = require("../utils/anchor");
10
9
  const txSizeEstimator_1 = require("../utils/txSizeEstimator");
11
10
  /**
@@ -39,7 +38,7 @@ class OnchainWallet {
39
38
  }
40
39
  const network = (0, networks_1.getNetwork)(networkName);
41
40
  const onchainProvider = provider || new onchain_1.EsploraProvider(onchain_1.ESPLORA_URL[networkName]);
42
- const onchainP2TR = (0, payment_js_1.p2tr)(pubkey, undefined, network);
41
+ const onchainP2TR = (0, btc_signer_1.p2tr)(pubkey, undefined, network);
43
42
  return new OnchainWallet(identity, network, onchainP2TR, onchainProvider);
44
43
  }
45
44
  get address() {
@@ -80,7 +79,7 @@ class OnchainWallet {
80
79
  // Select coins
81
80
  const selected = selectCoins(coins, totalNeeded);
82
81
  // Create transaction
83
- let tx = new transaction_js_1.Transaction();
82
+ let tx = new btc_signer_1.Transaction();
84
83
  // Add inputs
85
84
  for (const input of selected.inputs) {
86
85
  tx.addInput({
@@ -108,7 +107,7 @@ class OnchainWallet {
108
107
  }
109
108
  async bumpP2A(parent) {
110
109
  const parentVsize = parent.vsize;
111
- let child = new transaction_js_1.Transaction({
110
+ let child = new btc_signer_1.Transaction({
112
111
  allowUnknownInputs: true,
113
112
  allowLegacyWitnessUtxo: true,
114
113
  version: 3,
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_DB_NAME = void 0;
3
4
  exports.setupServiceWorker = setupServiceWorker;
5
+ exports.DEFAULT_DB_NAME = "arkade-service-worker";
4
6
  /**
5
7
  * setupServiceWorker sets up the service worker.
6
8
  * @param path - the path to the service worker script
@@ -25,7 +25,7 @@ class ServiceWorkerWallet {
25
25
  }
26
26
  static async create(options) {
27
27
  // Default to IndexedDB for service worker context
28
- const storage = options.storage || new indexedDB_1.IndexedDBStorageAdapter("wallet-db");
28
+ const storage = new indexedDB_1.IndexedDBStorageAdapter(options.dbName || utils_1.DEFAULT_DB_NAME, options.dbVersion);
29
29
  // Create repositories
30
30
  const walletRepo = new walletRepository_1.WalletRepositoryImpl(storage);
31
31
  const contractRepo = new contractRepository_1.ContractRepositoryImpl(storage);
@@ -34,7 +34,7 @@ class ServiceWorkerWallet {
34
34
  ? options.identity
35
35
  : null;
36
36
  if (!identity) {
37
- throw new Error("ServiceWorkerWallet.create() requires a Identity that can expose its private key");
37
+ throw new Error("ServiceWorkerWallet.create() requires a Identity that can expose a single private key");
38
38
  }
39
39
  // Extract private key for service worker initialization
40
40
  const privateKey = identity.toHex();
@@ -77,13 +77,9 @@ class ServiceWorkerWallet {
77
77
  // Register and setup the service worker
78
78
  const serviceWorker = await (0, utils_1.setupServiceWorker)(options.serviceWorkerPath);
79
79
  // Use the existing create method
80
- return await ServiceWorkerWallet.create({
81
- arkServerPublicKey: options.arkServerPublicKey,
82
- arkServerUrl: options.arkServerUrl,
83
- esploraUrl: options.esploraUrl,
84
- identity: options.identity,
80
+ return ServiceWorkerWallet.create({
81
+ ...options,
85
82
  serviceWorker,
86
- storage: options.storage,
87
83
  });
88
84
  }
89
85
  // send a message and wait for a response
@@ -14,14 +14,17 @@ const base_1 = require("@scure/base");
14
14
  const indexedDB_1 = require("../../storage/indexedDB");
15
15
  const walletRepository_1 = require("../../repositories/walletRepository");
16
16
  const utils_1 = require("../utils");
17
+ const utils_2 = require("./utils");
17
18
  /**
18
19
  * Worker is a class letting to interact with ServiceWorkerWallet from the client
19
20
  * it aims to be run in a service worker context
20
21
  */
21
22
  class Worker {
22
- constructor(messageCallback = () => { }) {
23
+ constructor(dbName = utils_2.DEFAULT_DB_NAME, dbVersion = 1, messageCallback = () => { }) {
24
+ this.dbName = dbName;
25
+ this.dbVersion = dbVersion;
23
26
  this.messageCallback = messageCallback;
24
- this.storage = new indexedDB_1.IndexedDBStorageAdapter("arkade-service-worker", 1);
27
+ this.storage = new indexedDB_1.IndexedDBStorageAdapter(dbName, dbVersion);
25
28
  this.walletRepository = new walletRepository_1.WalletRepositoryImpl(this.storage);
26
29
  }
27
30
  /**
@@ -107,6 +110,9 @@ class Worker {
107
110
  const txs = await this.wallet.getTransactionHistory();
108
111
  if (txs)
109
112
  await this.walletRepository.saveTransactions(address, txs);
113
+ // unsubscribe previous subscription if any
114
+ if (this.incomingFundsSubscription)
115
+ this.incomingFundsSubscription();
110
116
  // subscribe for incoming funds and notify all clients when new funds arrive
111
117
  this.incomingFundsSubscription = await this.wallet.notifyIncomingFunds(async (funds) => {
112
118
  if (funds.type === "vtxo") {
@@ -353,22 +359,21 @@ class Worker {
353
359
  return;
354
360
  }
355
361
  try {
356
- let vtxos = await this.getSpendableVtxos();
357
- if (!message.filter?.withRecoverable) {
358
- if (!this.wallet)
359
- throw new Error("Wallet not initialized");
360
- // exclude subdust and recoverable if we don't want recoverable
361
- const notSubdust = (v) => {
362
- const dustAmount = this.wallet?.dustAmount;
363
- return dustAmount == null
364
- ? true
365
- : !(0, __1.isSubdust)(v, dustAmount);
366
- };
367
- vtxos = vtxos
368
- .filter(notSubdust)
369
- .filter((v) => !(0, __1.isRecoverable)(v));
370
- }
371
- event.source?.postMessage(response_1.Response.vtxos(message.id, vtxos));
362
+ const vtxos = await this.getSpendableVtxos();
363
+ const dustAmount = this.wallet.dustAmount;
364
+ const includeRecoverable = message.filter?.withRecoverable ?? false;
365
+ const filteredVtxos = includeRecoverable
366
+ ? vtxos
367
+ : vtxos.filter((v) => {
368
+ if (dustAmount != null && (0, __1.isSubdust)(v, dustAmount)) {
369
+ return false;
370
+ }
371
+ if ((0, __1.isRecoverable)(v)) {
372
+ return false;
373
+ }
374
+ return true;
375
+ });
376
+ event.source?.postMessage(response_1.Response.vtxos(message.id, filteredVtxos));
372
377
  }
373
378
  catch (error) {
374
379
  console.error("Error getting vtxos:", error);