@arkade-os/swap 0.0.12 → 0.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,9 +1,9 @@
1
- import { ProvisionedKey, ProvisionedClaimSecret, asset, RelativeTimelock, IWallet, arkade, RestIndexerProvider, Transaction, IContractManager, OnchainProvider, PaymentRail, VHTLC, Identity, ActivityResolver } from '@arkade-os/sdk';
2
- import { S as SwapSecretsProjection, R as RfqSwapRecord, A as AssetSwapRepository, a as AssetSwap, M as MarketsCacheEntry, b as RefundArkProvider, c as RefundIndexer, L as LockupVtxo, d as RfqSwap, e as ArkadeRefundResult, f as LockupSpendIndexer, g as RfqSwapState } from './repository-DaK1RzRq.cjs';
3
- export { h as AssetSwapStatus, i as AvailableRfqSwapManagerCallbacks, B as BTC_ASSET_ID, I as InMemoryAssetSwapRepository, j as LightningReceiveSwap, k as LightningSendSwap, l as LockupFate, m as LockupNeedsRecoveryError, n as LockupParams, o as LockupSpend, O as OnchainSendAction, p as OnchainSendSwap, P as PersistableRfqSwap, q as PreimageBlockedReason, r as PreimageNotRecoverableError, s as REFUND_MTP_LAG_SECONDS, t as RFQ_RESOLVED_STATES, u as RFQ_SWAP_RETENTION_SECONDS, v as RFQ_SWAP_TERMINAL_STATES, w as RefundOutcome, x as RfqRestoreFailure, y as RfqRestoreOptions, z as RfqRestoreResult, C as RfqSwapActionName, D as RfqSwapLockup, E as RfqSwapManager, F as RfqSwapManagerCallbacks, G as RfqSwapManagerConfig, H as RfqSwapManagerDeps, J as RfqSwapManagerEvents, K as RfqSwapOrigin, N as RfqSwapOriginRequired, Q as RfqSwapOutcome, T as RfqSwapRecordStore, U as SwapContractRegistry, V as addAssetSwap, W as awaitRfqResolution, X as createRfqSwapRecord, Y as findLockupVtxos, Z as getAssetSwaps, _ as getAssetSwapsOrThrow, $ as isRfqSwapTerminal, a0 as isRfqTerminal, a1 as nextOnchainAction, a2 as preimageForSwapRecord, a3 as pushRefundWithoutReceiver, a4 as readLockupFate, a5 as rebuildRfqSwap, a6 as refundIfUnresolved, a7 as rfqSwapOriginOf, a8 as shouldRetainRfqSwap, a9 as swapSecretsToRecord, aa as updateAssetSwap, ab as updateAssetSwapBestEffort, ac as updateRfqSwapRecord } from './repository-DaK1RzRq.cjs';
1
+ import { ProvisionedKey, ProvisionedClaimSecret, asset, RelativeTimelock, IWallet, arkade, RestIndexerProvider, Transaction, IContractManager, OnchainProvider, PaymentRail, PaymentHandle, RouterPreferences, Wallet, PaymentRouter, PaymentStatus, VHTLC, Identity, ActivityResolver } from '@arkade-os/sdk';
2
+ import { S as SwapSecretsProjection, R as RfqSwapRecord, A as AssetSwapRepository, a as AssetSwap, b as SwapRecord, M as MarketsCacheEntry, c as AssetSwapStatus, O as Outcome, d as Swap, Q as QuoteInput, e as RouteResolution, f as Quote, g as SwapUpdate, U as Unsubscribe, h as RefundIndexer, L as LockupVtxo, i as SwapOperator, j as RfqSwap, k as ArkadeRefundResult, l as LockupSpendIndexer, m as RfqSwapState, n as RfqSwapManager, o as RfqSwapManagerCallbacks } from './repository-oeW8KZo1.cjs';
3
+ export { p as AvailableRfqSwapManagerCallbacks, B as BTC_ASSET_ID, I as InMemoryAssetSwapRepository, q as LightningReceiveSwap, r as LightningSendSwap, s as LockupFate, t as LockupNeedsRecoveryError, u as LockupParams, v as LockupSpend, w as OnchainSendAction, x as OnchainSendSwap, P as PersistableRfqSwap, y as PreimageBlockedReason, z as PreimageNotRecoverableError, C as REFUND_MTP_LAG_SECONDS, D as RFQ_RESOLVED_STATES, E as RFQ_SWAP_RETENTION_SECONDS, F as RFQ_SWAP_TERMINAL_STATES, G as RefundOutcome, H as RfqRestoreFailure, J as RfqRestoreOptions, K as RfqRestoreResult, N as RfqSwapActionName, T as RfqSwapLockup, V as RfqSwapManagerConfig, W as RfqSwapManagerDeps, X as RfqSwapManagerEvents, Y as RfqSwapOrigin, Z as RfqSwapOriginRequired, _ as RfqSwapOutcome, $ as RfqSwapRecordStore, a0 as SwapContractRegistry, a1 as addAssetSwap, a2 as awaitRfqResolution, a3 as createRfqSwapRecord, a4 as findLockupVtxos, a5 as getAssetSwaps, a6 as getAssetSwapsOrThrow, a7 as isRfqSwapTerminal, a8 as isRfqTerminal, a9 as nextOnchainAction, aa as normalizeRfqSwapRecord, ab as preimageForSwapRecord, ac as pushRefundWithoutReceiver, ad as readLockupFate, ae as rebuildRfqSwap, af as refundIfUnresolved, ag as rfqSwapOriginOf, ah as shouldRetainRfqSwap, ai as swapSecretsToRecord, aj as updateAssetSwap, ak as updateAssetSwapBestEffort, al as updateRfqSwapRecord } from './repository-oeW8KZo1.cjs';
4
4
  import { Network, LocalCardInput, DiscoveredMarket, Side, OfferPlan } from '@arkade-os/solver-discovery';
