@arkade-os/sdk 0.4.21 → 0.4.23

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 (80) hide show
  1. package/README.md +95 -12
  2. package/dist/cjs/contracts/arkcontract.js +2 -1
  3. package/dist/cjs/contracts/contractWatcher.js +16 -18
  4. package/dist/cjs/identity/descriptor.js +75 -4
  5. package/dist/cjs/identity/hdCapableIdentity.js +2 -0
  6. package/dist/cjs/identity/seedIdentity.js +225 -103
  7. package/dist/cjs/identity/serialize.js +5 -0
  8. package/dist/cjs/identity/staticDescriptorProvider.js +1 -1
  9. package/dist/cjs/index.js +12 -3
  10. package/dist/cjs/providers/electrum.js +285 -79
  11. package/dist/cjs/providers/expoIndexer.js +1 -1
  12. package/dist/cjs/providers/indexer.js +2 -2
  13. package/dist/cjs/providers/onchain.js +9 -3
  14. package/dist/cjs/repositories/migrations/walletRepositoryImpl.js +6 -2
  15. package/dist/cjs/repositories/realm/walletRepository.js +2 -2
  16. package/dist/cjs/repositories/serialization.js +34 -1
  17. package/dist/cjs/repositories/sqlite/walletRepository.js +4 -2
  18. package/dist/cjs/script/address.js +2 -1
  19. package/dist/cjs/utils/transactionHistory.js +4 -4
  20. package/dist/cjs/wallet/asset-manager.js +18 -18
  21. package/dist/cjs/wallet/asset.js +10 -8
  22. package/dist/cjs/wallet/delegator.js +29 -20
  23. package/dist/cjs/wallet/hdDescriptorProvider.js +159 -0
  24. package/dist/cjs/wallet/index.js +5 -1
  25. package/dist/cjs/wallet/onchain.js +2 -1
  26. package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +4 -2
  27. package/dist/cjs/wallet/serviceWorker/wallet.js +5 -4
  28. package/dist/cjs/wallet/validation.js +2 -3
  29. package/dist/cjs/wallet/vtxo-manager.js +7 -5
  30. package/dist/cjs/wallet/wallet.js +13 -14
  31. package/dist/esm/contracts/arkcontract.js +2 -1
  32. package/dist/esm/contracts/contractWatcher.js +14 -16
  33. package/dist/esm/identity/descriptor.js +74 -5
  34. package/dist/esm/identity/hdCapableIdentity.js +1 -0
  35. package/dist/esm/identity/seedIdentity.js +225 -103
  36. package/dist/esm/identity/serialize.js +5 -0
  37. package/dist/esm/identity/staticDescriptorProvider.js +1 -1
  38. package/dist/esm/index.js +7 -4
  39. package/dist/esm/providers/electrum.js +284 -78
  40. package/dist/esm/providers/expoIndexer.js +1 -1
  41. package/dist/esm/providers/indexer.js +2 -2
  42. package/dist/esm/providers/onchain.js +9 -3
  43. package/dist/esm/repositories/migrations/walletRepositoryImpl.js +6 -2
  44. package/dist/esm/repositories/realm/walletRepository.js +3 -3
  45. package/dist/esm/repositories/serialization.js +27 -0
  46. package/dist/esm/repositories/sqlite/walletRepository.js +5 -3
  47. package/dist/esm/script/address.js +2 -1
  48. package/dist/esm/utils/transactionHistory.js +4 -4
  49. package/dist/esm/wallet/asset-manager.js +18 -18
  50. package/dist/esm/wallet/asset.js +10 -8
  51. package/dist/esm/wallet/delegator.js +29 -20
  52. package/dist/esm/wallet/hdDescriptorProvider.js +155 -0
  53. package/dist/esm/wallet/index.js +4 -0
  54. package/dist/esm/wallet/onchain.js +2 -1
  55. package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +4 -2
  56. package/dist/esm/wallet/serviceWorker/wallet.js +5 -4
  57. package/dist/esm/wallet/validation.js +2 -3
  58. package/dist/esm/wallet/vtxo-manager.js +7 -5
  59. package/dist/esm/wallet/wallet.js +12 -14
  60. package/dist/types/contracts/arkcontract.d.ts +1 -1
  61. package/dist/types/contracts/types.d.ts +5 -5
  62. package/dist/types/identity/descriptor.d.ts +26 -0
  63. package/dist/types/identity/descriptorProvider.d.ts +11 -4
  64. package/dist/types/identity/hdCapableIdentity.d.ts +44 -0
  65. package/dist/types/identity/index.d.ts +1 -0
  66. package/dist/types/identity/seedIdentity.d.ts +113 -29
  67. package/dist/types/identity/serialize.d.ts +12 -0
  68. package/dist/types/identity/staticDescriptorProvider.d.ts +1 -1
  69. package/dist/types/index.d.ts +6 -3
  70. package/dist/types/providers/electrum.d.ts +115 -15
  71. package/dist/types/providers/onchain.d.ts +6 -0
  72. package/dist/types/repositories/serialization.d.ts +26 -2
  73. package/dist/types/script/address.d.ts +1 -1
  74. package/dist/types/wallet/delegator.d.ts +8 -3
  75. package/dist/types/wallet/hdDescriptorProvider.d.ts +93 -0
  76. package/dist/types/wallet/index.d.ts +19 -10
  77. package/dist/types/wallet/onchain.d.ts +1 -1
  78. package/dist/types/wallet/serviceWorker/wallet.d.ts +1 -1
  79. package/dist/types/wallet/wallet.d.ts +4 -1
  80. package/package.json +4 -4
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Wallet = exports.ReadonlyWallet = void 0;
3
+ exports.Wallet = exports.ReadonlyWallet = exports.getArkadeServerUrl = void 0;
4
4
  exports.selectVirtualCoins = selectVirtualCoins;
