@arkade-os/sdk 0.4.33 → 0.4.35

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 (84) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/expo.cjs +5 -5
  3. package/dist/adapters/expo.d.cts +2 -2
  4. package/dist/adapters/expo.d.ts +2 -2
  5. package/dist/adapters/expo.js +3 -3
  6. package/dist/adapters/indexedDB.cjs +5 -5
  7. package/dist/adapters/indexedDB.js +4 -4
  8. package/dist/{ark-DEsDMYGv.d.cts → ark-D6sau_6-.d.cts} +522 -9
  9. package/dist/{ark-DEsDMYGv.d.ts → ark-D6sau_6-.d.ts} +522 -9
  10. package/dist/{asyncStorageTaskQueue-D8T1VXEx.d.cts → asyncStorageTaskQueue-CpC027t_.d.cts} +2 -2
  11. package/dist/{asyncStorageTaskQueue-CMrTYlKG.d.ts → asyncStorageTaskQueue-GT8fmPUG.d.ts} +2 -2
  12. package/dist/{chunk-E22HEKLN.js → chunk-3JR77WQ4.js} +140 -42
  13. package/dist/chunk-3JR77WQ4.js.map +1 -0
  14. package/dist/{chunk-WMIPYZSB.cjs → chunk-CMPJR3HS.cjs} +42 -9
  15. package/dist/chunk-CMPJR3HS.cjs.map +1 -0
  16. package/dist/{chunk-AOJUURHM.js → chunk-CUSABEUQ.js} +141 -37
  17. package/dist/chunk-CUSABEUQ.js.map +1 -0
  18. package/dist/{chunk-HAVA4XB7.cjs → chunk-FM7T7JVL.cjs} +7 -7
  19. package/dist/{chunk-HAVA4XB7.cjs.map → chunk-FM7T7JVL.cjs.map} +1 -1
  20. package/dist/{chunk-GYSK5R57.cjs → chunk-GUTKJMSF.cjs} +164 -59
  21. package/dist/chunk-GUTKJMSF.cjs.map +1 -0
  22. package/dist/{chunk-7K3ROJF6.cjs → chunk-H2LX2KKY.cjs} +2161 -466
  23. package/dist/chunk-H2LX2KKY.cjs.map +1 -0
  24. package/dist/{chunk-DSS2GQUG.js → chunk-NOR7XOKN.js} +2021 -331
  25. package/dist/chunk-NOR7XOKN.js.map +1 -0
  26. package/dist/{chunk-BU3BU6XK.js → chunk-OURFR4UR.js} +3 -3
  27. package/dist/{chunk-BU3BU6XK.js.map → chunk-OURFR4UR.js.map} +1 -1
  28. package/dist/{chunk-TU3LVAPX.js → chunk-OUVTG72A.js} +43 -11
  29. package/dist/chunk-OUVTG72A.js.map +1 -0
  30. package/dist/{chunk-5CCRRL5S.cjs → chunk-VYS3KGRI.cjs} +19 -13
  31. package/dist/chunk-VYS3KGRI.cjs.map +1 -0
  32. package/dist/{chunk-SPDNHPM4.cjs → chunk-X2EQLK4O.cjs} +149 -46
  33. package/dist/chunk-X2EQLK4O.cjs.map +1 -0
  34. package/dist/{chunk-L6ZETTX3.js → chunk-XQS2HW4Q.js} +11 -5
  35. package/dist/chunk-XQS2HW4Q.js.map +1 -0
  36. package/dist/contracts/handlers/index.cjs +7 -7
  37. package/dist/contracts/handlers/index.d.cts +3 -3
  38. package/dist/contracts/handlers/index.d.ts +3 -3
  39. package/dist/contracts/handlers/index.js +2 -2
  40. package/dist/{delegate-BJeBNP5a.d.cts → delegate-C-L6gSZx.d.cts} +1 -1
  41. package/dist/{delegate-EXN2mfkb.d.ts → delegate-De5__fpZ.d.ts} +1 -1
  42. package/dist/{index-BG2ooYKO.d.ts → index-BETdjE_o.d.ts} +22 -16
  43. package/dist/{index-DHjEeHEp.d.cts → index-jwQfHP6D.d.cts} +22 -16
  44. package/dist/index.cjs +158 -130
  45. package/dist/index.d.cts +125 -16
  46. package/dist/index.d.ts +125 -16
  47. package/dist/index.js +4 -4
  48. package/dist/repositories/realm/index.cjs +14 -14
  49. package/dist/repositories/realm/index.cjs.map +1 -1
  50. package/dist/repositories/realm/index.d.cts +2 -2
  51. package/dist/repositories/realm/index.d.ts +2 -2
  52. package/dist/repositories/realm/index.js +5 -5
  53. package/dist/repositories/realm/index.js.map +1 -1
  54. package/dist/repositories/sqlite/index.cjs +13 -13
  55. package/dist/repositories/sqlite/index.d.cts +1 -1
  56. package/dist/repositories/sqlite/index.d.ts +1 -1
  57. package/dist/repositories/sqlite/index.js +4 -4
  58. package/dist/{taskRunner-pIGyarFG.d.cts → taskRunner-DCyp6Gea.d.cts} +2 -2
  59. package/dist/{taskRunner-B7lBU45X.d.ts → taskRunner-DnxtObeq.d.ts} +2 -2
  60. package/dist/wallet/expo/background.cjs +14 -14
  61. package/dist/wallet/expo/background.d.cts +3 -3
  62. package/dist/wallet/expo/background.d.ts +3 -3
  63. package/dist/wallet/expo/background.js +6 -6
  64. package/dist/wallet/expo/index.cjs +13 -13
  65. package/dist/wallet/expo/index.d.cts +5 -5
  66. package/dist/wallet/expo/index.d.ts +5 -5
  67. package/dist/wallet/expo/index.js +5 -5
  68. package/dist/{wallet-D4Dll5Gu.d.cts → wallet-BWHbd5b1.d.cts} +388 -10
  69. package/dist/{wallet-C4L_X0i6.d.ts → wallet-Bth5uucA.d.ts} +388 -10
  70. package/dist/worker/expo/index.cjs +9 -9
  71. package/dist/worker/expo/index.d.cts +4 -4
  72. package/dist/worker/expo/index.d.ts +4 -4
  73. package/dist/worker/expo/index.js +5 -5
  74. package/package.json +5 -5
  75. package/dist/chunk-5CCRRL5S.cjs.map +0 -1
  76. package/dist/chunk-7K3ROJF6.cjs.map +0 -1
  77. package/dist/chunk-AOJUURHM.js.map +0 -1
  78. package/dist/chunk-DSS2GQUG.js.map +0 -1
  79. package/dist/chunk-E22HEKLN.js.map +0 -1
  80. package/dist/chunk-GYSK5R57.cjs.map +0 -1
  81. package/dist/chunk-L6ZETTX3.js.map +0 -1
  82. package/dist/chunk-SPDNHPM4.cjs.map +0 -1
  83. package/dist/chunk-TU3LVAPX.js.map +0 -1
  84. package/dist/chunk-WMIPYZSB.cjs.map +0 -1
