@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
@@ -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);
@@ -418,7 +427,7 @@ class Wallet {
418
427
  // TODO persist final virtual tx and checkpoints to repository
419
428
  // sign the checkpoints
420
429
  const finalCheckpoints = await Promise.all(signedCheckpointTxs.map(async (c) => {
421
- const tx = transaction_js_1.Transaction.fromPSBT(base_1.base64.decode(c));
430
+ const tx = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(c));
422
431
  const signedCheckpoint = await this.identity.sign(tx);
423
432
  return base_1.base64.encode(signedCheckpoint.toPSBT());
424
433
  }));
@@ -476,8 +485,8 @@ class Wallet {
476
485
  }
477
486
  catch {
478
487
  // onchain
479
- const addr = (0, payment_js_1.Address)(this.network).decode(output.address);
480
- script = payment_js_1.OutScript.encode(addr);
488
+ const addr = (0, btc_signer_1.Address)(this.network).decode(output.address);
489
+ script = btc_signer_1.OutScript.encode(addr);
481
490
  onchainOutputIndexes.push(index);
482
491
  }
483
492
  outputs.push({
@@ -490,7 +499,7 @@ class Wallet {
490
499
  const signingPublicKeys = [];
491
500
  if (hasOffchainOutputs) {
492
501
  session = this.identity.signerSession();
493
- signingPublicKeys.push(base_1.hex.encode(session.getPublicKey()));
502
+ signingPublicKeys.push(base_1.hex.encode(await session.getPublicKey()));
494
503
  }
495
504
  const [intent, deleteIntent] = await Promise.all([
496
505
  this.makeRegisterIntentSignature(params.inputs, outputs, onchainOutputIndexes, signingPublicKeys),
@@ -529,7 +538,7 @@ class Wallet {
529
538
  if (step !== undefined) {
530
539
  continue;
531
540
  }
532
- const res = await this.handleBatchStartedEvent(event, intentId, this.arkServerPublicKey, this.forfeitOutputScript);
541
+ const res = await this.handleBatchStartedEvent(event, intentId, this.forfeitPubkey, this.forfeitOutputScript);
533
542
  if (!res.skip) {
534
543
  step = event.type;
535
544
  sweepTapTreeRoot = res.sweepTapTreeRoot;
@@ -714,10 +723,10 @@ class Wallet {
714
723
  };
715
724
  return stopFunc;
716
725
  }
717
- async handleBatchStartedEvent(event, intentId, serverPubKey, forfeitOutputScript) {
726
+ async handleBatchStartedEvent(event, intentId, forfeitPubKey, forfeitOutputScript) {
718
727
  const utf8IntentId = new TextEncoder().encode(intentId);
719
728
  const intentIdHash = (0, utils_js_1.sha256)(utf8IntentId);
720
- const intentIdHashStr = base_1.hex.encode(new Uint8Array(intentIdHash));
729
+ const intentIdHashStr = base_1.hex.encode(intentIdHash);
721
730
  let skip = true;
722
731
  // check if our intent ID hash matches any in the event
723
732
  for (const idHash of event.intentIdHashes) {
@@ -737,7 +746,7 @@ class Wallet {
737
746
  value: event.batchExpiry,
738
747
  type: event.batchExpiry >= 512n ? "seconds" : "blocks",
739
748
  },
740
- pubkeys: [serverPubKey],
749
+ pubkeys: [forfeitPubKey],
741
750
  }).script;
742
751
  const sweepTapTreeRoot = (0, payment_js_1.tapLeafHash)(sweepTapscript);
743
752
  return {
@@ -750,7 +759,7 @@ class Wallet {
750
759
  // validates the vtxo tree, creates a signing session and generates the musig2 nonces
751
760
  async handleSettlementSigningEvent(event, sweepTapTreeRoot, session, vtxoGraph) {
752
761
  // validate the unsigned vtxo tree
753
- const commitmentTx = transaction_js_1.Transaction.fromPSBT(base_1.base64.decode(event.unsignedCommitmentTx));
762
+ const commitmentTx = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(event.unsignedCommitmentTx));
754
763
  (0, validation_1.validateVtxoTxGraph)(vtxoGraph, commitmentTx, sweepTapTreeRoot);
755
764
  // TODO check if our registered outputs are in the vtxo tree
756
765
  const sharedOutput = commitmentTx.getOutput(0);
@@ -758,18 +767,21 @@ class Wallet {
758
767
  throw new Error("Shared output not found");
759
768
  }
760
769
  session.init(vtxoGraph, sweepTapTreeRoot, sharedOutput.amount);
761
- await this.arkProvider.submitTreeNonces(event.id, base_1.hex.encode(session.getPublicKey()), session.getNonces());
770
+ const pubkey = base_1.hex.encode(await session.getPublicKey());
771
+ const nonces = await session.getNonces();
772
+ await this.arkProvider.submitTreeNonces(event.id, pubkey, nonces);
762
773
  }
763
774
  async handleSettlementSigningNoncesGeneratedEvent(event, session) {
764
775
  session.setAggregatedNonces(event.treeNonces);
765
- const signatures = session.sign();
766
- await this.arkProvider.submitTreeSignatures(event.id, base_1.hex.encode(session.getPublicKey()), signatures);
776
+ const signatures = await session.sign();
777
+ const pubkey = base_1.hex.encode(await session.getPublicKey());
778
+ await this.arkProvider.submitTreeSignatures(event.id, pubkey, signatures);
767
779
  }
768
780
  async handleSettlementFinalizationEvent(event, inputs, forfeitOutputScript, connectorsGraph) {
769
781
  // the signed forfeits transactions to submit
770
782
  const signedForfeits = [];
771
783
  const vtxos = await this.getVirtualCoins();
772
- let settlementPsbt = transaction_js_1.Transaction.fromPSBT(base_1.base64.decode(event.commitmentTx));
784
+ let settlementPsbt = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(event.commitmentTx));
773
785
  let hasBoardingUtxos = false;
774
786
  let connectorIndex = 0;
775
787
  const connectorsLeaves = connectorsGraph?.leaves() || [];
@@ -811,7 +823,7 @@ class Wallet {
811
823
  throw new Error("not enough connectors received");
812
824
  }
813
825
  const connectorLeaf = connectorsLeaves[connectorIndex];
814
- const connectorTxId = base_1.hex.encode((0, utils_js_1.sha256x2)(connectorLeaf.toBytes(true)).reverse());
826
+ const connectorTxId = connectorLeaf.id;
815
827
  const connectorOutput = connectorLeaf.getOutput(0);
816
828
  if (!connectorOutput) {
817
829
  throw new Error("connector output not found");
@@ -830,7 +842,7 @@ class Wallet {
830
842
  amount: BigInt(vtxo.value),
831
843
  script: base_2.VtxoScript.decode(input.tapTree).pkScript,
832
844
  },
833
- sighashType: transaction_js_1.SigHash.DEFAULT,
845
+ sighashType: btc_signer_1.SigHash.DEFAULT,
834
846
  tapLeafScript: [input.forfeitTapLeafScript],
835
847
  },
836
848
  {
@@ -852,112 +864,69 @@ class Wallet {
852
864
  : undefined);
853
865
  }
854
866
  }
855
- async makeRegisterIntentSignature(bip322Inputs, outputs, onchainOutputsIndexes, cosignerPubKeys) {
867
+ async makeRegisterIntentSignature(coins, outputs, onchainOutputsIndexes, cosignerPubKeys) {
856
868
  const nowSeconds = Math.floor(Date.now() / 1000);
857
- const { inputs, inputTapTrees, finalizer } = this.prepareBIP322Inputs(bip322Inputs);
869
+ const inputs = this.prepareIntentProofInputs(coins);
858
870
  const message = {
859
871
  type: "register",
860
- input_tap_trees: inputTapTrees,
861
872
  onchain_output_indexes: onchainOutputsIndexes,
862
873
  valid_at: nowSeconds,
863
874
  expire_at: nowSeconds + 2 * 60, // valid for 2 minutes
864
875
  cosigners_public_keys: cosignerPubKeys,
865
876
  };
866
877
  const encodedMessage = JSON.stringify(message, null, 0);
867
- const signature = await this.makeBIP322Signature(encodedMessage, inputs, finalizer, outputs);
878
+ const proof = intent_1.Intent.create(encodedMessage, inputs, outputs);
879
+ const signedProof = await this.identity.sign(proof);
868
880
  return {
869
- signature,
881
+ proof: base_1.base64.encode(signedProof.toPSBT()),
870
882
  message: encodedMessage,
871
883
  };
872
884
  }
873
- async makeDeleteIntentSignature(bip322Inputs) {
885
+ async makeDeleteIntentSignature(coins) {
874
886
  const nowSeconds = Math.floor(Date.now() / 1000);
875
- const { inputs, finalizer } = this.prepareBIP322Inputs(bip322Inputs);
887
+ const inputs = this.prepareIntentProofInputs(coins);
876
888
  const message = {
877
889
  type: "delete",
878
890
  expire_at: nowSeconds + 2 * 60, // valid for 2 minutes
879
891
  };
880
892
  const encodedMessage = JSON.stringify(message, null, 0);
881
- const signature = await this.makeBIP322Signature(encodedMessage, inputs, finalizer);
893
+ const proof = intent_1.Intent.create(encodedMessage, inputs, []);
894
+ const signedProof = await this.identity.sign(proof);
882
895
  return {
883
- signature,
896
+ proof: base_1.base64.encode(signedProof.toPSBT()),
884
897
  message: encodedMessage,
885
898
  };
886
899
  }
887
- prepareBIP322Inputs(bip322Inputs) {
900
+ prepareIntentProofInputs(coins) {
888
901
  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);
902
+ for (const input of coins) {
903
+ const vtxoScript = base_2.VtxoScript.decode(input.tapTree);
904
+ const sequence = getSequence(input);
905
+ const unknown = [unknownFields_1.VtxoTaprootTree.encode(input.tapTree)];
906
+ if (input.extraWitness) {
907
+ unknown.push(unknownFields_1.ConditionWitness.encode(input.extraWitness));
908
+ }
894
909
  inputs.push({
895
- txid: base_1.hex.decode(bip322Input.txid),
896
- index: bip322Input.vout,
910
+ txid: base_1.hex.decode(input.txid),
911
+ index: input.vout,
897
912
  witnessUtxo: {
898
- amount: BigInt(bip322Input.value),
913
+ amount: BigInt(input.value),
899
914
  script: vtxoScript.pkScript,
900
915
  },
901
916
  sequence,
902
- tapLeafScript: [bip322Input.intentTapLeafScript],
917
+ tapLeafScript: [input.intentTapLeafScript],
918
+ unknown,
903
919
  });
904
- inputTapTrees.push(base_1.hex.encode(bip322Input.tapTree));
905
- inputExtraWitnesses.push(bip322Input.extraWitness || []);
906
920
  }
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);
921
+ return inputs;
917
922
  }
918
923
  }
919
924
  exports.Wallet = Wallet;
920
925
  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) {
926
+ function getSequence(coin) {
958
927
  let sequence = undefined;
959
928
  try {
960
- const scriptWithLeafVersion = bip322Input.intentTapLeafScript[1];
929
+ const scriptWithLeafVersion = coin.intentTapLeafScript[1];
961
930
  const script = scriptWithLeafVersion.subarray(0, scriptWithLeafVersion.length - 1);
962
931
  const params = tapscript_1.CSVMultisigTapscript.decode(script).params;
963
932
  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,9 +1,12 @@
1
- import { Transaction } from "@scure/btc-signer/transaction.js";
1
+ import { Transaction } from "@scure/btc-signer";
2
2
  import { P2A } from './utils/anchor.js';
3
3
  export function buildForfeitTx(inputs, forfeitPkScript, txLocktime) {
4
4
  const tx = new Transaction({
5
5
  version: 3,
6
6
  lockTime: txLocktime,
7
+ allowUnknownOutputs: true,
8
+ allowUnknown: true,
9
+ allowUnknownInputs: true,
7
10
  });
8
11
  let amount = 0n;
9
12
  for (const input of inputs) {
@@ -1,8 +1,8 @@
1
- import { pubECDSA, pubSchnorr, randomPrivateKeyBytes, sha256, } from "@scure/btc-signer/utils.js";
2
- import { hex } from "@scure/base";
1
+ import { pubECDSA, pubSchnorr, randomPrivateKeyBytes, } from "@scure/btc-signer/utils.js";
3
2
  import { SigHash } from "@scure/btc-signer/transaction.js";
3
+ import { hex } from "@scure/base";
4
4
  import { TreeSignerSession } from '../tree/signingSession.js';
5
- import { schnorr } from "@noble/secp256k1";
5
+ import { schnorr, sign } from "@noble/secp256k1";
6
6
  const ZERO_32 = new Uint8Array(32).fill(0);
7
7
  const ALL_SIGHASH = Object.values(SigHash).filter((x) => typeof x === "number");
8
8
  /**
@@ -79,8 +79,9 @@ export class SingleKey {
79
79
  signerSession() {
80
80
  return TreeSignerSession.random();
81
81
  }
82
- async signMessage(message) {
83
- const msgBytes = new TextEncoder().encode(message);
84
- return schnorr.sign(sha256(msgBytes), this.key);
82
+ async signMessage(message, signatureType = "schnorr") {
83
+ if (signatureType === "ecdsa")
84
+ return sign(message, this.key, { prehash: false });
85
+ return schnorr.sign(message, this.key);
85
86
  }
86
87
  }
package/dist/esm/index.js CHANGED
@@ -8,6 +8,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';
@@ -29,7 +30,7 @@ import { WalletRepositoryImpl } from './repositories/walletRepository.js';
29
30
  import { ContractRepositoryImpl } from './repositories/contractRepository.js';
30
31
  export {
31
32
  // Wallets
32
- Wallet, SingleKey, OnchainWallet, Ramps,
33
+ Wallet, SingleKey, OnchainWallet, Ramps, VtxoManager,
33
34
  // Providers
34
35
  ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider,
35
36
  // Script-related
@@ -43,15 +44,15 @@ decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTa
43
44
  // Ark PSBT fields
44
45
  ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness,
45
46
  // Utils
46
- buildOffchainTx, waitForIncomingFunds, hasBoardingTxExpired,
47
+ buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired,
47
48
  // Arknote
48
49
  ArkNote,
49
50
  // Network
50
51
  networks,
51
52
  // Repositories
52
53
  WalletRepositoryImpl, ContractRepositoryImpl,
53
- // BIP322
54
- BIP322,
54
+ // Intent proof
55
+ Intent,
55
56
  // TxTree
56
57
  TxTree,
57
58
  // Anchor
@@ -1,22 +1,19 @@
1
- import { OP } from "@scure/btc-signer/script.js";
2
- import { Transaction, SigHash } from "@scure/btc-signer/transaction.js";
3
- import { Script } from "@scure/btc-signer/script.js";
4
- import { ErrMissingData, ErrMissingInputs, ErrMissingWitnessUtxo, } from './errors.js';
1
+ import { OP, Transaction, Script, SigHash } from "@scure/btc-signer";
5
2
  import { schnorr } from "@noble/curves/secp256k1.js";
6
- import { base64 } from "@scure/base";
7
3
  /**
8
- * BIP-322 signature implementation for Bitcoin message signing.
4
+ * Intent proof implementation for Bitcoin message signing.
9
5
  *
10
- * BIP-322 defines a standard for signing Bitcoin messages as well as proving
6
+ * Intent proof defines a standard for signing Bitcoin messages as well as proving
11
7
  * ownership of coins. This namespace provides utilities for creating and
12
- * validating BIP-322.
8
+ * validating Intent proof.
13
9
  *
10
+ * it is greatly inspired by BIP322.
14
11
  * @see https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki
15
12
  *
16
13
  * @example
17
14
  * ```typescript
18
- * // Create a BIP-322 proof
19
- * const proof = BIP322.create(
15
+ * // Create a Intent proof
16
+ * const proof = Intent.create(
20
17
  * "Hello Bitcoin!",
21
18
  * [input],
22
19
  * [output]
@@ -25,65 +22,46 @@ import { base64 } from "@scure/base";
25
22
  * // Sign the proof
26
23
  * const signedProof = await identity.sign(proof);
27
24
  *
28
- * // Extract the signature
29
- * const signature = BIP322.signature(signedProof);
30
- * ```
31
25
  */
32
- export var BIP322;
33
- (function (BIP322) {
26
+ export var Intent;
27
+ (function (Intent) {
34
28
  /**
35
- * Creates a new BIP-322 "full" proof of funds unsigned transaction.
29
+ * Creates a new Intent proof unsigned transaction.
36
30
  *
37
31
  * This function constructs a special transaction that can be signed to prove
38
32
  * ownership of VTXOs and UTXOs. The proof includes the message to be
39
33
  * signed and the inputs/outputs that demonstrate ownership.
40
34
  *
41
- * @param message - The BIP-322 message to be signed
35
+ * @param message - The Intent message to be signed
42
36
  * @param inputs - Array of transaction inputs to prove ownership of
43
37
  * @param outputs - Optional array of transaction outputs
44
- * @returns An unsigned BIP-322 proof transaction
38
+ * @returns An unsigned Intent proof transaction
45
39
  */
46
40
  function create(message, inputs, outputs = []) {
47
41
  if (inputs.length == 0)
48
- throw ErrMissingInputs;
42
+ throw new Error("intent proof requires at least one input");
49
43
  if (!validateInputs(inputs))
50
- throw ErrMissingData;
44
+ throw new Error("invalid inputs");
51
45
  if (!validateOutputs(outputs))
52
- throw ErrMissingData;
46
+ throw new Error("invalid outputs");
53
47
  // create the initial transaction to spend
54
48
  const toSpend = craftToSpendTx(message, inputs[0].witnessUtxo.script);
55
49
  // create the transaction to sign
56
50
  return craftToSignTx(toSpend, inputs, outputs);
57
51
  }
58
- BIP322.create = create;
59
- /**
60
- * Finalizes and extracts the FullProof transaction into a BIP-322 signature.
61
- *
62
- * This function takes a signed proof transaction and converts it into a
63
- * base64-encoded signature string. If the proof's inputs have special
64
- * spending conditions, a custom finalizer can be provided.
65
- *
66
- * @param signedProof - The signed BIP-322 proof transaction
67
- * @param finalizer - Optional custom finalizer function
68
- * @returns Base64-encoded BIP-322 signature
69
- */
70
- function signature(signedProof, finalizer = (tx) => tx.finalize()) {
71
- finalizer(signedProof);
72
- return base64.encode(signedProof.extract());
73
- }
74
- BIP322.signature = signature;
75
- })(BIP322 || (BIP322 = {}));
52
+ Intent.create = create;
53
+ })(Intent || (Intent = {}));
76
54
  const OP_RETURN_EMPTY_PKSCRIPT = new Uint8Array([OP.RETURN]);
77
55
  const ZERO_32 = new Uint8Array(32).fill(0);
78
56
  const MAX_INDEX = 0xffffffff;
79
- const TAG_BIP322 = "BIP0322-signed-message";
57
+ const TAG_INTENT_PROOF = "ark-intent-proof-message";
80
58
  function validateInput(input) {
81
59
  if (input.index === undefined)
82
- throw ErrMissingData;
60
+ throw new Error("intent proof input requires index");
83
61
  if (input.txid === undefined)
84
- throw ErrMissingData;
62
+ throw new Error("intent proof input requires txid");
85
63
  if (input.witnessUtxo === undefined)
86
- throw ErrMissingWitnessUtxo;
64
+ throw new Error("intent proof input requires witness utxo");
87
65
  return true;
88
66
  }
89
67
  function validateInputs(inputs) {
@@ -92,9 +70,9 @@ function validateInputs(inputs) {
92
70
  }
93
71
  function validateOutput(output) {
94
72
  if (output.amount === undefined)
95
- throw ErrMissingData;
73
+ throw new Error("intent proof output requires amount");
96
74
  if (output.script === undefined)
97
- throw ErrMissingData;
75
+ throw new Error("intent proof output requires script");
98
76
  return true;
99
77
  }
100
78
  function validateOutputs(outputs) {
@@ -102,7 +80,7 @@ function validateOutputs(outputs) {
102
80
  return true;
103
81
  }
104
82
  // craftToSpendTx creates the initial transaction that will be spent in the proof
105
- export function craftToSpendTx(message, pkScript) {
83
+ function craftToSpendTx(message, pkScript) {
106
84
  const messageHash = hashMessage(message);
107
85
  const tx = new Transaction({
108
86
  version: 0,
@@ -148,11 +126,16 @@ function craftToSignTx(toSpend, inputs, outputs) {
148
126
  sighashType: SigHash.ALL,
149
127
  });
150
128
  // add other inputs
151
- for (const input of inputs) {
129
+ for (const [i, input] of inputs.entries()) {
152
130
  tx.addInput({
153
131
  ...input,
154
132
  sighashType: SigHash.ALL,
155
133
  });
134
+ if (input.unknown?.length) {
135
+ tx.updateInput(i + 1, {
136
+ unknown: input.unknown,
137
+ });
138
+ }
156
139
  }
157
140
  // add the special OP_RETURN output if no outputs are provided
158
141
  if (outputs.length === 0) {
@@ -172,5 +155,5 @@ function craftToSignTx(toSpend, inputs, outputs) {
172
155
  return tx;
173
156
  }
174
157
  function hashMessage(message) {
175
- return schnorr.utils.taggedHash(TAG_BIP322, new TextEncoder().encode(message));
158
+ return schnorr.utils.taggedHash(TAG_INTENT_PROOF, new TextEncoder().encode(message));
176
159
  }