5
- import { O as OnchainNetwork, a as OnchainHtlc, b as OnchainHtlcParams, C as ChainSource, R as RfqTransport, r as requestOnchainSend, I as InvoiceFacts, c as requestLightningSend } from './rfq-DzsmhXX3.cjs';
6
- export { A as ARKADE_ASSET, d as ARKADE_BTC, e as AddressMismatch, f as ChainUtxo, H as HtlcUtxo, L as LIGHTNING_BTC, g as LIGHTNING_RECEIVE_PAIR, h as LIGHTNING_SEND_PAIR, i as LOCKTIME_THRESHOLD, j as LightningReceiveTreeParams, k as LightningSendTreeParams, M as MAX_MIN_CONFIRMATIONS, l as MIN_CLAIM_WINDOW_SECONDS, m as MIN_HEADROOM_SECONDS, n as ONCHAIN_BTC, o as ONCHAIN_CLAIM_MARGIN_SECONDS, p as ONCHAIN_DUST_SATS, q as ONCHAIN_ORDER_MARGIN_SECONDS, s as ONCHAIN_RECEIVE_PAIR, t as ONCHAIN_SECONDS_PER_BLOCK, u as ONCHAIN_SEND_PAIR, v as OnchainHtlcPhase, w as RFQ_TERMINAL_STATES, x as RelaySocket, y as RfqQuote, z as RfqRefusalReason, B as RfqStatus, S as SOLO_REFUND_HEADROOM_SECONDS, D as SwapRefusal, E as arkadeAssetLeg, F as arkadeSwapRequest, G as assertFundable, J as assertReceivable, K as awaitOnchainFill, N as buildHtlcClaim, P as buildHtlcRefund, Q as claimOnchainFill, T as classifyOnchainHtlc, U as deriveLightningReceive, V as deriveOnchainReceive, W as deriveOnchainSend, X as extractPreimage, Y as httpTransport, Z as l1ScriptForAddress, _ as lightningReceiveRequest, $ as lightningSendRequest, a0 as lightningSendVtxoScript, a1 as newPreimage, a2 as newRfqId, a3 as offerTermsFromQuote, a4 as onchainHtlcScript, a5 as onchainReceiveRequest, a6 as onchainSendRequest, a7 as paymentHashOf, a8 as receiveVtxoScript, a9 as relayTransport, aa as requestLightningReceive, ab as requestOnchainReceive, ac as rfqPair, ad as unilateralClaimDelay, ae as unilateralRefundDelay, af as unilateralRefundWithoutReceiverDelay, ag as verifyLockupAddress, ah as verifyReceiveInvoice } from './rfq-DzsmhXX3.cjs';
5
+ import { O as OnchainNetwork, a as OnchainHtlc, b as OnchainHtlcParams, C as ChainSource, R as RfqTransport, r as requestOnchainSend, I as InvoiceFacts, c as requestLightningSend, d as requestLightningReceive } from './rfq-D0KGjmnn.cjs';
6
+ export { A as ARKADE_ASSET, e as ARKADE_BTC, f as AddressMismatch, g as ChainUtxo, H as HtlcUtxo, L as LIGHTNING_BTC, h as LIGHTNING_RECEIVE_PAIR, i as LIGHTNING_SEND_PAIR, j as LOCKTIME_THRESHOLD, k as LightningReceiveContractParams, l as LightningSendContractParams, M as MAX_MIN_CONFIRMATIONS, m as MIN_CLAIM_WINDOW_SECONDS, n as MIN_HEADROOM_SECONDS, o as ONCHAIN_BTC, p as ONCHAIN_CLAIM_MARGIN_SECONDS, q as ONCHAIN_DUST_SATS, s as ONCHAIN_ORDER_MARGIN_SECONDS, t as ONCHAIN_RECEIVE_PAIR, u as ONCHAIN_SECONDS_PER_BLOCK, v as ONCHAIN_SEND_PAIR, w as OnchainHtlcPhase, x as RFQ_TERMINAL_STATES, y as RelaySocket, z as RfqQuote, B as RfqRefusalReason, D as RfqStatus, S as SOLO_REFUND_HEADROOM_SECONDS, E as SwapRefusal, F as arkadeAssetLeg, G as arkadeSwapRequest, J as assertFundable, K as assertReceivable, N as awaitOnchainFill, P as buildHtlcClaim, Q as buildHtlcRefund, T as claimOnchainFill, U as classifyOnchainHtlc, V as deriveLightningReceive, W as deriveOnchainReceive, X as deriveOnchainSend, Y as extractPreimage, Z as httpTransport, _ as l1ScriptForAddress, $ as lightningReceiveContract, a0 as lightningReceiveRequest, a1 as lightningSendContract, a2 as lightningSendRequest, a3 as newPreimage, a4 as newRfqId, a5 as offerTermsFromQuote, a6 as onchainHtlcScript, a7 as onchainReceiveRequest, a8 as onchainSendRequest, a9 as paymentHashOf, aa as relayTransport, ab as requestOnchainReceive, ac as rfqPair, ad as unilateralClaimDelay, ae as unilateralRefundDelay, af as unilateralRefundWithoutReceiverDelay, ag as verifyLockupAddress, ah as verifyReceiveInvoice } from './rfq-D0KGjmnn.cjs';
7
7
 
8
8
  /**
9
9
  * Which wallet key signs this leg. Stored at `profile.signer`.
@@ -111,7 +111,7 @@ interface LightningReceiveProfile extends Record<string, unknown> {
111
111
  * preimage that is already public, and a swap that did claim is relabelled
112
112
  * `needs_counterparty` once its window shuts.
113
113
  */
114
- claimArkTxid?: string;
114
+ claimTxid?: string;
115
115
  }
116
116
  /** `arkade:BTC->onchain:BTC`. */
