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

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 (101) hide show
  1. package/README.md +48 -14
  2. package/dist/cjs/arknote/index.js +3 -3
  3. package/dist/cjs/forfeit.js +2 -2
  4. package/dist/cjs/identity/singleKey.js +8 -8
  5. package/dist/cjs/index.js +13 -5
  6. package/dist/cjs/{bip322 → intent}/index.js +38 -61
  7. package/dist/cjs/musig2/index.js +2 -1
  8. package/dist/cjs/musig2/nonces.js +4 -0
  9. package/dist/cjs/providers/ark.js +76 -45
  10. package/dist/cjs/providers/errors.js +59 -0
  11. package/dist/cjs/providers/expoArk.js +15 -170
  12. package/dist/cjs/providers/expoIndexer.js +22 -111
  13. package/dist/cjs/providers/expoUtils.js +124 -0
  14. package/dist/cjs/providers/onchain.js +19 -20
  15. package/dist/cjs/repositories/walletRepository.js +64 -28
  16. package/dist/cjs/script/base.js +15 -7
  17. package/dist/cjs/script/tapscript.js +20 -21
  18. package/dist/cjs/script/vhtlc.js +2 -2
  19. package/dist/cjs/tree/signingSession.js +44 -11
  20. package/dist/cjs/tree/txTree.js +3 -4
  21. package/dist/cjs/tree/validation.js +2 -3
  22. package/dist/cjs/utils/arkTransaction.js +105 -15
  23. package/dist/cjs/utils/transaction.js +28 -0
  24. package/dist/cjs/utils/unknownFields.js +7 -7
  25. package/dist/cjs/wallet/onchain.js +6 -7
  26. package/dist/cjs/wallet/serviceWorker/response.js +32 -0
  27. package/dist/cjs/wallet/serviceWorker/utils.js +2 -0
  28. package/dist/cjs/wallet/serviceWorker/wallet.js +7 -8
  29. package/dist/cjs/wallet/serviceWorker/worker.js +46 -27
  30. package/dist/cjs/wallet/unroll.js +7 -9
  31. package/dist/cjs/wallet/utils.js +9 -0
  32. package/dist/cjs/wallet/vtxo-manager.js +323 -0
  33. package/dist/cjs/wallet/wallet.js +98 -125
  34. package/dist/esm/arknote/index.js +2 -2
  35. package/dist/esm/forfeit.js +1 -1
  36. package/dist/esm/identity/singleKey.js +9 -9
  37. package/dist/esm/index.js +14 -10
  38. package/dist/esm/{bip322 → intent}/index.js +32 -54
  39. package/dist/esm/musig2/index.js +1 -1
  40. package/dist/esm/musig2/nonces.js +3 -0
  41. package/dist/esm/providers/ark.js +76 -45
  42. package/dist/esm/providers/errors.js +54 -0
  43. package/dist/esm/providers/expoArk.js +15 -137
  44. package/dist/esm/providers/expoIndexer.js +22 -78
  45. package/dist/esm/providers/expoUtils.js +87 -0
  46. package/dist/esm/providers/onchain.js +19 -20
  47. package/dist/esm/repositories/walletRepository.js +64 -28
  48. package/dist/esm/script/base.js +12 -4
  49. package/dist/esm/script/tapscript.js +1 -2
  50. package/dist/esm/script/vhtlc.js +1 -1
  51. package/dist/esm/tree/signingSession.js +45 -12
  52. package/dist/esm/tree/txTree.js +3 -4
  53. package/dist/esm/tree/validation.js +2 -3
  54. package/dist/esm/utils/arkTransaction.js +97 -8
  55. package/dist/esm/utils/transaction.js +24 -0
  56. package/dist/esm/utils/unknownFields.js +3 -3
  57. package/dist/esm/wallet/onchain.js +3 -4
  58. package/dist/esm/wallet/serviceWorker/response.js +32 -0
  59. package/dist/esm/wallet/serviceWorker/utils.js +1 -0
  60. package/dist/esm/wallet/serviceWorker/wallet.js +8 -9
  61. package/dist/esm/wallet/serviceWorker/worker.js +48 -29
  62. package/dist/esm/wallet/unroll.js +5 -7
  63. package/dist/esm/wallet/utils.js +8 -0
  64. package/dist/esm/wallet/vtxo-manager.js +317 -0
  65. package/dist/esm/wallet/wallet.js +92 -119
  66. package/dist/types/arknote/index.d.ts +1 -1
  67. package/dist/types/forfeit.d.ts +2 -2
  68. package/dist/types/identity/index.d.ts +2 -2
  69. package/dist/types/identity/singleKey.d.ts +2 -2
  70. package/dist/types/index.d.ts +9 -7
  71. package/dist/types/intent/index.d.ts +41 -0
  72. package/dist/types/musig2/index.d.ts +1 -1
  73. package/dist/types/musig2/nonces.d.ts +1 -0
  74. package/dist/types/providers/ark.d.ts +62 -26
  75. package/dist/types/providers/errors.d.ts +13 -0
  76. package/dist/types/providers/expoIndexer.d.ts +2 -10
  77. package/dist/types/providers/expoUtils.d.ts +18 -0
  78. package/dist/types/providers/indexer.d.ts +1 -9
  79. package/dist/types/providers/onchain.d.ts +6 -2
  80. package/dist/types/repositories/walletRepository.d.ts +9 -5
  81. package/dist/types/script/base.d.ts +5 -2
  82. package/dist/types/tree/signingSession.d.ts +16 -11
  83. package/dist/types/utils/anchor.d.ts +2 -2
  84. package/dist/types/utils/arkTransaction.d.ts +12 -4
  85. package/dist/types/utils/transaction.d.ts +13 -0
  86. package/dist/types/utils/unknownFields.d.ts +4 -4
  87. package/dist/types/wallet/index.d.ts +6 -4
  88. package/dist/types/wallet/onchain.d.ts +1 -1
  89. package/dist/types/wallet/serviceWorker/response.d.ts +16 -2
  90. package/dist/types/wallet/serviceWorker/utils.d.ts +1 -0
  91. package/dist/types/wallet/serviceWorker/wallet.d.ts +2 -2
  92. package/dist/types/wallet/serviceWorker/worker.d.ts +7 -1
  93. package/dist/types/wallet/unroll.d.ts +1 -1
  94. package/dist/types/wallet/utils.d.ts +2 -1
  95. package/dist/types/wallet/vtxo-manager.d.ts +179 -0
  96. package/dist/types/wallet/wallet.d.ts +8 -4
  97. package/package.json +1 -2
  98. package/dist/cjs/bip322/errors.js +0 -13
  99. package/dist/esm/bip322/errors.js +0 -9
  100. package/dist/types/bip322/errors.d.ts +0 -6
  101. package/dist/types/bip322/index.d.ts +0 -57