5
5
  exports.waitForIncomingFunds = waitForIncomingFunds;
6
6
  const base_1 = require("@scure/base");
@@ -39,6 +39,8 @@ const contractManager_1 = require("../contracts/contractManager");
39
39
  const handlers_1 = require("../contracts/handlers");
40
40
  const helpers_1 = require("../contracts/handlers/helpers");
41
41
  const syncCursors_1 = require("../utils/syncCursors");
42
+ const getArkadeServerUrl = ({ arkServerUrl, }) => arkServerUrl || _1.DEFAULT_ARKADE_SERVER_URL;
43
+ exports.getArkadeServerUrl = getArkadeServerUrl;
42
44
  // Historical unilateral exit delay for mainnet (~7 days in seconds).
43
45
  // Kept so existing wallets can still discover and spend VTXOs sent to the
44
46
  // legacy address after arkd starts advertising a different delay.
@@ -125,10 +127,7 @@ class ReadonlyWallet {
125
127
  // Use provided arkProvider instance or create a new one from arkServerUrl
126
128
  const arkProvider = config.arkProvider ||
127
129
  (() => {
128
- if (!config.arkServerUrl) {
129
- throw new Error("Either arkProvider or arkServerUrl must be provided");
130
- }
131
- return new ark_1.RestArkProvider(config.arkServerUrl);
130
+ return new ark_1.RestArkProvider((0, exports.getArkadeServerUrl)(config));
132
131
  })();
133
132
  // Extract arkServerUrl from provider if not explicitly provided
134
133
  const arkServerUrl = config.arkServerUrl || arkProvider.serverUrl;
@@ -307,7 +306,7 @@ class ReadonlyWallet {
307
306
  continue;
308
307
  if (vtxo.assets) {
309
308
  for (const a of vtxo.assets) {
310
- const current = assetBalances.get(a.assetId) ?? 0;
309
+ const current = assetBalances.get(a.assetId) ?? 0n;
311
310
  assetBalances.set(a.assetId, current + a.amount);
312
311
  }
313
312
  }
@@ -1129,12 +1128,12 @@ class Wallet extends ReadonlyWallet {
1129
1128
  for (const [, assets] of assetInputs) {
1130
1129
  for (const asset of assets) {
1131
1130
  const existing = allAssets.get(asset.assetId) ?? 0n;
1132
- allAssets.set(asset.assetId, existing + BigInt(asset.amount));
1131
+ allAssets.set(asset.assetId, existing + asset.amount);
1133
1132
  }
1134
1133
  }
1135
1134
  outputAssets = [];
1136
1135
  for (const [assetId, amount] of allAssets) {
1137
- outputAssets.push({ assetId, amount: Number(amount) });
1136
+ outputAssets.push({ assetId, amount });
1138
1137
  }
1139
1138
  }
1140
1139
  const recipients = params.outputs.map((output, i) => ({
@@ -1569,7 +1568,7 @@ class Wallet extends ReadonlyWallet {
1569
1568
  * const txid = await wallet.send({
1570
1569
  * address: 'ark1q...',
1571
1570
  * amount: 1000, // (optional, default to dust) btc amount to send to the output
1572
- * assets: [{ assetId: 'abc123...', amount: 50 }] // (optional) list of assets to send
1571
+ * assets: [{ assetId: 'abc123...', amount: 50n }] // (optional) list of assets to send
1573
1572
  * });
1574
1573
  * ```
1575
1574
  */
@@ -1600,7 +1599,7 @@ class Wallet extends ReadonlyWallet {
1600
1599
  continue;
1601
1600
  }
1602
1601
  for (const receiverAsset of recipient.assets) {
1603
- let amountToSelect = BigInt(receiverAsset.amount);
1602
+ let amountToSelect = receiverAsset.amount;
1604
1603
  // check if existing change covers the needed amount
1605
1604
  const existingChange = assetChanges.get(receiverAsset.assetId) ?? 0n;
1606
1605
  if (existingChange >= amountToSelect) {
@@ -1627,7 +1626,7 @@ class Wallet extends ReadonlyWallet {
1627
1626
  continue;
1628
1627
  }
1629
1628
  const existing = assetChanges.get(a.assetId) ?? 0n;
1630
- assetChanges.set(a.assetId, existing + BigInt(a.amount));
1629
+ assetChanges.set(a.assetId, existing + a.amount);
1631
1630
  }
1632
1631
  }
1633
1632
  }
@@ -1647,7 +1646,7 @@ class Wallet extends ReadonlyWallet {
1647
1646
  if (coin.assets) {
1648
1647
  for (const asset of coin.assets) {
1649
1648
  const existing = assetChanges.get(asset.assetId) ?? 0n;
1650
- assetChanges.set(asset.assetId, existing + BigInt(asset.amount));
1649
+ assetChanges.set(asset.assetId, existing + asset.amount);
1651
1650
  }
1652
1651
  }
1653
1652
  }
@@ -1669,7 +1668,7 @@ class Wallet extends ReadonlyWallet {
1669
1668
  if (coin.assets) {
1670
1669
  for (const asset of coin.assets) {
1671
1670
  const existing = assetChanges.get(asset.assetId) ?? 0n;
1672
- assetChanges.set(asset.assetId, existing + BigInt(asset.amount));
1671
+ assetChanges.set(asset.assetId, existing + asset.amount);
1673
1672
  }
1674
1673
  }
1675
1674
  }
@@ -1684,7 +1683,7 @@ class Wallet extends ReadonlyWallet {
1684
1683
  const changeAssets = [];
1685
1684
  for (const [assetId, amount] of assetChanges) {
1686
1685
  if (amount > 0n) {
1687
- changeAssets.push({ assetId, amount: Number(amount) });
1686
+ changeAssets.push({ assetId, amount });
1688
1687
  }
1689
1688
  }
1690
1689
  changeIndex = outputs.length;
@@ -1,5 +1,6 @@
1
1
  import { hex } from "@scure/base";
2
2
  import { contractHandlers } from './handlers/index.js';
3
+ import { DEFAULT_ARKADE_HRP } from '../wallet/index.js';
3
4
  /**
4
5
  * Prefix for arkcontract strings.
5
6
  */
@@ -115,7 +116,7 @@ export function contractFromArkContract(encoded, options = {}) {
115
116
  * @param options - Additional options
116
117
  * @returns A complete Contract object
117
118
  */
118
- export function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix, options = {}) {
119
+ export function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix = DEFAULT_ARKADE_HRP, options = {}) {
119
120
  const parsed = decodeArkContract(encoded);
120
121
  const handler = contractHandlers.getOrThrow(parsed.type);
121
122
  const params = parsed.data;
@@ -1,3 +1,4 @@
1
+ import { extendVirtualCoinForContract } from '../wallet/utils.js';
1
2
  import { isEventSourceError } from '../providers/utils.js';
2
3
  /**
3
4
  * Watches multiple contracts for virtual output state changes with resilient connection handling.
@@ -550,18 +551,22 @@ export class ContractWatcher {
550
551
  const state = this.contracts.get(contractScript);
551
552
  if (!state)
552
553
  return;
554
+ const extended = [];
555
+ for (const v of vtxos) {
556
+ try {
557
+ const extendedVtxo = extendVirtualCoinForContract(v, state.contract);
558
+ extended.push({ ...extendedVtxo, contractScript });
559
+ }
560
+ catch {
561
+ console.warn("failed to extend vtxo: ", v);
562
+ extended.push({ ...v, contractScript });
563
+ }
564
+ }
553
565
  switch (eventType) {
554
566
  case "vtxo_received":
555
567
  this.eventCallback({
556
568
  type: "vtxo_received",
557
- vtxos: vtxos.map((v) => ({
558
- ...v,
559
- contractScript,
560
- // These fields may not be available from basic VirtualCoin
561
- forfeitTapLeafScript: undefined,
562
- intentTapLeafScript: undefined,
563
- tapTree: undefined,
564
- })),
569
+ vtxos: extended,
565
570
  contractScript,
566
571
  contract: state.contract,
567
572
  timestamp,
@@ -570,14 +575,7 @@ export class ContractWatcher {
570
575
  case "vtxo_spent":
571
576
  this.eventCallback({
572
577
  type: "vtxo_spent",
573
- vtxos: vtxos.map((v) => ({
574
- ...v,
575
- contractScript,
576
- // These fields may not be available from basic VirtualCoin
577
- forfeitTapLeafScript: undefined,
578
- intentTapLeafScript: undefined,
579
- tapTree: undefined,
580
- })),
578
+ vtxos: extended,
581
579
  contractScript,
582
580
  contract: state.contract,
583
581
  timestamp,
@@ -1,7 +1,72 @@
1
- import { expand, networks, } from "@bitcoinerlab/descriptors-scure";
1
+ import { expand, networks } from "@bitcoinerlab/descriptors-scure";
2
2
  import { hex } from "@scure/base";
3
- function inferNetwork(descriptor) {
4
- return descriptor.includes("tpub") ? networks.testnet : networks.bitcoin;
3
+ /**
4
+ * True iff `descriptor` is a Bitcoin mainnet descriptor (xpub-prefixed
5
+ * BIP32 key).
6
+ *
7
+ * Note: testnet, signet, regtest, mutinynet, and other non-mainnet
8
+ * networks all share the same `tpub` BIP32 version bytes — they cannot
9
+ * be distinguished from one another at the descriptor level. Callers
10
+ * that need a `Network` constants object for `expand()` pick
11
+ * `networks.bitcoin` vs `networks.testnet` themselves; callers that
12
+ * need the *actual* network the wallet is on must track that
13
+ * out-of-band.
14
+ */
15
+ export function isMainnetDescriptor(descriptor) {
16
+ return !descriptor.includes("tpub");
17
+ }
18
+ /**
19
+ * Shared "does `candidate` belong to the identity backed by
20
+ * `ourDescriptor`?" predicate.
21
+ *
22
+ * - HD descriptors (expanding to a `bip32` key) match by account xpub
23
+ * on both sides — index-agnostic, so a wildcard template and any
24
+ * concrete index under it all collapse to the same xpub.
25
+ * - Bare `tr(pubkey)` candidates fall back to comparing the candidate
26
+ * pubkey against `ourXOnlyPubkey` (the cached pubkey on the identity
27
+ * side, since pulling it from `ourDescriptor` would require an index
28
+ * substitution the caller already performed).
29
+ */
30
+ export function descriptorIsOurs(candidate, ourDescriptor, ourXOnlyPubkey) {
31
+ if (!isDescriptor(candidate))
32
+ return false;
33
+ try {
34
+ const candidateInfo = expand({
35
+ descriptor: candidate,
36
+ network: isMainnetDescriptor(candidate)
37
+ ? networks.bitcoin
38
+ : networks.testnet,
39
+ }).expansionMap?.["@0"];
40
+ if (!candidateInfo)
41
+ return false;
42
+ if (candidateInfo.bip32) {
43
+ const ourBip32 = expand({
44
+ descriptor: ourDescriptor,
45
+ network: isMainnetDescriptor(ourDescriptor)
46
+ ? networks.bitcoin
47
+ : networks.testnet,
48
+ }).expansionMap?.["@0"]?.bip32;
49
+ if (!ourBip32)
50
+ return false;
51
+ return ourBip32.toBase58() === candidateInfo.bip32.toBase58();
52
+ }
53
+ if (candidateInfo.pubkey) {
54
+ // For tr() the library hands back a 32-byte x-only key, but
55
+ // strip a leading parity byte defensively so a 33-byte
56
+ // compressed key (mismatched length) doesn't silently
57
+ // false-negative against our 32-byte x-only side.
58
+ const candidatePub = candidateInfo.pubkey.length === 33
59
+ ? candidateInfo.pubkey.subarray(1)
60
+ : candidateInfo.pubkey;
61
+ if (candidatePub.length !== ourXOnlyPubkey.length)
62
+ return false;
63
+ return hex.encode(candidatePub) === hex.encode(ourXOnlyPubkey);
64
+ }
65
+ return false;
66
+ }
67
+ catch {
68
+ return false;
69
+ }
5
70
  }
6
71
  /**
7
72
  * Check if a string is a descriptor of the shape `tr(...)`.
@@ -43,7 +108,9 @@ export function extractPubKey(descriptor) {
43
108
  if (!isDescriptor(descriptor)) {
44
109
  return descriptor;
45
110
  }
46
- const network = inferNetwork(descriptor);
111
+ const network = isMainnetDescriptor(descriptor)
112
+ ? networks.bitcoin
113
+ : networks.testnet;
47
114
  const expansion = expand({ descriptor, network });
48
115
  if (!expansion.expansionMap) {
49
116
  throw new Error("Cannot extract pubkey from descriptor: expansion failed.");
@@ -70,7 +137,9 @@ export function parseHDDescriptor(descriptor) {
70
137
  }
71
138
  let expansion;
72
139
  try {
73
- const network = inferNetwork(descriptor);
140
+ const network = isMainnetDescriptor(descriptor)
141
+ ? networks.bitcoin
142
+ : networks.testnet;
74
143
  expansion = expand({ descriptor, network });
75
144
  }
76
145
  catch {
@@ -0,0 +1 @@
1
+ export {};