@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
@@ -11,7 +11,7 @@ import { buildForfeitTx } from '../forfeit.js';
11
11
  import { validateConnectorsTxGraph, validateVtxoTxGraph, } from '../tree/validation.js';
12
12
  import { validateBatchRecipients } from './validation.js';
13
13
  import { isBatchSignable } from '../identity/index.js';
14
- import { isExpired, isRecoverable, isSpendable, isSubdust, TxType, } from './index.js';
14
+ import { DEFAULT_ARKADE_SERVER_URL, isExpired, isRecoverable, isSpendable, isSubdust, TxType, } from './index.js';
15
15
  import { createAssetPacket, selectCoinsWithAsset, selectedCoinsToAssetInputs, } from './asset.js';
16
16
  import { VtxoScript } from '../script/base.js';
17
17
  import { CSVMultisigTapscript } from '../script/tapscript.js';
@@ -34,6 +34,7 @@ import { ContractManager } from '../contracts/contractManager.js';
34
34
  import { contractHandlers } from '../contracts/handlers/index.js';
35
35
  import { timelockToSequence } from '../contracts/handlers/helpers.js';
36
36
  import { clearSyncCursor, updateWalletState } from '../utils/syncCursors.js';
37
+ export const getArkadeServerUrl = ({ arkServerUrl, }) => arkServerUrl || DEFAULT_ARKADE_SERVER_URL;
37
38
  // Historical unilateral exit delay for mainnet (~7 days in seconds).
38
39
  // Kept so existing wallets can still discover and spend VTXOs sent to the
39
40
  // legacy address after arkd starts advertising a different delay.