@@ -38,8 +38,8 @@ exports.waitForIncomingFunds = waitForIncomingFunds;
38
38
  const base_1 = require("@scure/base");
39
39
  const bip68 = __importStar(require("bip68"));
40
40
  const payment_js_1 = require("@scure/btc-signer/payment.js");
41
- const transaction_js_1 = require("@scure/btc-signer/transaction.js");
42
- const psbt_js_1 = require("@scure/btc-signer/psbt.js");
41
+ const btc_signer_1 = require("@scure/btc-signer");
42
+ const utils_js_1 = require("@scure/btc-signer/utils.js");
43
43
  const transactionHistory_1 = require("../utils/transactionHistory");
44
44
  const address_1 = require("../script/address");
45
45
  const default_1 = require("../script/default");
@@ -49,14 +49,15 @@ const ark_1 = require("../providers/ark");
49
49
  const forfeit_1 = require("../forfeit");
50
50
  const validation_1 = require("../tree/validation");
51
51
  const _1 = require(".");
52
- const utils_js_1 = require("@scure/btc-signer/utils.js");
53
52
  const base_2 = require("../script/base");
54
53
  const tapscript_1 = require("../script/tapscript");
55
54
  const arkTransaction_1 = require("../utils/arkTransaction");
55
+ const vtxo_manager_1 = require("./vtxo-manager");
56
56
  const arknote_1 = require("../arknote");
57
- const bip322_1 = require("../bip322");
57
+ const intent_1 = require("../intent");
58
58
  const indexer_1 = require("../providers/indexer");
59
59
  const txTree_1 = require("../tree/txTree");
60
+ const unknownFields_1 = require("../utils/unknownFields");
60
61
  const inMemory_1 = require("../storage/inMemory");
61
62
  const walletRepository_1 = require("../repositories/walletRepository");
62
63
  const contractRepository_1 = require("../repositories/contractRepository");
