@arkade-os/swap 0.0.4 → 0.0.5

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,14 +1,47 @@
1
- import { ProvisionedKey, ProvisionedClaimSecret, asset, IWallet, arkade, RestIndexerProvider, Transaction, IContractManager, RestArkProvider, VHTLC, Identity } from '@arkade-os/sdk';
1
+ import { IWallet, ProvisionedKey, ProvisionedClaimSecret, asset, arkade, RestIndexerProvider, Transaction, IContractManager, RestArkProvider, VHTLC, Identity } from '@arkade-os/sdk';
2
2
  import { DiscoveredMarket, Network, LocalCardInput, Side, OfferPlan } from '@arkade-os/solver-discovery';
3
- import { R as RfqStatus, a as RfqTransport, O as OnchainHtlc, C as ChainSource, b as ChainUtxo, c as OnchainHtlcPhase } from './rfq-DjZlesr4.cjs';
4
- export { A as ARKADE_ASSET, d as ARKADE_BTC, e as AddressMismatch, H as HtlcUtxo, I as InvoiceFacts, L as LIGHTNING_BTC, f as LIGHTNING_RECEIVE_PAIR, g as LIGHTNING_SEND_PAIR, M as MAX_MIN_CONFIRMATIONS, h as MIN_CLAIM_WINDOW_SECONDS, i as MIN_HEADROOM_SECONDS, j as ONCHAIN_BTC, k as ONCHAIN_CLAIM_MARGIN_SECONDS, l as ONCHAIN_DUST_SATS, m as ONCHAIN_ORDER_MARGIN_SECONDS, n as ONCHAIN_RECEIVE_PAIR, o as ONCHAIN_SECONDS_PER_BLOCK, p as ONCHAIN_SEND_PAIR, q as OnchainHtlcParams, r as OnchainNetwork, s as RFQ_TERMINAL_STATES, t as RelaySocket, u as RfqQuote, v as RfqRefusalReason, S as SwapRefusal, w as arkadeSwapRequest, x as assertFundable, y as assertReceivable, z as awaitOnchainFill, B as buildHtlcClaim, D as buildHtlcRefund, E as claimOnchainFill, F as classifyOnchainHtlc, G as deriveLightningReceive, J as deriveOnchainReceive, K as deriveOnchainSend, N as extractPreimage, P as httpTransport, Q as lightningReceiveRequest, T as lightningSendRequest, U as lightningSendVtxoScript, V as newPreimage, W as newRfqId, X as offerTermsFromQuote, Y as onchainHtlcScript, Z as onchainReceiveRequest, _ as onchainSendRequest, $ as paymentHashOf, a0 as receiveVtxoScript, a1 as relayTransport, a2 as requestLightningReceive, a3 as requestLightningSend, a4 as requestOnchainReceive, a5 as requestOnchainSend, a6 as rfqPair, a7 as unilateralClaimDelay, a8 as unilateralRefundDelay, a9 as unilateralRefundWithoutReceiverDelay, aa as verifyLockupAddress, ab as verifyReceiveInvoice } from './rfq-DjZlesr4.cjs';
3
+ import { R as RfqStatus, a as RfqTransport, O as OnchainHtlc, C as ChainSource, b as ChainUtxo, c as OnchainHtlcPhase } from './rfq-BH2yvo3O.cjs';
4
+ export { A as ARKADE_ASSET, d as ARKADE_BTC, e as AddressMismatch, H as HtlcUtxo, I as InvoiceFacts, L as LIGHTNING_BTC, f as LIGHTNING_RECEIVE_PAIR, g as LIGHTNING_SEND_PAIR, M as MAX_MIN_CONFIRMATIONS, h as MIN_CLAIM_WINDOW_SECONDS, i as MIN_HEADROOM_SECONDS, j as ONCHAIN_BTC, k as ONCHAIN_CLAIM_MARGIN_SECONDS, l as ONCHAIN_DUST_SATS, m as ONCHAIN_ORDER_MARGIN_SECONDS, n as ONCHAIN_RECEIVE_PAIR, o as ONCHAIN_SECONDS_PER_BLOCK, p as ONCHAIN_SEND_PAIR, q as OnchainHtlcParams, r as OnchainNetwork, s as RFQ_TERMINAL_STATES, t as RelaySocket, u as RfqQuote, v as RfqRefusalReason, S as SOLO_REFUND_HEADROOM_SECONDS, w as SwapRefusal, x as arkadeSwapRequest, y as assertFundable, z as assertReceivable, B as awaitOnchainFill, D as buildHtlcClaim, E as buildHtlcRefund, F as claimOnchainFill, G as classifyOnchainHtlc, J as deriveLightningReceive, K as deriveOnchainReceive, N as deriveOnchainSend, P as extractPreimage, Q as httpTransport, T as lightningReceiveRequest, U as lightningSendRequest, V as lightningSendVtxoScript, W as newPreimage, X as newRfqId, Y as offerTermsFromQuote, Z as onchainHtlcScript, _ as onchainReceiveRequest, $ as onchainSendRequest, a0 as paymentHashOf, a1 as receiveVtxoScript, a2 as relayTransport, a3 as requestLightningReceive, a4 as requestLightningSend, a5 as requestOnchainReceive, a6 as requestOnchainSend, a7 as rfqPair, a8 as unilateralClaimDelay, a9 as unilateralRefundDelay, aa as unilateralRefundWithoutReceiverDelay, ab as verifyLockupAddress, ac as verifyReceiveInvoice } from './rfq-BH2yvo3O.cjs';
5
5
 
6
6
  type AssetSwapStatus = "pending" | "cancelling" | "fulfilled" | "cancelled" | "recoverable" | "awaiting_fill" | "claimable" | "claimed" | "refunded_l1";
7
7
  /** The sentinel asset id for BTC itself, as opposed to a 68-hex asset id.
8
8
  * Lives here with the {@link AssetSwap} fields it describes so the market and
9
9
  * restore layers share one spelling instead of re-typing the literal. */
10
10
  declare const BTC_ASSET_ID = "btc";
