@satora/swap 0.0.5 → 0.1.0

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.ts CHANGED
@@ -1,4 +1,956 @@
1
+ import { SwapStatus, Client as Client$1, ClientBuilder as ClientBuilder$1, StoredSwap } from '@lendasat/lendaswap-sdk-pure';
1
2
  export * from '@lendasat/lendaswap-sdk-pure';
2
- import '@lendasat/lendaswap-sdk-pure/node';
3
- import '@lendasat/lendaswap-sdk-pure/delegate';
4
- import '@lendasat/lendaswap-sdk-pure/cctp-bridge';
3
+ import { VirtualCoin } from '@arkade-os/sdk';
4
+ import { Log, Block } from 'viem';
5
+
6
+ /**
7
+ * The derived "what should the client do next?" model.
8
+ *
9
+ * `SwapStatus` says what *happened*; `SwapActions` says what the client *can or
10
+ * should do*. Actions are produced by the pure resolver {@link deriveSwapActions}
11
+ * from a plain {@link SwapActionInput} snapshot — no I/O, so the whole decision
12
+ * matrix is testable with mocked states.
13
+ */
14
+
15
+ /**
16
+ * How the background worker may run an action — the load-bearing safety field.
17
+ * `fund` is never `auto` (spends new money); claim / cctp-mint completion are
18
+ * safe to `auto` (they protect or continue existing funds); refunds are
19
+ * `confirm` (the user should know).
20
+ */
21
+ type SwapActionAutomation = "auto" | "confirm" | "manual";
22
+ /** Typed reasons an action can't run yet — no free strings. */
23
+ type BlockedReason = "timelock_not_expired";
24
+ type BlockedBy = {
25
+ kind: BlockedReason;
26
+ message: string;
27
+ };
28
+ /** Fields common to every action variant. */
29
+ type SwapActionBase = {
30
+ /** The SDK's suggested pick among the set. Exactly one action is recommended. */
31
+ recommended: boolean;
32
+ automation: SwapActionAutomation;
33
+ /** Human-readable why — for UI copy and worker logs. */
34
+ reason: string;
35
+ /**
36
+ * Why the action can't run yet. Absent ⟺ the action is runnable now; present
37
+ * ⟺ it's a valid-but-blocked option the UI can surface (e.g. "refund after the
38
+ * timelock"). The recommended action is always runnable (no `blockedBy`).
39
+ */
40
+ blockedBy?: BlockedBy;
41
+ };
42
+ /** Strongly-typed evidence, only where an action needs it. */
43
+ type CctpClaimEvidence = {
44
+ burnTxHash: `0x${string}`;
45
+ attestationAvailable: boolean;
46
+ };
47
+ type WaitAction = SwapActionBase & {
48
+ id: "wait";
49
+ };
50
+ type FundAction = SwapActionBase & {
51
+ id: "fund";
52
+ };
53
+ type ClaimAction = SwapActionBase & {
54
+ id: "claim";
55
+ };
56
+ type RefundCollaborativeAction = SwapActionBase & {
57
+ id: "refund_collaborative";
58
+ };
59
+ /** Reclaim the deposit yourself once the timelock passes — venue-agnostic (BTC L1, EVM, or Arkade). */
60
+ type RefundUnilateralAction = SwapActionBase & {
61
+ id: "refund_unilateral";
62
+ };
63
+ type RecoverCctpClaimAction = SwapActionBase & {
64
+ id: "recover_cctp_claim";
65
+ evidence: CctpClaimEvidence;
66
+ };
67
+ type NoneAction = SwapActionBase & {
68
+ id: "none";
69
+ };
70
+ /** A single next-action option. Discriminated union on `id`. */
71
+ type SwapAction = WaitAction | FundAction | ClaimAction | RefundCollaborativeAction | RefundUnilateralAction | RecoverCctpClaimAction | NoneAction;
72
+ /** Every valid action id — derived from the union so it can't drift. */
73
+ type SwapActionId = SwapAction["id"];
74
+ /** The resolver's result: what happened is `status`; what to do is here. */
75
+ type SwapActions = {
76
+ /** id of the recommended action, if any; convenience pointer into `actions`. */
77
+ recommended?: SwapActionId;
78
+ actions: SwapAction[];
79
+ };
80
+ /**
81
+ * The pure input to {@link deriveSwapActions}: a plain, fully-resolved snapshot.
82
+ *
83
+ * The resolver reads nothing ambient — `now` is injected (never `Date.now()`),
84
+ * and every environment fact is a field here. Grows as more states are modelled;
85
+ * unknown/omitted live facts make the resolver return a provisional or blocked
86
+ * action rather than reaching out for them.
87
+ */
88
+ type SwapActionInput = {
89
+ /**
90
+ * The swap's lifecycle status. Trusted source is the chain-derived status from
91
+ * {@link deriveSwapStatus}; the server's status is only a hint the wrapper
92
+ * cross-checks against it.
93
+ */
94
+ status: SwapStatus;
95
+ /**
96
+ * Current time (ms) on the chain holding the CLIENT's HTLC — the chain's own
97
+ * clock used to evaluate its timelock, NOT wall-clock: MTP (median-time-past)
98
+ * for Bitcoin/Arkade, block.timestamp for EVM, invoice-clock for Lightning.
99
+ * Injected so the resolver stays deterministic. (A wall-clock approximation
100
+ * works for a UI hint, but the chain's clock is what actually gates the swap.)
101
+ */
102
+ clientChainNow: number;
103
+ /** As {@link clientChainNow}, for the chain holding the SERVER's HTLC. */
104
+ serverChainNow: number;
105
+ /**
106
+ * Timelock (ms) on the client's HTLC, evaluated against {@link clientChainNow}.
107
+ * Bounds funding (pending: fund before it) and unlocks the unilateral refund
108
+ * (clientfunded: refund after it) — the same locktime, two readings.
109
+ */
110
+ clientRefundLocktime: number;
111
+ /**
112
+ * Timelock (ms) on the server's HTLC, evaluated against {@link serverChainNow}
113
+ * — the client's deadline to claim. Past it the server may reclaim its funds,
114
+ * so claiming becomes a race.
115
+ */
116
+ serverRefundLocktime: number;
117
+ /**
118
+ * Whether the client's deposit is an on-chain HTLC it funds itself (the
119
+ * default). `false` for pay-on-Lightning swaps (`lightning_to_*`): there the
120
+ * client "funds" by paying a Lightning invoice off-chain, so there is nothing
121
+ * for us to recommend funding and nothing to unilaterally refund — the
122
+ * Lightning wallet auto-unwinds a hold invoice that never settles. When
123
+ * `false`, `pending` resolves to `wait` (not `fund`) and no refund is offered.
124
+ */
125
+ clientFunds?: boolean;
126
+ };
127
+ /** On-chain state of one HTLC in a swap. */
128
+ type HtlcObservation = "absent" | "mempool" | "confirmed" | "invalid" | "spent_claim" | "spent_refund";
129
+ /**
130
+ * On-chain facts about a swap's two HTLCs, from the client's own observation (no
131
+ * server trust). `clientHtlc` is the HTLC the client funded; `serverHtlc` the one
132
+ * the server funded and the client claims.
133
+ *
134
+ * Spend semantics differ per side: on `clientHtlc`, `spent_claim` = the server
135
+ * swept it with the revealed preimage and `spent_refund` = the client reclaimed
136
+ * its deposit; on `serverHtlc`, `spent_claim` = the client redeemed and
137
+ * `spent_refund` = the server reclaimed its funds.
138
+ *
139
+ * One leg may be `undefined` for Lightning swaps. These are Boltz submarine swaps
140
+ * between an Arkade VHTLC and Lightning, so the "Lightning side" is itself realized
141
+ * on-chain as an Arkade VHTLC (`boltz_vhtlc_address`, or reconstructed for the EVM
142
+ * directions) — except `lightning_to_arkade`, whose Boltz reverse swap outputs the
143
+ * very VHTLC the client claims. That Boltz-side VHTLC is observable but not tracked
144
+ * yet: the client never funds or claims it, so it doesn't change the next action.
145
+ * We watch only the single leg the client funds or claims:
146
+ * - `serverHtlc` undefined (receive-on-LN, `*_to_lightning`): the client funds
147
+ * the on-chain leg and receives via Lightning; the server sweeping the
148
+ * client's leg (`spent_claim`) is the completion signal.
149
+ * - `clientHtlc` undefined (pay-on-LN, `lightning_to_*`): the client pays a
150
+ * Lightning invoice and claims the on-chain leg; that claim completes the swap.
151
+ */
152
+ type SwapObservations = {
153
+ clientHtlc?: HtlcObservation;
154
+ serverHtlc?: HtlcObservation;
155
+ };
156
+
157
+ declare function deriveSwapActions(input: SwapActionInput): SwapActions;
158
+
159
+ /**
160
+ * Derive a swap's lifecycle status from on-chain observations alone — the
161
+ * trusted, server-independent source of truth.
162
+ *
163
+ * Pure: `deriveSwapStatus(observations) -> SwapStatus | undefined`. The wrapper
164
+ * gathers the {@link SwapObservations} from chain (the server's status is only a
165
+ * hint used to fetch efficiently), then cross-checks: if this disagrees with the
166
+ * server, act on this. If the server is unavailable, derive from the local
167
+ * recovery bundle's HTLC addresses — recovery still works.
168
+ *
169
+ * Returns `undefined` for contradictory/indeterminate observations (e.g. the
170
+ * server's HTLC swept-by-claim while the client's HTLC was never involved — the
171
+ * server can't hold the preimage before the client reveals it).
172
+ *
173
+ * Scope: this maps *settled* HTLC state to a status. Time- or param-dependent
174
+ * refinements aren't derivable from HTLC state alone and are layered on
175
+ * afterwards (or collapse into the state here):
176
+ * - `expired` / `clientfundedtoolate`: `pending`/`clientfunded` + a clock check.
177
+ * - `clientinvalidfunded`: needs the expected HTLC params, not just "confirmed".
178
+ * - `serverwontfund`: a server intention, invisible on-chain — acts like
179
+ * `clientfunded` (refund after the timelock), so it never needs deriving.
180
+ * - `clientredeeming`: an in-flight (mempool) claim — a transient, not modelled
181
+ * from settled state here.
182
+ */
183
+
184
+ declare function deriveSwapStatus(obs: SwapObservations): SwapStatus | undefined;
185
+
186
+ /**
187
+ * The contract-monitoring layer — modeled on @arkade-os/sdk's
188
+ * `ContractManager`.
189
+ *
190
+ * A {@link ContractManager} is the per-ledger, stateful I/O layer that watches a
191
+ * set of HTLCs and maps their on-chain state to {@link HtlcObservation}. The pure
192
+ * pipeline (`deriveSwapStatus` → `deriveSwapActions`) consumes the observations
193
+ * it produces; a `SwapTracker` (built later) combines the two ledgers of each
194
+ * swap and notifies subscribers of the next action.
195
+ */
196
+
197
+ /** Ledgers a swap HTLC can live on. */
198
+ type Ledger = "arkade" | "bitcoin" | "evm" | "lightning";
199
+ /**
200
+ * Identifies and parameterises one HTLC on its ledger — enough for a
201
+ * {@link ContractManager} to observe it. Sourced from the swap's recovery
202
+ * bundle. Discriminated by `ledger`.
203
+ */
204
+ type HtlcRef = {
205
+ ledger: "arkade";
206
+ /** VHTLC pkScript (hex) — the contract's unique id. */
207
+ script: string;
208
+ address: string;
209
+ /** SHA256 of the preimage, to tell a claim spend from a refund spend. */
210
+ preimageHash: string;
211
+ /**
212
+ * Expected funding amount in sats. A funding below this is `invalid` (not on
213
+ * the swap's terms) rather than `confirmed` — so the client never claims a
214
+ * server leg the server short-funded.
215
+ */
216
+ expectedSats: number;
217
+ /**
218
+ * Serialized VHTLC parameters (`@arkade-os/sdk`'s `Contract.params`) — the
219
+ * sender/receiver/server keys, preimage hash, and timelocks needed to
220
+ * register the contract for watching. Opaque here: the Client serializes
221
+ * it from the swap's recovery bundle so this layer stays VHTLC-agnostic.
222
+ */
223
+ params: Record<string, string>;
224
+ } | {
225
+ ledger: "bitcoin";
226
+ /** HTLC witness-script address — the contract's unique id. */
227
+ address: string;
228
+ preimageHash: string;
229
+ /** Expected funding amount in sats; a funding below this is `invalid`. */
230
+ expectedSats: number;
231
+ } | {
232
+ ledger: "evm";
233
+ chainId: number;
234
+ /** The HTLCErc20 contract holding this leg — where its events are emitted. */
235
+ htlc: `0x${string}`;
236
+ /**
237
+ * SHA256 preimage hash (`0x`-prefixed) — the indexed topic that identifies
238
+ * this swap's HTLC in the contract's `SwapCreated`/`SwapRedeemed`/
239
+ * `SwapRefunded` events. Serves as the contract's unique id here.
240
+ */
241
+ preimageHash: `0x${string}`;
242
+ /**
243
+ * The address that can claim this HTLC — the second indexed topic used to
244
+ * filter `SwapCreated`, so only the HTLC actually claimable on the swap's
245
+ * terms is observed (an HTLC with our hash but a different recipient is
246
+ * never seen). Client's EVM address for a server-funded leg; the server's
247
+ * for the client's own leg.
248
+ */
249
+ claimAddress: `0x${string}`;
250
+ /**
251
+ * Expected locked amount (token's smallest unit). A `SwapCreated` below this
252
+ * → `invalid`, so the client never claims a short-funded leg.
253
+ */
254
+ expectedAmount: bigint;
255
+ /** Expected token address; the funding is `invalid` if it locks another token. */
256
+ expectedToken?: `0x${string}`;
257
+ } | {
258
+ ledger: "lightning";
259
+ /** Payment hash — the contract's unique id. */
260
+ paymentHash: string;
261
+ };
262
+ /** Stable, cross-ledger unique key for an {@link HtlcRef}. */
263
+ declare function htlcKey(ref: HtlcRef): string;
264
+ /**
265
+ * Per-ledger contract monitor. Implementations keep an internal, event-driven
266
+ * cache: `register` seeds it, `onEvent` pushes changes, `getState` reads it
267
+ * synchronously, `dispose` tears down subscriptions/loops.
268
+ *
269
+ * One manager exists per ledger actually in use and watches every tracked HTLC
270
+ * on that ledger at once (one connection, not one per HTLC).
271
+ */
272
+ interface ContractManager {
273
+ /** The ledger this manager observes. */
274
+ readonly ledger: Ledger;
275
+ /** Start tracking an HTLC (idempotent); seeds its state from the ledger. */
276
+ register(ref: HtlcRef): Promise<void>;
277
+ /** Stop tracking an HTLC. */
278
+ unregister(ref: HtlcRef): Promise<void>;
279
+ /**
280
+ * Current known observation for a tracked HTLC, or `undefined` if it isn't
281
+ * tracked or its state isn't known yet.
282
+ */
283
+ getState(ref: HtlcRef): HtlcObservation | undefined;
284
+ /**
285
+ * The current clock (ms) for evaluating this HTLC's timelock — MTP for
286
+ * Bitcoin/Arkade, `block.timestamp` for EVM. Ref-scoped because one ledger can
287
+ * span several chains with independent clocks (EVM chains); managers whose
288
+ * ledger has a single clock (Arkade) ignore the ref. `undefined` until known.
289
+ */
290
+ chainNow(ref: HtlcRef): number | undefined;
291
+ /** Subscribe to observation changes for any tracked HTLC. Returns unsubscribe. */
292
+ onEvent(cb: (ref: HtlcRef, state: HtlcObservation) => void): () => void;
293
+ /** Force a reconcile from the ledger. */
294
+ refresh(): Promise<void>;
295
+ /** Tear down subscriptions and background work. */
296
+ dispose(): void;
297
+ }
298
+
299
+ /**
300
+ * A swap the tracker watches: its HTLC legs + refund locktimes (from the recovery
301
+ * bundle). Chain↔chain swaps have both legs; Lightning swaps have exactly one
302
+ * on-chain leg (the other side is an off-chain Lightning payment) — see
303
+ * {@link SwapObservations}.
304
+ */
305
+ type TrackedSwap = {
306
+ swapId: string;
307
+ clientHtlc?: HtlcRef;
308
+ serverHtlc?: HtlcRef;
309
+ clientRefundLocktime: number;
310
+ serverRefundLocktime: number;
311
+ };
312
+ type ActionSubscriber = (swapId: string, actions: SwapActions) => void;
313
+ type SwapTrackerOptions = {
314
+ /**
315
+ * How often (ms) to re-poll every manager to advance clocks and reconcile
316
+ * observations. Needed because some ledgers (Arkade) have no event push, so
317
+ * state only moves on a poll. `0` disables the timer (tests drive `refresh`).
318
+ */
319
+ refreshIntervalMs?: number;
320
+ };
321
+ declare class SwapTracker {
322
+ #private;
323
+ constructor(managers: Map<Ledger, ContractManager>, options?: SwapTrackerOptions);
324
+ /** Register each swap's on-chain leg(s), subscribe to manager events, and seed state. */
325
+ startTracking(swaps: TrackedSwap[]): Promise<void>;
326
+ /** Notify `cb` of the current action for each tracked swap, then on every change. */
327
+ subscribeToActions(cb: ActionSubscriber): () => void;
328
+ /**
329
+ * Stop tracking: unregister every still-tracked leg (releasing its manager's
330
+ * watch — e.g. the EVM per-chain block watch that only `unregister` tears down),
331
+ * drop the poll timer, and detach event listeners + subscribers. Mirrors
332
+ * `startTracking`'s `register`, so no manager keeps watching a stopped tracker's
333
+ * swaps. The managers themselves are not owned here, so they are unregistered but
334
+ * never disposed.
335
+ */
336
+ stop(): void;
337
+ }
338
+
339
+ /**
340
+ * @satora/swap — the Satora swap client.
341
+ *
342
+ * A standalone `Client` with the same public surface as the legacy
343
+ * `@lendasat/lendaswap-sdk-pure` client, so it is a drop-in replacement. For
344
+ * now every legacy method is forwarded to an internally-owned legacy client
345
+ * instance (see the `@deprecated` delegators below). New Satora-native features
346
+ * are added directly on this class, and
347
+ * individual delegators get replaced with native implementations over time.
348
+ */
349
+
350
+ /** How the client should set up observe-mode tracking. */
351
+ type TrackingConfig = {
352
+ /** Whether tracking is enabled at all (default on; `withoutTracking()` clears). */
353
+ enabled: boolean;
354
+ /** Explicit per-ledger managers, bypassing auto-construction (advanced/testing). */
355
+ managers?: Map<Ledger, ContractManager>;
356
+ /** Ark server URL override; defaults to the mainnet server when unset. */
357
+ arkadeServerUrl?: string;
358
+ /** Per-chain EVM RPC overrides; the EVM manager is auto-built either way. */
359
+ evmRpcUrls?: Record<number, string>;
360
+ /** Esplora REST URL override for the Bitcoin manager; defaults to mainnet mempool.space. */
361
+ esploraUrl?: string;
362
+ /** Poll interval (ms) for advancing observations/clocks; defaults to 5s. */
363
+ refreshIntervalMs?: number;
364
+ };
365
+ declare class Client {
366
+ #private;
367
+ /**
368
+ * Creates a new Client instance.
369
+ *
370
+ * Prefer {@link Client.builder} for new code.
371
+ */
372
+ constructor(...args: ConstructorParameters<typeof Client$1>);
373
+ /** @internal Wrap an already-built legacy client, optionally with tracking. */
374
+ constructor(legacy: Client$1, tracking?: TrackingConfig);
375
+ /** Start building a {@link Client}. */
376
+ static builder(): ClientBuilder;
377
+ /** Escape hatch: the underlying legacy client, during migration. */
378
+ get legacy(): Client$1;
379
+ /** Delegated to the legacy client (migration checkpoint). */
380
+ get api(): Client$1["api"];
381
+ /** Delegated to the legacy client (migration checkpoint). */
382
+ get baseUrl(): Client$1["baseUrl"];
383
+ /** Delegated to the legacy client (migration checkpoint). */
384
+ get cctpInbound(): Client$1["cctpInbound"];
385
+ /** Delegated to the legacy client (migration checkpoint). */
386
+ get swapStorage(): Client$1["swapStorage"];
387
+ /** Delegated to the legacy client (migration checkpoint). */
388
+ subscribeToSwaps(...args: Parameters<Client$1["subscribeToSwaps"]>): ReturnType<Client$1["subscribeToSwaps"]>;
389
+ /** Delegated to the legacy client (migration checkpoint). */
390
+ unsubscribeFromSwaps(...args: Parameters<Client$1["unsubscribeFromSwaps"]>): ReturnType<Client$1["unsubscribeFromSwaps"]>;
391
+ /** Delegated to the legacy client (migration checkpoint). */
392
+ closeSwapStatusSocket(...args: Parameters<Client$1["closeSwapStatusSocket"]>): ReturnType<Client$1["closeSwapStatusSocket"]>;
393
+ /** Delegated to the legacy client (migration checkpoint). */
394
+ getMnemonic(...args: Parameters<Client$1["getMnemonic"]>): ReturnType<Client$1["getMnemonic"]>;
395
+ /** Delegated to the legacy client (migration checkpoint). */
396
+ loadMnemonic(...args: Parameters<Client$1["loadMnemonic"]>): ReturnType<Client$1["loadMnemonic"]>;
397
+ /** Delegated to the legacy client (migration checkpoint). */
398
+ getNostrKeyHex(...args: Parameters<Client$1["getNostrKeyHex"]>): ReturnType<Client$1["getNostrKeyHex"]>;
399
+ /** Delegated to the legacy client (migration checkpoint). */
400
+ getUserIdXpub(...args: Parameters<Client$1["getUserIdXpub"]>): ReturnType<Client$1["getUserIdXpub"]>;
401
+ /** Delegated to the legacy client (migration checkpoint). */
402
+ deriveSwapParams(...args: Parameters<Client$1["deriveSwapParams"]>): ReturnType<Client$1["deriveSwapParams"]>;
403
+ /** Delegated to the legacy client (migration checkpoint). */
404
+ deriveSwapParamsAtIndex(...args: Parameters<Client$1["deriveSwapParamsAtIndex"]>): ReturnType<Client$1["deriveSwapParamsAtIndex"]>;
405
+ /** Delegated to the legacy client (migration checkpoint). */
406
+ getEvmAddress(...args: Parameters<Client$1["getEvmAddress"]>): ReturnType<Client$1["getEvmAddress"]>;
407
+ /** Delegated to the legacy client (migration checkpoint). */
408
+ getKeyIndex(...args: Parameters<Client$1["getKeyIndex"]>): ReturnType<Client$1["getKeyIndex"]>;
409
+ /** Delegated to the legacy client (migration checkpoint). */
410
+ setKeyIndex(...args: Parameters<Client$1["setKeyIndex"]>): ReturnType<Client$1["setKeyIndex"]>;
411
+ /** Delegated to the legacy client (migration checkpoint). */
412
+ getStatus(...args: Parameters<Client$1["getStatus"]>): ReturnType<Client$1["getStatus"]>;
413
+ /** Delegated to the legacy client (migration checkpoint). */
414
+ healthCheck(...args: Parameters<Client$1["healthCheck"]>): ReturnType<Client$1["healthCheck"]>;
415
+ /** Delegated to the legacy client (migration checkpoint). */
416
+ getVersion(...args: Parameters<Client$1["getVersion"]>): ReturnType<Client$1["getVersion"]>;
417
+ /** Delegated to the legacy client (migration checkpoint). */
418
+ getSupportAgents(...args: Parameters<Client$1["getSupportAgents"]>): ReturnType<Client$1["getSupportAgents"]>;
419
+ /** Delegated to the legacy client (migration checkpoint). */
420
+ getMtp(...args: Parameters<Client$1["getMtp"]>): ReturnType<Client$1["getMtp"]>;
421
+ /** Delegated to the legacy client (migration checkpoint). */
422
+ getTokens(...args: Parameters<Client$1["getTokens"]>): ReturnType<Client$1["getTokens"]>;
423
+ /** Delegated to the legacy client (migration checkpoint). */
424
+ getSwapPairs(...args: Parameters<Client$1["getSwapPairs"]>): ReturnType<Client$1["getSwapPairs"]>;
425
+ /** Delegated to the legacy client (migration checkpoint). */
426
+ getChainConfig(...args: Parameters<Client$1["getChainConfig"]>): ReturnType<Client$1["getChainConfig"]>;
427
+ /** Delegated to the legacy client (migration checkpoint). */
428
+ getReferralFee(...args: Parameters<Client$1["getReferralFee"]>): ReturnType<Client$1["getReferralFee"]>;
429
+ /** Delegated to the legacy client (migration checkpoint). */
430
+ getNetworkFees(...args: Parameters<Client$1["getNetworkFees"]>): ReturnType<Client$1["getNetworkFees"]>;
431
+ /** Delegated to the legacy client (migration checkpoint). */
432
+ getDexQuote(...args: Parameters<Client$1["getDexQuote"]>): ReturnType<Client$1["getDexQuote"]>;
433
+ /** Delegated to the legacy client (migration checkpoint). */
434
+ composeQuote(...args: Parameters<Client$1["composeQuote"]>): ReturnType<Client$1["composeQuote"]>;
435
+ /** Delegated to the legacy client (migration checkpoint). */
436
+ getQuote(...args: Parameters<Client$1["getQuote"]>): ReturnType<Client$1["getQuote"]>;
437
+ /** Delegated to the legacy client (migration checkpoint). */
438
+ getSwap(...args: Parameters<Client$1["getSwap"]>): ReturnType<Client$1["getSwap"]>;
439
+ /** Delegated to the legacy client (migration checkpoint). */
440
+ getBulkStatus(...args: Parameters<Client$1["getBulkStatus"]>): ReturnType<Client$1["getBulkStatus"]>;
441
+ /** Delegated to the legacy client (migration checkpoint). */
442
+ getStoredSwap(...args: Parameters<Client$1["getStoredSwap"]>): ReturnType<Client$1["getStoredSwap"]>;
443
+ /** Delegated to the legacy client (migration checkpoint). */
444
+ listAllSwaps(...args: Parameters<Client$1["listAllSwaps"]>): ReturnType<Client$1["listAllSwaps"]>;
445
+ /** Delegated to the legacy client (migration checkpoint). */
446
+ deleteSwap(...args: Parameters<Client$1["deleteSwap"]>): ReturnType<Client$1["deleteSwap"]>;
447
+ /** Delegated to the legacy client (migration checkpoint). */
448
+ clearSwapStorage(...args: Parameters<Client$1["clearSwapStorage"]>): ReturnType<Client$1["clearSwapStorage"]>;
449
+ /** Delegated to the legacy client (migration checkpoint). */
450
+ recoverSwaps(...args: Parameters<Client$1["recoverSwaps"]>): ReturnType<Client$1["recoverSwaps"]>;
451
+ /** Delegated to the legacy client (migration checkpoint). */
452
+ recoverAllSwaps(...args: Parameters<Client$1["recoverAllSwaps"]>): ReturnType<Client$1["recoverAllSwaps"]>;
453
+ /** Delegated to the legacy client (migration checkpoint). */
454
+ amountsForSwap(...args: Parameters<Client$1["amountsForSwap"]>): ReturnType<Client$1["amountsForSwap"]>;
455
+ /** Delegated to the legacy client (migration checkpoint). */
456
+ claim(...args: Parameters<Client$1["claim"]>): ReturnType<Client$1["claim"]>;
457
+ /** Delegated to the legacy client (migration checkpoint). */
458
+ claimViaGasless(...args: Parameters<Client$1["claimViaGasless"]>): ReturnType<Client$1["claimViaGasless"]>;
459
+ /** Delegated to the legacy client (migration checkpoint). */
460
+ claimArkade(...args: Parameters<Client$1["claimArkade"]>): ReturnType<Client$1["claimArkade"]>;
461
+ /** Delegated to the legacy client (migration checkpoint). */
462
+ continueArkadeClaimSwap(...args: Parameters<Client$1["continueArkadeClaimSwap"]>): ReturnType<Client$1["continueArkadeClaimSwap"]>;
463
+ /** Delegated to the legacy client (migration checkpoint). */
464
+ refundSwap(...args: Parameters<Client$1["refundSwap"]>): ReturnType<Client$1["refundSwap"]>;
465
+ /** Delegated to the legacy client (migration checkpoint). */
466
+ getCollabRefundEvmParams(...args: Parameters<Client$1["getCollabRefundEvmParams"]>): ReturnType<Client$1["getCollabRefundEvmParams"]>;
467
+ /** Delegated to the legacy client (migration checkpoint). */
468
+ buildCollabRefundEvmTypedData(...args: Parameters<Client$1["buildCollabRefundEvmTypedData"]>): ReturnType<Client$1["buildCollabRefundEvmTypedData"]>;
469
+ /** Delegated to the legacy client (migration checkpoint). */
470
+ collabRefundEvmSwap(...args: Parameters<Client$1["collabRefundEvmSwap"]>): ReturnType<Client$1["collabRefundEvmSwap"]>;
471
+ /** Delegated to the legacy client (migration checkpoint). */
472
+ submitCollabRefundEvm(...args: Parameters<Client$1["submitCollabRefundEvm"]>): ReturnType<Client$1["submitCollabRefundEvm"]>;
473
+ /** Delegated to the legacy client (migration checkpoint). */
474
+ createSwap(...args: Parameters<Client$1["createSwap"]>): ReturnType<Client$1["createSwap"]>;
475
+ /** Delegated to the legacy client (migration checkpoint). */
476
+ createArkadeToEvmSwapGeneric(...args: Parameters<Client$1["createArkadeToEvmSwapGeneric"]>): ReturnType<Client$1["createArkadeToEvmSwapGeneric"]>;
477
+ /** Delegated to the legacy client (migration checkpoint). */
478
+ createLightningToEvmSwapGeneric(...args: Parameters<Client$1["createLightningToEvmSwapGeneric"]>): ReturnType<Client$1["createLightningToEvmSwapGeneric"]>;
479
+ /** Delegated to the legacy client (migration checkpoint). */
480
+ createBitcoinToEvmSwap(...args: Parameters<Client$1["createBitcoinToEvmSwap"]>): ReturnType<Client$1["createBitcoinToEvmSwap"]>;
481
+ /** Delegated to the legacy client (migration checkpoint). */
482
+ createBitcoinToArkadeSwap(...args: Parameters<Client$1["createBitcoinToArkadeSwap"]>): ReturnType<Client$1["createBitcoinToArkadeSwap"]>;
483
+ /** Delegated to the legacy client (migration checkpoint). */
484
+ createLightningToArkadeSwap(...args: Parameters<Client$1["createLightningToArkadeSwap"]>): ReturnType<Client$1["createLightningToArkadeSwap"]>;
485
+ /** Delegated to the legacy client (migration checkpoint). */
486
+ createArkadeToLightningSwap(...args: Parameters<Client$1["createArkadeToLightningSwap"]>): ReturnType<Client$1["createArkadeToLightningSwap"]>;
487
+ /** Delegated to the legacy client (migration checkpoint). */
488
+ getArkadeToLightningQuote(...args: Parameters<Client$1["getArkadeToLightningQuote"]>): ReturnType<Client$1["getArkadeToLightningQuote"]>;
489
+ /** Delegated to the legacy client (migration checkpoint). */
490
+ retryArkadeToLightningSwap(...args: Parameters<Client$1["retryArkadeToLightningSwap"]>): ReturnType<Client$1["retryArkadeToLightningSwap"]>;
491
+ /** Delegated to the legacy client (migration checkpoint). */
492
+ createEvmToArkadeSwapGeneric(...args: Parameters<Client$1["createEvmToArkadeSwapGeneric"]>): ReturnType<Client$1["createEvmToArkadeSwapGeneric"]>;
493
+ /** Delegated to the legacy client (migration checkpoint). */
494
+ createEvmToBitcoinSwap(...args: Parameters<Client$1["createEvmToBitcoinSwap"]>): ReturnType<Client$1["createEvmToBitcoinSwap"]>;
495
+ /** Delegated to the legacy client (migration checkpoint). */
496
+ createEvmToLightningSwapGeneric(...args: Parameters<Client$1["createEvmToLightningSwapGeneric"]>): ReturnType<Client$1["createEvmToLightningSwapGeneric"]>;
497
+ /** Delegated to the legacy client (migration checkpoint). */
498
+ getCoordinatorFundingCallDataPermit2(...args: Parameters<Client$1["getCoordinatorFundingCallDataPermit2"]>): ReturnType<Client$1["getCoordinatorFundingCallDataPermit2"]>;
499
+ /** Delegated to the legacy client (migration checkpoint). */
500
+ getPermit2FundingParamsUnsigned(...args: Parameters<Client$1["getPermit2FundingParamsUnsigned"]>): ReturnType<Client$1["getPermit2FundingParamsUnsigned"]>;
501
+ /** Delegated to the legacy client (migration checkpoint). */
502
+ fundSwap(...args: Parameters<Client$1["fundSwap"]>): ReturnType<Client$1["fundSwap"]>;
503
+ /** Delegated to the legacy client (migration checkpoint). */
504
+ refundEvmWithSigner(...args: Parameters<Client$1["refundEvmWithSigner"]>): ReturnType<Client$1["refundEvmWithSigner"]>;
505
+ /** Delegated to the legacy client (migration checkpoint). */
506
+ collabRefundEvmWithSigner(...args: Parameters<Client$1["collabRefundEvmWithSigner"]>): ReturnType<Client$1["collabRefundEvmWithSigner"]>;
507
+ /** Delegated to the legacy client (migration checkpoint). */
508
+ fundSwapGasless(...args: Parameters<Client$1["fundSwapGasless"]>): ReturnType<Client$1["fundSwapGasless"]>;
509
+ /** Delegated to the legacy client (migration checkpoint). */
510
+ getSwapDepositorKey(...args: Parameters<Client$1["getSwapDepositorKey"]>): ReturnType<Client$1["getSwapDepositorKey"]>;
511
+ /** Delegated to the legacy client (migration checkpoint). */
512
+ getEvmDepositorKey(...args: Parameters<Client$1["getEvmDepositorKey"]>): ReturnType<Client$1["getEvmDepositorKey"]>;
513
+ /** Delegated to the legacy client (migration checkpoint). */
514
+ recoverGaslessFunds(...args: Parameters<Client$1["recoverGaslessFunds"]>): ReturnType<Client$1["recoverGaslessFunds"]>;
515
+ /** Delegated to the legacy client (migration checkpoint). */
516
+ hasReceivedVtxo(...args: Parameters<Client$1["hasReceivedVtxo"]>): ReturnType<Client$1["hasReceivedVtxo"]>;
517
+ /**
518
+ * Start observing the user's active swaps and deriving each one's next action.
519
+ *
520
+ * Loads stored swaps, maps the ones whose ledgers are observable to
521
+ * {@link TrackedSwap}s, and runs the per-ledger monitors. Idempotent. Requires
522
+ * the client to have been built with {@link ClientBuilder.withTracking}.
523
+ * Subscribe with {@link subscribeToActions}; release with
524
+ * {@link stopTracking}.
525
+ */
526
+ startTracking(): Promise<void>;
527
+ /**
528
+ * Subscribe to next-action updates: `cb` fires with the current action for each
529
+ * tracked swap immediately, then on every change. Call after
530
+ * {@link startTracking}. Returns an unsubscribe fn.
531
+ */
532
+ subscribeToActions(cb: ActionSubscriber): () => void;
533
+ /** Stop tracking and drop subscribers. The managers themselves are not disposed. */
534
+ stopTracking(): void;
535
+ }
536
+ /**
537
+ * Builds a {@link Client}. Mirrors the legacy `ClientBuilder` fluent surface and
538
+ * constructs the legacy client internally, then wraps it.
539
+ */
540
+ declare class ClientBuilder {
541
+ #private;
542
+ /**
543
+ * Override the EVM JSON-RPC endpoint per chainId. Optional — tracking uses
544
+ * tested public defaults otherwise; an override is tried first, with the
545
+ * defaults kept as fallbacks.
546
+ */
547
+ withEvmRpcUrls(urls: Record<number, string>): this;
548
+ /** Turn observe-mode tracking off. */
549
+ withoutTracking(): this;
550
+ /**
551
+ * Advanced: supply per-ledger {@link ContractManager}s explicitly instead of
552
+ * letting the client auto-build them from config (useful for tests or custom
553
+ * chain sources).
554
+ */
555
+ withContractManagers(managers: Map<Ledger, ContractManager>): this;
556
+ withBaseUrl(...args: Parameters<ClientBuilder$1["withBaseUrl"]>): this;
557
+ withReferralCode(...args: Parameters<ClientBuilder$1["withReferralCode"]>): this;
558
+ withOrgCode(...args: Parameters<ClientBuilder$1["withOrgCode"]>): this;
559
+ withDefaultHeaders(...args: Parameters<ClientBuilder$1["withDefaultHeaders"]>): this;
560
+ /**
561
+ * Override the Esplora REST URL. Optional for tracking — the Bitcoin manager
562
+ * otherwise defaults to mainnet mempool.space; set this for a dev/regtest node.
563
+ */
564
+ withEsploraUrl(url: string): this;
565
+ /**
566
+ * Override the Ark server URL. Optional for tracking — it otherwise defaults to
567
+ * the mainnet server; set this to track a non-mainnet (dev/signet) deployment.
568
+ */
569
+ withArkadeServerUrl(url: string): this;
570
+ withSignerStorage(...args: Parameters<ClientBuilder$1["withSignerStorage"]>): this;
571
+ withSwapStorage(...args: Parameters<ClientBuilder$1["withSwapStorage"]>): this;
572
+ withMnemonic(...args: Parameters<ClientBuilder$1["withMnemonic"]>): this;
573
+ withXprv(...args: Parameters<ClientBuilder$1["withXprv"]>): this;
574
+ withAa(...args: Parameters<ClientBuilder$1["withAa"]>): this;
575
+ withLogger(...args: Parameters<ClientBuilder$1["withLogger"]>): this;
576
+ withLogLevel(...args: Parameters<ClientBuilder$1["withLogLevel"]>): this;
577
+ build(): Promise<Client>;
578
+ }
579
+
580
+ /** The slice of `@arkade-os/sdk`'s indexer the spend classifier needs. */
581
+ type VirtualTxSource = {
582
+ getVirtualTxs(txids: string[]): Promise<{
583
+ txs: string[];
584
+ }>;
585
+ };
586
+
587
+ /**
588
+ * The Arkade {@link ContractManager} — the stateful I/O adapter that observes a
589
+ * swap's VHTLC by polling the Ark indexer.
590
+ *
591
+ * We deliberately do NOT use `@arkade-os/sdk`'s `ContractManager`: its vtxo
592
+ * annotation calls `script.forfeit()` on every contract, but a VHTLC script has
593
+ * no `forfeit()` leaf (it exposes `claim()`/`refund()`), so watching a VHTLC
594
+ * through it throws. Instead we read vtxos directly by pkScript — exactly what
595
+ * the legacy SDK's claim/refund paths do — and map them with the pure helpers in
596
+ * `./arkade.js`.
597
+ *
598
+ * There is no event push here, so observations advance when {@link refresh} runs;
599
+ * the SwapTracker drives that (initial prime + periodic poll).
600
+ */
601
+
602
+ /** The Ark indexer surface the observer needs (RestIndexerProvider satisfies it). */
603
+ type ArkadeIndexer = VirtualTxSource & {
604
+ getVtxos(opts: {
605
+ scripts: string[];
606
+ spendableOnly?: boolean;
607
+ }): Promise<{
608
+ vtxos: VirtualCoin[];
609
+ }>;
610
+ };
611
+ type ArkadeCreateConfig = {
612
+ /** Ark server base URL — used for the indexer. */
613
+ serverUrl: string;
614
+ /**
615
+ * The current Bitcoin MTP (ms) for evaluating VHTLC timelocks. Typically
616
+ * `async () => (await client.getMtp()).mtp * 1000`.
617
+ */
618
+ chainTime?: () => Promise<number>;
619
+ };
620
+ type ArkadeContractManagerDeps = {
621
+ indexer: ArkadeIndexer;
622
+ /**
623
+ * The current Bitcoin MTP (ms) — arkade CLTV timelocks are evaluated against
624
+ * Bitcoin's clock, not the Ark server's. Optional: until wired, `chainNow()`
625
+ * reports `undefined` and the tracker holds swaps as provisional.
626
+ */
627
+ chainTime?: () => Promise<number>;
628
+ };
629
+ declare class ArkadeContractManager implements ContractManager {
630
+ #private;
631
+ readonly ledger: Ledger;
632
+ private constructor();
633
+ static fromDeps(deps: ArkadeContractManagerDeps): ArkadeContractManager;
634
+ /** Construct a manager backed by a `RestIndexerProvider` over the Ark server. */
635
+ static create(config: ArkadeCreateConfig): Promise<ArkadeContractManager>;
636
+ register(ref: HtlcRef): Promise<void>;
637
+ unregister(ref: HtlcRef): Promise<void>;
638
+ getState(ref: HtlcRef): HtlcObservation | undefined;
639
+ chainNow(_ref: HtlcRef): number | undefined;
640
+ onEvent(cb: (ref: HtlcRef, state: HtlcObservation) => void): () => void;
641
+ refresh(): Promise<void>;
642
+ dispose(): void;
643
+ /** The verified preimage recovered from a claim spend, if one was seen. */
644
+ getPreimage(ref: HtlcRef): Uint8Array | undefined;
645
+ }
646
+
647
+ /**
648
+ * The default Ark server URL for a Bitcoin network name (case-insensitive), or
649
+ * `undefined` for networks without a public default (e.g. regtest/testnet),
650
+ * where a URL must be supplied explicitly.
651
+ */
652
+ declare function defaultArkadeServerUrl(network: string): string | undefined;
653
+
654
+ type ArkadeRef = Extract<HtlcRef, {
655
+ ledger: "arkade";
656
+ }>;
657
+ type ArkadeVhtlcInput = {
658
+ /** Pubkey hex (x-only or compressed) for each VHTLC role. */
659
+ senderPk: string;
660
+ receiverPk: string;
661
+ serverPk: string;
662
+ /**
663
+ * The swap's `hash_lock`, hex, `0x`-prefixed or not. Either `sha256(preimage)`
664
+ * (32 bytes — most directions) or the `ripemd160(sha256(preimage))` HASH160 the
665
+ * VHTLC commits to directly (20 bytes — `btc_to_arkade`). Length disambiguates.
666
+ */
667
+ hashLock: string;
668
+ /** The VHTLC address the server reported. */
669
+ address: string;
670
+ /** Absolute CLTV refund locktime (unix seconds). */
671
+ refundLocktime: number;
672
+ /** Relative unilateral delays (seconds). */
673
+ unilateralClaimDelay: number;
674
+ unilateralRefundDelay: number;
675
+ unilateralRefundWithoutReceiverDelay: number;
676
+ /** Expected funding amount in sats (a short funding is `invalid`, not confirmed). */
677
+ expectedSats: number;
678
+ };
679
+ /**
680
+ * The VHTLC always commits to `ripemd160(sha256(preimage))` (HASH160). When
681
+ * `hashLock` is `sha256(preimage)` (32 bytes) we hash it once more to get that;
682
+ * when it is already the HASH160 (20 bytes, `btc_to_arkade`) we use it as-is. The
683
+ * ref keeps `preimageHash` as the raw `hashLock` — whatever length — and the spend
684
+ * classifier verifies a revealed preimage against it, auto-detecting the algorithm
685
+ * from that length.
686
+ */
687
+ declare function buildArkadeVhtlcRef(input: ArkadeVhtlcInput): ArkadeRef;
688
+
689
+ /** On-chain funding state of the HTLC address. */
690
+ type BitcoinFunding = "absent" | "mempool" | "confirmed";
691
+ /** Facts gathered for an HTLC address from esplora. */
692
+ type BitcoinHtlcFacts = {
693
+ funding: BitcoinFunding;
694
+ /** Total sats paid to the HTLC address by the funding tx (0 when absent). */
695
+ fundedSats: number;
696
+ /**
697
+ * The witness stack (hex items) of the input that spent the HTLC output, if it
698
+ * was spent. Absent while the output is still unspent.
699
+ */
700
+ spendWitness?: string[];
701
+ };
702
+
703
+ /** The esplora surface the observer needs (a `BitcoinReaderEsplora` satisfies it). */
704
+ type BitcoinChainReader = {
705
+ /** Funding + spend facts for an HTLC witness-script address. */
706
+ getHtlcFacts(address: string): Promise<BitcoinHtlcFacts>;
707
+ };
708
+ type BitcoinCreateConfig = {
709
+ /** One or more esplora REST base URLs; several are tried in rotation with failover. */
710
+ esploraUrl: string | string[];
711
+ /** The current Bitcoin MTP (ms); typically `async () => (await client.getMtp()).mtp * 1000`. */
712
+ chainTime?: () => Promise<number>;
713
+ };
714
+ type BitcoinContractManagerDeps = {
715
+ reader: BitcoinChainReader;
716
+ chainTime?: () => Promise<number>;
717
+ };
718
+ declare class BitcoinContractManager implements ContractManager {
719
+ #private;
720
+ readonly ledger: Ledger;
721
+ private constructor();
722
+ static fromDeps(deps: BitcoinContractManagerDeps): BitcoinContractManager;
723
+ static create(config: BitcoinCreateConfig): Promise<BitcoinContractManager>;
724
+ register(ref: HtlcRef): Promise<void>;
725
+ unregister(ref: HtlcRef): Promise<void>;
726
+ getState(ref: HtlcRef): HtlcObservation | undefined;
727
+ chainNow(_ref: HtlcRef): number | undefined;
728
+ onEvent(cb: (ref: HtlcRef, state: HtlcObservation) => void): () => void;
729
+ refresh(): Promise<void>;
730
+ dispose(): void;
731
+ /** The preimage a claim revealed on this HTLC, if one was seen. */
732
+ getPreimage(ref: HtlcRef): Uint8Array | undefined;
733
+ }
734
+
735
+ /**
736
+ * A esplora-backed {@link BitcoinChainReader} — the concrete chain source the
737
+ * {@link BitcoinContractManager} uses in production.
738
+ *
739
+ * Kept separate from the manager so the manager stays free of any HTTP/esplora
740
+ * dependency (and unit-testable against a fake reader). A single
741
+ * `GET /address/{addr}/txs` yields both the funding state and the spending
742
+ * input's witness, so no extra round-trips are needed.
743
+ */
744
+
745
+ /** The slice of esplora's tx JSON we read. */
746
+ type EsploraTx = {
747
+ vin: Array<{
748
+ witness?: string[];
749
+ prevout?: {
750
+ scriptpubkey_address?: string;
751
+ } | null;
752
+ }>;
753
+ vout: Array<{
754
+ scriptpubkey_address?: string;
755
+ value?: number;
756
+ }>;
757
+ status?: {
758
+ confirmed?: boolean;
759
+ };
760
+ };
761
+ /**
762
+ * Reduce an address's esplora tx history to HTLC facts. If a tx spends an output
763
+ * at the address, that's the resolving spend (its witness classifies claim vs
764
+ * refund); otherwise a tx paying the address is the funding.
765
+ */
766
+ declare function htlcFactsFromEsploraTxs(txs: EsploraTx[], address: string): BitcoinHtlcFacts;
767
+ /**
768
+ * Public esplora endpoints tried in rotation (mainnet). blockstream.info runs the
769
+ * reference esplora, so it's API-compatible with mempool.space; spreading calls
770
+ * across both halves the per-provider load and survives one being throttled.
771
+ */
772
+ declare const DEFAULT_ESPLORA_URLS: string[];
773
+ /**
774
+ * Build a {@link BitcoinChainReader} over one or more esplora REST endpoints.
775
+ * With several, each call starts at a rotating endpoint (to spread load across
776
+ * providers) and fails over to the rest on error — so a throttled or failing
777
+ * provider doesn't stall tracking.
778
+ */
779
+ declare function esploraReader(esploraUrls: string | string[], fetchImpl?: typeof fetch): BitcoinChainReader;
780
+
781
+ /**
782
+ * The `EvmContractManager`'s pure core.
783
+ *
784
+ * An EVM HTLC (an `HTLCErc20` swap) exposes its lifecycle as three events, all
785
+ * indexed by the swap's `preimageHash`: `SwapCreated` (funded), `SwapRedeemed`
786
+ * (claimed — reveals the preimage), and `SwapRefunded` (reclaimed after the
787
+ * timelock). This maps a decoded event history to an {@link HtlcObservation}.
788
+ */
789
+
790
+ /** One decoded `HTLCErc20` lifecycle event for a single swap's `preimageHash`. */
791
+ type EvmHtlcEvent = {
792
+ kind: "created";
793
+ amount: bigint;
794
+ token: `0x${string}`;
795
+ } | {
796
+ kind: "redeemed";
797
+ preimage: `0x${string}`;
798
+ } | {
799
+ kind: "refunded";
800
+ };
801
+
802
+ /**
803
+ * The EVM {@link ContractManager} — the stateful I/O adapter that observes
804
+ * `HTLCErc20` swaps across one or more EVM chains.
805
+ *
806
+ * Reading chain state is delegated to an injected {@link EvmChainReader} (one per
807
+ * chainId) rather than a bundled viem/ethers client, so the swap package stays
808
+ * chain-library-agnostic and this adapter is testable against a fake. The pure
809
+ * event→observation mapping lives in `./evm.js`.
810
+ *
811
+ * Unlike Arkade, EVM spans multiple chains with independent `block.timestamp`
812
+ * clocks, so this manager is chain-aware: it routes each ref by `chainId` and
813
+ * {@link chainNow} is ref-scoped.
814
+ */
815
+
816
+ /** Reads `HTLCErc20` state for one EVM chain. Implemented over viem/ethers/etc. */
817
+ type EvmChainReader = {
818
+ /**
819
+ * The decoded lifecycle events (oldest→newest) for the HTLC identified by
820
+ * `(htlc contract, preimageHash)`.
821
+ */
822
+ getHtlcEvents(htlc: `0x${string}`, preimageHash: `0x${string}`, claimAddress: `0x${string}`): Promise<EvmHtlcEvent[]>;
823
+ /** The latest block's `block.timestamp`, in ms. */
824
+ getBlockTimeMs(): Promise<number>;
825
+ /** Fire `cb` when new blocks/logs may have changed watched HTLCs; returns unsubscribe. */
826
+ watch(cb: () => void): () => void;
827
+ };
828
+ type EvmContractManagerDeps = {
829
+ /** A chain reader per EVM `chainId` this manager serves. */
830
+ readers: Map<number, EvmChainReader>;
831
+ };
832
+ declare class EvmContractManager implements ContractManager {
833
+ #private;
834
+ readonly ledger: Ledger;
835
+ private constructor();
836
+ static fromDeps(deps: EvmContractManagerDeps): EvmContractManager;
837
+ register(ref: HtlcRef): Promise<void>;
838
+ unregister(ref: HtlcRef): Promise<void>;
839
+ getState(ref: HtlcRef): HtlcObservation | undefined;
840
+ chainNow(ref: HtlcRef): number | undefined;
841
+ onEvent(cb: (ref: HtlcRef, state: HtlcObservation) => void): () => void;
842
+ refresh(): Promise<void>;
843
+ dispose(): void;
844
+ /** The preimage a claim revealed on this HTLC, if one was seen. */
845
+ getPreimage(ref: HtlcRef): `0x${string}` | undefined;
846
+ }
847
+
848
+ /**
849
+ * A viem-backed {@link EvmChainReader} — the concrete chain source the
850
+ * {@link EvmContractManager} uses in production.
851
+ *
852
+ * Kept separate from the manager so the manager itself stays free of any
853
+ * chain-library dependency (and unit-testable against a fake reader). This module
854
+ * is the only place that touches viem and the `HTLCErc20` ABI.
855
+ */
856
+
857
+ /**
858
+ * Tested public RPC endpoints per supported chainId, tried in order via viem's
859
+ * ranked `fallback`. Mirrors the frontend's `evmTransport.ts` list — the client
860
+ * uses these by default so Arkade↔EVM tracking works out of the box; a caller can
861
+ * override per chain with `ClientBuilder.withEvmRpcUrls`.
862
+ */
863
+ declare const DEFAULT_EVM_RPCS: Record<number, string[]>;
864
+ declare const SWAP_CREATED: {
865
+ readonly name: "SwapCreated";
866
+ readonly type: "event";
867
+ readonly inputs: readonly [{
868
+ readonly type: "bytes32";
869
+ readonly name: "preimageHash";
870
+ readonly indexed: true;
871
+ }, {
872
+ readonly type: "address";
873
+ readonly name: "refundAddress";
874
+ readonly indexed: true;
875
+ }, {
876
+ readonly type: "address";
877
+ readonly name: "claimAddress";
878
+ readonly indexed: true;
879
+ }, {
880
+ readonly type: "address";
881
+ readonly name: "token";
882
+ }, {
883
+ readonly type: "uint256";
884
+ readonly name: "amount";
885
+ }, {
886
+ readonly type: "uint256";
887
+ readonly name: "timelock";
888
+ }];
889
+ };
890
+ declare const SWAP_REDEEMED: {
891
+ readonly name: "SwapRedeemed";
892
+ readonly type: "event";
893
+ readonly inputs: readonly [{
894
+ readonly type: "bytes32";
895
+ readonly name: "preimageHash";
896
+ readonly indexed: true;
897
+ }, {
898
+ readonly type: "bytes32";
899
+ readonly name: "preimage";
900
+ }];
901
+ };
902
+ declare const SWAP_REFUNDED: {
903
+ readonly name: "SwapRefunded";
904
+ readonly type: "event";
905
+ readonly inputs: readonly [{
906
+ readonly type: "bytes32";
907
+ readonly name: "preimageHash";
908
+ readonly indexed: true;
909
+ }];
910
+ };
911
+ /** The viem surface the reader needs — a seam so it can be faked in tests. */
912
+ type EvmLogClient = {
913
+ getLogs(args: {
914
+ address: `0x${string}`;
915
+ event: typeof SWAP_CREATED | typeof SWAP_REDEEMED | typeof SWAP_REFUNDED;
916
+ args: {
917
+ preimageHash: `0x${string}`;
918
+ claimAddress?: `0x${string}`;
919
+ };
920
+ fromBlock: bigint | "earliest";
921
+ }): Promise<Log[]>;
922
+ getBlock(): Promise<Pick<Block, "timestamp">>;
923
+ watchBlocks(args: {
924
+ onBlock: () => void;
925
+ }): () => void;
926
+ };
927
+ /** Build an {@link EvmChainReader} over an existing viem-like client. */
928
+ declare function evmReaderFromClient(client: EvmLogClient): EvmChainReader;
929
+ /**
930
+ * Build an {@link EvmChainReader} over one or more EVM JSON-RPC endpoints. With
931
+ * several, viem's ranked `fallback` picks the healthiest and fails over.
932
+ */
933
+ declare function createEvmRpcReader(rpcUrls: string | string[]): EvmChainReader;
934
+ /**
935
+ * Resolve the per-chain readers used for tracking: the tested {@link
936
+ * DEFAULT_EVM_RPCS} by default, with any `overrides` taking priority for their
937
+ * chain (kept ahead of the defaults, which remain as fallbacks).
938
+ */
939
+ declare function defaultEvmReaders(overrides?: Record<number, string>): Map<number, EvmChainReader>;
940
+
941
+ /**
942
+ * Map a stored swap to the {@link TrackedSwap} the {@link SwapTracker} watches.
943
+ *
944
+ * The recovery bundle (`StoredSwap.response`) is a discriminated union over swap
945
+ * directions; each carries the two HTLC legs and their refund locktimes. This
946
+ * extracts the client-funded and server-funded HTLCs plus their locktimes so the
947
+ * pure pipeline can derive the next action.
948
+ *
949
+ * Directions whose both legs are observable today (Arkade↔EVM, Bitcoin↔EVM) are
950
+ * mapped; others return `undefined` until their ledger managers exist, rather than
951
+ * producing a half-watchable swap.
952
+ */
953
+
954
+ declare function swapToTracked(stored: StoredSwap): TrackedSwap | undefined;
955
+
956
+ export { type ActionSubscriber, ArkadeContractManager, type ArkadeContractManagerDeps, type ArkadeCreateConfig, type ArkadeVhtlcInput, type BitcoinChainReader, BitcoinContractManager, type BitcoinContractManagerDeps, type BitcoinCreateConfig, type BlockedBy, type BlockedReason, type CctpClaimEvidence, type ClaimAction, Client, ClientBuilder, type ContractManager, DEFAULT_ESPLORA_URLS, DEFAULT_EVM_RPCS, type EvmChainReader, EvmContractManager, type EvmContractManagerDeps, type EvmLogClient, type FundAction, type HtlcObservation, type HtlcRef, type Ledger, type NoneAction, type RecoverCctpClaimAction, type RefundCollaborativeAction, type RefundUnilateralAction, type SwapAction, type SwapActionAutomation, type SwapActionId, type SwapActionInput, type SwapActions, type SwapObservations, SwapTracker, type TrackedSwap, type WaitAction, buildArkadeVhtlcRef, createEvmRpcReader, defaultArkadeServerUrl, defaultEvmReaders, deriveSwapActions, deriveSwapStatus, esploraReader, evmReaderFromClient, htlcFactsFromEsploraTxs, htlcKey, swapToTracked };