@@ -95,7 +96,7 @@ const utils_1 = require("./utils");
95
96
  * ```
96
97
  */
97
98
  class Wallet {
98
- constructor(identity, network, networkName, onchainProvider, arkProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, serverUnrollScript, forfeitOutputScript, dustAmount, walletRepository, contractRepository) {
99
+ constructor(identity, network, networkName, onchainProvider, arkProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, serverUnrollScript, forfeitOutputScript, forfeitPubkey, dustAmount, walletRepository, contractRepository, renewalConfig) {
99
100
  this.identity = identity;
100
101
  this.network = network;
101
102
  this.networkName = networkName;
@@ -107,9 +108,15 @@ class Wallet {
107
108
  this.boardingTapscript = boardingTapscript;
108
109
  this.serverUnrollScript = serverUnrollScript;
109
110
  this.forfeitOutputScript = forfeitOutputScript;
111
+ this.forfeitPubkey = forfeitPubkey;
110
112
  this.dustAmount = dustAmount;
111
113
  this.walletRepository = walletRepository;
112
114
  this.contractRepository = contractRepository;
115
+ this.renewalConfig = {
116
+ enabled: renewalConfig?.enabled ?? false,
117
+ ...vtxo_manager_1.DEFAULT_RENEWAL_CONFIG,
118
+ ...renewalConfig,
119
+ };
113
120
  }
114
121
  static async create(config) {
115
122
  const pubkey = await config.identity.xOnlyPublicKey();
@@ -139,6 +146,7 @@ class Wallet {
139
146
  const esploraUrl = config.esploraUrl || onchain_1.ESPLORA_URL[info.network];
140
147
  // Use provided onchainProvider instance or create a new one
141
148
  const onchainProvider = config.onchainProvider || new onchain_1.EsploraProvider(esploraUrl);
149
+ // Generate timelocks
142
150
  const exitTimelock = {
143
151
  value: info.unilateralExitDelay,
144
152
  type: info.unilateralExitDelay < 512n ? "blocks" : "seconds",
@@ -164,21 +172,22 @@ class Wallet {
164
172
  // the serverUnrollScript is the one used to create output scripts of the checkpoint transactions
165
173
  let serverUnrollScript;
166
174
  try {
167
- const raw = base_1.hex.decode(info.checkpointExitClosure);
175
+ const raw = base_1.hex.decode(info.checkpointTapscript);
168
176
  serverUnrollScript = tapscript_1.CSVMultisigTapscript.decode(raw);
169
177
  }
170
178
  catch (e) {
171
- throw new Error("Invalid checkpointExitClosure from server");
179
+ throw new Error("Invalid checkpointTapscript from server");
172
180
  }
173
181
  // parse the server forfeit address
174
182
  // server is expecting funds to be sent to this address
175
- const forfeitAddress = (0, payment_js_1.Address)(network).decode(info.forfeitAddress);
176
- const forfeitOutputScript = payment_js_1.OutScript.encode(forfeitAddress);
183
+ const forfeitPubkey = base_1.hex.decode(info.forfeitPubkey).slice(1);
184
+ const forfeitAddress = (0, btc_signer_1.Address)(network).decode(info.forfeitAddress);
185
+ const forfeitOutputScript = btc_signer_1.OutScript.encode(forfeitAddress);
177
186
  // Set up storage and repositories
178
187
  const storage = config.storage || new inMemory_1.InMemoryStorageAdapter();
179
188
  const walletRepository = new walletRepository_1.WalletRepositoryImpl(storage);
180
189
  const contractRepository = new contractRepository_1.ContractRepositoryImpl(storage);
181
- return new Wallet(config.identity, network, info.network, onchainProvider, arkProvider, indexerProvider, serverPubKey, offchainTapscript, boardingTapscript, serverUnrollScript, forfeitOutputScript, info.dust, walletRepository, contractRepository);
190
+ return new Wallet(config.identity, network, info.network, onchainProvider, arkProvider, indexerProvider, serverPubKey, offchainTapscript, boardingTapscript, serverUnrollScript, forfeitOutputScript, forfeitPubkey, info.dust, walletRepository, contractRepository, config.renewalConfig);
182
191
  }
183
192
  get arkAddress() {
184
193
  return this.offchainTapscript.address(this.network.hrp, this.arkServerPublicKey);
@@ -361,15 +370,12 @@ class Wallet {
361
370
  async getBoardingUtxos() {
362
371
  const boardingAddress = await this.getBoardingAddress();
363
372
  const boardingUtxos = await this.onchainProvider.getCoins(boardingAddress);
364
- const encodedBoardingTapscript = this.boardingTapscript.encode();
365
- const forfeit = this.boardingTapscript.forfeit();
366
- const exit = this.boardingTapscript.exit();
367
- return boardingUtxos.map((utxo) => ({
368
- ...utxo,
369
- forfeitTapLeafScript: forfeit,
370
- intentTapLeafScript: exit,
371
- tapTree: encodedBoardingTapscript,
372
- }));
373
+ const utxos = boardingUtxos.map((utxo) => {
374
+ return (0, utils_1.extendCoin)(this, utxo);
375
+ });
376
+ // Save boardingUtxos using unified repository
377
+ await this.walletRepository.saveUtxos(boardingAddress, utxos);
378
+ return utxos;
373
379
  }
374
380
  async sendBitcoin(params) {
375
381
  if (params.amount <= 0) {
@@ -418,7 +424,7 @@ class Wallet {
418
424
  // TODO persist final virtual tx and checkpoints to repository
419
425
  // sign the checkpoints
420
426
  const finalCheckpoints = await Promise.all(signedCheckpointTxs.map(async (c) => {
421
- const tx = transaction_js_1.Transaction.fromPSBT(base_1.base64.decode(c));
427
+ const tx = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(c));
422
428
  const signedCheckpoint = await this.identity.sign(tx);
423
429
  return base_1.base64.encode(signedCheckpoint.toPSBT());
424
430
  }));
@@ -476,8 +482,8 @@ class Wallet {
476
482
  }
477
483
  catch {
478
484
  // onchain
479
- const addr = (0, payment_js_1.Address)(this.network).decode(output.address);
480
- script = payment_js_1.OutScript.encode(addr);
485
+ const addr = (0, btc_signer_1.Address)(this.network).decode(output.address);
486
+ script = btc_signer_1.OutScript.encode(addr);
481
487
  onchainOutputIndexes.push(index);
482
488
  }
483
489
  outputs.push({
@@ -490,7 +496,7 @@ class Wallet {
490
496
  const signingPublicKeys = [];
491
497
  if (hasOffchainOutputs) {
492
498
  session = this.identity.signerSession();
493
- signingPublicKeys.push(base_1.hex.encode(session.getPublicKey()));
499
+ signingPublicKeys.push(base_1.hex.encode(await session.getPublicKey()));
494
500
  }
495
501
  const [intent, deleteIntent] = await Promise.all([
496
502
  this.makeRegisterIntentSignature(params.inputs, outputs, onchainOutputIndexes, signingPublicKeys),
@@ -506,8 +512,8 @@ class Wallet {
506
512
  ...params.inputs.map((input) => `${input.txid}:${input.vout}`),
507
513
  ];
508
514
  const settlementStream = this.arkProvider.getEventStream(abortController.signal, topics);
509
- // roundId, sweepTapTreeRoot and forfeitOutputScript are set once the BatchStarted event is received
510
- let roundId;
515
+ // batchId, sweepTapTreeRoot and forfeitOutputScript are set once the BatchStarted event is received
516
+ let batchId;
511
517
  let sweepTapTreeRoot;
512
518
  const vtxoChunks = [];
513
519
  const connectorsChunks = [];
@@ -520,30 +526,26 @@ class Wallet {
520
526
  switch (event.type) {
521
527
  // the settlement failed
522
528
  case ark_1.SettlementEventType.BatchFailed:
523
- // fail if the roundId is the one joined
524
- if (event.id === roundId) {
525
- throw new Error(event.reason);
526
- }
527
- break;
529
+ throw new Error(event.reason);
528
530
  case ark_1.SettlementEventType.BatchStarted:
529
531
  if (step !== undefined) {
530
532
  continue;
531
533
  }
532
- const res = await this.handleBatchStartedEvent(event, intentId, this.arkServerPublicKey, this.forfeitOutputScript);
534
+ const res = await this.handleBatchStartedEvent(event, intentId, this.forfeitPubkey, this.forfeitOutputScript);
533
535
  if (!res.skip) {
534
536
  step = event.type;
535
537
  sweepTapTreeRoot = res.sweepTapTreeRoot;
536
- roundId = res.roundId;
538
+ batchId = res.roundId;
537
539
  if (!hasOffchainOutputs) {
538
540
  // if there are no offchain outputs, we don't have to handle musig2 tree signatures
539
541
  // we can directly advance to the finalization step
540
- step = ark_1.SettlementEventType.TreeNoncesAggregated;
542
+ step = ark_1.SettlementEventType.TreeNonces;
541
543
  }
542
544
  }
543
545
  break;
544
546
  case ark_1.SettlementEventType.TreeTx:
545
547
  if (step !== ark_1.SettlementEventType.BatchStarted &&
546
- step !== ark_1.SettlementEventType.TreeNoncesAggregated) {
548
+ step !== ark_1.SettlementEventType.TreeNonces) {
547
549
  continue;
548
550
  }
549
551
  // index 0 = vtxo tree
@@ -559,7 +561,7 @@ class Wallet {
559
561
  }
560
562
  break;
561
563
  case ark_1.SettlementEventType.TreeSignature:
562
- if (step !== ark_1.SettlementEventType.TreeNoncesAggregated) {
564
+ if (step !== ark_1.SettlementEventType.TreeNonces) {
563
565
  continue;
564
566
  }
565
567
  if (!hasOffchainOutputs) {
@@ -601,7 +603,7 @@ class Wallet {
601
603
  break;
602
604
  // the musig2 nonces of the vtxo tree transactions are generated
603
605
  // the server expects now the partial musig2 signatures
604
- case ark_1.SettlementEventType.TreeNoncesAggregated:
606
+ case ark_1.SettlementEventType.TreeNonces:
605
607
  if (step !== ark_1.SettlementEventType.TreeSigningStarted) {
606
608
  continue;
607
609
  }
@@ -609,14 +611,18 @@ class Wallet {
609
611
  if (!session) {
610
612
  throw new Error("Signing session not set");
611
613
  }
612
- await this.handleSettlementSigningNoncesGeneratedEvent(event, session);
614
+ const signed = await this.handleSettlementTreeNoncesEvent(event, session);
615
+ if (signed) {
616
+ step = event.type;
617
+ }
618
+ break;
613
619
  }
614
620
  step = event.type;
615
621
  break;
616
622
  // the vtxo tree is signed, craft, sign and submit forfeit transactions
617
623
  // if any boarding utxos are involved, the settlement tx is also signed
618
624
  case ark_1.SettlementEventType.BatchFinalization:
619
- if (step !== ark_1.SettlementEventType.TreeNoncesAggregated) {
625
+ if (step !== ark_1.SettlementEventType.TreeNonces) {
620
626
  continue;
621
627
  }
622
628
  if (!this.forfeitOutputScript) {
@@ -634,8 +640,10 @@ class Wallet {
634
640
  if (step !== ark_1.SettlementEventType.BatchFinalization) {
635
641
  continue;
636
642
  }
637
- abortController.abort();
638
- return event.commitmentTxid;
643
+ if (event.id === batchId) {
644
+ abortController.abort();
645
+ return event.commitmentTxid;
646
+ }
639
647
  }
640
648
  }
641
649
  }
@@ -714,10 +722,10 @@ class Wallet {
714
722
  };
715
723
  return stopFunc;
716
724
  }
717
- async handleBatchStartedEvent(event, intentId, serverPubKey, forfeitOutputScript) {
725
+ async handleBatchStartedEvent(event, intentId, forfeitPubKey, forfeitOutputScript) {
718
726
  const utf8IntentId = new TextEncoder().encode(intentId);
719
727
  const intentIdHash = (0, utils_js_1.sha256)(utf8IntentId);
720
- const intentIdHashStr = base_1.hex.encode(new Uint8Array(intentIdHash));
728
+ const intentIdHashStr = base_1.hex.encode(intentIdHash);
721
729
  let skip = true;
722
730
  // check if our intent ID hash matches any in the event
723
731
  for (const idHash of event.intentIdHashes) {
@@ -737,7 +745,7 @@ class Wallet {
737
745
  value: event.batchExpiry,
738
746
  type: event.batchExpiry >= 512n ? "seconds" : "blocks",
739
747
  },
740
- pubkeys: [serverPubKey],
748
+ pubkeys: [forfeitPubKey],
741
749
  }).script;
742
750
  const sweepTapTreeRoot = (0, payment_js_1.tapLeafHash)(sweepTapscript);
743
751
  return {
@@ -750,7 +758,7 @@ class Wallet {
750
758
  // validates the vtxo tree, creates a signing session and generates the musig2 nonces
751
759
  async handleSettlementSigningEvent(event, sweepTapTreeRoot, session, vtxoGraph) {
752
760
  // validate the unsigned vtxo tree
753
- const commitmentTx = transaction_js_1.Transaction.fromPSBT(base_1.base64.decode(event.unsignedCommitmentTx));
761
+ const commitmentTx = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(event.unsignedCommitmentTx));
754
762
  (0, validation_1.validateVtxoTxGraph)(vtxoGraph, commitmentTx, sweepTapTreeRoot);
755
763
  // TODO check if our registered outputs are in the vtxo tree
756
764
  const sharedOutput = commitmentTx.getOutput(0);
@@ -758,18 +766,25 @@ class Wallet {
758
766
  throw new Error("Shared output not found");
759
767
  }
760
768
  session.init(vtxoGraph, sweepTapTreeRoot, sharedOutput.amount);
761
- await this.arkProvider.submitTreeNonces(event.id, base_1.hex.encode(session.getPublicKey()), session.getNonces());
769
+ const pubkey = base_1.hex.encode(await session.getPublicKey());
770
+ const nonces = await session.getNonces();
771
+ await this.arkProvider.submitTreeNonces(event.id, pubkey, nonces);
762
772
  }
763
- async handleSettlementSigningNoncesGeneratedEvent(event, session) {
764
- session.setAggregatedNonces(event.treeNonces);
765
- const signatures = session.sign();
766
- await this.arkProvider.submitTreeSignatures(event.id, base_1.hex.encode(session.getPublicKey()), signatures);
773
+ async handleSettlementTreeNoncesEvent(event, session) {
774
+ const { hasAllNonces } = await session.aggregatedNonces(event.txid, event.nonces);
775
+ // wait to receive and aggregate all nonces before sending signatures
776
+ if (!hasAllNonces)
777
+ return false;
778
+ const signatures = await session.sign();
779
+ const pubkey = base_1.hex.encode(await session.getPublicKey());
780
+ await this.arkProvider.submitTreeSignatures(event.id, pubkey, signatures);
781
+ return true;
767
782
  }
768
783
  async handleSettlementFinalizationEvent(event, inputs, forfeitOutputScript, connectorsGraph) {
769
784
  // the signed forfeits transactions to submit
770
785
  const signedForfeits = [];
771
786
  const vtxos = await this.getVirtualCoins();
772
- let settlementPsbt = transaction_js_1.Transaction.fromPSBT(base_1.base64.decode(event.commitmentTx));
787
+ let settlementPsbt = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(event.commitmentTx));
773
788
  let hasBoardingUtxos = false;
774
789
  let connectorIndex = 0;
775
790
  const connectorsLeaves = connectorsGraph?.leaves() || [];
@@ -778,8 +793,6 @@ class Wallet {
778
793
  const vtxo = vtxos.find((vtxo) => vtxo.txid === input.txid && vtxo.vout === input.vout);
779
794
  // boarding utxo, we need to sign the settlement tx
780
795
  if (!vtxo) {
781
- hasBoardingUtxos = true;
782
- const inputIndexes = [];
783
796
  for (let i = 0; i < settlementPsbt.inputsLength; i++) {
784
797
  const settlementInput = settlementPsbt.getInput(i);
785
798
  if (!settlementInput.txid ||
@@ -795,9 +808,12 @@ class Wallet {
795
808
  settlementPsbt.updateInput(i, {
796
809
  tapLeafScript: [input.forfeitTapLeafScript],
797
810
  });
798
- inputIndexes.push(i);
811
+ settlementPsbt = await this.identity.sign(settlementPsbt, [
812
+ i,
813
+ ]);
814
+ hasBoardingUtxos = true;
815
+ break;
799
816
  }
800
- settlementPsbt = await this.identity.sign(settlementPsbt, inputIndexes);
801
817
  continue;
802
818
  }
803
819
  if ((0, _1.isRecoverable)(vtxo) || (0, _1.isSubdust)(vtxo, this.dustAmount)) {
@@ -811,7 +827,7 @@ class Wallet {
811
827
  throw new Error("not enough connectors received");
812
828
  }
813
829
  const connectorLeaf = connectorsLeaves[connectorIndex];
814
- const connectorTxId = base_1.hex.encode((0, utils_js_1.sha256x2)(connectorLeaf.toBytes(true)).reverse());
830
+ const connectorTxId = connectorLeaf.id;
815
831
  const connectorOutput = connectorLeaf.getOutput(0);
816
832
  if (!connectorOutput) {
817
833
  throw new Error("connector output not found");
@@ -830,7 +846,7 @@ class Wallet {
830
846
  amount: BigInt(vtxo.value),
831
847
  script: base_2.VtxoScript.decode(input.tapTree).pkScript,
832
848
  },
833
- sighashType: transaction_js_1.SigHash.DEFAULT,
849
+ sighashType: btc_signer_1.SigHash.DEFAULT,
834
850
  tapLeafScript: [input.forfeitTapLeafScript],
835
851
  },
836
852
  {
@@ -852,112 +868,69 @@ class Wallet {
852
868
  : undefined);
853
869
  }
854
870
  }
855
- async makeRegisterIntentSignature(bip322Inputs, outputs, onchainOutputsIndexes, cosignerPubKeys) {
871
+ async makeRegisterIntentSignature(coins, outputs, onchainOutputsIndexes, cosignerPubKeys) {
856
872
  const nowSeconds = Math.floor(Date.now() / 1000);
857
- const { inputs, inputTapTrees, finalizer } = this.prepareBIP322Inputs(bip322Inputs);
873
+ const inputs = this.prepareIntentProofInputs(coins);
858
874
  const message = {
859
875
  type: "register",
860
- input_tap_trees: inputTapTrees,
861
876
  onchain_output_indexes: onchainOutputsIndexes,
862
877
  valid_at: nowSeconds,
863
878
  expire_at: nowSeconds + 2 * 60, // valid for 2 minutes
864
879
  cosigners_public_keys: cosignerPubKeys,
865
880
  };
866
881
  const encodedMessage = JSON.stringify(message, null, 0);
867
- const signature = await this.makeBIP322Signature(encodedMessage, inputs, finalizer, outputs);
882
+ const proof = intent_1.Intent.create(encodedMessage, inputs, outputs);
883
+ const signedProof = await this.identity.sign(proof);
868
884
  return {
869
- signature,
885
+ proof: base_1.base64.encode(signedProof.toPSBT()),
870
886
  message: encodedMessage,
871
887
  };
872
888
  }
873
- async makeDeleteIntentSignature(bip322Inputs) {
889
+ async makeDeleteIntentSignature(coins) {
874
890
  const nowSeconds = Math.floor(Date.now() / 1000);
875
- const { inputs, finalizer } = this.prepareBIP322Inputs(bip322Inputs);
891
+ const inputs = this.prepareIntentProofInputs(coins);
876
892
  const message = {
877
893
  type: "delete",
878
894
  expire_at: nowSeconds + 2 * 60, // valid for 2 minutes
879
895
  };
880
896
  const encodedMessage = JSON.stringify(message, null, 0);
881
- const signature = await this.makeBIP322Signature(encodedMessage, inputs, finalizer);
897
+ const proof = intent_1.Intent.create(encodedMessage, inputs, []);
898
+ const signedProof = await this.identity.sign(proof);
882
899
  return {
883
- signature,
900
+ proof: base_1.base64.encode(signedProof.toPSBT()),
884
901
  message: encodedMessage,
885
902
  };
886
903
  }
887
- prepareBIP322Inputs(bip322Inputs) {
904
+ prepareIntentProofInputs(coins) {
888
905
  const inputs = [];
889
- const inputTapTrees = [];
890
- const inputExtraWitnesses = [];
891
- for (const bip322Input of bip322Inputs) {
892
- const vtxoScript = base_2.VtxoScript.decode(bip322Input.tapTree);
893
- const sequence = getSequence(bip322Input);
906
+ for (const input of coins) {
907
+ const vtxoScript = base_2.VtxoScript.decode(input.tapTree);
908
+ const sequence = getSequence(input);
909
+ const unknown = [unknownFields_1.VtxoTaprootTree.encode(input.tapTree)];
910
+ if (input.extraWitness) {
911
+ unknown.push(unknownFields_1.ConditionWitness.encode(input.extraWitness));
912
+ }
894
913
  inputs.push({
895
- txid: base_1.hex.decode(bip322Input.txid),
896
- index: bip322Input.vout,
914
+ txid: base_1.hex.decode(input.txid),
915
+ index: input.vout,
897
916
  witnessUtxo: {
898
- amount: BigInt(bip322Input.value),
917
+ amount: BigInt(input.value),
899
918
  script: vtxoScript.pkScript,
900
919
  },
901
920
  sequence,
902
- tapLeafScript: [bip322Input.intentTapLeafScript],
921
+ tapLeafScript: [input.intentTapLeafScript],
922
+ unknown,
903
923
  });
904
- inputTapTrees.push(base_1.hex.encode(bip322Input.tapTree));
905
- inputExtraWitnesses.push(bip322Input.extraWitness || []);
906
924
  }
907
- return {
908
- inputs,
909
- inputTapTrees,
910
- finalizer: finalizeWithExtraWitnesses(inputExtraWitnesses),
911
- };
912
- }
913
- async makeBIP322Signature(message, inputs, finalizer, outputs) {
914
- const proof = bip322_1.BIP322.create(message, inputs, outputs);
915
- const signedProof = await this.identity.sign(proof);
916
- return bip322_1.BIP322.signature(signedProof, finalizer);
925
+ return inputs;
917
926
  }
918
927
  }
919
928
  exports.Wallet = Wallet;
920
929
  Wallet.MIN_FEE_RATE = 1; // sats/vbyte
921
- function finalizeWithExtraWitnesses(inputExtraWitnesses) {
922
- return function (tx) {
923
- for (let i = 0; i < tx.inputsLength; i++) {
924
- try {
925
- tx.finalizeIdx(i);
926
- }
927
- catch (e) {
928
- // handle empty witness error
929
- if (e instanceof Error &&
930
- e.message.includes("finalize/taproot: empty witness")) {
931
- const tapLeaves = tx.getInput(i).tapLeafScript;
932
- if (!tapLeaves || tapLeaves.length <= 0)
933
- throw e;
934
- const [cb, s] = tapLeaves[0];
935
- const script = s.slice(0, -1);
936
- tx.updateInput(i, {
937
- finalScriptWitness: [
938
- script,
939
- psbt_js_1.TaprootControlBlock.encode(cb),
940
- ],
941
- });
942
- }
943
- }
944
- const finalScriptWitness = tx.getInput(i).finalScriptWitness;
945
- if (!finalScriptWitness)
946
- throw new Error("input not finalized");
947
- // input 0 and 1 spend the same pkscript
948
- const extra = inputExtraWitnesses[i === 0 ? 0 : i - 1];
949
- if (extra && extra.length > 0) {
950
- tx.updateInput(i, {
951
- finalScriptWitness: [...extra, ...finalScriptWitness],
952
- });
953
- }
954
- }
955
- };
956
- }
957
- function getSequence(bip322Input) {
930
+ function getSequence(coin) {
958
931
  let sequence = undefined;
959
932
  try {
960
- const scriptWithLeafVersion = bip322Input.intentTapLeafScript[1];
933
+ const scriptWithLeafVersion = coin.intentTapLeafScript[1];
961
934
  const script = scriptWithLeafVersion.subarray(0, scriptWithLeafVersion.length - 1);
962
935
  const params = tapscript_1.CSVMultisigTapscript.decode(script).params;
963
936
  sequence = bip68.encode(params.timelock.type === "blocks"
@@ -1,7 +1,7 @@
1
1
  import { base58, hex } from "@scure/base";
2
- import { VtxoScript } from '../script/base.js';
3
2
  import { sha256 } from "@scure/btc-signer/utils.js";
4
- import { Script } from "@scure/btc-signer/script.js";
3
+ import { Script } from "@scure/btc-signer";
4
+ import { VtxoScript } from '../script/base.js';
5
5
  /**
6
6
  * ArkNotes are special virtual coins in the Ark protocol that can be created
7
7
  * and spent without requiring any transactions. The server mints them, and they
@@ -1,4 +1,4 @@
1
- import { Transaction } from "@scure/btc-signer/transaction.js";
1
+ import { Transaction } from './utils/transaction.js';
2
2
  import { P2A } from './utils/anchor.js';
3
3
  export function buildForfeitTx(inputs, forfeitPkScript, txLocktime) {
4
4
  const tx = new Transaction({
@@ -1,9 +1,8 @@
1
- import { pubECDSA, pubSchnorr, randomPrivateKeyBytes, sha256, } from "@scure/btc-signer/utils.js";
1
+ import { pubECDSA, pubSchnorr, randomPrivateKeyBytes, } from "@scure/btc-signer/utils.js";
2
+ import { SigHash } from "@scure/btc-signer";
2
3
  import { hex } from "@scure/base";
3
- import { SigHash } from "@scure/btc-signer/transaction.js";
4
4
  import { TreeSignerSession } from '../tree/signingSession.js';
5
- import { schnorr } from "@noble/secp256k1";
6
- const ZERO_32 = new Uint8Array(32).fill(0);
5
+ import { schnorr, sign } from "@noble/secp256k1";
7
6
  const ALL_SIGHASH = Object.values(SigHash).filter((x) => typeof x === "number");
8
7
  /**
9
8
  * In-memory single key implementation for Bitcoin transaction signing.
@@ -48,7 +47,7 @@ export class SingleKey {
48
47
  const txCpy = tx.clone();
49
48
  if (!inputIndexes) {
50
49
  try {
51
- if (!txCpy.sign(this.key, ALL_SIGHASH, ZERO_32)) {
50
+ if (!txCpy.sign(this.key, ALL_SIGHASH)) {
52
51
  throw new Error("Failed to sign transaction");
53
52
  }
54
53
  }
@@ -64,7 +63,7 @@ export class SingleKey {
64
63
  return txCpy;
65
64
  }
66
65
  for (const inputIndex of inputIndexes) {
67
- if (!txCpy.signIdx(this.key, inputIndex, ALL_SIGHASH, ZERO_32)) {
66
+ if (!txCpy.signIdx(this.key, inputIndex, ALL_SIGHASH)) {
68
67
  throw new Error(`Failed to sign input #${inputIndex}`);