@@ -120,10 +121,7 @@ export class ReadonlyWallet {
120
121
  // Use provided arkProvider instance or create a new one from arkServerUrl
121
122
  const arkProvider = config.arkProvider ||
122
123
  (() => {
123
- if (!config.arkServerUrl) {
124
- throw new Error("Either arkProvider or arkServerUrl must be provided");
125
- }
126
- return new RestArkProvider(config.arkServerUrl);
124
+ return new RestArkProvider(getArkadeServerUrl(config));
127
125
  })();
128
126
  // Extract arkServerUrl from provider if not explicitly provided
129
127
  const arkServerUrl = config.arkServerUrl || arkProvider.serverUrl;
@@ -302,7 +300,7 @@ export class ReadonlyWallet {
302
300
  continue;
303
301
  if (vtxo.assets) {
304
302
  for (const a of vtxo.assets) {
305
- const current = assetBalances.get(a.assetId) ?? 0;
303
+ const current = assetBalances.get(a.assetId) ?? 0n;
306
304
  assetBalances.set(a.assetId, current + a.amount);
307
305
  }
308
306
  }
@@ -1123,12 +1121,12 @@ export class Wallet extends ReadonlyWallet {
1123
1121
  for (const [, assets] of assetInputs) {
1124
1122
  for (const asset of assets) {
1125
1123
  const existing = allAssets.get(asset.assetId) ?? 0n;
1126
- allAssets.set(asset.assetId, existing + BigInt(asset.amount));
1124
+ allAssets.set(asset.assetId, existing + asset.amount);
1127
1125
  }
1128
1126
  }
1129
1127
  outputAssets = [];
1130
1128
  for (const [assetId, amount] of allAssets) {
1131
- outputAssets.push({ assetId, amount: Number(amount) });
1129
+ outputAssets.push({ assetId, amount });
1132
1130
  }
1133
1131
  }
1134
1132
  const recipients = params.outputs.map((output, i) => ({
@@ -1563,7 +1561,7 @@ export class Wallet extends ReadonlyWallet {
1563
1561
  * const txid = await wallet.send({
1564
1562
  * address: 'ark1q...',
1565
1563
  * amount: 1000, // (optional, default to dust) btc amount to send to the output
1566
- * assets: [{ assetId: 'abc123...', amount: 50 }] // (optional) list of assets to send
1564
+ * assets: [{ assetId: 'abc123...', amount: 50n }] // (optional) list of assets to send
1567
1565
  * });
1568
1566
  * ```
1569
1567
  */
@@ -1594,7 +1592,7 @@ export class Wallet extends ReadonlyWallet {
1594
1592
  continue;
1595
1593
  }
1596
1594
  for (const receiverAsset of recipient.assets) {
1597
- let amountToSelect = BigInt(receiverAsset.amount);
1595
+ let amountToSelect = receiverAsset.amount;
1598
1596
  // check if existing change covers the needed amount
1599
1597
  const existingChange = assetChanges.get(receiverAsset.assetId) ?? 0n;
1600
1598
  if (existingChange >= amountToSelect) {
@@ -1621,7 +1619,7 @@ export class Wallet extends ReadonlyWallet {
1621
1619
  continue;
1622
1620
  }
1623
1621
  const existing = assetChanges.get(a.assetId) ?? 0n;
1624
- assetChanges.set(a.assetId, existing + BigInt(a.amount));
1622
+ assetChanges.set(a.assetId, existing + a.amount);
1625
1623
  }
1626
1624
  }
1627
1625
  }
@@ -1641,7 +1639,7 @@ export class Wallet extends ReadonlyWallet {
1641
1639
  if (coin.assets) {
1642
1640
  for (const asset of coin.assets) {
1643
1641
  const existing = assetChanges.get(asset.assetId) ?? 0n;
1644
- assetChanges.set(asset.assetId, existing + BigInt(asset.amount));
1642
+ assetChanges.set(asset.assetId, existing + asset.amount);
1645
1643
  }
1646
1644
  }
1647
1645
  }
@@ -1663,7 +1661,7 @@ export class Wallet extends ReadonlyWallet {
1663
1661
  if (coin.assets) {
1664
1662
  for (const asset of coin.assets) {
1665
1663
  const existing = assetChanges.get(asset.assetId) ?? 0n;
1666
- assetChanges.set(asset.assetId, existing + BigInt(asset.amount));
1664
+ assetChanges.set(asset.assetId, existing + asset.amount);
1667
1665
  }
1668
1666
  }
1669
1667
  }
@@ -1678,7 +1676,7 @@ export class Wallet extends ReadonlyWallet {
1678
1676
  const changeAssets = [];
1679
1677
  for (const [assetId, amount] of assetChanges) {
1680
1678
  if (amount > 0n) {
1681
- changeAssets.push({ assetId, amount: Number(amount) });
1679
+ changeAssets.push({ assetId, amount });
1682
1680
  }
1683
1681
  }
1684
1682
  changeIndex = outputs.length;
@@ -88,7 +88,7 @@ export declare function contractFromArkContract(encoded: string, options?: {
88
88
  * @param options - Additional options
89
89
  * @returns A complete Contract object
90
90
  */
91
- export declare function contractFromArkContractWithAddress(encoded: string, serverPubKey: Uint8Array, addressPrefix: string, options?: {
91
+ export declare function contractFromArkContractWithAddress(encoded: string, serverPubKey: Uint8Array, addressPrefix?: string, options?: {
92
92
  label?: string;
93
93
  state?: "active" | "inactive";
94
94
  metadata?: Record<string, unknown>;
@@ -1,6 +1,6 @@
1
1
  import { Bytes } from "@scure/btc-signer/utils.js";
2
- import { TapLeafScript, VtxoScript } from "../script/base";
3
- import { VirtualCoin, ExtendedVirtualCoin } from "../wallet";
2
+ import { EncodedVtxoScript, TapLeafScript, VtxoScript } from "../script/base";
3
+ import { VirtualCoin, TapLeaves } from "../wallet";
4
4
  import { ContractFilter } from "../repositories";
5
5
  /**
6
6
  * Contract state indicating whether it should be actively monitored.
@@ -66,10 +66,10 @@ export interface Contract {
66
66
  /**
67
67
  * A virtual output that has been associated with a specific contract.
68
68
  */
69
- export interface ContractVtxo extends ExtendedVirtualCoin {
70
- /** The contract script this virtual output belongs to. */
69
+ export type ContractVtxo = VirtualCoin & Partial<TapLeaves & EncodedVtxoScript> & {
70
+ extraWitness?: Bytes[];
71
71
  contractScript: string;
72
- }
72
+ };
73
73
  /**
74
74
  * Result of path selection, including the tapleaf to use and any extra witness data.
75
75
  */
@@ -1,3 +1,29 @@
1
+ /**
2
+ * True iff `descriptor` is a Bitcoin mainnet descriptor (xpub-prefixed
3
+ * BIP32 key).
4
+ *
5
+ * Note: testnet, signet, regtest, mutinynet, and other non-mainnet
6
+ * networks all share the same `tpub` BIP32 version bytes — they cannot
7
+ * be distinguished from one another at the descriptor level. Callers
8
+ * that need a `Network` constants object for `expand()` pick
9
+ * `networks.bitcoin` vs `networks.testnet` themselves; callers that
10
+ * need the *actual* network the wallet is on must track that
11
+ * out-of-band.
12
+ */
13
+ export declare function isMainnetDescriptor(descriptor: string): boolean;
14
+ /**
15
+ * Shared "does `candidate` belong to the identity backed by
16
+ * `ourDescriptor`?" predicate.
17
+ *
18
+ * - HD descriptors (expanding to a `bip32` key) match by account xpub
19
+ * on both sides — index-agnostic, so a wildcard template and any
20
+ * concrete index under it all collapse to the same xpub.
21
+ * - Bare `tr(pubkey)` candidates fall back to comparing the candidate
22
+ * pubkey against `ourXOnlyPubkey` (the cached pubkey on the identity
23
+ * side, since pulling it from `ourDescriptor` would require an index
24
+ * substitution the caller already performed).
25
+ */
26
+ export declare function descriptorIsOurs(candidate: string, ourDescriptor: string, ourXOnlyPubkey: Uint8Array): boolean;
1
27
  /**
2
28
  * Check if a string is a descriptor of the shape `tr(...)`.
3
29
  *
@@ -13,12 +13,19 @@ export interface DescriptorSigningRequest {
13
13
  *
14
14
  * Implementations include:
15
15
  * - {@link StaticDescriptorProvider}: wraps a legacy {@link Identity} with a single key.
16
- * - HD-wallet provider: signs with keys derived from an xpub-based descriptor
17
- * (planned — tracked separately from this interface).
16
+ * - {@link HDDescriptorProvider}: rotates through HD-derived descriptors.
17
+ *
18
+ * The provider has no read accessor for "current" — it is a pure descriptor
19
+ * allocator. "What addresses am I currently bound to?" is a question the
20
+ * contract repository answers, not the provider.
18
21
  */
19
22
  export interface DescriptorProvider {
20
- /** Returns the current signing descriptor. */
21
- getSigningDescriptor(): string;
23
+ /**
24
+ * Allocate a new signing descriptor. For HD providers each call advances
25
+ * the internal index and returns a fresh descriptor; for single-key
26
+ * providers each call returns the same descriptor.
27
+ */
28
+ getNextSigningDescriptor(): Promise<string>;
22
29
  /** Checks if a descriptor belongs to this provider. */
23
30
  isOurs(descriptor: string): boolean;
24
31
  /** Signs transactions, each with its own descriptor-derived key. */
@@ -0,0 +1,44 @@
1
+ import { Identity, ReadonlyIdentity } from ".";
2
+ import { DescriptorSigningRequest } from "./descriptorProvider";
3
+ import { Transaction } from "../utils/transaction";
4
+ /**
5
+ * Read-side HD capability marker. Exposes the wildcard-suffixed account
6
+ * descriptor *template* and the descriptor-membership predicate, but no
7
+ * signing primitives — suitable for watch-only identities backed by an
8
+ * xpub.
9
+ *
10
+ * Extracted from {@link HDCapableIdentity} so that
11
+ * `ReadonlyDescriptorIdentity` can stand in for an HD wallet's read-only
12
+ * surface (template-aware, derives pubkeys at any index) without having
13
+ * to claim signing capability it cannot honour.
14
+ */
15
+ export interface ReadonlyHDCapableIdentity extends ReadonlyIdentity {
16
+ /**
17
+ * The wildcard-suffixed account descriptor template
18
+ * (e.g. `tr([fp/86'/0'/0']xpub/0/*)`). Consumers materialize a
19
+ * concrete descriptor by replacing the `*` with a derivation index.
20
+ */
21
+ readonly descriptor: string;
22
+ /** True iff `descriptor` derives from this identity's xpub/seed. */
23
+ isOurs(descriptor: string): boolean;
24
+ }
25
+ /**
26
+ * Capability marker for identities that can be rotated through an HD
27
+ * derivation tree AND can sign at each rotated index.
28
+ *
29
+ * Deliberately does NOT extend `DescriptorProvider`: if an HD-capable
30
+ * identity were silently usable as a concrete descriptor source, callers
31
+ * could bypass receive rotation and unknowingly reuse a single address
32
+ * forever. To use this identity as a wallet's descriptor source, wrap
33
+ * it explicitly:
34
+ *
35
+ * - `HDDescriptorProvider` — rotating, recommended for new wallets.
36
+ * - `StaticDescriptorProvider` — pinned to a single key, for legacy or
37
+ * explicitly-non-rotating use cases.
38
+ */
39
+ export interface HDCapableIdentity extends ReadonlyHDCapableIdentity, Identity {
40
+ /** Signs each request with the key derived from its descriptor. */
41
+ signWithDescriptor(requests: DescriptorSigningRequest[]): Promise<Transaction[]>;
42
+ /** Signs a message using the key derived from `descriptor`. */
43
+ signMessageWithDescriptor(descriptor: string, message: Uint8Array, signatureType?: "schnorr" | "ecdsa"): Promise<Uint8Array>;
44
+ }
@@ -52,4 +52,5 @@ export * from "./serialize";
52
52
  export { isDescriptor, normalizeToDescriptor, extractPubKey, parseHDDescriptor, } from "./descriptor";
53
53
  export type { ParsedHDDescriptor } from "./descriptor";
54
54
  export type { DescriptorProvider, DescriptorSigningRequest, } from "./descriptorProvider";
55
+ export type { HDCapableIdentity, ReadonlyHDCapableIdentity, } from "./hdCapableIdentity";
55
56
  export { StaticDescriptorProvider } from "./staticDescriptorProvider";
@@ -1,7 +1,8 @@
1
- import { Identity, ReadonlyIdentity } from ".";
2
1
  import { Transaction } from "../utils/transaction";
3
2
  import { SignerSession } from "../tree/signingSession";
4
3
  import type { SerializedSigningIdentity, SerializedReadonlyIdentity } from "./serialize";
4
+ import { DescriptorSigningRequest } from "./descriptorProvider";
5
+ import { HDCapableIdentity, ReadonlyHDCapableIdentity } from "./hdCapableIdentity";
5
6
  /** Used for default BIP86 derivation with network selection. */
6
7
  export interface NetworkOptions {
7
8
  /**
@@ -11,12 +12,16 @@ export interface NetworkOptions {
11
12
  */
12
13
  isMainnet?: boolean;
13
14
  }
14
- /** Used for custom output descriptor derivation. */
15
+ /** Used for a caller-supplied account-descriptor template. */
15
16
  export interface DescriptorOptions {
16
- /** Custom output descriptor that determines the derivation path. */
17
+ /**
18
+ * Account-descriptor *template* — must end with the BIP-32 wildcard
19
+ * suffix `/*)`. Stored as-is on {@link SeedIdentity.descriptor} and
20
+ * read by HD providers to rotate through derivation indices.
21
+ */
17
22
  descriptor: string;
18
23
  }
19
- /** Either default BIP86 derivation (with optional network selection) or a custom descriptor. */
24
+ /** Either default BIP86 derivation (with optional network selection) or a caller-supplied template. */
20
25
  export type SeedIdentityOptions = NetworkOptions | DescriptorOptions;
21
26
  /** Used for deriving an identity from a BIP39 mnemonic. */
22
27
  export type MnemonicOptions = SeedIdentityOptions & {
@@ -24,44 +29,77 @@ export type MnemonicOptions = SeedIdentityOptions & {
24
29
  passphrase?: string;
25
30
  };
26
31
  /**
27
- * Seed-based identity derived from a raw seed and an output descriptor.
32
+ * Seed-based identity derived from a raw seed and an account descriptor
33
+ * *template*.
28
34
  *
29
35
  * This is the recommended identity type for most applications. It uses
30
- * standard BIP86 (Taproot) derivation by default and stores an output
31
- * descriptor for interoperability with other wallets.
36
+ * standard BIP86 (Taproot) derivation by default; callers that need a
37
+ * different path supply the wildcard template directly.
32
38
  *
33
39
  * Prefer this (or @see MnemonicIdentity) over `SingleKey` for new
34
40
  * integrations — `SingleKey` exists for backward compatibility with
35
41
  * raw nsec-style keys.
36
42
  *
37
- * For descriptor-based signing, wrap with {@link StaticDescriptorProvider}.
43
+ * The identity holds the wildcard *template* (e.g.
44
+ * `tr([fp/86'/0'/0']xpub/0/*)`) on its public {@link descriptor}
45
+ * field. HD rotation reads it directly; consumers that need a
46
+ * concrete descriptor at a specific index materialize it themselves
47
+ * (see `HDDescriptorProvider` in the wallet layer).
48
+ *
49
+ * Exposes seed-level primitives (signing, derivation, the template)
50
+ * but is deliberately NOT a `DescriptorProvider`. Wrap it explicitly
51
+ * to get one:
52
+ * - `HDDescriptorProvider` for rotating receive addresses.
53
+ * - {@link StaticDescriptorProvider} for legacy, single-key behaviour.
54
+ *
55
+ * The split prevents a SeedIdentity from being silently used as a
56
+ * concrete descriptor source, which would defeat HD rotation without
57
+ * any compile-time signal that something was wrong.
38
58
  *
39
59
  * @example
40
60
  * ```typescript
41
61
  * const seed = mnemonicToSeedSync(mnemonic);
42
62
  *
43
- * // Testnet (BIP86 path m/86'/1'/0'/0/0)
63
+ * // Testnet (BIP86 wildcard descriptor m/86'/1'/0'/0/*)
44
64
  * const identity = SeedIdentity.fromSeed(seed, { isMainnet: false });
45
65
  *
46
- * // Mainnet (BIP86 path m/86'/0'/0'/0/0)
66
+ * // Mainnet (BIP86 wildcard descriptor m/86'/0'/0'/0/*)
47
67
  * const identity = SeedIdentity.fromSeed(seed, { isMainnet: true });
48
68
  *
49
- * // Custom descriptor
69
+ * // Caller-supplied wildcard descriptor (must end in `/*)`).
50
70
  * const identity = SeedIdentity.fromSeed(seed, { descriptor });
51
71
  * ```
52
72
  */
53
- export declare class SeedIdentity implements Identity {
73
+ export declare class SeedIdentity implements HDCapableIdentity {
54
74
  private readonly derivedKey;
75
+ /**
76
+ * Wildcard account-descriptor template (e.g.
77
+ * `tr([fp/86'/0'/0']xpub/0/*)`). The canonical thing to pass
78
+ * through the system; consumers materialize a concrete descriptor
79
+ * at a specific index themselves (see `HDDescriptorProvider` in
80
+ * the wallet layer for the rotating-counter use case).
81
+ */
55
82
  readonly descriptor: string;
56
- constructor(seed: Uint8Array, descriptor: string);
83
+ /**
84
+ * Constructs a SeedIdentity from a 64-byte seed and either a
85
+ * caller-supplied wildcard descriptor (`{ descriptor }`) or the
86
+ * default BIP86 path at the requested network (`{ isMainnet }`).
87
+ * Prefer the {@link fromSeed} factory for symmetry with
88
+ * {@link MnemonicIdentity.fromMnemonic}.
89
+ *
90
+ * Throws on a non-wildcard descriptor, an xpub mismatch with the
91
+ * seed, or a missing derivation path.
92
+ */
93
+ constructor(seed: Uint8Array, opts?: SeedIdentityOptions);
57
94
  /**
58
95
  * Creates a SeedIdentity from a raw 64-byte seed.
59
96
  *
60
97
  * Pass `{ isMainnet }` for default BIP86 derivation, or
61
- * `{ descriptor }` for a custom derivation path.
98
+ * `{ descriptor }` for a caller-supplied account-descriptor
99
+ * template (the option's value must end with `/*)`).
62
100
  *
63
101
  * @param seed - 64-byte seed (typically from mnemonicToSeedSync)
64
- * @param opts - Network selection or custom descriptor.
102
+ * @param opts - Network selection or descriptor template.
65
103
  */
66
104
  static fromSeed(seed: Uint8Array, opts?: SeedIdentityOptions): SeedIdentity;
67
105
  xOnlyPublicKey(): Promise<Uint8Array>;
@@ -70,9 +108,29 @@ export declare class SeedIdentity implements Identity {
70
108
  signMessage(message: Uint8Array, signatureType?: "schnorr" | "ecdsa"): Promise<Uint8Array>;
71
109
  signerSession(): SignerSession;
72
110
  /**
73
- * Converts to a watch-only identity that cannot sign.
111
+ * Converts to a watch-only identity that cannot sign. Carries the
112
+ * template forward, so the readonly side stays HD-capable (can
113
+ * derive descriptors at any index without seed access).
74
114
  */
75
115
  toReadonly(): Promise<ReadonlyDescriptorIdentity>;
116
+ /**
117
+ * Returns true when `descriptor` is derived from this identity's seed.
118
+ * HD descriptors match by account xpub; bare `tr(pubkey)` descriptors
119
+ * match by raw pubkey. See {@link descriptorIsOurs}.
120
+ */
121
+ isOurs(descriptor: string): boolean;
122
+ /**
123
+ * Signs each request with the key derived from its descriptor.
124
+ * Each descriptor must share this identity's seed ({@link isOurs}).
125
+ */
126
+ signWithDescriptor(requests: DescriptorSigningRequest[]): Promise<Transaction[]>;
127
+ /**
128
+ * Signs a message with the key derived from `descriptor`.
129
+ */
130
+ signMessageWithDescriptor(descriptor: string, message: Uint8Array, signatureType?: "schnorr" | "ecdsa"): Promise<Uint8Array>;
131
+ private derivePrivateKeyForDescriptor;
132
+ private signTxWithKey;
133
+ private signMessageWithKey;
76
134
  }
77
135
  /**
78
136
  * Mnemonic-based identity derived from a BIP39 phrase.
@@ -96,40 +154,66 @@ export declare class MnemonicIdentity extends SeedIdentity {
96
154
  * Creates a MnemonicIdentity from a BIP39 mnemonic phrase.
97
155
  *
98
156
  * Pass `{ isMainnet }` for default BIP86 derivation, or
99
- * `{ descriptor }` for a custom derivation path.
157
+ * `{ descriptor }` for a caller-supplied account-descriptor
158
+ * template (the option's value must end with `/*)`).
100
159
  *
101
160
  * @param phrase - BIP39 mnemonic phrase (12 or 24 words)
102
- * @param opts - Network selection or custom descriptor, plus optional passphrase
161
+ * @param opts - Network selection or descriptor template, plus optional passphrase
103
162
  */
104
163
  static fromMnemonic(phrase: string, opts?: MnemonicOptions): MnemonicIdentity;
105
164
  }
106
165
  /**
107
- * Watch-only identity from an output descriptor.
166
+ * Watch-only HD identity from a descriptor *template*.
108
167
  *
109
168
  * Can derive public keys but cannot sign transactions. Use this for
110
- * watch-only wallets or when sharing identity information without
111
- * exposing private keys.
169
+ * watch-only wallets given just an xpub-based template, the readonly
170
+ * side still rotates through HD indices.
171
+ *
172
+ * Constructed from a wildcard template (e.g.
173
+ * `tr([fp/86'/0'/0']xpub.../0/*)`); the {@link descriptor} field
174
+ * holds it for HD providers to consume.
112
175
  *
113
176
  * @example
114
177
  * ```typescript
115
- * const descriptor = "tr([fingerprint/86'/0'/0']xpub.../0/0)";
116
- * const readonly = ReadonlyDescriptorIdentity.fromDescriptor(descriptor);
117
- * const pubKey = await readonly.xOnlyPublicKey();
178
+ * const ro = ReadonlyDescriptorIdentity.fromDescriptor(
179
+ * "tr([fp/86'/0'/0']xpub.../0/*)"
180
+ * );
181
+ * ro.descriptor;
182
+ * // => "tr([fp/86'/0'/0']xpub.../0/*)" — the template
118
183
  * ```
119
184
  */
120
- export declare class ReadonlyDescriptorIdentity implements ReadonlyIdentity {
185
+ export declare class ReadonlyDescriptorIdentity implements ReadonlyHDCapableIdentity {
186
+ /**
187
+ * Index-0 expansion of {@link descriptor}. Both the x-only pubkey
188
+ * (taproot, returned by the library as 32 bytes) and the compressed
189
+ * pubkey (derived through the bip32 node when needed) are read off
190
+ * this on demand — no separate caches.
191
+ */
192
+ private readonly indexZero;
193
+ /**
194
+ * Wildcard account-descriptor template (e.g.
195
+ * `tr([fp/86'/0'/0']xpub/0/*)`). HD rotation consumers materialize
196
+ * a concrete descriptor at a specific index themselves.
197
+ */
121
198
  readonly descriptor: string;
122
- private readonly xOnlyPubKey;
123
- private readonly compressedPubKey;
124
199
  private constructor();
125
200
  /**
126
- * Creates a ReadonlyDescriptorIdentity from an output descriptor.
201
+ * Creates a ReadonlyDescriptorIdentity from an account-descriptor
202
+ * *template* (must end with the BIP-32 wildcard suffix `/*)`).
127
203
  *
128
- * @param descriptor - Taproot descriptor: tr([fingerprint/path']xpub.../child/path)
204
+ * @param descriptor - Wildcard-suffixed Taproot template
205
+ * (`tr([fp/path']xpub.../child/*)`).
129
206
  */
130
207
  static fromDescriptor(descriptor: string): ReadonlyDescriptorIdentity;
131
208
  xOnlyPublicKey(): Promise<Uint8Array>;
132
209
  compressedPublicKey(): Promise<Uint8Array>;
210
+ /**
211
+ * Returns true when `descriptor` derives from this identity's xpub.
212
+ * HD descriptors match by account xpub; bare `tr(pubkey)` descriptors
213
+ * fall back to comparing against the index-0 x-only pubkey. See
214
+ * {@link descriptorIsOurs}.
215
+ */
216
+ isOurs(descriptor: string): boolean;
133
217
  }
134
218
  /**
135
219
  * Serialize a seed-backed signing identity into a
@@ -4,6 +4,11 @@ import type { Identity, ReadonlyIdentity } from ".";
4
4
  * service-worker boundary. All variants are structured-clone safe
5
5
  * (plain strings only — no functions or prototypes).
6
6
  *
7
+ * `descriptor` carries the wildcard *template* (e.g.
8
+ * `tr([fp/86'/0'/0']xpub.../0/*)`), not a concrete index — the
9
+ * receiving factories require a template, and storing it directly
10
+ * means nothing here has to convert concrete → template on rehydrate.
11
+ *
7
12
  * Adding a new variant is a source change in every worker build; keep
8
13
  * old variants around until all deployed workers handle them.
9
14
  */
@@ -23,6 +28,8 @@ export type SerializedSigningIdentity = {
23
28
  /**
24
29
  * Tagged envelope for a readonly identity transported across the
25
30
  * service-worker boundary. All variants are structured-clone safe.
31
+ * `descriptor` is the wildcard template (see
32
+ * {@link SerializedSigningIdentity}).
26
33
  */
27
34
  export type SerializedReadonlyIdentity = {
28
35
  type: "readonly-single-key";
@@ -57,6 +64,11 @@ export declare function serializeReadonlyIdentity(identity: ReadonlyIdentity): P
57
64
  * The return type is the union of signing and readonly; use
58
65
  * {@link isSigningSerialized} on the envelope before hydration if the caller
59
66
  * needs to know which side it ends up on.
67
+ *
68
+ * Envelopes store the wildcard template directly (see
69
+ * `serializeSeedOwnedSigningIdentity` / `serializeSeedOwnedReadonlyIdentity`),
70
+ * so the `descriptor` field is passed straight through to the
71
+ * template-only factories.
60
72
  */
61
73
  export declare function hydrateIdentity(s: SerializedIdentity): Identity | ReadonlyIdentity;
62
74
  /**
@@ -11,7 +11,7 @@ export declare class StaticDescriptorProvider implements DescriptorProvider {
11
11
  private readonly pubKeyHex;
12
12
  constructor(identity: Identity, pubKeyHex: string);
13
13
  static create(identity: Identity): Promise<StaticDescriptorProvider>;
14
- getSigningDescriptor(): string;
14
+ getNextSigningDescriptor(): Promise<string>;
15
15
  isOurs(descriptor: string): boolean;
16
16
  signWithDescriptor(requests: DescriptorSigningRequest[]): Promise<Transaction[]>;
17
17
  signMessageWithDescriptor(descriptor: string, message: Uint8Array, type?: "schnorr" | "ecdsa"): Promise<Uint8Array>;
@@ -15,6 +15,7 @@ import { Wallet, ReadonlyWallet, waitForIncomingFunds, IncomingFunds } from "./w
15
15
  import { TxTree, TxTreeNode } from "./tree/txTree";
16
16
  import { SignerSession, TreeNonces, TreePartialSigs } from "./tree/signingSession";
17
17
  import { Ramps } from "./wallet/ramps";
18
+ import { HDDescriptorProvider } from "./wallet/hdDescriptorProvider";
18
19
  import { isVtxoExpiringSoon, VtxoManager } from "./wallet/vtxo-manager";
19
20
  import type { IVtxoManager, SettlementConfig } from "./wallet/vtxo-manager";
20
21
  import { ServiceWorkerWallet, ServiceWorkerReadonlyWallet, DEFAULT_MESSAGE_TIMEOUTS } from "./wallet/serviceWorker/wallet";
@@ -22,7 +23,7 @@ import type { MessageTimeouts } from "./wallet/serviceWorker/wallet";
22
23
  import { OnchainWallet } from "./wallet/onchain";
23
24
  import { setupServiceWorker } from "./worker/browser/utils";
24
25
  import { ESPLORA_URL, EsploraProvider, OnchainProvider, ExplorerTransaction } from "./providers/onchain";
25
- import { ElectrumOnchainProvider, WsElectrumChainSource } from "./providers/electrum";
26
+ import { ELECTRUM_TCP_HOST, ELECTRUM_WS_URL, ElectrumOnchainProvider, WsElectrumChainSource } from "./providers/electrum";
26
27
  import type { TransactionHistory as ElectrumTransactionHistory, BlockHeader as ElectrumBlockHeader, Unspent as ElectrumUnspent } from "./providers/electrum";
27
28
  import { RestArkProvider, ArkProvider, SettlementEvent, SettlementEventType, ArkInfo, SignedIntent, Output, TxNotification, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, FeeInfo } from "./providers/ark";
28
29
  import { DelegatorProvider, DelegateInfo, DelegateOptions, RestDelegatorProvider } from "./providers/delegator";
@@ -37,6 +38,7 @@ import { RestIndexerProvider, IndexerProvider, IndexerTxType, ChainTxType, PageR
37
38
  import { Nonces } from "./musig2/nonces";
38
39
  import { PartialSig } from "./musig2/sign";
39
40
  import { AnchorBumper, P2A } from "./utils/anchor";
41
+ import { TxWeightEstimator, type VSize } from "./utils/txSizeEstimator";
40
42
  import { Unroll } from "./wallet/unroll";
41
43
  import { ArkError, maybeArkError } from "./providers/errors";
42
44
  import { validateVtxoTxGraph, validateConnectorsTxGraph } from "./tree/validation";
@@ -49,8 +51,9 @@ export * as asset from "./extension/asset";
49
51
  import { ContractManager, ContractWatcher, contractHandlers, DefaultContractHandler, DelegateContractHandler, VHTLCContractHandler, encodeArkContract, decodeArkContract, contractFromArkContract, contractFromArkContractWithAddress, isArkContract } from "./contracts";
50
52
  import type { Contract, ContractVtxo, ContractState, ContractEvent, ContractEventCallback, ContractBalance, ContractWithVtxos, ContractHandler, PathSelection, PathContext, ContractManagerConfig, CreateContractParams, ContractWatcherConfig, ParsedArkContract, DefaultContractParams, DelegateContractParams, VHTLCContractParams } from "./contracts";
51
53
  import { IContractManager } from "./contracts/contractManager";
54
+ import { timelockToSequence, sequenceToTimelock } from "./contracts/handlers/helpers";
52
55
  import { closeDatabase, openDatabase } from "./repositories/indexedDB/manager";
53
56
  import { WalletMessageHandler, WalletNotInitializedError, ReadonlyWalletError, DelegatorNotConfiguredError } from "./wallet/serviceWorker/wallet-message-handler";
54
57
  import { MESSAGE_BUS_NOT_INITIALIZED, MessageBusNotInitializedError, ServiceWorkerTimeoutError } from "./worker/errors";
55
- export { Wallet, ReadonlyWallet, SingleKey, ReadonlySingleKey, SeedIdentity, MnemonicIdentity, ReadonlyDescriptorIdentity, isBatchSignable, OnchainWallet, Ramps, VtxoManager, DelegatorManagerImpl, RestDelegatorProvider, ESPLORA_URL, EsploraProvider, ElectrumOnchainProvider, WsElectrumChainSource, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, DelegateVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, MessageBus, WalletMessageHandler, WalletNotInitializedError, ReadonlyWalletError, DelegatorNotConfiguredError, MESSAGE_BUS_NOT_INITIALIZED, MessageBusNotInitializedError, ServiceWorkerTimeoutError, ServiceWorkerWallet, ServiceWorkerReadonlyWallet, DEFAULT_MESSAGE_TIMEOUTS, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, TapTreeCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired, combineTapscriptSigs, isVtxoExpiringSoon, isValidArkAddress, ArkNote, networks, closeDatabase, openDatabase, IndexedDBWalletRepository, IndexedDBContractRepository, InMemoryWalletRepository, InMemoryContractRepository, MIGRATION_KEY, migrateWalletRepository, requiresMigration, getMigrationStatus, rollbackMigration, WalletRepositoryImpl, ContractRepositoryImpl, Intent, BIP322, TxTree, P2A, Unroll, Transaction, ArkError, maybeArkError, Batch, validateVtxoTxGraph, validateConnectorsTxGraph, buildForfeitTx, isRecoverable, isSpendable, isSubdust, isExpired, getSequence, ContractManager, ContractWatcher, contractHandlers, DefaultContractHandler, DelegateContractHandler, VHTLCContractHandler, encodeArkContract, decodeArkContract, contractFromArkContract, contractFromArkContractWithAddress, isArkContract, };
56
- export type { Identity, ReadonlyIdentity, BatchSignableIdentity, SignRequest, IWallet, IReadonlyWallet, BaseWalletConfig, WalletConfig, ReadonlyWalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, SeedIdentityOptions, MnemonicOptions, NetworkOptions, DescriptorOptions, IndexerProvider, PageResponse, BatchInfo, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, FeeInfo, ArkInfo, SignedIntent, Output, TxNotification, ExplorerTransaction, ElectrumTransactionHistory, ElectrumBlockHeader, ElectrumUnspent, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, SettlementConfig, IVtxoManager, Asset, Recipient, IssuanceParams, IssuanceResult, ReissuanceParams, BurnParams, AssetDetails, AssetMetadata, KnownMetadata, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, StorageConfig, Contract, ContractVtxo, ContractState, ContractEvent, ContractEventCallback, ContractBalance, ContractWithVtxos, ContractHandler, IContractManager, PathSelection, PathContext, ContractManagerConfig, CreateContractParams, ContractWatcherConfig, ParsedArkContract, DefaultContractParams, DelegateContractParams, VHTLCContractParams, MessageHandler, RequestEnvelope, ResponseEnvelope, MessageTimeouts, IDelegatorManager, DelegatorProvider, DelegateInfo, DelegateOptions, WalletRepository, ContractRepository, MigrationStatus, };
58
+ export { Wallet, ReadonlyWallet, SingleKey, ReadonlySingleKey, SeedIdentity, MnemonicIdentity, ReadonlyDescriptorIdentity, isBatchSignable, OnchainWallet, Ramps, VtxoManager, HDDescriptorProvider, DelegatorManagerImpl, RestDelegatorProvider, ESPLORA_URL, EsploraProvider, ELECTRUM_WS_URL, ELECTRUM_TCP_HOST, ElectrumOnchainProvider, WsElectrumChainSource, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, DelegateVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, MessageBus, WalletMessageHandler, WalletNotInitializedError, ReadonlyWalletError, DelegatorNotConfiguredError, MESSAGE_BUS_NOT_INITIALIZED, MessageBusNotInitializedError, ServiceWorkerTimeoutError, ServiceWorkerWallet, ServiceWorkerReadonlyWallet, DEFAULT_MESSAGE_TIMEOUTS, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, TapTreeCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired, combineTapscriptSigs, isVtxoExpiringSoon, isValidArkAddress, ArkNote, networks, closeDatabase, openDatabase, IndexedDBWalletRepository, IndexedDBContractRepository, InMemoryWalletRepository, InMemoryContractRepository, MIGRATION_KEY, migrateWalletRepository, requiresMigration, getMigrationStatus, rollbackMigration, WalletRepositoryImpl, ContractRepositoryImpl, Intent, BIP322, TxTree, P2A, Unroll, Transaction, TxWeightEstimator, timelockToSequence, sequenceToTimelock, ArkError, maybeArkError, Batch, validateVtxoTxGraph, validateConnectorsTxGraph, buildForfeitTx, isRecoverable, isSpendable, isSubdust, isExpired, getSequence, ContractManager, ContractWatcher, contractHandlers, DefaultContractHandler, DelegateContractHandler, VHTLCContractHandler, encodeArkContract, decodeArkContract, contractFromArkContract, contractFromArkContractWithAddress, isArkContract, };
59
+ export type { Identity, ReadonlyIdentity, BatchSignableIdentity, SignRequest, IWallet, IReadonlyWallet, BaseWalletConfig, WalletConfig, ReadonlyWalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, SeedIdentityOptions, MnemonicOptions, NetworkOptions, DescriptorOptions, IndexerProvider, PageResponse, BatchInfo, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, FeeInfo, ArkInfo, SignedIntent, Output, TxNotification, ExplorerTransaction, ElectrumTransactionHistory, ElectrumBlockHeader, ElectrumUnspent, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, SettlementConfig, IVtxoManager, Asset, Recipient, IssuanceParams, IssuanceResult, ReissuanceParams, BurnParams, AssetDetails, AssetMetadata, KnownMetadata, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, VSize, StorageConfig, Contract, ContractVtxo, ContractState, ContractEvent, ContractEventCallback, ContractBalance, ContractWithVtxos, ContractHandler, IContractManager, PathSelection, PathContext, ContractManagerConfig, CreateContractParams, ContractWatcherConfig, ParsedArkContract, DefaultContractParams, DelegateContractParams, VHTLCContractParams, MessageHandler, RequestEnvelope, ResponseEnvelope, MessageTimeouts, IDelegatorManager, DelegatorProvider, DelegateInfo, DelegateOptions, WalletRepository, ContractRepository, MigrationStatus, };