11
- interface AssetSwap {
11
+ /**
12
+ * The record fields a wallet-provisioned secret becomes — what
13
+ * {@link swapSecretsToRecord} emits, and what every record type carrying swap
14
+ * secrets embeds.
15
+ *
16
+ * A named type rather than four fields restated per record: the mapper and the
17
+ * records it feeds must agree exactly, and a record that silently omits one of
18
+ * these round-trips a swap whose preimage cannot be re-derived. Embedding makes
19
+ * the omission a compile error instead.
20
+ *
21
+ * **Only `preimageHex` is secret.** `signingDescriptor` and `preimageSaltHex`
22
+ * are public derivation inputs — they must survive a field-mapped backend, but
23
+ * they leak nothing without the seed.
24
+ */
25
+ interface SwapSecretsProjection {
26
+ /**
27
+ * The wallet descriptor this swap's sender key comes from — a fresh HD
28
+ * child, or a static wallet's `tr(pubkey)`. Public — the signer
29
+ * re-derives from the wallet, so the record carries no key material.
30
+ */
31
+ signingDescriptor?: string;
32
+ /** P, hex, when it cannot be re-derived from the seed at all: the user
33
+ * supplied it, or the signer cannot sign deterministically. The swap's only
34
+ * claim secret when present. */
35
+ preimageHex?: string;
36
+ /**
37
+ * The salt P derives from, hex, on the salted arm — what a static wallet
38
+ * gets instead of storing P. **Public**, and unlike every other field here
39
+ * it is minted per swap: it is what stops one repeating key from handing
40
+ * every swap the same preimage.
41
+ */
42
+ preimageSaltHex?: string;
43
+ }
44
+ interface AssetSwap extends SwapSecretsProjection {
12
45
  /** Funding txid — the swap's identity. */
13
46
  id: string;
14
47
  /** 'btc' or a 68-hex asset id. */
@@ -33,16 +66,6 @@ interface AssetSwap {
33
66
  /** `sha256(P)`, hex. Public, and how a restore confirms a candidate
34
67
  * derivation is the right one. */
35
68
  paymentHash?: string;
36
- /**
37
- * The wallet descriptor this swap's sender key comes from — a fresh HD
38
- * child, or a static wallet's `tr(pubkey)`. Public — the signer
39
- * re-derives from the wallet, so the record carries no key material.
40
- */
41
- signingDescriptor?: string;
42
- /** P, hex, when it cannot be re-derived from the seed: the user supplied
43
- * it, or the descriptor is static (shared across swaps, so a derived
44
- * preimage would collide). The swap's only claim secret when present. */
45
- preimageHex?: string;
46
69
  /** The L1 HTLC's pkScript, hex — the chain-watch key. */
47
70
  htlcPkScriptHex?: string;
48
71
  htlcLocktime?: number;
@@ -85,13 +108,70 @@ declare const updateAssetSwapBestEffort: (repository: AssetSwapRepository, id: s
85
108
  * The record fields a wallet-provisioned secret becomes.
86
109
  *
87
110
  * `signingDescriptor` is public and always stored — it is what recovers the
88
- * signer. `preimageHex` is stored only when the wallet says it cannot
89
- * re-derive P, and is then the swap's only claim secret.
111
+ * signer. Then at most one of: `preimageHex`, when the wallet says it cannot
112
+ * re-derive P and it becomes the swap's only claim secret; or
113
+ * `preimageSaltHex`, the public input a derivable-but-repeating key needs.
90
114
  */
91
- declare const swapSecretsToRecord: (secrets: ProvisionedKey | ProvisionedClaimSecret) => {
115
+ declare const swapSecretsToRecord: (secrets: ProvisionedKey | ProvisionedClaimSecret) => SwapSecretsProjection & {
92
116
  signingDescriptor: string;
93
- preimageHex?: string;
94
117
  };
118
+ /** Why a wallet cannot produce a swap's preimage. */
119
+ type PreimageBlockedReason =
120
+ /** The record carries no `signingDescriptor`. */
121
+ "no-secrets"
122
+ /** `preimageHex` or `preimageSaltHex` is present but not 32 bytes of hex. */
123
+ | "malformed-record"
124
+ /**
125
+ * Nothing to derive from: a descriptor that repeats across swaps, with
126
+ * neither a stored preimage nor a salt — or one this wallet holds no key
127
+ * for. Merged deliberately: `contractSigner` reports a key it does not
128
+ * hold as a plain `Error` for static wallets and a `ForeignDescriptorError`
129
+ * for HD ones, so splitting the two here would mean matching on message
130
+ * text, which is the thing this type exists to avoid. The `cause` carries
131
+ * whichever it was.
132
+ */
133
+ | "not-derivable"
134
+ /** Derived, but it does not hash to the record's `paymentHash`. */
135
+ | "hash-mismatch";
136
+ /**
137
+ * The wallet cannot produce this swap's preimage, and which of the four ways
138
+ * is `reason`.
139
+ *
140
+ * Deliberately **not** {@link RefundNotLocallyPossibleError}: that one means
141
+ * "no local refund is possible", and `RfqSwapManager` acts on it by reporting
142
+ * `needs_counterparty`. A claim-path read failure is a different verdict, and
143
+ * borrowing the refund error would have the manager announce one for the
144
+ * other.
145
+ */
146
+ declare class PreimageNotRecoverableError extends Error {
147
+ readonly reason: PreimageBlockedReason;
148
+ readonly name = "PreimageNotRecoverableError";
149
+ constructor(reason: PreimageBlockedReason, message: string, options?: {
150
+ cause?: unknown;
151
+ });
152
+ }
153
+ /**
154
+ * The preimage a swap record claims with — stored, or re-derived from the
155
+ * wallet.
156
+ *
157
+ * The record-shaped inverse of {@link swapSecretsToRecord}, and the one place
158
+ * that knows which of a record's fields `contractPreimage` needs. Wire claim
159
+ * paths here rather than composing it by hand: a caller that forgets to pass
160
+ * `preimageSaltHex` gets a *wrong* preimage from a wallet that can derive,
161
+ * not an error.
162
+ *
163
+ * Verifies the result against `paymentHash` when the record carries one. The
164
+ * salted arm has two inputs that can be wrong — the key and the salt — where
165
+ * the HD arm had one, and a wrong P otherwise surfaces as an opaque script
166
+ * failure at claim time, long after the mistake.
167
+ *
168
+ * Every refusal is a {@link PreimageNotRecoverableError} carrying a `reason`,
169
+ * so a caller can tell "this record predates the descriptor" from "the salt is
170
+ * corrupt" without reading message text.
171
+ */
172
+ declare const preimageForSwapRecord: (wallet: IWallet, record: SwapSecretsProjection & {
173
+ paymentHash?: string;
174
+ }) => Promise<Uint8Array>;
95
175
 
96
176
  /** A registry discovery result held for reuse. Refetchable — unlike a swap
97
177
  * record, losing it costs one network round trip — but it must survive a cold
@@ -116,11 +196,12 @@ interface MarketsCacheEntry {
116
196
  * subset queries.
117
197
  */
118
198
  interface AssetSwapRepository extends AsyncDisposable {
119
- readonly version: 1;
199
+ readonly version: 2;
120
200
  /** Insert or replace a swap by id. Store the record whole: `preimageHex`
121
- * is secret-bearing the only claim secret of a swap whose descriptor is
122
- * not per-swapand a field-mapped backend that drops it leaves the swap
123
- * unclaimable. */
201
+ * and `preimageSaltHex` both leave the swap unclaimable if a field-mapped
202
+ * backend drops them the first is the only claim secret of a swap whose
203
+ * signer cannot derive, the second the public input every other static
204
+ * wallet's preimage derives from. */
124
205
  saveSwap(swap: AssetSwap): Promise<void>;
125
206
  /** All stored swaps, in no particular order — `getAssetSwaps` is the
126
207
  * canonical newest-first read. */
@@ -134,7 +215,7 @@ interface AssetSwapRepository extends AsyncDisposable {
134
215
  clear(): Promise<void>;
135
216
  }
136
217
  declare class InMemoryAssetSwapRepository implements AssetSwapRepository {
137
- readonly version: 1;
218
+ readonly version: 2;
138
219
  private readonly swaps;
139
220
  private readonly scanned;
140
221
  private readonly markets;
@@ -363,7 +444,7 @@ declare const validatePlan: (plan: OfferPlan, giveBalance: bigint, dust: bigint)
363
444
  * infrastructure the wallet already uses for its Boltz swap repository. */
364
445
  declare class IndexedDbAssetSwapRepository implements AssetSwapRepository {
365
446
  private readonly dbName;
366
- readonly version: 1;
447
+ readonly version: 2;
367
448
  private dbPromise;
368
449
  constructor(dbName?: string);
369
450
  private ensureDb;
@@ -1929,4 +2010,4 @@ interface RfqSwapOutcome {
1929
2010
  txid?: string;
1930
2011
  }
1931
2012
 
1932
- export { type ArkadeRefundResult, type AssetSwap, type AssetSwapRepository, type AssetSwapStatus, BTC_ASSET_ID, ChainSource, ChainUtxo, type ClaimArkProvider, type ClaimPacketInput, type DiscoverMarketsOptions, InMemoryAssetSwapRepository, IndexedDbAssetSwapRepository, type LightningReceiveSwap, type LightningSendSwap, LockupAmountMismatchError, type LockupContractWriter, type LockupFate, LockupNeedsRecoveryError, LockupRegistrationFailed, type LockupSpendIndexer, type LockupVtxo, type MarketsCacheEntry, OFFER_PACKET_TYPE, type Offer, type OfferContractRetirer, type OfferSwapWatcher, OnchainHtlc, OnchainHtlcPhase, type OnchainSendAction, type OnchainSendSwap, type PlanError, QUOTE_OPTIONS, REFUND_MTP_LAG_SECONDS, RFQ_RESOLVED_STATES, RFQ_SWAP_TERMINAL_STATES, type RefundArkProvider, type RefundBlockedReason, type RefundIndexer, RefundNotLocallyPossibleError, type RefundOutcome, type RestoreIndexer, RfqStatus, type RfqSwap, type RfqSwapActionName, type RfqSwapLockup, RfqSwapManager, type RfqSwapManagerCallbacks, type RfqSwapManagerConfig, type RfqSwapManagerDeps, type RfqSwapManagerEvents, type RfqSwapOutcome, type RfqSwapState, RfqTransport, SWAP_LOCKUP_CONTRACT_KIND, SWAP_LOCKUP_CONTRACT_LABEL, SWAP_LOCKUP_CONTRACT_TYPE, type SealedClaimPacket, type SpendKind, type SwapContractRegistry, type Tx, type WatchOfferSwapsParams, addAssetSwap, awaitLockupFunding, awaitRfqResolution, cancelOffer, claimReceiveLockup, classifyDepositSpend, classifySpend, createOffer, decodeOffer, discoverMarkets, encodeOffer, findLockupVtxos, findMarket, getAssetSwaps, getAssetSwapsOrThrow, isRfqSwapTerminal, isRfqTerminal, makeCachedFeedFetch, nextOnchainAction, offerVtxoScript, pushClaim, pushRefundWithoutReceiver, readLockupFate, refundIfUnresolved, registerLockupContract, restoreAssetSwaps, retireSettledOfferContracts, sealClaimPacket, senderIdentityForSwapRecord, spendTxidsOf, spendUpdate, swapPrograms, swapSecretsToRecord, updateAssetSwap, updateAssetSwapBestEffort, validatePlan, watchOfferSwaps };
2013
+ export { type ArkadeRefundResult, type AssetSwap, type AssetSwapRepository, type AssetSwapStatus, BTC_ASSET_ID, ChainSource, ChainUtxo, type ClaimArkProvider, type ClaimPacketInput, type DiscoverMarketsOptions, InMemoryAssetSwapRepository, IndexedDbAssetSwapRepository, type LightningReceiveSwap, type LightningSendSwap, LockupAmountMismatchError, type LockupContractWriter, type LockupFate, LockupNeedsRecoveryError, LockupRegistrationFailed, type LockupSpendIndexer, type LockupVtxo, type MarketsCacheEntry, OFFER_PACKET_TYPE, type Offer, type OfferContractRetirer, type OfferSwapWatcher, OnchainHtlc, OnchainHtlcPhase, type OnchainSendAction, type OnchainSendSwap, type PlanError, type PreimageBlockedReason, PreimageNotRecoverableError, QUOTE_OPTIONS, REFUND_MTP_LAG_SECONDS, RFQ_RESOLVED_STATES, RFQ_SWAP_TERMINAL_STATES, type RefundArkProvider, type RefundBlockedReason, type RefundIndexer, RefundNotLocallyPossibleError, type RefundOutcome, type RestoreIndexer, RfqStatus, type RfqSwap, type RfqSwapActionName, type RfqSwapLockup, RfqSwapManager, type RfqSwapManagerCallbacks, type RfqSwapManagerConfig, type RfqSwapManagerDeps, type RfqSwapManagerEvents, type RfqSwapOutcome, type RfqSwapState, RfqTransport, SWAP_LOCKUP_CONTRACT_KIND, SWAP_LOCKUP_CONTRACT_LABEL, SWAP_LOCKUP_CONTRACT_TYPE, type SealedClaimPacket, type SpendKind, type SwapContractRegistry, type SwapSecretsProjection, type Tx, type WatchOfferSwapsParams, addAssetSwap, awaitLockupFunding, awaitRfqResolution, cancelOffer, claimReceiveLockup, classifyDepositSpend, classifySpend, createOffer, decodeOffer, discoverMarkets, encodeOffer, findLockupVtxos, findMarket, getAssetSwaps, getAssetSwapsOrThrow, isRfqSwapTerminal, isRfqTerminal, makeCachedFeedFetch, nextOnchainAction, offerVtxoScript, preimageForSwapRecord, pushClaim, pushRefundWithoutReceiver, readLockupFate, refundIfUnresolved, registerLockupContract, restoreAssetSwaps, retireSettledOfferContracts, sealClaimPacket, senderIdentityForSwapRecord, spendTxidsOf, spendUpdate, swapPrograms, swapSecretsToRecord, updateAssetSwap, updateAssetSwapBestEffort, validatePlan, watchOfferSwaps };
package/dist/index.d.ts CHANGED
@@ -1,14 +1,47 @@
1
- import { ProvisionedKey, ProvisionedClaimSecret, asset, IWallet, arkade, RestIndexerProvider, Transaction, IContractManager, RestArkProvider, VHTLC, Identity } from '@arkade-os/sdk';
1
+ import { IWallet, ProvisionedKey, ProvisionedClaimSecret, asset, arkade, RestIndexerProvider, Transaction, IContractManager, RestArkProvider, VHTLC, Identity } from '@arkade-os/sdk';
2
2
  import { DiscoveredMarket, Network, LocalCardInput, Side, OfferPlan } from '@arkade-os/solver-discovery';
3
- import { R as RfqStatus, a as RfqTransport, O as OnchainHtlc, C as ChainSource, b as ChainUtxo, c as OnchainHtlcPhase } from './rfq-DjZlesr4.js';
4
- export { A as ARKADE_ASSET, d as ARKADE_BTC, e as AddressMismatch, H as HtlcUtxo, I as InvoiceFacts, L as LIGHTNING_BTC, f as LIGHTNING_RECEIVE_PAIR, g as LIGHTNING_SEND_PAIR, M as MAX_MIN_CONFIRMATIONS, h as MIN_CLAIM_WINDOW_SECONDS, i as MIN_HEADROOM_SECONDS, j as ONCHAIN_BTC, k as ONCHAIN_CLAIM_MARGIN_SECONDS, l as ONCHAIN_DUST_SATS, m as ONCHAIN_ORDER_MARGIN_SECONDS, n as ONCHAIN_RECEIVE_PAIR, o as ONCHAIN_SECONDS_PER_BLOCK, p as ONCHAIN_SEND_PAIR, q as OnchainHtlcParams, r as OnchainNetwork, s as RFQ_TERMINAL_STATES, t as RelaySocket, u as RfqQuote, v as RfqRefusalReason, S as SwapRefusal, w as arkadeSwapRequest, x as assertFundable, y as assertReceivable, z as awaitOnchainFill, B as buildHtlcClaim, D as buildHtlcRefund, E as claimOnchainFill, F as classifyOnchainHtlc, G as deriveLightningReceive, J as deriveOnchainReceive, K as deriveOnchainSend, N as extractPreimage, P as httpTransport, Q as lightningReceiveRequest, T as lightningSendRequest, U as lightningSendVtxoScript, V as newPreimage, W as newRfqId, X as offerTermsFromQuote, Y as onchainHtlcScript, Z as onchainReceiveRequest, _ as onchainSendRequest, $ as paymentHashOf, a0 as receiveVtxoScript, a1 as relayTransport, a2 as requestLightningReceive, a3 as requestLightningSend, a4 as requestOnchainReceive, a5 as requestOnchainSend, a6 as rfqPair, a7 as unilateralClaimDelay, a8 as unilateralRefundDelay, a9 as unilateralRefundWithoutReceiverDelay, aa as verifyLockupAddress, ab as verifyReceiveInvoice } from './rfq-DjZlesr4.js';
3
+ import { R as RfqStatus, a as RfqTransport, O as OnchainHtlc, C as ChainSource, b as ChainUtxo, c as OnchainHtlcPhase } from './rfq-BH2yvo3O.js';
4
+ export { A as ARKADE_ASSET, d as ARKADE_BTC, e as AddressMismatch, H as HtlcUtxo, I as InvoiceFacts, L as LIGHTNING_BTC, f as LIGHTNING_RECEIVE_PAIR, g as LIGHTNING_SEND_PAIR, M as MAX_MIN_CONFIRMATIONS, h as MIN_CLAIM_WINDOW_SECONDS, i as MIN_HEADROOM_SECONDS, j as ONCHAIN_BTC, k as ONCHAIN_CLAIM_MARGIN_SECONDS, l as ONCHAIN_DUST_SATS, m as ONCHAIN_ORDER_MARGIN_SECONDS, n as ONCHAIN_RECEIVE_PAIR, o as ONCHAIN_SECONDS_PER_BLOCK, p as ONCHAIN_SEND_PAIR, q as OnchainHtlcParams, r as OnchainNetwork, s as RFQ_TERMINAL_STATES, t as RelaySocket, u as RfqQuote, v as RfqRefusalReason, S as SOLO_REFUND_HEADROOM_SECONDS, w as SwapRefusal, x as arkadeSwapRequest, y as assertFundable, z as assertReceivable, B as awaitOnchainFill, D as buildHtlcClaim, E as buildHtlcRefund, F as claimOnchainFill, G as classifyOnchainHtlc, J as deriveLightningReceive, K as deriveOnchainReceive, N as deriveOnchainSend, P as extractPreimage, Q as httpTransport, T as lightningReceiveRequest, U as lightningSendRequest, V as lightningSendVtxoScript, W as newPreimage, X as newRfqId, Y as offerTermsFromQuote, Z as onchainHtlcScript, _ as onchainReceiveRequest, $ as onchainSendRequest, a0 as paymentHashOf, a1 as receiveVtxoScript, a2 as relayTransport, a3 as requestLightningReceive, a4 as requestLightningSend, a5 as requestOnchainReceive, a6 as requestOnchainSend, a7 as rfqPair, a8 as unilateralClaimDelay, a9 as unilateralRefundDelay, aa as unilateralRefundWithoutReceiverDelay, ab as verifyLockupAddress, ac as verifyReceiveInvoice } from './rfq-BH2yvo3O.js';
5
5
 
6
6
  type AssetSwapStatus = "pending" | "cancelling" | "fulfilled" | "cancelled" | "recoverable" | "awaiting_fill" | "claimable" | "claimed" | "refunded_l1";
7
7
  /** The sentinel asset id for BTC itself, as opposed to a 68-hex asset id.
8
8
  * Lives here with the {@link AssetSwap} fields it describes so the market and
9
9
  * restore layers share one spelling instead of re-typing the literal. */
10
10
  declare const BTC_ASSET_ID = "btc";
11
- interface AssetSwap {
11
+ /**
12
+ * The record fields a wallet-provisioned secret becomes — what
13
+ * {@link swapSecretsToRecord} emits, and what every record type carrying swap
14
+ * secrets embeds.
15
+ *
16
+ * A named type rather than four fields restated per record: the mapper and the
17
+ * records it feeds must agree exactly, and a record that silently omits one of
18
+ * these round-trips a swap whose preimage cannot be re-derived. Embedding makes
19
+ * the omission a compile error instead.
20
+ *
21
+ * **Only `preimageHex` is secret.** `signingDescriptor` and `preimageSaltHex`
22
+ * are public derivation inputs — they must survive a field-mapped backend, but
23
+ * they leak nothing without the seed.
24
+ */
25
+ interface SwapSecretsProjection {
26
+ /**
27
+ * The wallet descriptor this swap's sender key comes from — a fresh HD
28
+ * child, or a static wallet's `tr(pubkey)`. Public — the signer
29
+ * re-derives from the wallet, so the record carries no key material.
30
+ */
31
+ signingDescriptor?: string;
32
+ /** P, hex, when it cannot be re-derived from the seed at all: the user
33
+ * supplied it, or the signer cannot sign deterministically. The swap's only
34
+ * claim secret when present. */
35
+ preimageHex?: string;
36
+ /**
37
+ * The salt P derives from, hex, on the salted arm — what a static wallet
38
+ * gets instead of storing P. **Public**, and unlike every other field here
39
+ * it is minted per swap: it is what stops one repeating key from handing
40
+ * every swap the same preimage.
41
+ */
42
+ preimageSaltHex?: string;
43
+ }
44
+ interface AssetSwap extends SwapSecretsProjection {
12
45
  /** Funding txid — the swap's identity. */
13
46
  id: string;
14
47
  /** 'btc' or a 68-hex asset id. */
@@ -33,16 +66,6 @@ interface AssetSwap {
33
66
  /** `sha256(P)`, hex. Public, and how a restore confirms a candidate
34
67
  * derivation is the right one. */
35
68
  paymentHash?: string;
36
- /**
37
- * The wallet descriptor this swap's sender key comes from — a fresh HD
38
- * child, or a static wallet's `tr(pubkey)`. Public — the signer
39
- * re-derives from the wallet, so the record carries no key material.
40
- */
41
- signingDescriptor?: string;
42
- /** P, hex, when it cannot be re-derived from the seed: the user supplied
43
- * it, or the descriptor is static (shared across swaps, so a derived
44
- * preimage would collide). The swap's only claim secret when present. */
45
- preimageHex?: string;
46
69
  /** The L1 HTLC's pkScript, hex — the chain-watch key. */
47
70
  htlcPkScriptHex?: string;
48
71
  htlcLocktime?: number;
@@ -85,13 +108,70 @@ declare const updateAssetSwapBestEffort: (repository: AssetSwapRepository, id: s
85
108
  * The record fields a wallet-provisioned secret becomes.
86
109
  *
87
110
  * `signingDescriptor` is public and always stored — it is what recovers the
88
- * signer. `preimageHex` is stored only when the wallet says it cannot
89
- * re-derive P, and is then the swap's only claim secret.
111
+ * signer. Then at most one of: `preimageHex`, when the wallet says it cannot
112
+ * re-derive P and it becomes the swap's only claim secret; or
113
+ * `preimageSaltHex`, the public input a derivable-but-repeating key needs.
90
114
  */
91
- declare const swapSecretsToRecord: (secrets: ProvisionedKey | ProvisionedClaimSecret) => {
115
+ declare const swapSecretsToRecord: (secrets: ProvisionedKey | ProvisionedClaimSecret) => SwapSecretsProjection & {
92
116
  signingDescriptor: string;
93
- preimageHex?: string;
94
117
  };
118
+ /** Why a wallet cannot produce a swap's preimage. */
119
+ type PreimageBlockedReason =
120
+ /** The record carries no `signingDescriptor`. */
121
+ "no-secrets"
122
+ /** `preimageHex` or `preimageSaltHex` is present but not 32 bytes of hex. */
123
+ | "malformed-record"
124
+ /**
125
+ * Nothing to derive from: a descriptor that repeats across swaps, with
126
+ * neither a stored preimage nor a salt — or one this wallet holds no key
127
+ * for. Merged deliberately: `contractSigner` reports a key it does not
128
+ * hold as a plain `Error` for static wallets and a `ForeignDescriptorError`
129
+ * for HD ones, so splitting the two here would mean matching on message
130
+ * text, which is the thing this type exists to avoid. The `cause` carries
131
+ * whichever it was.
132
+ */
133
+ | "not-derivable"
134
+ /** Derived, but it does not hash to the record's `paymentHash`. */
135
+ | "hash-mismatch";
136
+ /**
137
+ * The wallet cannot produce this swap's preimage, and which of the four ways
138
+ * is `reason`.
139
+ *
140
+ * Deliberately **not** {@link RefundNotLocallyPossibleError}: that one means
141
+ * "no local refund is possible", and `RfqSwapManager` acts on it by reporting
142
+ * `needs_counterparty`. A claim-path read failure is a different verdict, and
143
+ * borrowing the refund error would have the manager announce one for the
144
+ * other.
145
+ */
146
+ declare class PreimageNotRecoverableError extends Error {
147
+ readonly reason: PreimageBlockedReason;
148
+ readonly name = "PreimageNotRecoverableError";
149
+ constructor(reason: PreimageBlockedReason, message: string, options?: {
150
+ cause?: unknown;
151
+ });
152
+ }
153
+ /**
154
+ * The preimage a swap record claims with — stored, or re-derived from the
155
+ * wallet.
156
+ *
157
+ * The record-shaped inverse of {@link swapSecretsToRecord}, and the one place
158
+ * that knows which of a record's fields `contractPreimage` needs. Wire claim
159
+ * paths here rather than composing it by hand: a caller that forgets to pass
160
+ * `preimageSaltHex` gets a *wrong* preimage from a wallet that can derive,
161
+ * not an error.
162
+ *
163
+ * Verifies the result against `paymentHash` when the record carries one. The
164
+ * salted arm has two inputs that can be wrong — the key and the salt — where
165
+ * the HD arm had one, and a wrong P otherwise surfaces as an opaque script
166
+ * failure at claim time, long after the mistake.
167
+ *
168
+ * Every refusal is a {@link PreimageNotRecoverableError} carrying a `reason`,
169
+ * so a caller can tell "this record predates the descriptor" from "the salt is
170
+ * corrupt" without reading message text.
171
+ */
172
+ declare const preimageForSwapRecord: (wallet: IWallet, record: SwapSecretsProjection & {
173
+ paymentHash?: string;
174
+ }) => Promise<Uint8Array>;
95
175
 
96
176
  /** A registry discovery result held for reuse. Refetchable — unlike a swap
97
177
  * record, losing it costs one network round trip — but it must survive a cold
@@ -116,11 +196,12 @@ interface MarketsCacheEntry {
116
196
  * subset queries.
117
197
  */
118
198
  interface AssetSwapRepository extends AsyncDisposable {
119
- readonly version: 1;
199
+ readonly version: 2;
120
200
  /** Insert or replace a swap by id. Store the record whole: `preimageHex`
121
- * is secret-bearing the only claim secret of a swap whose descriptor is
122
- * not per-swapand a field-mapped backend that drops it leaves the swap
123
- * unclaimable. */
201
+ * and `preimageSaltHex` both leave the swap unclaimable if a field-mapped
202
+ * backend drops them the first is the only claim secret of a swap whose
203
+ * signer cannot derive, the second the public input every other static
204
+ * wallet's preimage derives from. */
124
205
  saveSwap(swap: AssetSwap): Promise<void>;
125
206
  /** All stored swaps, in no particular order — `getAssetSwaps` is the
126
207
  * canonical newest-first read. */
@@ -134,7 +215,7 @@ interface AssetSwapRepository extends AsyncDisposable {
134
215
  clear(): Promise<void>;
135
216
  }
136
217
  declare class InMemoryAssetSwapRepository implements AssetSwapRepository {
137
- readonly version: 1;
218
+ readonly version: 2;
138
219
  private readonly swaps;
139
220
  private readonly scanned;
140
221
  private readonly markets;
@@ -363,7 +444,7 @@ declare const validatePlan: (plan: OfferPlan, giveBalance: bigint, dust: bigint)
363
444
  * infrastructure the wallet already uses for its Boltz swap repository. */
364
445
  declare class IndexedDbAssetSwapRepository implements AssetSwapRepository {
365
446
  private readonly dbName;
366
- readonly version: 1;
447
+ readonly version: 2;
367
448
  private dbPromise;
368
449
  constructor(dbName?: string);
369
450
  private ensureDb;
@@ -1929,4 +2010,4 @@ interface RfqSwapOutcome {
1929
2010
  txid?: string;
1930
2011
  }
1931
2012
 
1932
- export { type ArkadeRefundResult, type AssetSwap, type AssetSwapRepository, type AssetSwapStatus, BTC_ASSET_ID, ChainSource, ChainUtxo, type ClaimArkProvider, type ClaimPacketInput, type DiscoverMarketsOptions, InMemoryAssetSwapRepository, IndexedDbAssetSwapRepository, type LightningReceiveSwap, type LightningSendSwap, LockupAmountMismatchError, type LockupContractWriter, type LockupFate, LockupNeedsRecoveryError, LockupRegistrationFailed, type LockupSpendIndexer, type LockupVtxo, type MarketsCacheEntry, OFFER_PACKET_TYPE, type Offer, type OfferContractRetirer, type OfferSwapWatcher, OnchainHtlc, OnchainHtlcPhase, type OnchainSendAction, type OnchainSendSwap, type PlanError, QUOTE_OPTIONS, REFUND_MTP_LAG_SECONDS, RFQ_RESOLVED_STATES, RFQ_SWAP_TERMINAL_STATES, type RefundArkProvider, type RefundBlockedReason, type RefundIndexer, RefundNotLocallyPossibleError, type RefundOutcome, type RestoreIndexer, RfqStatus, type RfqSwap, type RfqSwapActionName, type RfqSwapLockup, RfqSwapManager, type RfqSwapManagerCallbacks, type RfqSwapManagerConfig, type RfqSwapManagerDeps, type RfqSwapManagerEvents, type RfqSwapOutcome, type RfqSwapState, RfqTransport, SWAP_LOCKUP_CONTRACT_KIND, SWAP_LOCKUP_CONTRACT_LABEL, SWAP_LOCKUP_CONTRACT_TYPE, type SealedClaimPacket, type SpendKind, type SwapContractRegistry, type Tx, type WatchOfferSwapsParams, addAssetSwap, awaitLockupFunding, awaitRfqResolution, cancelOffer, claimReceiveLockup, classifyDepositSpend, classifySpend, createOffer, decodeOffer, discoverMarkets, encodeOffer, findLockupVtxos, findMarket, getAssetSwaps, getAssetSwapsOrThrow, isRfqSwapTerminal, isRfqTerminal, makeCachedFeedFetch, nextOnchainAction, offerVtxoScript, pushClaim, pushRefundWithoutReceiver, readLockupFate, refundIfUnresolved, registerLockupContract, restoreAssetSwaps, retireSettledOfferContracts, sealClaimPacket, senderIdentityForSwapRecord, spendTxidsOf, spendUpdate, swapPrograms, swapSecretsToRecord, updateAssetSwap, updateAssetSwapBestEffort, validatePlan, watchOfferSwaps };
2013
+ export { type ArkadeRefundResult, type AssetSwap, type AssetSwapRepository, type AssetSwapStatus, BTC_ASSET_ID, ChainSource, ChainUtxo, type ClaimArkProvider, type ClaimPacketInput, type DiscoverMarketsOptions, InMemoryAssetSwapRepository, IndexedDbAssetSwapRepository, type LightningReceiveSwap, type LightningSendSwap, LockupAmountMismatchError, type LockupContractWriter, type LockupFate, LockupNeedsRecoveryError, LockupRegistrationFailed, type LockupSpendIndexer, type LockupVtxo, type MarketsCacheEntry, OFFER_PACKET_TYPE, type Offer, type OfferContractRetirer, type OfferSwapWatcher, OnchainHtlc, OnchainHtlcPhase, type OnchainSendAction, type OnchainSendSwap, type PlanError, type PreimageBlockedReason, PreimageNotRecoverableError, QUOTE_OPTIONS, REFUND_MTP_LAG_SECONDS, RFQ_RESOLVED_STATES, RFQ_SWAP_TERMINAL_STATES, type RefundArkProvider, type RefundBlockedReason, type RefundIndexer, RefundNotLocallyPossibleError, type RefundOutcome, type RestoreIndexer, RfqStatus, type RfqSwap, type RfqSwapActionName, type RfqSwapLockup, RfqSwapManager, type RfqSwapManagerCallbacks, type RfqSwapManagerConfig, type RfqSwapManagerDeps, type RfqSwapManagerEvents, type RfqSwapOutcome, type RfqSwapState, RfqTransport, SWAP_LOCKUP_CONTRACT_KIND, SWAP_LOCKUP_CONTRACT_LABEL, SWAP_LOCKUP_CONTRACT_TYPE, type SealedClaimPacket, type SpendKind, type SwapContractRegistry, type SwapSecretsProjection, type Tx, type WatchOfferSwapsParams, addAssetSwap, awaitLockupFunding, awaitRfqResolution, cancelOffer, claimReceiveLockup, classifyDepositSpend, classifySpend, createOffer, decodeOffer, discoverMarkets, encodeOffer, findLockupVtxos, findMarket, getAssetSwaps, getAssetSwapsOrThrow, isRfqSwapTerminal, isRfqTerminal, makeCachedFeedFetch, nextOnchainAction, offerVtxoScript, preimageForSwapRecord, pushClaim, pushRefundWithoutReceiver, readLockupFate, refundIfUnresolved, registerLockupContract, restoreAssetSwaps, retireSettledOfferContracts, sealClaimPacket, senderIdentityForSwapRecord, spendTxidsOf, spendUpdate, swapPrograms, swapSecretsToRecord, updateAssetSwap, updateAssetSwapBestEffort, validatePlan, watchOfferSwaps };
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  ONCHAIN_SECONDS_PER_BLOCK,
18
18
  ONCHAIN_SEND_PAIR,
19
19
  RFQ_TERMINAL_STATES,
20
+ SOLO_REFUND_HEADROOM_SECONDS,
20
21
  SWAP_LOCKUP_CONTRACT_KIND,
21
22
  SWAP_LOCKUP_CONTRACT_LABEL,
22
23
  SWAP_LOCKUP_CONTRACT_TYPE,
@@ -58,7 +59,7 @@ import {
58
59
  unilateralRefundWithoutReceiverDelay,
59
60
  verifyLockupAddress,
60
61
  verifyReceiveInvoice
61
- } from "./chunk-DLM6BVTB.js";
62
+ } from "./chunk-Q4FAYBXS.js";
62
63
 
63
64
  // src/offer.ts
64
65
  import { hex as hex2 } from "@scure/base";
@@ -203,6 +204,8 @@ async function retireSettledOfferContracts(manager, swaps) {
203
204
 
204
205
  // src/store.ts
205
206
  import { hex } from "@scure/base";
207
+ import { sha256 } from "@noble/hashes/sha2.js";
208
+ import { contractPreimage } from "@arkade-os/sdk";
206
209
  var BTC_ASSET_ID = "btc";
207
210
  var byNewest = (a, b) => b.createdAt - a.createdAt;
208
211
  var getAssetSwapsOrThrow = async (repository) => {
@@ -257,8 +260,61 @@ var updateAssetSwapBestEffort = async (repository, id, changes) => {
257
260
  };
258
261
  var swapSecretsToRecord = (secrets) => ({
259
262
  signingDescriptor: secrets.descriptor,
260
- ..."mustPersistPreimage" in secrets && secrets.mustPersistPreimage ? { preimageHex: hex.encode(secrets.preimage) } : {}
263
+ ..."mustPersistPreimage" in secrets && secrets.mustPersistPreimage ? { preimageHex: hex.encode(secrets.preimage) } : {},
264
+ ..."preimageSalt" in secrets && secrets.preimageSalt ? { preimageSaltHex: hex.encode(secrets.preimageSalt) } : {}
261
265
  });
266
+ var decodeHex32 = (value, field) => {
267
+ const bytes = hex.decode(value);
268
+ if (bytes.length !== 32) {
269
+ throw new Error(`${field} must be 32 bytes, got ${bytes.length}`);
270
+ }
271
+ return bytes;
272
+ };
273
+ var PreimageNotRecoverableError = class extends Error {
274
+ constructor(reason, message, options) {
275
+ super(message, options);
276
+ this.reason = reason;
277
+ }
278
+ reason;
279
+ name = "PreimageNotRecoverableError";
280
+ };
281
+ var preimageForSwapRecord = async (wallet, record) => {
282
+ if (!record.signingDescriptor) {
283
+ throw new PreimageNotRecoverableError(
284
+ "no-secrets",
285
+ "this swap record carries no signing descriptor"
286
+ );
287
+ }
288
+ let stored;
289
+ let salt;
290
+ try {
291
+ stored = record.preimageHex ? decodeHex32(record.preimageHex, "preimageHex") : void 0;
292
+ salt = record.preimageSaltHex ? decodeHex32(record.preimageSaltHex, "preimageSaltHex") : void 0;
293
+ } catch (cause) {
294
+ throw new PreimageNotRecoverableError(
295
+ "malformed-record",
296
+ `this swap record's secrets projection is unreadable: ${String(cause)}`,
297
+ { cause }
298
+ );
299
+ }
300
+ let preimage;
301
+ try {
302
+ preimage = await contractPreimage(wallet, record.signingDescriptor, { stored, salt });
303
+ } catch (cause) {
304
+ throw new PreimageNotRecoverableError(
305
+ "not-derivable",
306
+ `this wallet cannot produce the preimage for ${record.signingDescriptor}`,
307
+ { cause }
308
+ );
309
+ }
310
+ if (record.paymentHash && hex.encode(sha256(preimage)) !== record.paymentHash.toLowerCase()) {
311
+ throw new PreimageNotRecoverableError(
312
+ "hash-mismatch",
313
+ "the derived preimage does not match this swap's payment hash: wrong wallet, or a tampered salt"
314
+ );
315
+ }
316
+ return preimage;
317
+ };
262
318
 
263
319
  // src/offer.ts
264
320
  var swapPrograms = {
@@ -637,7 +693,7 @@ var validatePlan = (plan, giveBalance, dust) => {
637
693
  // src/repository.ts
638
694
  var marketsCacheKey = (network, registry) => `arkade-intents-markets-${network}-${registry}`;
639
695
  var InMemoryAssetSwapRepository = class {
640
- version = 1;
696
+ version = 2;
641
697
  swaps = /* @__PURE__ */ new Map();
642
698
  scanned = /* @__PURE__ */ new Set();
643
699
  markets = /* @__PURE__ */ new Map();
@@ -699,7 +755,7 @@ var IndexedDbAssetSwapRepository = class {
699
755
  this.dbName = dbName;
700
756
  }
701
757
  dbName;
702
- version = 1;
758
+ version = 2;
703
759
  // the promise, not the resolved database: openDatabase bumps a refcount on
704
760
  // every call including cache hits, while dispose closes once, so two
705
761
  // concurrent first calls would strand the refcount above zero and leak the
@@ -1025,7 +1081,7 @@ async function watchOfferSwaps({
1025
1081
  // src/claim.ts
1026
1082
  import { hex as hex6 } from "@scure/base";
1027
1083
  import { ripemd160 } from "@noble/hashes/legacy.js";
1028
- import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1084
+ import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
1029
1085
  import {
1030
1086
  CSVMultisigTapscript as CSVMultisigTapscript2,
1031
1087
  claimWithPreimageIdentity,
@@ -1034,7 +1090,7 @@ import {
1034
1090
 
1035
1091
  // src/refund.ts
1036
1092
  import { base64 as base643, hex as hex5 } from "@scure/base";
1037
- import { sha256 } from "@noble/hashes/sha2.js";
1093
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1038
1094
  import {
1039
1095
  CSVMultisigTapscript,
1040
1096
  ConditionWitness,
@@ -1115,7 +1171,7 @@ async function findLockupVtxos(indexer, swapPkScript) {
1115
1171
  }
1116
1172
  return out;
1117
1173
  }
1118
- var hashesTo = (candidate, paymentHash) => hex5.encode(sha256(candidate)) === paymentHash;
1174
+ var hashesTo = (candidate, paymentHash) => hex5.encode(sha2562(candidate)) === paymentHash;
1119
1175
  var candidateWitnessItems = (tx, inputIndex) => [
1120
1176
  ...getArkPsbtFields(tx, inputIndex, ConditionWitness).flat(),
1121
1177
  ...tx.getInput(inputIndex).finalScriptWitness ?? []
@@ -1284,7 +1340,7 @@ async function pushClaim(ark, input) {
1284
1340
  }
1285
1341
  }
1286
1342
  const committed = input.script.options.preimageHash;
1287
- if (hex6.encode(ripemd160(sha2562(input.preimage))) !== hex6.encode(committed)) {
1343
+ if (hex6.encode(ripemd160(sha2563(input.preimage))) !== hex6.encode(committed)) {
1288
1344
  throw new Error("preimage does not match the covenant's payment hash");
1289
1345
  }
1290
1346
  const info = await ark.getInfo();
@@ -2175,6 +2231,7 @@ export {
2175
2231
  ONCHAIN_RECEIVE_PAIR,
2176
2232
  ONCHAIN_SECONDS_PER_BLOCK,
2177
2233
  ONCHAIN_SEND_PAIR,
2234
+ PreimageNotRecoverableError,
2178
2235
  QUOTE_OPTIONS,
2179
2236
  REFUND_MTP_LAG_SECONDS,
2180
2237
  RFQ_RESOLVED_STATES,
@@ -2182,6 +2239,7 @@ export {
2182
2239
  RFQ_TERMINAL_STATES,
2183
2240
  RefundNotLocallyPossibleError,
2184
2241
  RfqSwapManager,
2242
+ SOLO_REFUND_HEADROOM_SECONDS,
2185
2243
  SWAP_LOCKUP_CONTRACT_KIND,
2186
2244
  SWAP_LOCKUP_CONTRACT_LABEL,
2187
2245
  SWAP_LOCKUP_CONTRACT_TYPE,
@@ -2229,6 +2287,7 @@ export {
2229
2287
  onchainReceiveRequest,
2230
2288
  onchainSendRequest,
2231
2289
  paymentHashOf,
2290
+ preimageForSwapRecord,
2232
2291
  pushClaim,
2233
2292
  pushRefundWithoutReceiver,
2234
2293
  readLockupFate,
package/dist/nostr.cjs CHANGED
@@ -33,6 +33,7 @@ __export(nostr_exports, {
33
33
  RFQ_AD_KIND: () => RFQ_AD_KIND,
34
34
  RFQ_DIRECTED_KIND: () => RFQ_DIRECTED_KIND,
35
35
  RelayUnavailable: () => RelayUnavailable,
36
+ TransportClosed: () => TransportClosed,
36
37
  nostrRfqTransport: () => nostrRfqTransport
37
38
  });
38
39
  module.exports = __toCommonJS(nostr_exports);
@@ -90,6 +91,8 @@ var SwapRefusal = class extends Error {
90
91
  }
91
92
  };
92
93
  var MIN_HEADROOM_SECONDS = 90 * 60;
94
+ var SEQUENCE_GRANULARITY_SECONDS = 512;
95
+ var SOLO_REFUND_HEADROOM_SECONDS = 8 * SEQUENCE_GRANULARITY_SECONDS;
93
96
  var MIN_CLAIM_WINDOW_SECONDS = 30 * 60;
94
97
 
95
98
  // src/nostr.ts
@@ -105,6 +108,12 @@ var RelayUnavailable = class extends Error {
105
108
  this.reasons = reasons;
106
109
  }
107
110
  };
111
+ var TransportClosed = class extends Error {
112
+ constructor() {
113
+ super("transport closed before the solver replied");
114
+ this.name = "TransportClosed";
115
+ }
116
+ };
108
117
  var closeReasons = (raw) => raw.map((entry) => {
109
118
  if (typeof entry === "string") return entry;
110
119
  const { url, reason } = entry ?? {};
@@ -204,6 +213,7 @@ var nostrRfqTransport = (options) => {
204
213
  },
205
214
  async close() {
206
215
  closed = true;
216
+ for (const waiter of waiters.values()) waiter.reject(new TransportClosed());
207
217
  waiters.clear();
208
218
  if (ownsPool) pool.close(relays);
209
219
  else subscription.close();
@@ -215,5 +225,6 @@ var nostrRfqTransport = (options) => {
215
225
  RFQ_AD_KIND,
216
226
  RFQ_DIRECTED_KIND,
217
227
  RelayUnavailable,
228
+ TransportClosed,
218
229
  nostrRfqTransport
219
230
  });
package/dist/nostr.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as RfqTransport } from './rfq-DjZlesr4.cjs';
1
+ import { a as RfqTransport } from './rfq-BH2yvo3O.cjs';
2
2
  import { SimplePool } from 'nostr-tools';
3
3
  import '@arkade-os/sdk';
4
4
 
@@ -70,6 +70,18 @@ declare class RelayUnavailable extends Error {
70
70
  readonly reasons: string[];
71
71
  constructor(reasons: string[]);
72
72
  }
73
+ /**
74
+ * `close()` was called while a negotiation was still waiting on a reply.
75
+ *
76
+ * Distinct from both a timeout and {@link RelayUnavailable}, which describe the
77
+ * wire; this describes a decision on our own side of it. A caller that closed
78
+ * deliberately — a user leaving the screen, a flow abandoning its request — can
79
+ * match on this and stay quiet, rather than reporting a solver failure that
80
+ * never happened.
81
+ */
82
+ declare class TransportClosed extends Error {
83
+ constructor();
84
+ }
73
85
  interface NostrRfqOptions {
74
86
  /** Relay URLs from the solver's card. The rendezvous, not solver endpoints. */
75
87
  relays: string[];
@@ -95,4 +107,4 @@ interface NostrRfqOptions {
95
107
  */
96
108
  declare const nostrRfqTransport: (options: NostrRfqOptions) => RfqTransport;
97
109
 
98
- export { type NostrRfqOptions, RFQ_AD_KIND, RFQ_DIRECTED_KIND, RelayUnavailable, nostrRfqTransport };
110
+ export { type NostrRfqOptions, RFQ_AD_KIND, RFQ_DIRECTED_KIND, RelayUnavailable, TransportClosed, nostrRfqTransport };
package/dist/nostr.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as RfqTransport } from './rfq-DjZlesr4.js';
1
+ import { a as RfqTransport } from './rfq-BH2yvo3O.js';
2
2
  import { SimplePool } from 'nostr-tools';
3
3
  import '@arkade-os/sdk';
4
4
 
@@ -70,6 +70,18 @@ declare class RelayUnavailable extends Error {
70
70
  readonly reasons: string[];
71
71
  constructor(reasons: string[]);
72
72
  }
73
+ /**
74
+ * `close()` was called while a negotiation was still waiting on a reply.
75
+ *
76
+ * Distinct from both a timeout and {@link RelayUnavailable}, which describe the
77
+ * wire; this describes a decision on our own side of it. A caller that closed
78
+ * deliberately — a user leaving the screen, a flow abandoning its request — can
79
+ * match on this and stay quiet, rather than reporting a solver failure that
80
+ * never happened.
81
+ */
82
+ declare class TransportClosed extends Error {
83
+ constructor();
84
+ }
73
85
  interface NostrRfqOptions {
74
86
  /** Relay URLs from the solver's card. The rendezvous, not solver endpoints. */
75
87
  relays: string[];
@@ -95,4 +107,4 @@ interface NostrRfqOptions {
95
107
  */
96
108
  declare const nostrRfqTransport: (options: NostrRfqOptions) => RfqTransport;
97
109
 
98
- export { type NostrRfqOptions, RFQ_AD_KIND, RFQ_DIRECTED_KIND, RelayUnavailable, nostrRfqTransport };
110
+ export { type NostrRfqOptions, RFQ_AD_KIND, RFQ_DIRECTED_KIND, RelayUnavailable, TransportClosed, nostrRfqTransport };