117
117
  interface OnchainSendProfile extends Record<string, unknown> {
@@ -228,7 +228,7 @@ interface Offer {
228
228
  exitDelay?: RelativeTimelock;
229
229
  }
230
230
  /** Compile the offer's contract: program + args -> taproot tree. */
231
- declare function offerVtxoScript(offer: Omit<Offer, "swapPkScript">, serverPubkey: Uint8Array): InstanceType<typeof arkade.ArkadeProgramScript>;
231
+ declare function offerContract(offer: Omit<Offer, "swapPkScript">, operatorPubkey: Uint8Array): InstanceType<typeof arkade.ArkadeProgramScript>;
232
232
  /** Extension packet type tag for Arkade Intents offers. */
233
233
  declare const OFFER_PACKET_TYPE = 3;
234
234
  /** Serialize an offer to TLV bytes (the packet payload). */
@@ -240,11 +240,11 @@ declare function decodeOffer(data: Uint8Array): Offer;
240
240
  * you deposit, embedding the returned extension, and the solver does the rest:
241
241
  *
242
242
  * // BTC -> asset
243
- * const o = await createOffer(wallet, ARK, { wantAmount: 1000n, wantAsset })
243
+ * const o = await createOffer(wallet, { wantAmount: 1000n, wantAsset })
244
244
  * await wallet.send({ address: o.address, amount: 1000, extensions: [o.extension] })
245
245
  *
246
246
  * // asset -> BTC (the sats are the VTXO carrier for the asset)
247
- * const o = await createOffer(wallet, ARK, { wantAmount: 1000n, offerAsset })
247
+ * const o = await createOffer(wallet, { wantAmount: 1000n, offerAsset })
248
248
  * await wallet.send({ address: o.address, amount: 500,
249
249
  * assets: [{ assetId, amount: 1000n }],
250
250
  * extensions: [o.extension] })
@@ -265,7 +265,7 @@ declare function decodeOffer(data: Uint8Array): Offer;
265
265
  * so that exposure has no end. `noExit` opts out for a caller who wants the
266
266
  * smaller tree and accepts the dependency.
267
267
  */
268
- declare function createOffer(wallet: IWallet, arkServerUrl: string, params: {
268
+ declare function createOffer(wallet: IWallet, params: {
269
269
  wantAmount: bigint;
270
270
  wantAsset?: asset.AssetId;
271
271
  offerAsset?: asset.AssetId;
@@ -332,8 +332,8 @@ declare function createOffer(wallet: IWallet, arkServerUrl: string, params: {
332
332
  * Identical offers derive the same address, so `fundingTxid` selects the exact
333
333
  * deposit; without it the address must hold exactly one spendable VTXO — with
334
334
  * several, cancel refuses to guess and throws.
335
- * `swapAddress` (the funded address) pins the server key the covenant was
336
- * built with, so cancel keeps working across a server signer rotation; without
335
+ * `swapAddress` (the funded address) pins the operator key the covenant was
336
+ * built with, so cancel keeps working across an operator signer rotation; without
337
337
  * it a rotated key is detected and reported rather than reading as a missing
338
338
  * VTXO.
339
339
  *
@@ -354,12 +354,44 @@ declare function createOffer(wallet: IWallet, arkServerUrl: string, params: {
354
354
  * returns, so a spend event that arrives in that window finds a `cancelling`
355
355
  * record and classifies the spend by its covenant leaf instead — the same
356
356
  * answer, one indexer read more.
357
+ *
358
+ * Takes no server URL, like every other entrypoint here: broadcast comes from
359
+ * `wallet.getArkadeBroadcaster()` and the indexer fallback from
360
+ * `wallet.getArkadeReader()`, so the wallet's own connection is the only one
361
+ * used (#734).
357
362
  */
358
- declare function cancelOffer(wallet: IWallet, arkServerUrl: string, offerHex: string, opts: {
363
+ declare function cancelOffer(wallet: IWallet, offerHex: string, opts: {
359
364
  repository: AssetSwapRepository;
360
365
  fundingTxid?: string;
361
366
  swapAddress?: string;
362
367
  }): Promise<string>;
368
+ /**
369
+ * No deposit left to cancel at the swap address.
370
+ *
371
+ * Almost always the fill winning the race — v1's documented
372
+ * throw-means-completed trap, which the v2 client's `cancel()` reconciles
373
+ * against the covenant's leaves instead of surfacing (see `client/cancel.ts`).
374
+ * Typed so that reconciliation is an `instanceof`, not a message match; the
375
+ * message is v1's, unchanged.
376
+ */
377
+ declare class NoSpendableDepositError extends Error {
378
+ readonly name = "NoSpendableDepositError";
379
+ constructor(options?: ErrorOptions);
380
+ }
381
+ /**
382
+ * The rebuilt covenant disagrees with the offer's own `swapPkScript`: the
383
+ * operator key the rebuild pinned is not the one the covenant was funded with.
384
+ *
385
+ * v1's fallback read this as a missing VTXO; with a pinned `swapAddress` the
386
+ * only remaining causes are a record corrupted or a `swapAddress` that is not
387
+ * the one funded — so the condition is typed rather than left to surface raw.
388
+ * Fires before any broadcast, where §7's law still governs.
389
+ */
390
+ declare class OfferCovenantMismatchError extends Error {
391
+ readonly swapPkScript: string;
392
+ readonly name = "OfferCovenantMismatchError";
393
+ constructor(swapPkScript: string, options?: ErrorOptions);
394
+ }
363
395
 
364
396
  /**
365
397
  * Quoting: solver discovery and the pricing guardrails around a plan.
@@ -434,10 +466,9 @@ type PlanError = "insufficient-balance" | "side-disabled" | "below-min" | "above
434
466
  /** Validate a plan against the user's balance and the server dust limit. */
435
467
  declare const validatePlan: (plan: OfferPlan, giveBalance: bigint, dust: bigint) => PlanError | undefined;
436
468
 
437
- /** Browser backend over the SDK's shared IndexedDB manager — the same
438
- * infrastructure the wallet already uses for its Boltz swap repository. */
469
+ /** Browser backend over the SDK's shared IndexedDB manager. */
439
470
  declare class IndexedDbAssetSwapRepository implements AssetSwapRepository {
440
- readonly version: 4;
471
+ readonly version: 5;
441
472
  private readonly connection;
442
473
  constructor(dbName?: string);
443
474
  private ensureDb;
@@ -452,6 +483,10 @@ declare class IndexedDbAssetSwapRepository implements AssetSwapRepository {
452
483
  getRfqSwap(rfqId: string): Promise<RfqSwapRecord | undefined>;
453
484
  getAllRfqSwaps(): Promise<RfqSwapRecord[]>;
454
485
  removeRfqSwap(rfqId: string): Promise<void>;
486
+ saveSwapRecord(record: SwapRecord): Promise<void>;
487
+ getSwapRecord(id: string): Promise<SwapRecord | undefined>;
488
+ getAllSwapRecords(): Promise<SwapRecord[]>;
489
+ removeSwapRecord(id: string): Promise<void>;
455
490
  getScannedTxids(): Promise<Set<string>>;
456
491
  markTxidsScanned(txids: Iterable<string>): Promise<void>;
457
492
  getCachedMarkets(network: string, registry: string): Promise<MarketsCacheEntry | undefined>;
@@ -524,12 +559,12 @@ type SpendKind = "cancelled" | "fulfilled" | "indeterminate";
524
559
  * and they also survive batching: a solver filling several offers in one tx
525
560
  * gives each input its own leaf.
526
561
  *
527
- * `serverPubkey` must be the key the covenant was *funded* against. If it has
562
+ * `operatorPubkey` must be the key the covenant was *funded* against. If it has
528
563
  * rotated since, the rebuilt script will not match the offer's own
529
564
  * `swapPkScript` and this returns `indeterminate` rather than guessing —
530
565
  * `cancelOffer` diagnoses the same mismatch the same way.
531
566
  */
532
- declare function classifySpend(offer: Offer, serverPubkey: Uint8Array, spendTx: Transaction, deposit: {
567
+ declare function classifySpend(offer: Offer, operatorPubkey: Uint8Array, spendTx: Transaction, deposit: {
533
568
  txid: string;
534
569
  vout: number;
535
570
  }): SpendKind;
@@ -550,7 +585,7 @@ declare const spendTxidsOf: (vtxo: {
550
585
  * settlement they may be the same id. Try each and take the first definite
551
586
  * answer, so the classification does not depend on that distinction.
552
587
  */
553
- declare function classifyDepositSpend(offer: Offer, serverPubkey: Uint8Array, spendTxs: Iterable<Transaction>, deposit: {
588
+ declare function classifyDepositSpend(offer: Offer, operatorPubkey: Uint8Array, spendTxs: Iterable<Transaction>, deposit: {
554
589
  txid: string;
555
590
  vout: number;
556
591
  }): SpendKind;
@@ -575,18 +610,65 @@ declare function classifyDepositSpend(offer: Offer, serverPubkey: Uint8Array, sp
575
610
  * does, so the `existingIds` escape hatch is no longer a correction mechanism
576
611
  * for a wrong label — it is only a skip list.
577
612
  *
578
- * `serverPubkey` must be the server key the covenants were funded against; a
613
+ * `operatorPubkey` must be the operator key the covenants were funded against; a
579
614
  * key that has rotated since makes every affected swap unclassifiable rather
580
615
  * than misclassified.
581
616
  */
582
617
  declare function restoreAssetSwaps(indexer: RestoreIndexer, txs: Tx[], existingIds: ReadonlySet<string>, opts: {
583
- serverPubkey: Uint8Array;
618
+ operatorPubkey: Uint8Array;
584
619
  scanned?: ReadonlySet<string>;
585
620
  }): Promise<{
586
621
  restored: AssetSwap[];
587
622
  scannedTxids: string[];
588
623
  }>;
589
624
 
625
+ /**
626
+ * What this watcher needs to know about an offer swap.
627
+ *
628
+ * Structural, and narrower than {@link AssetSwap}, because two record families
629
+ * now answer the same question. v1 keys its records on the funding txid — the
630
+ * deposit IS the identity, so no record can exist before the money does — while
631
+ * the v2 client keys on the quote id and writes the record BEFORE funding, with
632
+ * `fundingTxid` a later best-effort write. Projecting the second onto the first
633
+ * is impossible for the whole pre-funding window, so the parameter widens
634
+ * instead: `id` is whatever key the source stores under, and the spend is
635
+ * matched on `fundingTxid` and `swapPkScript`, which both families carry.
636
+ *
637
+ * `createdAt` is unix **milliseconds**, the unit `coverage.ts` marks issuance
638
+ * in; see {@link CoveredSwap}.
639
+ */
640
+ interface OfferSwapFacts {
641
+ readonly id: string;
642
+ readonly status: AssetSwapStatus;
643
+ /** The TLV offer, hex — what {@link classifyDepositSpend} needs. */
644
+ readonly offerHex: string;
645
+ readonly swapPkScript: string;
646
+ readonly fundingTxid?: string;
647
+ readonly spentTxid?: string;
648
+ readonly createdAt: number;
649
+ }
650
+ /** The record change a classified spend implies. */
651
+ interface OfferSpendChanges {
652
+ readonly status: AssetSwapStatus;
653
+ readonly spentTxid: string;
654
+ readonly completedAt?: number;
655
+ }
656
+ /**
657
+ * Where the watcher reads offer records and writes their spends.
658
+ *
659
+ * One seam, two implementations: {@link assetSwapSource} over v1's store, and
660
+ * the v2 client's own over its quote-id-keyed record store. `apply` returns
661
+ * both halves for the same reason `updateAssetSwapBestEffort` does — a lost
662
+ * write must not retire a script, and the post-update view is what the liveness
663
+ * check reads without a third round trip.
664
+ */
665
+ interface OfferSwapSource<S extends OfferSwapFacts = OfferSwapFacts> {
666
+ list(): Promise<S[]>;
667
+ apply(swap: S, changes: OfferSpendChanges): Promise<{
668
+ persisted: boolean;
669
+ swaps: S[];
670
+ }>;
671
+ }
590
672
  /**
591
673
  * The record change a classified spend implies, or `undefined` when it implies
592
674
  * none — an already-resolved swap, or a spend nobody could classify.
@@ -595,25 +677,26 @@ declare function restoreAssetSwaps(indexer: RestoreIndexer, txs: Tx[], existingI
595
677
  * taking the watcher, and so re-delivery of an event is a no-op rather than a
596
678
  * rewrite.
597
679
  */
598
- declare function spendUpdate(swap: AssetSwap, spend: {
680
+ declare function spendUpdate(swap: Pick<OfferSwapFacts, "status">, spend: {
599
681
  txid: string;
600
682
  kind: SpendKind;
601
683
  at?: number;
602
- }): Partial<Omit<AssetSwap, "id">> | undefined;
684
+ }): OfferSpendChanges | undefined;
603
685
  /** A running watcher. `idle()` exists because the writes are async: shutdown
604
686
  * and tests both need to know when in-flight updates have settled. */
605
687
  interface OfferSwapWatcher {
606
688
  stop(): void;
607
689
  idle(): Promise<void>;
608
690
  }
609
- interface WatchOfferSwapsParams {
691
+ interface WatchOfferSwapsParams<S extends OfferSwapFacts = OfferSwapFacts> {
610
692
  wallet: IWallet;
611
- /** Same URL `createOffer`/`cancelOffer` take; used to read a spending tx
612
- * when the exact classifier cannot answer. */
613
- arkServerUrl: string;
614
- repository: AssetSwapRepository;
693
+ /** v1's record source. Ignored when {@link source} is given. */
694
+ repository?: AssetSwapRepository;
695
+ /** Where records are read and spends written. Defaults to
696
+ * {@link assetSwapSource} over `repository`. */
697
+ source?: OfferSwapSource<S>;
615
698
  /** Called after a change is persisted. A notification, not a store. */
616
- onUpdate?: (swap: AssetSwap) => void;
699
+ onUpdate?: (swap: S) => void;
617
700
  }
618
701
  /**
619
702
  * Subscribe to the wallet's contract events and drive offer swap status.
@@ -626,7 +709,16 @@ interface WatchOfferSwapsParams {
626
709
  * provide an `EventSource` implementation or use a runtime where it is enabled;
627
710
  * otherwise live updates do not arrive and restore remains the fallback.
628
711
  */
629
- declare function watchOfferSwaps({ wallet, arkServerUrl, repository, onUpdate, }: WatchOfferSwapsParams): Promise<OfferSwapWatcher>;
712
+ declare function watchOfferSwaps(params: {
713
+ wallet: IWallet;
714
+ repository: AssetSwapRepository;
715
+ onUpdate?: (swap: AssetSwap) => void;
716
+ }): Promise<OfferSwapWatcher>;
717
+ declare function watchOfferSwaps<S extends OfferSwapFacts>(params: {
718
+ wallet: IWallet;
719
+ source: OfferSwapSource<S>;
720
+ onUpdate?: (swap: S) => void;
721
+ }): Promise<OfferSwapWatcher>;
630
722
 
631
723
  /**
632
724
  * Coverage: whether an offer's script is in the wallet's watched set.
@@ -659,6 +751,25 @@ declare function watchOfferSwaps({ wallet, arkServerUrl, repository, onUpdate, }
659
751
  * the same backstop every other best-effort step here relies on.
660
752
  */
661
753
 
754
+ /**
755
+ * What coverage needs to know about a swap, and nothing else.
756
+ *
757
+ * Structural rather than `AssetSwap`, because two record families now ask the
758
+ * same question: v1's offer swaps and the v2 client's `OfferSwapRecord`s, which
759
+ * are keyed on a quote id and carry none of `AssetSwap`'s other fields.
760
+ * Liveness is a property of the status and the funding time, so those are the
761
+ * whole parameter.
762
+ *
763
+ * `createdAt` is unix **milliseconds** — the unit {@link promoteOfferContract}
764
+ * marks issuance in. A v2 record stores seconds, so its adapter converts;
765
+ * comparing seconds against a `Date.now()` mark would leave every issued script
766
+ * outstanding forever and never retire one.
767
+ */
768
+ interface CoveredSwap {
769
+ readonly swapPkScript: string;
770
+ readonly status: AssetSwapStatus;
771
+ readonly createdAt: number;
772
+ }
662
773
  /** The one contract-manager capability changing coverage needs. */
663
774
  type OfferContractRetirer = Pick<IContractManager, "setContractWatchState">;
664
775
  /**
@@ -669,7 +780,7 @@ type OfferContractRetirer = Pick<IContractManager, "setContractWatchState">;
669
780
  * Takes the caller's full record list: liveness is a property of all records at
670
781
  * a script, so a partial list would retire a script another record still holds.
671
782
  */
672
- declare function retireSettledOfferContracts(manager: OfferContractRetirer, swaps: AssetSwap[]): Promise<void>;
783
+ declare function retireSettledOfferContracts(manager: OfferContractRetirer, swaps: readonly CoveredSwap[]): Promise<void>;
673
784
 
674
785
  /** `network` is `requestOnchainSend`'s `l1Network`, and only decodes scripts to
675
786
  * addresses — the provider decides which chain is read, so mismatching the two
@@ -720,7 +831,6 @@ type SolverOnchainSend = Awaited<ReturnType<typeof requestOnchainSend>> & {
720
831
  payoutPkScript: Uint8Array;
721
832
  };
722
833
  interface SolverOnchainRailDeps {
723
- arkServerUrl: string;
724
834
  l1Network: OnchainNetwork;
725
835
  /** x-only L1 key that AUTHORISES the claim — not where it pays. */
726
836
  payoutPubkey: Uint8Array;
@@ -759,7 +869,6 @@ type SolverLightningSend = Awaited<ReturnType<typeof requestLightningSend>> & {
759
869
  };
760
870
  /** Mirrors {@link SolverOnchainRailDeps}; see there for the shared seams. */
761
871
  interface SolverLightningRailDeps {
762
- arkServerUrl: string;
763
872
  /** A decoder that throws drops the rail rather than taking the router
764
873
  * down — correct, since an undecodable invoice cannot be paid. */
765
874
  decodeInvoice(bolt11: string): InvoiceFacts;
@@ -776,6 +885,289 @@ interface SolverLightningRailDeps {
776
885
  declare const solverLightningRendezvous: (markets: DiscoveredMarket[], amountSats: number, fallbackEmulatorPubkey?: Uint8Array) => SolverRendezvous | undefined;
777
886
  declare function solverLightningRail(deps: SolverLightningRailDeps): PaymentRail;
778
887
 
888
+ /**
889
+ * What the two v2 swap rails share: the client seam, the quote arithmetic, and
890
+ * the handle that observes a swap through core's four-state stream.
891
+ *
892
+ * A rail here is a thin adapter and deliberately nothing more. Persistence,
893
+ * refunds, recovery and the outcome vocabulary all live behind the v2 client;
894
+ * the rail's whole job is to turn a `PaymentRequest` into a `QuoteInput`, a
895
+ * `Quote` into a receiver-exact `RouteQuote`, and a swap's outcome stream into
896
+ * a `PaymentHandle`.
897
+ *
898
+ * Two boundaries are crossed here and both are named. Amounts narrow from P3's
899
+ * `bigint` to core's `number` (see `client/sats.ts`). And a ranking estimate
900
+ * meets a binding quote: `RouteQuote.fee` is documented as "a display and
901
+ * ranking figure, not a guarantee" while a v2 `Quote` is verified before return
902
+ * and expires. `PaymentOption.quote()` is lazy and `options()` never calls it,
903
+ * so ranking is free — but a swap rail's `quote()` is an RFQ round trip that
904
+ * discloses an invoice and an amount, and an app that ranks then quotes several
905
+ * options would disclose to every solver. `available()` therefore **never
906
+ * quotes**: it resolves, which is network-free against the cached snapshot.
907
+ *
908
+ * A held `RouteQuote` can outlive its `Quote` — core's shape carries no
909
+ * `expiresAt` — and then `send()` throws `QuoteExpired` inside `makeHandle`'s
910
+ * run, which core turns into a terminal `failed`. That stays: re-quoting inside
911
+ * `send()` is the silent re-quote §3.2 forbids.
912
+ */
913
+
914
+ /**
915
+ * The slice of `SwapClient` a rail uses.
916
+ *
917
+ * Structural and minimal, so what a rail can reach is visible in one place and
918
+ * a test can stand in for it without a wallet, a repository or a solver behind
919
+ * it. A full `SwapClient` satisfies it.
920
+ */
921
+ interface SwapRailClient {
922
+ resolve(input: QuoteInput): Promise<RouteResolution>;
923
+ quote(input: QuoteInput): Promise<Quote>;
924
+ accept(quote: Quote): Promise<Swap>;
925
+ onUpdate(fn: (update: SwapUpdate) => void): Unsubscribe;
926
+ }
927
+ /**
928
+ * A payment that ended in something other than success.
929
+ *
930
+ * Not a member of §7's taxonomy and suffixed to say so: that taxonomy is thrown
931
+ * *before* value moves, and this is an outcome reported after it did. It exists
932
+ * to carry the {@link Outcome} onto the handle's terminal `error`, which is
933
+ * where `refunded` and `lapsed` stay distinguishable after the four-state
934
+ * projection has mapped both to `failed`.
935
+ */
936
+ declare class SwapPaymentFailedError extends Error {
937
+ readonly railId: string;
938
+ readonly outcome: Outcome;
939
+ readonly swap: Swap;
940
+ readonly name = "SwapPaymentFailedError";
941
+ constructor(railId: string, outcome: Outcome, swap: Swap);
942
+ }
943
+ /** `eligible > 0` for this input, or false for anything that will not route. */
944
+ declare const railAvailable: (client: SwapRailClient, input: QuoteInput) => Promise<boolean>;
945
+ /**
946
+ * The three receiver-exact numbers, checked against each other.
947
+ *
948
+ * `total === amount + fee` is core's contract and this is where a rail proves
949
+ * it rather than asserting it in a comment: `amount` is what the recipient
950
+ * gets, `fee` is what the rail and its counterparty charge on top, and `total`
951
+ * is what leaves the wallet. A `Quote` whose give leg does not equal the take
952
+ * leg plus the spread has broken an invariant M3 owns, and surfacing it here
953
+ * beats quoting a number that would rank this rail against the collaborative
954
+ * exit on a fee it does not charge.
955
+ */
956
+ declare const receiverExact: (railId: string, parts: {
957
+ amount: bigint;
958
+ fee: bigint;
959
+ total: bigint;
960
+ }) => {
961
+ amount: number;
962
+ fee: number;
963
+ total: number;
964
+ };
965
+ /**
966
+ * Accept the quote, then observe it to its first terminal outcome.
967
+ *
968
+ * The handle's contract, stated once: it observes the payment up to and
969
+ * including the first terminal outcome, and every recovery past that point is
970
+ * observed on `client.onUpdate` — keyed by the tagged `RouteResult.swapId`, so
971
+ * the two views join. `client.onUpdate` replays synchronously on subscribe, so
972
+ * a swap that was already terminal by the time we subscribed still resolves.
973
+ */
974
+ declare const swapHandle: (railId: string, client: SwapRailClient, quote: Quote) => Promise<PaymentHandle>;
975
+
976
+ /**
977
+ * `lightning` — pay a BOLT11 invoice out of an Arkade balance, through the v2
978
+ * swap client.
979
+ *
980
+ * The rail id is a registry key with published history: the factory deleted
981
+ * with `packages/boltz-swap` registered `"lightning"`, and a key is what an
982
+ * app's `priority` array and `disabled` list name. It therefore stays
983
+ * `lightning` even though Q12 renamed the lightning *asset* namespace to
984
+ * `bolt11` — the divergence between a registry key and an asset vocabulary is
985
+ * recorded here, not resolved by a rename that would break every consumer's
986
+ * preferences.
987
+ *
988
+ * The whole rail is an adapter. The invoice fixes the amount, the client
989
+ * verifies and prices the route, `accept()` persists before it funds, and the
990
+ * drive owns everything after — so there is no `persist`, no `awaitSettlement`
991
+ * and no solver selection to configure here.
992
+ */
993
+
994
+ declare const LIGHTNING_RAIL = "lightning";
995
+ /**
996
+ * Register alongside core's rails. The deleted factory's ranking was
997
+ * `["ark", "lightning", "onchain-swap", "onchain"]`; see
998
+ * {@link createSwapPaymentRouter}.
999
+ */
1000
+ declare function lightningRail(client: SwapRailClient): PaymentRail;
1001
+
1002
+ /**
1003
+ * `onchain-swap` — pay an L1 address out of an Arkade balance through a solver,
1004
+ * via the v2 swap client.
1005
+ *
1006
+ * Registered alongside core's `onchain` rail (the collaborative exit) and
1007
+ * ranked ahead of it, with both left registered: the default is a *preference*,
1008
+ * not a restriction. The preference self-heals by amount — an out-of-range
1009
+ * request drops this rail at `available()` and `onchain` wins with no error.
1010
+ *
1011
+ * The id is the deleted factory's published registry key, `"onchain-swap"`,
1012
+ * kept for the reason the `lightning` rail keeps its own: a rail id is what an
1013
+ * app's `priority` array names.
1014
+ *
1015
+ * **The claim fee is this rail's whole subtlety.** On `arkade -> onchain` the
1016
+ * trader claims the solver's L1 HTLC itself, and that claim's fee comes out of
1017
+ * the HTLC output — `payout = utxo.amount - fee`. So the sats the recipient
1018
+ * actually receives are less than the sats the solver locks, by an amount the
1019
+ * swap quote knows nothing about. A rail that quoted the solver's spread alone
1020
+ * would be reporting a fee it does not charge, and would win a ranking against
1021
+ * the collaborative exit that it should lose.
1022
+ *
1023
+ * This rail therefore takes a claim fee-rate policy at construction and grosses
1024
+ * the swap up by the estimate: it asks the solver for `amount + claimFee` on the
1025
+ * take leg, so what lands after the claim is the `amount` the caller asked for,
1026
+ * and it reports the estimate inside `fee` where a ranking can see it. A fee
1027
+ * rate is environment-specific and is nobody's to default — the same reason
1028
+ * `CorridorOverrides.onchain.claim` has no default.
1029
+ */
1030
+
1031
+ declare const ONCHAIN_SWAP_RAIL = "onchain-swap";
1032
+ interface OnchainSwapRailDeps {
1033
+ /**
1034
+ * Sat/vB the trader's L1 claim will be built at — the rate the corridor's
1035
+ * own `claim` dep will use.
1036
+ *
1037
+ * No default, and the rail refuses to exist without it: the fee comes out
1038
+ * of the recipient's payout, so a rail with no rate either quotes a fee it
1039
+ * does not charge or short-pays the recipient. Neither is a default.
1040
+ */
1041
+ readonly claimFeeRateSatVb: number;
1042
+ /** vsize the claim is priced at. Defaults to {@link ONCHAIN_CLAIM_VSIZE}. */
1043
+ readonly claimVsize?: number;
1044
+ }
1045
+ /** What the trader's L1 claim will cost, rounded up as the builder rounds it. */
1046
+ declare const claimFeeSats: (deps: OnchainSwapRailDeps) => bigint;
1047
+ /**
1048
+ * Register alongside core's rails, ranked ahead of `onchain`:
1049
+ * `["ark", "lightning", "onchain-swap", "onchain"]`. See
1050
+ * {@link createSwapPaymentRouter}.
1051
+ */
1052
+ declare function onchainSwapRail(client: SwapRailClient, deps: OnchainSwapRailDeps): PaymentRail;
1053
+
1054
+ /**
1055
+ * The router that puts lightning and `arkade -> onchain` back into a payment
1056
+ * app's reach.
1057
+ *
1058
+ * Core's `createDefaultPaymentRouter(wallet)` registers `ark` and `onchain` and
1059
+ * nothing else. The two swap rails never lived there — they were in
1060
+ * `packages/boltz-swap`, behind a second overload with the priority
1061
+ * `["ark", "lightning", "onchain-swap", "onchain"]`, and ts-sdk #811 removed
1062
+ * them along with the package. This is that overload's shape, rebuilt on the v2
1063
+ * client.
1064
+ *
1065
+ * **The rails close over their own dependencies, and `RouterContext` is not
1066
+ * re-opened.** Widening core's context was the alternative and it is the wrong
1067
+ * half: it edits a published payment type, re-imports the `swaps?: unknown`
1068
+ * smell that was deliberately deleted, and asks core to name things it cannot —
1069
+ * a repository, a transport, a discovery index. A rail factory over an
1070
+ * already-constructed `SwapClient` names none of that in core.
1071
+ *
1072
+ * This factory stays out of core's own, which is pinned at exactly
1073
+ * `["ark", "onchain"]`. Registering the swap rails is the app's decision, and
1074
+ * the ranking it gets is a *preference*: both `onchain-swap` and `onchain` stay
1075
+ * registered, so an amount outside the solver's range drops the swap rail at
1076
+ * `available()` and the collaborative exit wins with no error.
1077
+ */
1078
+
1079
+ /** The deleted factory's ranking, and the one this factory ships. */
1080
+ declare const SWAP_ROUTER_PRIORITY: readonly string[];
1081
+ interface SwapPaymentRouterConfig extends OnchainSwapRailDeps {
1082
+ /** Overrides the shipped ranking; `disabled`, `caps` and `tieBreak` pass through. */
1083
+ readonly prefs?: RouterPreferences;
1084
+ }
1085
+ /**
1086
+ * Core's four rails plus the two this package supplies, ranked as the deleted
1087
+ * factory ranked them.
1088
+ *
1089
+ * Takes the concrete `Wallet` because that is what `RouterContext` holds — core
1090
+ * types it as the class, not `IWallet` — and the already-constructed client,
1091
+ * because building one here would put storage, discovery and corridor policy
1092
+ * behind a payment-router call that has no business deciding any of them.
1093
+ */
1094
+ declare function createSwapPaymentRouter(wallet: Wallet, client: SwapRailClient, config: SwapPaymentRouterConfig): PaymentRouter;
1095
+
1096
+ /**
1097
+ * Fourteen outcomes onto four payment statuses — the only artefact M7 mints.
1098
+ *
1099
+ * Declared **total** even though a send rail cannot reach every member, because
1100
+ * a partial map is where the collapse hides: an outcome with no row does not
1101
+ * fail loudly, it renders as whatever the lookup happens to return.
1102
+ *
1103
+ * The projection is lossy by construction and the loss is recoverable, which is
1104
+ * the whole design. `refunded` and `lapsed` both land on `failed` — P6 exists so
1105
+ * those two never become one word, and the difference survives on the update's
1106
+ * `error`, which core's `PaymentHandle` docblock already reserves for it. No
1107
+ * fifth `PaymentStatus` is proposed: a status is what a payment UI branches on,
1108
+ * and "the trader's value came back" versus "the incoming payment never arrived"
1109
+ * is a sentence, not a branch.
1110
+ *
1111
+ * **Where the rail goes terminal is a decision, not a rounding.** It goes
1112
+ * terminal at `refunding`, not at `refunded`: `makeHandle` clears its subscriber
1113
+ * set on a terminal update and replays-without-registering afterwards, so the
1114
+ * `refunded` that follows could not reach that handle anyway — and holding
1115
+ * terminality back until the refund resolves would hang every
1116
+ * `settled({ timeoutMs })` caller for a whole refund window. The refund is
1117
+ * observed through `client.onUpdate` and `swaps()`, keyed by the tagged
1118
+ * `RouteResult.swapId`.
1119
+ *
1120
+ * The same rule answers the `unblock` backslide. `needs_recovery -> funded` is
1121
+ * a legal re-entry that crosses the terminality boundary the rail just drew; it
1122
+ * is emitted rather than swallowed, because the drive's idempotence key is the
1123
+ * DERIVED outcome and the second `funded` is a new key — delivered on
1124
+ * `client.onUpdate`, never through the handle, which stays terminal. A handle
1125
+ * observes a payment up to and including its first terminal outcome; every
1126
+ * recovery past that point is observed on the client's update stream.
1127
+ */
1128
+
1129
+ /**
1130
+ * The projection, total over {@link Outcome}.
1131
+ *
1132
+ * The `on the rail` column of M7's table is not encoded here: a send rail
1133
+ * cannot reach `open`, `filled`, `cancelling`, `cancelled` or `lapsed`, but a
1134
+ * map that refused them would be a map with holes, and the point of totality is
1135
+ * that there are none.
1136
+ */
1137
+ declare const PAYMENT_STATUS: {
1138
+ /** Persisted, funding not broadcast. */
1139
+ readonly accepted: "pending";
1140
+ readonly funding: "pending";
1141
+ /** The lockup is funded. Nothing has emitted `"sent"` in core since the
1142
+ * `onchain-swap` rail left with `packages/boltz-swap`. */
1143
+ readonly funded: "sent";
1144
+ /** Asset swaps only: an unfilled offer. */
1145
+ readonly open: "pending";
1146
+ /** Asset swaps only. */
1147
+ readonly filled: "settled";
1148
+ /** The trader's L1 claim on `arkade -> onchain`. */
1149
+ readonly claimed: "settled";
1150
+ /** Terminal success on `arkade -> lightning`: the solver's hash-verified
1151
+ * spend IS the invoice being paid. */
1152
+ readonly paid: "settled";
1153
+ readonly cancelling: "pending";
1154
+ /** Value returned, and the router has no non-loss terminal to say so with. */
1155
+ readonly cancelled: "failed";
1156
+ /** Terminal HERE, not at `refunded` — see the module docblock. */
1157
+ readonly refunding: "failed";
1158
+ /** The trader's value came back. Reaches `onUpdate`, not the handle. */
1159
+ readonly refunded: "failed";
1160
+ /** The solver reclaimed a receive-leg lockup: a loss, and not `refunded`. */
1161
+ readonly lapsed: "failed";
1162
+ /** Never retried silently; `client.recover` drives it. */
1163
+ readonly needs_recovery: "failed";
1164
+ readonly failed: "failed";
1165
+ };
1166
+ /** Where a payment stands, in core's four-state vocabulary. */
1167
+ declare const paymentStatusOf: (outcome: Outcome) => PaymentStatus;
1168
+ /** Whether this status ends the handle's observation. Core's own rule. */
1169
+ declare const isTerminalStatus: (status: PaymentStatus) => boolean;
1170
+
779
1171
  interface SealedClaimPacket {
780
1172
  /** `ephPub(33) ‖ nonce(12) ‖ ciphertext`, base64 — wire-ready. This is
781
1173
  * the whole packet: the RFQ request's `claim_packet` field carries
@@ -799,8 +1191,6 @@ interface ClaimPacketInput {
799
1191
  */
800
1192
  declare function sealClaimPacket(input: ClaimPacketInput): Promise<SealedClaimPacket>;
801
1193
 
802
- /** The Ark surface the claim push needs — the same seam the refund push uses. */
803
- type ClaimArkProvider = RefundArkProvider;
804
1194
  /**
805
1195
  * The lockup is funded for less than the swap agreed.
806
1196
  *
@@ -843,9 +1233,9 @@ declare class LockupAmountMismatchError extends Error {
843
1233
  * server at submit — but it turns "reported claimed, nothing landed, the
844
1234
  * solver refunds hours later" into an immediate failure.
845
1235
  */
846
- declare function pushClaim(ark: ClaimArkProvider, input: {
847
- /** The receive-direction covenant (see `receiveVtxoScript`). */
848
- script: InstanceType<typeof VHTLC.ScriptV2>;
1236
+ declare function pushClaim(operator: SwapOperator, input: {
1237
+ /** The receive-direction covenant (see `lightningReceiveContract`). */
1238
+ contract: InstanceType<typeof VHTLC.ScriptV2>;
849
1239
  /** The trader's `receiver` signer. Build it from the swap's `secrets`
850
1240
  * with `contractSigner` — on an HD wallet that resolves
851
1241
  * from the seed, with no stored key bytes anywhere. */
@@ -865,7 +1255,7 @@ declare function pushClaim(ark: ClaimArkProvider, input: {
865
1255
  * the remainder. */
866
1256
  partiallyClaimed?: boolean;
867
1257
  }): Promise<{
868
- arkTxid: string;
1258
+ txid: string;
869
1259
  amount: number;
870
1260
  }>;
871
1261
  /**
@@ -892,13 +1282,13 @@ declare function awaitLockupFunding(indexer: RefundIndexer, swapPkScript: Uint8A
892
1282
  * rest lands is safe — and that is also the answer to a genuinely underfunded
893
1283
  * lockup, which never gets past the gate at all.
894
1284
  */
895
- declare function claimReceiveLockup(indexer: RefundIndexer, ark: ClaimArkProvider, input: Parameters<typeof pushClaim>[1] & {
1285
+ declare function claimReceiveLockup(indexer: RefundIndexer, operator: SwapOperator, input: Parameters<typeof pushClaim>[1] & {
896
1286
  /** The covenant's scriptPubKey, from the request flow's `swapPkScript`. */
897
1287
  swapPkScript: Uint8Array;
898
1288
  pollMs?: number;
899
1289
  deadline?: number;
900
1290
  }): Promise<{
901
- arkTxid: string;
1291
+ txid: string;
902
1292
  amount: number;
903
1293
  }>;
904
1294
 
@@ -965,7 +1355,7 @@ declare function senderIdentityForSwapRecord(wallet: IWallet, record: {
965
1355
  */
966
1356
 
967
1357
  interface ArkadeRefunderDeps {
968
- ark: RefundArkProvider;
1358
+ operator: SwapOperator;
969
1359
  indexer: RefundIndexer;
970
1360
  /** Asked for the descriptor's signer; never asked to mint a key. */
971
1361
  wallet: IWallet;
@@ -981,7 +1371,7 @@ interface ArkadeRefunderDeps {
981
1371
  *
982
1372
  * @example
983
1373
  * manager.setCallbacks({
984
- * refundArkade: arkadeRefunder({ ark, indexer, wallet, repository }),
1374
+ * refundArkade: arkadeRefunder({ operator, indexer, wallet, repository }),
985
1375
  * saveSwap,
986
1376
  * });
987
1377
  */
@@ -1109,7 +1499,7 @@ interface RfqSwapActivityDeps {
1109
1499
  repository: Pick<AssetSwapRepository, "getAllRfqSwaps">;
1110
1500
  /**
1111
1501
  * Consulted only for what a record cannot answer: a record written before
1112
- * `fundingArkTxid` existed, and the counterparty's spend on a swap that
1502
+ * `fundingTxid` existed, and the counterparty's spend on a swap that
1113
1503
  * ended without a refund of ours.
1114
1504
  *
1115
1505
  * Optional because the stored fields are the primary source — cheaper, and
@@ -1123,7 +1513,7 @@ interface RfqSwapActivityDeps {
1123
1513
  * groups on.
1124
1514
  *
1125
1515
  * The txids come from four places, in order of preference: the record's own
1126
- * `fundingArkTxid` and `refundArkTxid`, the corridor's `activityTxids` (the
1516
+ * `fundingTxid` and `refundTxid`, the corridor's `activityTxids` (the
1127
1517
  * receive leg's Arkade claim, the onchain leg's L1 one), and — only when the
1128
1518
  * first two cannot answer — one read of the lockup's VTXOs.
1129
1519
  *
@@ -1133,4 +1523,110 @@ interface RfqSwapActivityDeps {
1133
1523
  */
1134
1524
  declare function rfqSwapActivityInputs(deps: RfqSwapActivityDeps): Promise<SwapActivityInput[]>;
1135
1525
 
1136
- export { ArkadeRefundResult, type ArkadeRefunderDeps, AssetSwap, AssetSwapRepository, ChainSource, type ClaimArkProvider, type ClaimPacketInput, type DiscoverMarketsOptions, IndexedDbAssetSwapRepository, InvoiceFacts, type LightningReceiveProfile, type LightningSendProfile, LockupAmountMismatchError, LockupContractMissing, type LockupContractReader, type LockupContractWriter, LockupRegistrationFailed, LockupSpendIndexer, LockupVtxo, MarketsCacheEntry, OFFER_PACKET_TYPE, type Offer, type OfferContractRetirer, type OfferSwapWatcher, OnchainHtlc, OnchainHtlcParams, OnchainNetwork, type OnchainSendProfile, type PlanError, QUOTE_OPTIONS, RefundArkProvider, type RefundBlockedReason, RefundIndexer, RefundNotLocallyPossibleError, type RestoreIndexer, type RfqClaimSecretProjection, type RfqHashlockProjection, type RfqSignerProjection, RfqSwap, type RfqSwapActivityDeps, RfqSwapRecord, RfqSwapState, RfqTransport, SOLVER_LIGHTNING_RAIL, SOLVER_ONCHAIN_RAIL, SWAP_LOCKUP_CONTRACT_KIND, SWAP_LOCKUP_CONTRACT_LABEL, SWAP_LOCKUP_CONTRACT_TYPE, type SealedClaimPacket, type SolverLightningRailDeps, type SolverLightningSend, type SolverOnchainRailDeps, type SolverOnchainSend, type SolverRendezvous, type SpendKind, type SwapActivityInput, SwapSecretsProjection, type Tx, type WatchOfferSwapsParams, arkadeRefunder, awaitLockupFunding, cancelOffer, chainSourceFrom, claimReceiveLockup, classifyDepositSpend, classifySpend, createOffer, decodeOffer, discoverMarkets, encodeOffer, findMarket, lockupContractParams, makeCachedFeedFetch, offerVtxoScript, onchainSendProfile, pushClaim, registerLockupContract, requestLightningSend, requestOnchainSend, restoreAssetSwaps, retireSettledOfferContracts, rfqClaimSecretOf, rfqSecretsProfile, rfqSignerOf, rfqSwapActivityInputs, sealClaimPacket, senderIdentityForSwapRecord, solverLightningRail, solverLightningRendezvous, solverOnchainRail, solverOnchainRendezvous, solverRendezvous, spendTxidsOf, spendUpdate, swapActivityResolver, swapPrograms, validatePlan, watchOfferSwaps };
1526
+ interface SwapQuoteInput {
1527
+ /** Which side of the market the trader deposits. */
1528
+ give: "base" | "quote";
1529
+ /** Size on the named side ("give" = exact-in, "receive" = exact-out).
1530
+ * Spot: display string or atomic bigint; corridors: sats. A lightning
1531
+ * send takes its amount from the invoice instead. */
1532
+ amount?: string | number | bigint;
1533
+ amountOn?: "give" | "receive";
1534
+ /** Required when the receive side is lightning. */
1535
+ invoice?: InvoiceFacts;
1536
+ /** Trader's x-only L1 claim key; required when the receive side is onchain. */
1537
+ payoutPubkey?: Uint8Array;
1538
+ /**
1539
+ * The L1 address the claim PAYS to, when the receive side is onchain.
1540
+ *
1541
+ * Distinct from {@link payoutPubkey}, which only AUTHORISES the claim: the
1542
+ * claim's output is the spender's own choice, and nothing on the wire names
1543
+ * it. Omitted, the claim pays the trader's own `payoutPubkey` as a key-path
1544
+ * P2TR — the conservative default, since that is the one destination the
1545
+ * trader is already known to hold the key for.
1546
+ */
1547
+ payoutAddress?: string;
1548
+ preimage?: Uint8Array;
1549
+ maxPayAmount?: number;
1550
+ }
1551
+ interface SpotQuote {
1552
+ kind: "spot";
1553
+ market: DiscoveredMarket;
1554
+ plan: OfferPlan;
1555
+ }
1556
+ interface LightningSendQuote {
1557
+ kind: "ln_send";
1558
+ market: DiscoveredMarket;
1559
+ request: Awaited<ReturnType<typeof requestLightningSend>>;
1560
+ }
1561
+ interface LightningReceiveQuote {
1562
+ kind: "ln_receive";
1563
+ market: DiscoveredMarket;
1564
+ request: Awaited<ReturnType<typeof requestLightningReceive>>;
1565
+ /** The solver's hold invoice, for the payer. */
1566
+ invoice: string;
1567
+ }
1568
+ interface OnchainSendQuote {
1569
+ kind: "onchain_send";
1570
+ market: DiscoveredMarket;
1571
+ request: Awaited<ReturnType<typeof requestOnchainSend>>;
1572
+ /** Where the claim pays, resolved at quote time from `payoutAddress` (or
1573
+ * defaulted to the trader's own claim key) and persisted with the record:
1574
+ * `buildHtlcClaim` needs it and nothing else gives it back. */
1575
+ payoutPkScript: Uint8Array;
1576
+ }
1577
+ type SwapQuote = SpotQuote | LightningSendQuote | LightningReceiveQuote | OnchainSendQuote;
1578
+ type UnifiedSwap = {
1579
+ family: "offer";
1580
+ swap: AssetSwap;
1581
+ } | {
1582
+ family: "rfq";
1583
+ swap: RfqSwap;
1584
+ };
1585
+ interface SwapClientDeps {
1586
+ /** The server connection too: every provider below defaults to this
1587
+ * wallet's own, so no server URL is passed in (arkade-os/ts-sdk#734). */
1588
+ wallet: IWallet;
1589
+ repository: AssetSwapRepository;
1590
+ /** The rendezvous for a corridor market; never called for a spot one.
1591
+ *
1592
+ * The market's own `base_corridor`/`quote_corridor` are what route a swap
1593
+ * here rather than to the offer path, so whoever publishes the market
1594
+ * chooses which backend you are asked to open a transport to. Resolve one
1595
+ * only for markets from an index you trust — this client does not, and
1596
+ * cannot, check that a market named a corridor honestly. */
1597
+ transportFor: (market: DiscoveredMarket) => RfqTransport;
1598
+ discovery: Omit<DiscoverMarketsOptions, "repository">;
1599
+ /** BOLT11 decoder for the solver's hold invoice; required to quote lightning receives. */
1600
+ decodeInvoice?: (bolt11: string) => InvoiceFacts;
1601
+ /** covclaimd's 33-byte compressed pubkey — the lightning-receive claim
1602
+ * packet seals to it; required to quote lightning receives. */
1603
+ covclaimdPubkey?: Uint8Array;
1604
+ /** L1 access; required to quote onchain sends. */
1605
+ chain?: ChainSource;
1606
+ /** L1 claim callback (fee rate and signing are environment-specific);
1607
+ * without it the manager reports onchain claims as blocked. */
1608
+ claimOnchain?: RfqSwapManagerCallbacks["claimOnchain"];
1609
+ emulatorPubkey?: string;
1610
+ /** Overrides the wallet's own connection; for tests and for a caller that
1611
+ * must reach a different operator. */
1612
+ ark?: SwapOperator;
1613
+ indexer?: LockupSpendIndexer;
1614
+ }
1615
+ interface SwapClient {
1616
+ markets(useCache?: boolean): Promise<DiscoveredMarket[]>;
1617
+ quote(market: DiscoveredMarket, input: SwapQuoteInput): Promise<SwapQuote>;
1618
+ accept(quote: SwapQuote): Promise<UnifiedSwap>;
1619
+ /** Spot only: the covenant's cooperative reclaim. */
1620
+ cancel(fundingTxid: string): Promise<void>;
1621
+ /** Every swap this client knows of, both families and both live and ended
1622
+ * — not a live-only view. The RFQ half is bounded by what the manager has
1623
+ * loaded and by `RFQ_SWAP_RETENTION_SECONDS`. */
1624
+ swaps(): Promise<UnifiedSwap[]>;
1625
+ onUpdate(listener: (swap: UnifiedSwap) => void): () => void;
1626
+ start(): Promise<void>;
1627
+ stop(): Promise<void>;
1628
+ readonly manager: RfqSwapManager;
1629
+ }
1630
+ declare function createSwapClient(deps: SwapClientDeps): SwapClient;
1631
+
1632
+ export { ArkadeRefundResult, type ArkadeRefunderDeps, AssetSwap, AssetSwapRepository, AssetSwapStatus, ChainSource, type ClaimPacketInput, type DiscoverMarketsOptions, IndexedDbAssetSwapRepository, InvoiceFacts, LIGHTNING_RAIL, type LightningReceiveProfile, type LightningReceiveQuote, type LightningSendProfile, type LightningSendQuote, LockupAmountMismatchError, LockupContractMissing, type LockupContractReader, type LockupContractWriter, LockupRegistrationFailed, LockupSpendIndexer, LockupVtxo, MarketsCacheEntry, NoSpendableDepositError, OFFER_PACKET_TYPE, ONCHAIN_SWAP_RAIL, type Offer, type OfferContractRetirer, OfferCovenantMismatchError, type OfferSwapWatcher, OnchainHtlc, OnchainHtlcParams, OnchainNetwork, type OnchainSendProfile, type OnchainSendQuote, type OnchainSwapRailDeps, PAYMENT_STATUS, type PlanError, QUOTE_OPTIONS, type RefundBlockedReason, RefundIndexer, RefundNotLocallyPossibleError, type RestoreIndexer, type RfqClaimSecretProjection, type RfqHashlockProjection, type RfqSignerProjection, RfqSwap, type RfqSwapActivityDeps, RfqSwapManager, RfqSwapManagerCallbacks, RfqSwapRecord, RfqSwapState, RfqTransport, SOLVER_LIGHTNING_RAIL, SOLVER_ONCHAIN_RAIL, SWAP_LOCKUP_CONTRACT_KIND, SWAP_LOCKUP_CONTRACT_LABEL, SWAP_LOCKUP_CONTRACT_TYPE, SWAP_ROUTER_PRIORITY, type SealedClaimPacket, type SolverLightningRailDeps, type SolverLightningSend, type SolverOnchainRailDeps, type SolverOnchainSend, type SolverRendezvous, type SpendKind, type SpotQuote, type SwapActivityInput, type SwapClient, type SwapClientDeps, SwapOperator, SwapPaymentFailedError, type SwapPaymentRouterConfig, type SwapQuote, type SwapQuoteInput, type SwapRailClient, SwapSecretsProjection, type Tx, type UnifiedSwap, type WatchOfferSwapsParams, arkadeRefunder, awaitLockupFunding, cancelOffer, chainSourceFrom, claimFeeSats, claimReceiveLockup, classifyDepositSpend, classifySpend, createOffer, createSwapClient, createSwapPaymentRouter, decodeOffer, discoverMarkets, encodeOffer, findMarket, isTerminalStatus, lightningRail, lockupContractParams, makeCachedFeedFetch, offerContract, onchainSendProfile, onchainSwapRail, paymentStatusOf, pushClaim, railAvailable, receiverExact, registerLockupContract, requestLightningReceive, requestLightningSend, requestOnchainSend, restoreAssetSwaps, retireSettledOfferContracts, rfqClaimSecretOf, rfqSecretsProfile, rfqSignerOf, rfqSwapActivityInputs, sealClaimPacket, senderIdentityForSwapRecord, solverLightningRail, solverLightningRendezvous, solverOnchainRail, solverOnchainRendezvous, solverRendezvous, spendTxidsOf, spendUpdate, swapActivityResolver, swapHandle, swapPrograms, validatePlan, watchOfferSwaps };