69
68
  }
70
69
  }
@@ -79,8 +78,9 @@ export class SingleKey {
79
78
  signerSession() {
80
79
  return TreeSignerSession.random();
81
80
  }
82
- async signMessage(message) {
83
- const msgBytes = new TextEncoder().encode(message);
84
- return schnorr.sign(sha256(msgBytes), this.key);
81
+ async signMessage(message, signatureType = "schnorr") {
82
+ if (signatureType === "ecdsa")
83
+ return sign(message, this.key, { prehash: false });
84
+ return schnorr.sign(message, this.key);
85
85
  }
86
86
  }
package/dist/esm/index.js CHANGED
@@ -1,13 +1,14 @@
1
- import { Transaction } from "@scure/btc-signer/transaction.js";
1
+ import { Transaction } from './utils/transaction.js';
2
2
  import { SingleKey } from './identity/singleKey.js';
3
3
  import { ArkAddress } from './script/address.js';
4
4
  import { VHTLC } from './script/vhtlc.js';
5
5
  import { DefaultVtxo } from './script/default.js';
6
- import { VtxoScript } from './script/base.js';
6
+ import { VtxoScript, TapTreeCoder, } from './script/base.js';
7
7
  import { TxType, } from './wallet/index.js';
8
8
  import { Wallet, waitForIncomingFunds } from './wallet/wallet.js';
9
9
  import { TxTree } from './tree/txTree.js';
10
10
  import { Ramps } from './wallet/ramps.js';
11
+ import { VtxoManager } from './wallet/vtxo-manager.js';
11
12
  import { ServiceWorkerWallet } from './wallet/serviceWorker/wallet.js';
12
13
  import { OnchainWallet } from './wallet/onchain.js';
13
14
  import { setupServiceWorker } from './wallet/serviceWorker/utils.js';
@@ -17,9 +18,9 @@ import { Response } from './wallet/serviceWorker/response.js';
17
18
  import { ESPLORA_URL, EsploraProvider, } from './providers/onchain.js';
18
19
  import { RestArkProvider, SettlementEventType, } from './providers/ark.js';
19
20
  import { CLTVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CSVMultisigTapscript, decodeTapscript, MultisigTapscript, } from './script/tapscript.js';
20
- import { hasBoardingTxExpired, buildOffchainTx, } from './utils/arkTransaction.js';
21
+ import { hasBoardingTxExpired, buildOffchainTx, verifyTapscriptSignatures, } from './utils/arkTransaction.js';
21
22
  import { VtxoTaprootTree, ConditionWitness, getArkPsbtFields, setArkPsbtField, ArkPsbtFieldKey, ArkPsbtFieldKeyType, CosignerPublicKey, VtxoTreeExpiry, } from './utils/unknownFields.js';
22
- import { BIP322 } from './bip322/index.js';
23
+ import { Intent } from './intent/index.js';
23
24
  import { ArkNote } from './arknote/index.js';
24
25
  import { networks } from './networks.js';
25
26
  import { RestIndexerProvider, IndexerTxType, ChainTxType, } from './providers/indexer.js';
@@ -27,9 +28,10 @@ import { P2A } from './utils/anchor.js';
27
28
  import { Unroll } from './wallet/unroll.js';
28
29
  import { WalletRepositoryImpl } from './repositories/walletRepository.js';
29
30
  import { ContractRepositoryImpl } from './repositories/contractRepository.js';
31
+ import { ArkError, maybeArkError } from './providers/errors.js';
30
32
  export {
31
33
  // Wallets
32
- Wallet, SingleKey, OnchainWallet, Ramps,
34
+ Wallet, SingleKey, OnchainWallet, Ramps, VtxoManager,
33
35
  // Providers
34
36
  ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider,
35
37
  // Script-related
@@ -39,20 +41,22 @@ TxType, IndexerTxType, ChainTxType, SettlementEventType,
39
41
  // Service Worker
40
42
  setupServiceWorker, Worker, ServiceWorkerWallet, Request, Response,
41
43
  // Tapscript
42
- decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript,
44
+ decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, TapTreeCoder,
43
45
  // Ark PSBT fields
44
46
  ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness,
45
47
  // Utils
46
- buildOffchainTx, waitForIncomingFunds, hasBoardingTxExpired,
48
+ buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired,
47
49
  // Arknote
48
50
  ArkNote,
49
51
  // Network
50
52
  networks,
51
53
  // Repositories
52
54
  WalletRepositoryImpl, ContractRepositoryImpl,
53
- // BIP322
54
- BIP322,
55
+ // Intent proof
56
+ Intent,
55
57
  // TxTree
56
58
  TxTree,
57
59
  // Anchor
58
- P2A, Unroll, Transaction, };
60
+ P2A, Unroll, Transaction,
61
+ // Errors
62
+ ArkError, maybeArkError, };