@satora/swap 0.0.5-rc.0 → 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/README.md +5 -3
- package/dist/bitcoin-reader-esplora-GRUP7RAG.js +11 -0
- package/dist/bitcoin-reader-esplora-GRUP7RAG.js.map +1 -0
- package/dist/chunk-J35RZBDW.js +65 -0
- package/dist/chunk-J35RZBDW.js.map +1 -0
- package/dist/index.cjs +1856 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +955 -3
- package/dist/index.d.ts +955 -3
- package/dist/index.js +1770 -0
- package/dist/index.js.map +1 -1
- package/dist/node.d.cts +2 -0
- package/dist/node.d.ts +2 -0
- package/package.json +10 -3
package/dist/index.d.cts
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 '@
|
|
3
|
-
import '
|
|
4
|
-
|
|
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 };
|