@@ -1,7 +1,8 @@
1
+ import { Transaction } from '@scure/btc-signer';
1
2
  import { Bytes } from '@scure/btc-signer/utils.js';
2
- import { B as BatchStartedEvent, v as TreeSigningStartedEvent, w as TxTree, x as TreeNoncesEvent, y as BatchFinalizationEvent, z as BatchFinalizedEvent, D as BatchFailedEvent, F as TreeTxEvent, H as TreeSignatureEvent, h as SettlementEvent, b as WalletConfig, W as WalletRepository, C as ContractRepository, J as DescriptorProvider, e as IContractManager, K as IReadonlyWallet, L as ReadonlyIdentity, N as Network, O as OnchainProvider, n as IndexerProvider, M as DelegateProvider, P as ReadonlyWalletConfig, o as RelativeTimelock, Q as IReadonlyAssetManager, m as ArkProvider, U as NetworkName, X as ArkInfo, Y as ArkAddress, c as WalletBalance, G as GetVtxosFilter, E as ExtendedVirtualCoin, A as ArkTransaction, d as ExtendedCoin, Z as Coin, _ as ContractManager, I as IWallet, $ as CSVMultisigTapscript, a as Identity, a0 as SettlementConfig, i as IAssetManager, a1 as VtxoManager, f as IDelegateManager, S as SendBitcoinParams, g as SettleParams, R as Recipient, a2 as SignerSession, a3 as SignedIntent, a4 as Intent } from './ark-DEsDMYGv.cjs';
3
+ import { B as BatchStartedEvent, v as TreeSigningStartedEvent, w as TxTree, x as TreeNoncesEvent, y as BatchFinalizationEvent, z as BatchFinalizedEvent, D as BatchFailedEvent, F as TreeTxEvent, H as TreeSignatureEvent, h as SettlementEvent, b as WalletConfig, W as WalletRepository, C as ContractRepository, J as DescriptorProvider, e as IContractManager, K as IReadonlyWallet, L as ReadonlyIdentity, N as Network, O as OnchainProvider, n as IndexerProvider, M as DelegateProvider, P as ReadonlyWalletConfig, o as RelativeTimelock, Q as IReadonlyAssetManager, m as ArkProvider, U as NetworkName, X as ArkInfo, Y as ArkAddress, c as WalletBalance, G as GetVtxosFilter, E as ExtendedVirtualCoin, A as ArkTransaction, d as ExtendedCoin, Z as Coin, _ as ContractManager, I as IWallet, a as Identity, $ as CSVMultisigTapscript, a0 as SettlementConfig, i as IAssetManager, a1 as VtxoManager, f as IDelegateManager, S as SendBitcoinParams, g as SettleParams, R as Recipient, a2 as SignerSession, a3 as SignedIntent, a4 as Intent } from './ark-D6sau_6-.cjs';
3
4
  import { TransactionOutput } from '@scure/btc-signer/psbt.js';
4
- import { D as DefaultVtxo, a as DelegateVtxo } from './delegate-BJeBNP5a.cjs';
5
+ import { D as DefaultVtxo, a as DelegateVtxo } from './delegate-C-L6gSZx.cjs';
5
6
 
6
7
  /**
7
8
  * Batch namespace provides utilities for joining and processing batch session.
@@ -129,6 +130,17 @@ interface ReceiveRotatorBootOpts {
129
130
  * accidentally picking up a delegate contract or vice versa.
130
131
  */
131
132
  expectedContractType?: "default" | "delegate";
133
+ /**
134
+ * The wallet's baseline (index-0) receive pubkey — the x-only key the
135
+ * initial offchain tapscript is built from. Used by {@link
136
+ * WalletReceiveRotator.defaultBoot} as the no-tagged-row fallback:
137
+ * because boarding shares the single HD index stream, the raw watermark
138
+ * may have been advanced by a boarding-only allocation, so the boot must
139
+ * NOT derive the receive pubkey from it. A wallet with no tagged receive
140
+ * row has never rotated L2, so its correct current receive *is* the
141
+ * baseline index-0 key (plan §6-II.5).
142
+ */
143
+ baselineReceivePubKey?: Uint8Array;
132
144
  /**
133
145
  * Logger to receive rotation-failure + backoff diagnostics. Defaults
134
146
  * to `console` when omitted. Any object implementing
@@ -336,6 +348,15 @@ declare class WalletReceiveRotator {
336
348
  * needs to call this directly.
337
349
  */
338
350
  drain(): Promise<void>;
351
+ /**
352
+ * Run `fn` on the rotator's serialization chain, so it cannot interleave
353
+ * with a receive `rotate()`. Used by {@link Wallet.rotateServerSigner} to
354
+ * serialize server-signer rotation against HD receive rotation: both
355
+ * rebuild and swap `offchainTapscript`, so running them concurrently could
356
+ * tear the wallet's visible receive state. The chain keeps advancing even
357
+ * if `fn` rejects (its own caller still sees the rejection).
358
+ */
359
+ runExclusive<T>(fn: () => Promise<T>): Promise<T>;
339
360
  /**
340
361
  * Tear down the subscription first so no late `vtxo_received` event
341
362
  * can queue work on a disposing wallet, then drain any in-flight
@@ -373,13 +394,29 @@ type IncomingFunds = {
373
394
  spentVtxos: ExtendedVirtualCoin[];
374
395
  };
375
396
 
397
+ /**
398
+ * Boarding UTXOs grouped by the boarding address they sit on, carrying that
399
+ * address's signer association explicitly. Returned by
400
+ * {@link ReadonlyWallet.getBoardingUtxosForSigners} because a flat
401
+ * {@link ExtendedCoin} cannot carry the signer: it retains only the encoded
402
+ * leaves/tapTree the spend needs, not the owning `DefaultVtxo.Script` (and so
403
+ * not its `serverPubKey` or CSV delay). The deprecated-signer boarding
404
+ * classification reads both back from this group (Section 7).
405
+ */
406
+ interface BoardingUtxoGroup {
407
+ /** Tapscript of the boarding address the coins sit on. */
408
+ tapscript: DefaultVtxo.Script;
409
+ /** Server key of that address, normalized x-only hex. */
410
+ serverPubKey: string;
411
+ /** CSV exit timelock decoded from THIS tapscript's exit leaf. */
412
+ csvTimelock: RelativeTimelock;
413
+ coins: ExtendedCoin[];
414
+ }
376
415
  declare class ReadonlyWallet implements IReadonlyWallet {
377
416
  readonly identity: ReadonlyIdentity;
378
417
  readonly network: Network;
379
418
  readonly onchainProvider: OnchainProvider;
380
419
  readonly indexerProvider: IndexerProvider;
381
- readonly arkServerPublicKey: Bytes;
382
- readonly boardingTapscript: DefaultVtxo.Script;
383
420
  readonly dustAmount: bigint;
384
421
  readonly walletRepository: WalletRepository;
385
422
  readonly contractRepository: ContractRepository;
@@ -388,7 +425,6 @@ declare class ReadonlyWallet implements IReadonlyWallet {
388
425
  private _contractManagerInitializing?;
389
426
  protected readonly watcherConfig?: ReadonlyWalletConfig["watcherConfig"];
390
427
  private readonly _assetManager;
391
- private _syncVtxosInflight?;
392
428
  readonly walletContractTimelocks: RelativeTimelock[];
393
429
  protected _pendingSpendOutpoints: Set<string>;
394
430
  get assetManager(): IReadonlyAssetManager;
@@ -399,13 +435,105 @@ declare class ReadonlyWallet implements IReadonlyWallet {
399
435
  * {@link WalletReceiveRotator.rotate} is the sole intended caller of.
400
436
  */
401
437
  protected _offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script;
438
+ /**
439
+ * Backing field for the current boarding tapscript (the QR / onboarding
440
+ * target). Read via the public `boardingTapscript` getter; written only
441
+ * by {@link Wallet.setBoardingTapscriptForRotation}, the sanctioned
442
+ * boarding-rotation write path (analogue of `_offchainTapscript`). It is
443
+ * a *current value*, not a fixed setup constant, because per-derivation
444
+ * boarding rotation (plan §6-II) swaps it when a fresh boarding address
445
+ * is explicitly allocated. Static / `auto` wallets never rotate it, so
446
+ * it stays the index-0 baseline for their lifetime.
447
+ */
448
+ protected _boardingTapscript: DefaultVtxo.Script;
449
+ /**
450
+ * Backing field for the active server signer (x-only, 32 bytes). Read via
451
+ * the public {@link arkServerPublicKey} getter; written only by
452
+ * {@link Wallet.setArkServerPublicKeyForRotation}, the sanctioned
453
+ * server-signer rotation write path (analogue of `_offchainTapscript`). It
454
+ * is a *current value*, not a fixed constructor constant, because
455
+ * mid-session server-signer rotation (plan §4) swaps it when arkd rotates
456
+ * its active signer. Wallets that never span a rotation keep their
457
+ * construction-time snapshot for their lifetime.
458
+ */
459
+ protected _arkServerPublicKey: Bytes;
402
460
  protected constructor(identity: ReadonlyIdentity, network: Network, onchainProvider: OnchainProvider, indexerProvider: IndexerProvider, arkServerPublicKey: Bytes, offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script, boardingTapscript: DefaultVtxo.Script, dustAmount: bigint, walletRepository: WalletRepository, contractRepository: ContractRepository, delegateProvider?: DelegateProvider | undefined, watcherConfig?: ReadonlyWalletConfig["watcherConfig"], walletContractTimelocks?: RelativeTimelock[]);
461
+ /**
462
+ * x-only hex of the operator's deprecated signer keys (from
463
+ * `ArkInfo.deprecatedSigners`), cached for the OFFLINE read/watch paths.
464
+ * The boarding watch/history surfaces ({@link getBoardingAddresses},
465
+ * {@link getBoardingTxs}) fan out over {current} ∪ this set so a deposit at
466
+ * a boarding address minted under a now-rotated operator signer keeps being
467
+ * watched. Refreshed from the server-info snapshot at construction (via the
468
+ * create() factories) and on a detected signer change. Deliberately NOT
469
+ * consulted by the spend path — {@link getBoardingUtxos} stays
470
+ * current-signer-only (a deprecated-signer input in a plain settle() is
471
+ * rejected; old-signer recovery goes through the migration API).
472
+ */
473
+ protected _deprecatedSigners: Map<string, bigint>;
474
+ /**
475
+ * Refresh the cached deprecated-signer set from a fresh server-info
476
+ * snapshot. Called by the create() factories at construction and by the
477
+ * server-info-change handler mid-session. Lenient: a malformed deprecated
478
+ * entry is skipped, never fatal to wallet creation.
479
+ */
480
+ refreshDeprecatedSigners(info: {
481
+ deprecatedSigners?: readonly {
482
+ pubkey?: string;
483
+ cutoffDate?: bigint;
484
+ }[];
485
+ }): void;
486
+ /**
487
+ * The signer set the boarding WATCH/HISTORY paths fan out over: the wallet's
488
+ * current signer plus every cached deprecated signer. Distinct from the
489
+ * spend path, which is current-signer-only.
490
+ */
491
+ protected watchedBoardingSigners(): Set<string>;
403
492
  /**
404
493
  * Currently-active receive tapscript. Read-only from the outside;
405
494
  * mutated only via {@link Wallet.setOffchainTapscriptForRotation}
406
495
  * by {@link WalletReceiveRotator.rotate}.
407
496
  */
408
497
  get offchainTapscript(): DefaultVtxo.Script | DelegateVtxo.Script;
498
+ /**
499
+ * The wallet's current active server signer (x-only, 32 bytes). Read-only
500
+ * from the outside; mutated only via
501
+ * {@link Wallet.setArkServerPublicKeyForRotation} during mid-session
502
+ * server-signer rotation (plan §4). Single-valued for wallets that never
503
+ * span a rotation.
504
+ */
505
+ get arkServerPublicKey(): Bytes;
506
+ /**
507
+ * The wallet's current boarding tapscript (the on-chain onboarding
508
+ * target). Read-only from the outside; mutated only via
509
+ * {@link Wallet.setBoardingTapscriptForRotation} when a fresh boarding
510
+ * address is explicitly allocated. Single-valued for static / `auto`
511
+ * wallets.
512
+ */
513
+ get boardingTapscript(): DefaultVtxo.Script;
514
+ /**
515
+ * Listeners fired after the boarding tapscript rotates to a fresh index
516
+ * (see {@link Wallet.setBoardingTapscriptForRotation}). A live
517
+ * {@link notifyIncomingFunds} onchain watcher registers one so it can
518
+ * re-subscribe to include the newly allocated boarding address within the
519
+ * same session — without it, a deposit to the fresh address wouldn't fire
520
+ * a notification until the watcher's next re-init. Always empty for
521
+ * readonly / static / `auto` wallets, which never rotate boarding.
522
+ */
523
+ private readonly _boardingRotationListeners;
524
+ /**
525
+ * Register a listener invoked synchronously after each boarding rotation.
526
+ * Returns an unsubscribe function. Protected: only internal subscribers
527
+ * (the incoming-funds watcher) participate.
528
+ */
529
+ protected onBoardingRotation(listener: () => void): () => void;
530
+ /**
531
+ * Notify boarding-rotation listeners. Called by the boarding-rotation
532
+ * write path ({@link Wallet.setBoardingTapscriptForRotation}) once the new
533
+ * tapscript is in place. A throwing listener is isolated so it can neither
534
+ * break the rotation nor starve sibling listeners.
535
+ */
536
+ protected notifyBoardingRotation(): void;
409
537
  /**
410
538
  * Protected helper to set up shared wallet configuration.
411
539
  * Extracts common logic used by both ReadonlyWallet.create() and Wallet.create().
@@ -455,6 +583,15 @@ declare class ReadonlyWallet implements IReadonlyWallet {
455
583
  * @param filter - Optional flags controlling whether recoverable or unrolled VTXOs are included
456
584
  */
457
585
  getVtxos(filter?: GetVtxosFilter): Promise<ExtendedVirtualCoin[]>;
586
+ /**
587
+ * Outpoints of VTXOs whose deprecated signer is past its cutoff (EXPIRED) and
588
+ * which have not yet been swept — unspendable until they recover. Offline:
589
+ * classifies the repo's contracts against the cached signer set (active +
590
+ * {@link _deprecatedSigners}, cutoffs included). Empty fast-path when no
591
+ * signer is deprecated. Consumed by {@link getBalance} (the `pendingRecovery`
592
+ * bucket) and the send coin-selection path so neither counts nor spends them.
593
+ */
594
+ pendingRecoveryOutpoints(): Promise<Set<string>>;
458
595
  /**
459
596
  * Return wallet transaction history derived from Arkade state and boarding transactions.
460
597
  */
@@ -465,19 +602,83 @@ declare class ReadonlyWallet implements IReadonlyWallet {
465
602
  */
466
603
  clearSyncCursor(): Promise<void>;
467
604
  /**
468
- * Build a transaction history view for the wallet's boarding address.
605
+ * The on-chain (P2TR) addresses of every boarding tapscript this wallet
606
+ * uses — the current address plus any historical rotated boarding
607
+ * addresses. The aggregating boarding readers (history, notifications) fan
608
+ * out over this set so deposits at previous boarding addresses are still
609
+ * surfaced (plan §6-IV); {@link getBoardingAddress} stays single-valued.
610
+ */
611
+ getBoardingAddresses(): Promise<string[]>;
612
+ /**
613
+ * Build a transaction history view across the wallet's boarding addresses
614
+ * (current + historical rotated; plan §6-IV.1).
469
615
  */
470
616
  getBoardingTxs(): Promise<{
471
617
  boardingTxs: ArkTransaction[];
472
618
  commitmentsToIgnore: Set<string>;
473
619
  }>;
474
620
  /**
475
- * Fetch and cache onchain inputs (UTXOs) received at the boarding address.
621
+ * The set of boarding tapscripts whose on-chain UTXOs belong to this
622
+ * wallet — the current display tapscript plus every historical boarding
623
+ * address it has used. Under per-derivation rotation (plan §6-II) a wallet
624
+ * can hold unspent boarding UTXOs at several addresses at once, so fund
625
+ * discovery / spending must enumerate them all, not just the current one
626
+ * (plan §6-III.1). Deduplicated by scriptPubKey.
627
+ *
628
+ * Always includes the index-0 baseline (identity x-only key), which covers
629
+ * the degenerate equal-delay case where the index-0 boarding row is
630
+ * coalesced onto a `default` row and so isn't a `boarding`-typed contract.
631
+ *
632
+ * @param allowedSigners - Optional set of x-only-hex server keys whose
633
+ * persisted boarding rows are included. Defaults to `{current x-only
634
+ * signer}`, preserving today's current-signer-only discovery (and the
635
+ * foreign-ASP guard). The deprecated-signer migration path widens this to
636
+ * reach old-signer boarding addresses. The index-0 baseline and the
637
+ * current display tapscript are always included regardless of the set.
638
+ */
639
+ protected getBoardingTapscripts(allowedSigners?: Set<string>): Promise<DefaultVtxo.Script[]>;
640
+ /**
641
+ * Fetch and cache onchain inputs (UTXOs) received at the boarding addresses
642
+ * of the given signer set, grouped per boarding address so the caller keeps
643
+ * the address↔signer association that {@link ExtendedCoin} cannot carry
644
+ * (it retains only the encoded leaves/tapTree the spend needs, not the
645
+ * `DefaultVtxo.Script` and its `serverPubKey`/CSV delay).
646
+ *
647
+ * Per group it does exactly what {@link getBoardingUtxos} does per tapscript:
648
+ * `getCoins` → {@link extendCoinWithTapscript} → `saveUtxos`. Offline-first:
649
+ * it does not call `getInfo()`; the caller supplies the allowed signer set,
650
+ * so the only network calls are the per-address `getCoins`.
651
+ *
652
+ * @param allowedSigners - x-only-hex server keys whose boarding addresses to
653
+ * fetch (passed through to {@link getBoardingTapscripts}).
654
+ */
655
+ getBoardingUtxosForSigners(allowedSigners: Set<string>): Promise<BoardingUtxoGroup[]>;
656
+ /**
657
+ * Fetch and cache onchain inputs (UTXOs) received at the wallet's boarding
658
+ * addresses — the current address plus any historical rotated boarding
659
+ * addresses that still hold unspent UTXOs (plan §6-III.1). Each UTXO is
660
+ * annotated with the tapscript of the address it actually sits on, so the
661
+ * spending path forfeits / exits it with the correct per-index leaves.
662
+ *
663
+ * Current-signer only: a flatten of {@link getBoardingUtxosForSigners} over
664
+ * the wallet's current signer, so the two paths cannot drift. Old-signer
665
+ * boarding recovery goes through the deprecated-signer migration API
666
+ * instead (it would otherwise pull EXPIRED-signer inputs into a plain
667
+ * `settle()` that the server must reject).
476
668
  */
477
669
  getBoardingUtxos(): Promise<ExtendedCoin[]>;
478
670
  /**
479
671
  * Subscribe to onchain and offchain notifications for newly received funds.
480
672
  *
673
+ * The onchain watcher tracks the full boarding-address set (current +
674
+ * historical rotated). When boarding rotates *after* subscribing — e.g.
675
+ * rotate-on-board allocates a fresh address via
676
+ * {@link getNewBoardingAddress} — the watcher automatically re-subscribes
677
+ * to widen its set, so a deposit to the new address fires a notification
678
+ * within the same session (no watcher re-init required). The re-subscribe
679
+ * is driven by {@link onBoardingRotation}; static / `auto` / readonly
680
+ * wallets never rotate boarding, so it never fires for them.
681
+ *
481
682
  * @param eventCallback - Callback invoked when matching funds are detected
482
683
  * @returns A function that stops the subscriptions
483
684
  */
@@ -563,7 +764,6 @@ declare class ReadonlyWallet implements IReadonlyWallet {
563
764
  */
564
765
  declare class Wallet extends ReadonlyWallet implements IWallet {
565
766
  readonly arkProvider: ArkProvider;
566
- readonly serverUnrollScript: CSVMultisigTapscript.Type;
567
767
  readonly forfeitOutputScript: Bytes;
568
768
  readonly forfeitPubkey: Bytes;
569
769
  static MIN_FEE_RATE: number;
@@ -581,6 +781,29 @@ declare class Wallet extends ReadonlyWallet implements IWallet {
581
781
  * the contract manager is up first.
582
782
  */
583
783
  private _receiveRotator?;
784
+ /**
785
+ * Unsubscribe handle for the arkProvider's `onServerInfoChanged` stream
786
+ * (mid-session signer-rotation detection). Torn down in {@link dispose}.
787
+ */
788
+ private _serverInfoUnsub?;
789
+ /**
790
+ * Tail of the serialized {@link handleServerInfoChanged} chain. Each
791
+ * `onServerInfoChanged` event chains onto it so handlers run one at a time,
792
+ * and {@link dispose} awaits it so an in-flight re-derive/rotation settles
793
+ * before the contract manager is torn down underneath it.
794
+ */
795
+ private _serverInfoInFlight;
796
+ /**
797
+ * React to a mid-session server-info change (driven by the arkProvider's
798
+ * `DIGEST_MISMATCH` detection). First refresh the cached deprecated-signer
799
+ * set so the boarding WATCH path immediately widens to the just-deprecated
800
+ * signer, then — only if the active signer actually changed — rotate the
801
+ * wallet onto it via {@link rotateServerSigner} (re-deriving the offchain +
802
+ * boarding display tapscripts and registering the current-signer rows).
803
+ * Old-signer rows stay active, so existing funds remain watched. Failures
804
+ * are logged, never thrown back into the provider's emit loop.
805
+ */
806
+ private handleServerInfoChanged;
584
807
  private _receiveRotatorInstalled;
585
808
  /**
586
809
  * Descriptor-aware signer used by {@link _signerRouter} to sign
@@ -598,6 +821,101 @@ declare class Wallet extends ReadonlyWallet implements IWallet {
598
821
  * `offchainTapscript` as read-only.
599
822
  */
600
823
  setOffchainTapscriptForRotation(tapscript: DefaultVtxo.Script | DelegateVtxo.Script): void;
824
+ /**
825
+ * @internal Sole write path for `boardingTapscript` after construction.
826
+ * Called by {@link Wallet.getNewBoardingAddress} once the rotated
827
+ * boarding contract has been persisted. External code must treat
828
+ * `boardingTapscript` as read-only.
829
+ */
830
+ setBoardingTapscriptForRotation(tapscript: DefaultVtxo.Script): void;
831
+ /**
832
+ * @internal Sole write path for `arkServerPublicKey` after construction.
833
+ * Called by {@link Wallet.rotateServerSigner} once the rotated offchain and
834
+ * boarding contract rows have been persisted. External code must treat
835
+ * `arkServerPublicKey` as read-only.
836
+ */
837
+ setArkServerPublicKeyForRotation(serverPubKey: Bytes): void;
838
+ /**
839
+ * Output script for checkpoint transactions, decoded from the server's
840
+ * `checkpointTapscript`. Server-controlled state: pinned at construction
841
+ * and re-sourced from a fresh `ArkInfo` on server-signer rotation. Read it
842
+ * through {@link serverUnrollScript}; write it only through
843
+ * {@link setServerUnrollScriptForRotation}.
844
+ */
845
+ protected _serverUnrollScript: CSVMultisigTapscript.Type;
846
+ get serverUnrollScript(): CSVMultisigTapscript.Type;
847
+ /**
848
+ * @internal Sole write path for `serverUnrollScript` after construction.
849
+ * Called by {@link Wallet._doRotateServerSigner} with the checkpoint script
850
+ * sourced from the fresh `ArkInfo` that triggered the rotation, so the send
851
+ * path builds checkpoints against the new server epoch. External code must
852
+ * treat `serverUnrollScript` as read-only.
853
+ */
854
+ setServerUnrollScriptForRotation(script: CSVMultisigTapscript.Type): void;
855
+ /**
856
+ * Serializes {@link rotateServerSigner} for static / non-HD wallets (which
857
+ * have no {@link WalletReceiveRotator} chain to ride). Coalesces concurrent
858
+ * migration passes so two callers cannot both rebuild and swap the
859
+ * tapscripts. HD wallets serialize on the rotator's chain instead, via
860
+ * {@link WalletReceiveRotator.runExclusive}.
861
+ */
862
+ private _serverRotationChain;
863
+ /**
864
+ * Allocate and return a *fresh* on-chain boarding address, rotating the
865
+ * wallet's current boarding tapscript to a new HD index.
866
+ *
867
+ * This is the explicit boarding allocator — the analogue of dotnet's
868
+ * `GetNextContract(NextContractPurpose.Boarding)`. Unlike
869
+ * {@link getBoardingAddress} (a stable read of the current display
870
+ * address that never burns an index), each call here:
871
+ *
872
+ * - allocates the next index from the shared HD stream (so boarding and
873
+ * L2 receive interleave on one monotonic index);
874
+ * - builds the boarding tapscript at that index with the boarding-exit
875
+ * CSV;
876
+ * - persists an `active` `boarding` contract tagged
877
+ * {@link WALLET_RECEIVE_SOURCE} (with its `signingDescriptor`) so the
878
+ * ContractWatcher monitors it, boot can restore it as the current
879
+ * boarding address, and descriptor-aware signing can recover the
880
+ * per-index key;
881
+ * - swaps the wallet's current `boardingTapscript`.
882
+ *
883
+ * Gated by `walletMode`: a static / `auto` wallet has no descriptor
884
+ * provider and keeps a single index-0 boarding address for its lifetime,
885
+ * so this returns the existing {@link getBoardingAddress} unchanged
886
+ * (no rotation, no index burned).
887
+ */
888
+ getNewBoardingAddress(): Promise<string>;
889
+ /**
890
+ * Mid-session server-signer rotation (plan §4). When arkd rotates its
891
+ * active signer mid-session — the case the long-lived service worker and
892
+ * Expo background processes that own automatic migration must handle — a
893
+ * wallet constructed before the rotation keeps deriving old-signer receive
894
+ * addresses. Building a migration output to such an address would produce a
895
+ * VTXO the server must reject, so the wallet must first re-derive its own
896
+ * receive state under the new active signer.
897
+ *
898
+ * Follows the {@link WalletReceiveRotator.rotate} write-path pattern with
899
+ * the server key swapped instead of the user key: build the new offchain
900
+ * and boarding tapscripts locally (preserving every other option),
901
+ * register the matching `default`/`delegate` and `boarding` contract rows
902
+ * through {@link ContractManager.createContract}, and only then commit the
903
+ * new tapscripts and server key to the wallet's visible state. The signing
904
+ * metadata of the current receive/boarding rows is carried onto the new
905
+ * rows so a rotated (descriptor-backed) receive pubkey can still sign.
906
+ *
907
+ * The old-signer contract rows are intentionally left `active` and watched
908
+ * — they are exactly the deprecated-signer contracts the migration pass
909
+ * drains. Idempotent: a no-op when the wallet already tracks `xonly`.
910
+ *
911
+ * Serialized against HD receive rotation so the two paths (both of which
912
+ * rebuild and swap `offchainTapscript`) cannot interleave.
913
+ *
914
+ * @internal Invoked by the {@link VtxoManager} migration pass; not part of
915
+ * the stable public API.
916
+ */
917
+ rotateServerSigner(newServerPubKey: Bytes, checkpointTapscript: string): Promise<void>;
918
+ private _doRotateServerSigner;
601
919
  /**
602
920
  * Async mutex that serializes all operations submitting VTXOs to the Arkade
603
921
  * server (`settle`, `send`, `sendBitcoin`). This prevents VtxoManager's
@@ -706,6 +1024,30 @@ declare class Wallet extends ReadonlyWallet implements IWallet {
706
1024
  */
707
1025
  settle(params?: SettleParams, eventCallback?: (event: SettlementEvent) => void): Promise<string>;
708
1026
  private _settleImpl;
1027
+ /**
1028
+ * Rotate the boarding address after a board (rotate-on-board trigger).
1029
+ *
1030
+ * Mirrors {@link WalletReceiveRotator}'s L2 rotation, but driven by a
1031
+ * board instead of a `vtxo_received` event: when a settle consumes at
1032
+ * least one boarding (on-chain) UTXO, the current boarding address has
1033
+ * served its purpose, so we allocate a fresh one via
1034
+ * {@link getNewBoardingAddress}. A settle that consumed only VTXOs (a
1035
+ * renewal / offboard) is not a board and leaves the boarding address
1036
+ * untouched.
1037
+ *
1038
+ * Boarding inputs are the non-VTXO coins (no `virtualStatus`), the same
1039
+ * discriminator {@link handleSettlementFinalizationEvent} uses; the
1040
+ * `typeof` guard skips arknote string inputs before the `in` test.
1041
+ *
1042
+ * No-ops for static / `auto` wallets (no descriptor provider — boarding
1043
+ * stays on its fixed index-0 address). Best-effort and non-fatal: the
1044
+ * settle has already committed and its txid must be returned, so a
1045
+ * rotation failure is logged and swallowed rather than thrown. Funds at
1046
+ * the retired boarding address remain discoverable — the old `boarding`
1047
+ * contract stays active and {@link getBoardingUtxos} fans out over the
1048
+ * full historical boarding set.
1049
+ */
1050
+ private maybeRotateBoardingAfterBoard;
709
1051
  private handleSettlementFinalizationEvent;
710
1052
  /**
711
1053
  * Create a batch event handler for settlement flows.
@@ -723,6 +1065,16 @@ declare class Wallet extends ReadonlyWallet implements IWallet {
723
1065
  * historical silent-skip behaviour for cosigner/connector inputs.
724
1066
  */
725
1067
  private inputSigningJobsFromWitnessUtxos;
1068
+ /**
1069
+ * @internal Sign an on-chain boarding exit / sweep transaction, routing
1070
+ * each input to the correct key by its `witnessUtxo.script`: the identity
1071
+ * for index-0 / static boarding, the per-index descriptor for a rotated
1072
+ * boarding UTXO (plan §6-III.3). Used by
1073
+ * {@link VtxoManager.sweepExpiredBoardingUtxos}; without it, the
1074
+ * unilateral exit of a rotated boarding UTXO would be signed with the
1075
+ * wrong (index-0) key and rejected.
1076
+ */
1077
+ signOnchainBoardingTx(tx: Transaction): Promise<Transaction>;
726
1078
  safeRegisterIntent(intent: SignedIntent<Intent.RegisterMessage>, inputs: ExtendedCoin[]): Promise<string>;
727
1079
  makeRegisterIntentSignature(coins: ExtendedCoin[], outputs: TransactionOutput[], onchainOutputsIndexes: number[], cosignerPubKeys: string[], validAt?: number): Promise<SignedIntent<Intent.RegisterMessage>>;
728
1080
  makeDeleteIntentSignature(coins: ExtendedCoin[]): Promise<SignedIntent<Intent.DeleteMessage>>;
@@ -756,12 +1108,38 @@ declare class Wallet extends ReadonlyWallet implements IWallet {
756
1108
  */
757
1109
  send(...args: [Recipient, ...Recipient[]]): Promise<string>;
758
1110
  private _sendImpl;
1111
+ /**
1112
+ * Shared tail of every Ark-transaction spend path (`send`, selected-VTXO
1113
+ * `sendBitcoin`, and {@link sendSelectedVtxosToSelf}): hide the inputs from
1114
+ * concurrent `getVtxos()`, build+submit the offchain tx, persist the spent
1115
+ * inputs and any wallet-owned (change / self) output, then release the
1116
+ * pending-spend hold. Callers own coin selection, output construction, and
1117
+ * the synchronous epoch snapshot; this owns the submit/persist sequence.
1118
+ */
1119
+ private _submitOffchainSpend;
1120
+ /**
1121
+ * @internal Migration primitive (deprecated-signer plan, step 1). Spend an
1122
+ * explicit set of the wallet's own deprecated-signer VTXOs into a single
1123
+ * full-value output on the wallet's *active* signer, through the Ark send
1124
+ * path (not `settle`) so arkd builds checkpoints against the active server
1125
+ * epoch. Consumed in-process by {@link VtxoManager}'s migration pass; not
1126
+ * part of the public `IWallet` API and never accepts boarding `ExtendedCoin`
1127
+ * inputs.
1128
+ *
1129
+ * The caller (`migrateCore`) must have already moved the wallet onto the
1130
+ * active signer (`ensureReceiveOnActiveSigner`) and sized the batch (caps +
1131
+ * dust floor); this method validates the inputs, preserves all input assets
1132
+ * on the self output, and persists the new active-signer VTXO even though
1133
+ * there is no separate change output. It records no `TxSent` history — the
1134
+ * funds never leave the wallet.
1135
+ */
1136
+ sendSelectedVtxosToSelf(inputs: ExtendedVirtualCoin[]): Promise<string>;
759
1137
  /**
760
1138
  * Build an offchain transaction from the given inputs and outputs,
761
1139
  * sign it, submit to the Arkade provider, and finalize.
762
1140
  * @returns The Arkade transaction id and server-signed checkpoint PSBTs (for bookkeeping)
763
1141
  */
764
- buildAndSubmitOffchainTx(inputs: ExtendedVirtualCoin[], outputs: TransactionOutput[]): Promise<{
1142
+ buildAndSubmitOffchainTx(inputs: ExtendedVirtualCoin[], outputs: TransactionOutput[], serverUnrollScript?: CSVMultisigTapscript.Type): Promise<{
765
1143
  arkTxid: string;
766
1144
  signedCheckpointTxs: string[];
767
1145
  }>;
@@ -775,4 +1153,4 @@ declare class Wallet extends ReadonlyWallet implements IWallet {
775
1153
  */
776
1154
  declare function waitForIncomingFunds(wallet: Wallet): Promise<IncomingFunds>;
777
1155
 
778
- export { Batch as B, type IncomingFunds as I, ReadonlyWallet as R, Wallet as W, type ReceiveRotatorFactory as a, type ReceiveRotatorBootOpts as b, type ReceiveRotatorBoot as c, waitForIncomingFunds as w };
1156
+ export { Batch as B, type IncomingFunds as I, ReadonlyWallet as R, Wallet as W, type ReceiveRotatorFactory as a, type ReceiveRotatorBootOpts as b, type ReceiveRotatorBoot as c, type BoardingUtxoGroup as d, waitForIncomingFunds as w };