@satora/escrow-client 0.0.1-alpha.2 → 0.0.1-alpha.4

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 ADDED
@@ -0,0 +1,243 @@
1
+ # @satora/escrow-client
2
+
3
+ High-level escrow flows for [Arkade](https://arkade.sh): fund a 2-of-2 escrow
4
+ from Lightning, and withdraw a released payout to Lightning or to L1. It bundles
5
+ [`@satora/escrow`](../escrow) (the escrow primitives, all re-exported) with the
6
+ escrow monitor, and an **injected** swap client.
7
+
8
+ You set up two things — a Satora swap client and an `EscrowClient` — and this
9
+ README walks through both from scratch. Everything else (escrow primitives, the
10
+ monitor) comes from this package.
11
+
12
+ ## Install
13
+
14
+ ```sh
15
+ npm install @satora/escrow-client
16
+ ```
17
+
18
+ Peer dependencies (you provide these):
19
+
20
+ ```sh
21
+ npm install @arkade-os/sdk @satora/swap
22
+ ```
23
+
24
+ - `@arkade-os/sdk` — Ark providers, repositories, and the `Wallet` used for withdrawals.
25
+ - `@satora/swap` — the Satora swap client: the Lightning/L1 on/off-ramp. You
26
+ build one (shown below) and inject it; escrow-client only imports its type, so it
27
+ carries none of that bundle's runtime weight.
28
+
29
+ ## Setup
30
+
31
+ Two pieces: a **swap client** and an **`EscrowClient`**.
32
+
33
+ ### 1. Build the swap client
34
+
35
+ ```ts
36
+ import { Client } from "@satora/swap";
37
+
38
+ // The minimal form generates a fresh ephemeral wallet on build(). For anything
39
+ // real, persist it — pass .withMnemonic("abandon abandon …") (or a storage
40
+ // backend) so pending swaps survive restarts.
41
+ const swap = await Client.builder()
42
+ .withBaseUrl("https://api.satora.io") // the Satora API
43
+ .build();
44
+ ```
45
+
46
+ ### 2. Build the EscrowClient
47
+
48
+ It needs the swap client plus Ark providers and repositories. Create one for the
49
+ lifetime of your app.
50
+
51
+ ```ts
52
+ import {
53
+ RestArkProvider,
54
+ RestIndexerProvider,
55
+ InMemoryContractRepository,
56
+ InMemoryWalletRepository,
57
+ networks,
58
+ } from "@arkade-os/sdk";
59
+ import { EscrowClient } from "@satora/escrow-client";
60
+
61
+ const ARK_URL = "https://master.arkade.sh"; // the ASP (serves Ark + indexer)
62
+
63
+ const arkProvider = new RestArkProvider(ARK_URL);
64
+ const indexerProvider = new RestIndexerProvider(ARK_URL);
65
+
66
+ const escrowClient = await EscrowClient.create({
67
+ swap,
68
+ arkProvider,
69
+ indexerProvider,
70
+ contractRepository: new InMemoryContractRepository(),
71
+ walletRepository: new InMemoryWalletRepository(),
72
+ });
73
+
74
+ // Resolve the network from the ASP (used for address derivation below).
75
+ const info = await arkProvider.getInfo();
76
+ const network = networks[info.network as keyof typeof networks];
77
+ ```
78
+
79
+ > Works the same in the browser — build the providers and the swap client there
80
+ > (the SDK ships browser storage backends) and pass them in.
81
+
82
+ ## Fund an escrow from Lightning
83
+
84
+ Describe the escrow you want to fund as `EscrowScriptOptions` (x-only 32-byte
85
+ pubkeys; `exitTimelock` is the ASP-mandated CSV). `fundFromLightning` derives the
86
+ escrow address, starts watching it, and creates a Lightning→Arkade swap whose
87
+ payout claims into that escrow.
88
+
89
+ ```ts
90
+ import type { EscrowScriptOptions } from "@satora/escrow-client"; // re-exported from @satora/escrow
91
+
92
+ const escrow: EscrowScriptOptions = {
93
+ sellerPubKey, // Uint8Array(32)
94
+ arbiterPubKey, // Uint8Array(32)
95
+ aspPubKey, // Uint8Array(32) — the ASP's signer pubkey
96
+ exitTimelock: {type: "blocks", value: 144n},
97
+ };
98
+
99
+ const handle = await escrowClient.fundFromLightning({
100
+ escrow,
101
+ network,
102
+ amountSats: 50_000, // sats to receive at the escrow
103
+ });
104
+
105
+ console.log("pay this invoice:", handle.invoice);
106
+ console.log("escrow address:", handle.escrowAddress);
107
+
108
+ // After the invoice is paid: claim the swap into the escrow and wait for the
109
+ // VTXO to land (rejects on timeout).
110
+ const funded = await handle.awaitFunded(120_000);
111
+ console.log("escrow funded:", funded.contract.script);
112
+ ```
113
+
114
+ `handle` is `{ swapId, invoice, escrowAddress, awaitFunded(timeoutMs?) }`.
115
+
116
+ ## Withdraw a released payout
117
+
118
+ Once the escrow has been cooperatively released to the recipient's wallet, the
119
+ payout sits as a normal VTXO in their `@arkade-os/sdk` `Wallet`. You hand that
120
+ `Wallet` to the withdrawal methods — build it from the recipient's key and the
121
+ same providers:
122
+
123
+ ```ts
124
+ import { Wallet, SingleKey } from "@arkade-os/sdk";
125
+
126
+ const wallet = await Wallet.create({
127
+ identity: SingleKey.fromPrivateKey(recipientSecretKey), // Uint8Array(32)
128
+ arkProvider,
129
+ indexerProvider,
130
+ // ...onchain provider + repositories as your environment needs
131
+ });
132
+ ```
133
+
134
+ Then withdraw it — either with the smart `withdraw` (which auto-routes by
135
+ inspecting the destination) or with a specific method.
136
+
137
+ ### Smart withdraw (auto-route)
138
+
139
+ `withdraw` figures out where `destination` points and dispatches accordingly:
140
+
141
+ ```ts
142
+ const result = await escrowClient.withdraw({
143
+ wallet,
144
+ destination, // BOLT11 / LNURL / user@host → Lightning
145
+ // ark1… / tark1… → Arkade transfer
146
+ // bc1… / tb1… / 1… → L1 offboard
147
+ amountSats, // required for Arkade + LNURL/address; optional for L1; ignored for BOLT11
148
+ });
149
+
150
+ result.txid; // present on every branch
151
+ if (result.method === "lightning") result.swapId; // lightning also has swapId + sourceAmountSats
152
+ ```
153
+
154
+ `result` is discriminated by `method` (`"lightning" | "l1" | "arkade"`). Use the
155
+ specific methods below if you already know the destination type.
156
+
157
+ ### To Lightning
158
+
159
+ `destination` may be a **BOLT11 invoice**, an **LNURL** (`lnurl1…`), or a
160
+ **Lightning address** (`user@host`). For LNURL / address the swap backend
161
+ resolves and negotiates the invoice, so pass `amountSats` (what the recipient
162
+ receives); for a BOLT11 invoice the amount is in the invoice and `amountSats` is
163
+ ignored.
164
+
165
+ ```ts
166
+ // Optional: quote the recipient amount for a full-payout withdrawal
167
+ // (payout minus the swap fee) so you don't have to do fee math.
168
+ // `availableSats` is the spendable payout in your wallet.
169
+ const {recipientSats} = await escrowClient.quoteLightningWithdrawal(availableSats);
170
+
171
+ const {swapId, fundingTxid, sourceAmountSats} =
172
+ await escrowClient.withdrawToLightning({
173
+ wallet, // @arkade-os/sdk Wallet holding the payout
174
+ destination: "user@lnurl.example.com", // invoice | lnurl1… | user@host
175
+ amountSats: recipientSats, // required for LNURL / address
176
+ });
177
+ ```
178
+
179
+ `sourceAmountSats` is what was spent from the payout (recipient amount + swap fee);
180
+ the swap server then pays the recipient.
181
+
182
+ ### To L1 (onchain)
183
+
184
+ A collaborative Arkade offboard (settlement round) to an onchain address:
185
+
186
+ ```ts
187
+ const settlementTxid = await escrowClient.withdrawToL1({
188
+ wallet,
189
+ destinationAddress: "bc1q…",
190
+ // amountSats?: bigint // omit to offboard the whole payout
191
+ });
192
+ ```
193
+
194
+ ### To another Arkade address
195
+
196
+ A plain offchain Ark transfer — the funds stay on Ark, so it's the cheapest and
197
+ fastest withdrawal (no swap, no settlement round):
198
+
199
+ ```ts
200
+ const arkTxid = await escrowClient.withdrawToArkade({
201
+ wallet,
202
+ destinationAddress: "ark1…", // or tark1… off mainnet
203
+ amountSats: 50_000,
204
+ });
205
+ ```
206
+
207
+ ## Escrow primitives
208
+
209
+ `@satora/escrow-client` re-exports everything from `@satora/escrow`, so you can
210
+ build/verify/sign escrow transactions and access the monitor without a second
211
+ import:
212
+
213
+ ```ts
214
+ import {
215
+ EscrowVtxoScript, // 2-of-2 escrow VtxoScript
216
+ buildEscrowReleaseTx, // build the cooperative release ark-tx
217
+ signEscrowArkTx, // sign a release as a co-party
218
+ verifyReleaseArkTx, // verify a release pays the agreed outputs
219
+ } from "@satora/escrow-client";
220
+
221
+ // The underlying monitor (onFunded/onReleased, watch, listEscrows):
222
+ escrowClient.escrowMonitor;
223
+ ```
224
+
225
+ ## Cleanup
226
+
227
+ ```ts
228
+ escrowClient.dispose(); // stop watching, clear listeners
229
+ ```
230
+
231
+ ## API summary
232
+
233
+ | Method | Purpose |
234
+ | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
235
+ | `EscrowClient.create(config)` | Construct with `{ swap, arkProvider, indexerProvider, contractRepository, walletRepository }`. |
236
+ | `fundFromLightning({ escrow, network, amountSats })` | Create a LN→escrow swap; returns `{ swapId, invoice, escrowAddress, awaitFunded() }`. |
237
+ | `withdraw({ wallet, destination, amountSats? })` | Smart withdrawal — auto-routes to Lightning / L1 / Arkade by destination. Returns `{ method, txid, … }`. |
238
+ | `quoteLightningWithdrawal(sourceAmountSats)` | `{ recipientSats, sourceSats }` — recipient amount after the swap fee. |
239
+ | `withdrawToLightning({ wallet, destination, amountSats? })` | Withdraw the payout to a BOLT11 / LNURL / Lightning address. |
240
+ | `withdrawToL1({ wallet, destinationAddress, amountSats? })` | Withdraw the payout onchain via collaborative offboard. |
241
+ | `withdrawToArkade({ wallet, destinationAddress, amountSats })` | Withdraw the payout to another Arkade address (offchain Ark transfer). |
242
+ | `escrowMonitor` | The underlying `EscrowMonitor`. |
243
+ | `dispose()` | Release monitor resources. |
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Pure classification of a withdrawal destination string — which rail it
3
+ * targets, and (for Lightning) how to map it to the swap SDK's fields. No
4
+ * network calls; the swap backend resolves LNURL / Lightning addresses.
5
+ */
6
+ export declare const isBolt11: (s: string) => boolean;
7
+ export declare const isLnurl: (s: string) => boolean;
8
+ export declare const isLnAddress: (s: string) => boolean;
9
+ /** A Lightning destination: a BOLT11 invoice, an LNURL, or a Lightning address. */
10
+ export declare function isLightningDestination(s: string): boolean;
11
+ /** An Arkade address (bech32m, hrp `ark` mainnet / `tark` test networks). */
12
+ export declare function isArkadeAddress(s: string): boolean;
13
+ /** Which withdrawal rail a destination string targets. */
14
+ export type DestinationKind = "lightning" | "arkade" | "l1";
15
+ /**
16
+ * Classify a withdrawal destination. Lightning (invoice/LNURL/address) and
17
+ * Arkade (`ark1…`/`tark1…`) are matched explicitly; everything else is treated
18
+ * as an onchain Bitcoin (L1) address.
19
+ */
20
+ export declare function classifyDestination(destination: string): DestinationKind;
21
+ /** Fields of the swap SDK's Arkade→Lightning options we route a destination to. */
22
+ export interface LightningDestination {
23
+ lightningInvoice?: string;
24
+ lightningAddress?: string;
25
+ lnurl?: string;
26
+ amountSats?: number;
27
+ }
28
+ /**
29
+ * Map a Lightning destination string to the swap SDK's mutually-exclusive
30
+ * `lightningInvoice` / `lightningAddress` / `lnurl` fields. Throws if it isn't a
31
+ * Lightning destination, or if `amountSats` is missing for LNURL / address.
32
+ */
33
+ export declare function toLightningDestination(destination: string, amountSats?: number): LightningDestination;
34
+ //# sourceMappingURL=destination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destination.d.ts","sourceRoot":"","sources":["../src/destination.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,KAAG,OACF,CAAC;AACpC,eAAO,MAAM,OAAO,GAAI,GAAG,MAAM,KAAG,OACC,CAAC;AACtC,eAAO,MAAM,WAAW,GAAI,GAAG,MAAM,KAAG,OACF,CAAC;AAEvC,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,0DAA0D;AAC1D,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,QAAQ,GAAG,IAAI,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAKxE;AAED,mFAAmF;AACnF,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,oBAAoB,CAsBtB"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Pure classification of a withdrawal destination string — which rail it
3
+ * targets, and (for Lightning) how to map it to the swap SDK's fields. No
4
+ * network calls; the swap backend resolves LNURL / Lightning addresses.
5
+ */
6
+ // BOLT11 on any network: bc / tb / tbs / bcrt / sb.
7
+ export const isBolt11 = (s) => /^ln(bcrt|bc|tbs|tb|sb)/i.test(s);
8
+ export const isLnurl = (s) => /^lnurl1[0-9ac-hj-np-z]+$/i.test(s);
9
+ export const isLnAddress = (s) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s);
10
+ /** A Lightning destination: a BOLT11 invoice, an LNURL, or a Lightning address. */
11
+ export function isLightningDestination(s) {
12
+ const input = s.trim();
13
+ return isBolt11(input) || isLnurl(input) || isLnAddress(input);
14
+ }
15
+ /** An Arkade address (bech32m, hrp `ark` mainnet / `tark` test networks). */
16
+ export function isArkadeAddress(s) {
17
+ return /^t?ark1[0-9ac-hj-np-z]+$/i.test(s.trim());
18
+ }
19
+ /**
20
+ * Classify a withdrawal destination. Lightning (invoice/LNURL/address) and
21
+ * Arkade (`ark1…`/`tark1…`) are matched explicitly; everything else is treated
22
+ * as an onchain Bitcoin (L1) address.
23
+ */
24
+ export function classifyDestination(destination) {
25
+ const input = destination.trim();
26
+ if (isLightningDestination(input))
27
+ return "lightning";
28
+ if (isArkadeAddress(input))
29
+ return "arkade";
30
+ return "l1";
31
+ }
32
+ /**
33
+ * Map a Lightning destination string to the swap SDK's mutually-exclusive
34
+ * `lightningInvoice` / `lightningAddress` / `lnurl` fields. Throws if it isn't a
35
+ * Lightning destination, or if `amountSats` is missing for LNURL / address.
36
+ */
37
+ export function toLightningDestination(destination, amountSats) {
38
+ const input = destination.trim();
39
+ // The BOLT11 invoice carries its own amount, so amountSats is not needed.
40
+ if (isBolt11(input)) {
41
+ return { lightningInvoice: input };
42
+ }
43
+ const address = isLnAddress(input);
44
+ const lnurl = isLnurl(input);
45
+ if (!address && !lnurl) {
46
+ throw new Error("unrecognized Lightning destination: expected a BOLT11 invoice, " +
47
+ "LNURL (lnurl1...), or Lightning address (user@host)");
48
+ }
49
+ if (amountSats === undefined) {
50
+ throw new Error(`amountSats is required for a Lightning ${address ? "address" : "LNURL"} destination`);
51
+ }
52
+ return address
53
+ ? { lightningAddress: input, amountSats }
54
+ : { lnurl: input, amountSats };
55
+ }
56
+ //# sourceMappingURL=destination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destination.js","sourceRoot":"","sources":["../src/destination.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,oDAAoD;AACpD,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAW,EAAE,CAC7C,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAS,EAAW,EAAE,CAC5C,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAS,EAAW,EAAE,CAChD,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEvC,mFAAmF;AACnF,MAAM,UAAU,sBAAsB,CAAC,CAAS;IAC9C,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACvB,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;AACjE,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,eAAe,CAAC,CAAS;IACvC,OAAO,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACpD,CAAC;AAKD;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB;IACrD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IACjC,IAAI,sBAAsB,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IACtD,IAAI,eAAe,CAAC,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC5C,OAAO,IAAI,CAAC;AACd,CAAC;AAUD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,WAAmB,EACnB,UAAmB;IAEnB,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IACjC,0EAA0E;IAC1E,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC;IACrC,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,iEAAiE;YAC/D,qDAAqD,CACxD,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,0CAA0C,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,cAAc,CACtF,CAAC;IACJ,CAAC;IACD,OAAO,OAAO;QACZ,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,EAAE;QACzC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AACnC,CAAC"}
@@ -11,7 +11,7 @@ import type { Client } from "@satora/swap";
11
11
  * has private fields, so the full class would be a nominal mismatch across
12
12
  * copies).
13
13
  */
14
- export type SwapClient = Pick<Client, "createLightningToArkadeSwap" | "claimArkade" | "createArkadeToLightningSwap">;
14
+ export type SwapClient = Pick<Client, "createLightningToArkadeSwap" | "claimArkade" | "createArkadeToLightningSwap" | "getArkadeToLightningQuote">;
15
15
  /**
16
16
  * Dependencies for {@link EscrowClient}.
17
17
  *
@@ -31,6 +31,23 @@ export interface EscrowClientConfig {
31
31
  /** Wallet repository (vtxo storage) for the escrow monitor. */
32
32
  walletRepository: WalletRepository;
33
33
  }
34
+ /**
35
+ * Result of {@link EscrowClient.withdraw}, discriminated by `method`. `txid` is
36
+ * present on every branch — the VHTLC funding txid (lightning), the offboard
37
+ * settlement txid (l1), or the Ark transfer txid (arkade).
38
+ */
39
+ export type WithdrawResult = {
40
+ method: "lightning";
41
+ txid: string;
42
+ swapId: string;
43
+ sourceAmountSats: number;
44
+ } | {
45
+ method: "l1";
46
+ txid: string;
47
+ } | {
48
+ method: "arkade";
49
+ txid: string;
50
+ };
34
51
  export interface FundFromLightningParams {
35
52
  /** The escrow to fund (script params, used to derive the address + watch). */
36
53
  escrow: EscrowScriptOptions;
@@ -79,6 +96,21 @@ export declare class EscrowClient {
79
96
  * server-funded VHTLC into the escrow and resolves when the VTXO lands.
80
97
  */
81
98
  fundFromLightning(params: FundFromLightningParams): Promise<FundFromLightningHandle>;
99
+ /**
100
+ * Quote a Lightning withdrawal: given how many sats you'd spend from the
101
+ * payout (`sourceAmountSats`), returns what the recipient receives after the
102
+ * swap fee and what is actually spent.
103
+ *
104
+ * Use `recipientSats` as the `amountSats` for an LNURL / Lightning-address
105
+ * {@link withdrawToLightning} — e.g. pre-fill the amount from the available
106
+ * payout balance so the user doesn't have to compute fees by hand.
107
+ */
108
+ quoteLightningWithdrawal(sourceAmountSats: number): Promise<{
109
+ /** Sats the recipient receives (pass as `amountSats` to withdrawToLightning). */
110
+ recipientSats: number;
111
+ /** Sats actually spent from the payout to fund the swap VHTLC. */
112
+ sourceSats: number;
113
+ }>;
82
114
  /**
83
115
  * Withdraw a released payout to Lightning via an Arkade→Lightning swap.
84
116
  *
@@ -122,6 +154,42 @@ export declare class EscrowClient {
122
154
  /** Amount to offboard in sats; omit to offboard everything. */
123
155
  amountSats?: bigint;
124
156
  }): Promise<string>;
157
+ /**
158
+ * Withdraw a released payout to another Arkade address — a plain offchain Ark
159
+ * transfer. The funds stay on Ark (no swap, no settlement round), so this is
160
+ * the cheapest, fastest withdrawal. Returns the ark txid.
161
+ *
162
+ * The buyer holds the released payout as a normal VTXO at their wallet's
163
+ * address, so this is a plain send — no escrow-specific signing.
164
+ */
165
+ withdrawToArkade(params: {
166
+ /** Buyer wallet holding the released payout VTXO(s). */
167
+ wallet: IWallet;
168
+ /** Destination Arkade address. */
169
+ destinationAddress: string;
170
+ /** Amount to send in sats. */
171
+ amountSats: number;
172
+ }): Promise<string>;
173
+ /**
174
+ * Smart withdrawal: route the payout to wherever `destination` points by
175
+ * inspecting the string, dispatching to {@link withdrawToLightning},
176
+ * {@link withdrawToArkade}, or {@link withdrawToL1}.
177
+ *
178
+ * - BOLT11 invoice / LNURL / Lightning address → Lightning
179
+ * - Arkade address (`ark1…` / `tark1…`) → offchain Ark transfer
180
+ * - anything else (a Bitcoin address) → L1 offboard
181
+ *
182
+ * `amountSats` is **required** for an Arkade address and for a Lightning
183
+ * LNURL/address; **optional** for L1 (omit to offboard everything) and
184
+ * **ignored** for a BOLT11 invoice. The result is discriminated by `method`;
185
+ * `txid` is present for every branch.
186
+ */
187
+ withdraw(params: {
188
+ wallet: IWallet;
189
+ /** Lightning (invoice/LNURL/address), Arkade, or onchain Bitcoin address. */
190
+ destination: string;
191
+ amountSats?: number;
192
+ }): Promise<WithdrawResult>;
125
193
  /** Release the monitor's resources (stop watching, clear listeners). */
126
194
  dispose(): void;
127
195
  }
@@ -1 +1 @@
1
- {"version":3,"file":"escrow-client.d.ts","sourceRoot":"","sources":["../src/escrow-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,OAAO,EAEZ,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,iBAAiB,EACtB,aAAa,EACb,KAAK,mBAAmB,EAEzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG,IAAI,CAC3B,MAAM,EACN,6BAA6B,GAAG,aAAa,GAAG,6BAA6B,CAC9E,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,IAAI,EAAE,UAAU,CAAC;IACjB,oDAAoD;IACpD,WAAW,EAAE,WAAW,CAAC;IACzB,uDAAuD;IACvD,eAAe,EAAE,eAAe,CAAC;IACjC,kDAAkD;IAClD,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,+DAA+D;IAC/D,gBAAgB,EAAE,gBAAgB,CAAC;CACpC;AAED,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,MAAM,EAAE,mBAAmB,CAAC;IAC5B,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC7D;AAED;;;;;;;;GAQG;AACH,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAH1B,OAAO;WAMM,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;IAStE,+EAA+E;IAC/E,IAAI,aAAa,IAAI,aAAa,CAEjC;IAED;;;;;;;OAOG;IACG,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,uBAAuB,CAAC;IA6CnC;;;;;;;;;;;;;OAaG;IACG,mBAAmB,CAAC,MAAM,EAAE;QAChC,wDAAwD;QACxD,MAAM,EAAE,OAAO,CAAC;QAChB,+EAA+E;QAC/E,WAAW,EAAE,MAAM,CAAC;QACpB,kFAAkF;QAClF,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC;QACV,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IAaF;;;;;;;;OAQG;IACG,YAAY,CAAC,MAAM,EAAE;QACzB,wDAAwD;QACxD,MAAM,EAAE,OAAO,CAAC;QAChB,wCAAwC;QACxC,kBAAkB,EAAE,MAAM,CAAC;QAC3B,+DAA+D;QAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,MAAM,CAAC;IASnB,wEAAwE;IACxE,OAAO,IAAI,IAAI;CAGhB"}
1
+ {"version":3,"file":"escrow-client.d.ts","sourceRoot":"","sources":["../src/escrow-client.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { Ramps, } from "@arkade-os/sdk";
2
2
  import { EscrowMonitor, EscrowVtxoScript, } from "@satora/escrow";
3
3
  import { hex } from "@scure/base";
4
+ import { classifyDestination, toLightningDestination } from "./destination.js";
4
5
  /**
5
6
  * High-level escrow flows that bundle the swap on/off-ramp with the escrow
6
7
  * monitor: fund an escrow from Lightning, and withdraw a released payout to
@@ -78,6 +79,23 @@ export class EscrowClient {
78
79
  awaitFunded,
79
80
  };
80
81
  }
82
+ /**
83
+ * Quote a Lightning withdrawal: given how many sats you'd spend from the
84
+ * payout (`sourceAmountSats`), returns what the recipient receives after the
85
+ * swap fee and what is actually spent.
86
+ *
87
+ * Use `recipientSats` as the `amountSats` for an LNURL / Lightning-address
88
+ * {@link withdrawToLightning} — e.g. pre-fill the amount from the available
89
+ * payout balance so the user doesn't have to compute fees by hand.
90
+ */
91
+ async quoteLightningWithdrawal(sourceAmountSats) {
92
+ const quote = await this.swap.getArkadeToLightningQuote(sourceAmountSats);
93
+ // Amounts are serialized as strings over the wire.
94
+ return {
95
+ recipientSats: Number(quote.net_target_amount),
96
+ sourceSats: Number(quote.net_source_amount),
97
+ };
98
+ }
81
99
  /**
82
100
  * Withdraw a released payout to Lightning via an Arkade→Lightning swap.
83
101
  *
@@ -115,36 +133,78 @@ export class EscrowClient {
115
133
  const { fees } = await this.arkProvider.getInfo();
116
134
  return new Ramps(params.wallet).offboard(params.destinationAddress, fees, params.amountSats);
117
135
  }
136
+ /**
137
+ * Withdraw a released payout to another Arkade address — a plain offchain Ark
138
+ * transfer. The funds stay on Ark (no swap, no settlement round), so this is
139
+ * the cheapest, fastest withdrawal. Returns the ark txid.
140
+ *
141
+ * The buyer holds the released payout as a normal VTXO at their wallet's
142
+ * address, so this is a plain send — no escrow-specific signing.
143
+ */
144
+ async withdrawToArkade(params) {
145
+ return params.wallet.send({
146
+ address: params.destinationAddress,
147
+ amount: params.amountSats,
148
+ });
149
+ }
150
+ /**
151
+ * Smart withdrawal: route the payout to wherever `destination` points by
152
+ * inspecting the string, dispatching to {@link withdrawToLightning},
153
+ * {@link withdrawToArkade}, or {@link withdrawToL1}.
154
+ *
155
+ * - BOLT11 invoice / LNURL / Lightning address → Lightning
156
+ * - Arkade address (`ark1…` / `tark1…`) → offchain Ark transfer
157
+ * - anything else (a Bitcoin address) → L1 offboard
158
+ *
159
+ * `amountSats` is **required** for an Arkade address and for a Lightning
160
+ * LNURL/address; **optional** for L1 (omit to offboard everything) and
161
+ * **ignored** for a BOLT11 invoice. The result is discriminated by `method`;
162
+ * `txid` is present for every branch.
163
+ */
164
+ async withdraw(params) {
165
+ const destination = params.destination.trim();
166
+ switch (classifyDestination(destination)) {
167
+ case "lightning": {
168
+ const { swapId, fundingTxid, sourceAmountSats } = await this.withdrawToLightning({
169
+ wallet: params.wallet,
170
+ destination,
171
+ amountSats: params.amountSats,
172
+ });
173
+ return {
174
+ method: "lightning",
175
+ txid: fundingTxid,
176
+ swapId,
177
+ sourceAmountSats,
178
+ };
179
+ }
180
+ case "arkade": {
181
+ if (params.amountSats === undefined) {
182
+ throw new Error("amountSats is required to withdraw to an Arkade address");
183
+ }
184
+ const txid = await this.withdrawToArkade({
185
+ wallet: params.wallet,
186
+ destinationAddress: destination,
187
+ amountSats: params.amountSats,
188
+ });
189
+ return { method: "arkade", txid };
190
+ }
191
+ case "l1": {
192
+ const txid = await this.withdrawToL1({
193
+ wallet: params.wallet,
194
+ destinationAddress: destination,
195
+ amountSats: params.amountSats === undefined
196
+ ? undefined
197
+ : BigInt(params.amountSats),
198
+ });
199
+ return { method: "l1", txid };
200
+ }
201
+ }
202
+ }
118
203
  /** Release the monitor's resources (stop watching, clear listeners). */
119
204
  dispose() {
120
205
  this.monitor.dispose();
121
206
  }
122
207
  }
123
- /**
124
- * Classify a Lightning destination string and map it to the swap SDK's
125
- * mutually-exclusive `lightningInvoice` / `lightningAddress` / `lnurl` fields.
126
- * Pure string inspection — no network calls; the backend resolves LNURL.
127
- */
128
- function toLightningDestination(destination, amountSats) {
129
- const input = destination.trim();
130
- // BOLT11 on any network: bc / tb / tbs / bcrt / sb. The invoice carries its
131
- // own amount, so amountSats is not needed.
132
- if (/^ln(bcrt|bc|tbs|tb|sb)/i.test(input)) {
133
- return { lightningInvoice: input };
134
- }
135
- const isAddress = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input);
136
- const isLnurl = /^lnurl1[0-9ac-hj-np-z]+$/i.test(input);
137
- if (!isAddress && !isLnurl) {
138
- throw new Error("unrecognized Lightning destination: expected a BOLT11 invoice, " +
139
- "LNURL (lnurl1...), or Lightning address (user@host)");
140
- }
141
- if (amountSats === undefined) {
142
- throw new Error(`amountSats is required for a Lightning ${isAddress ? "address" : "LNURL"} destination`);
143
- }
144
- return isAddress
145
- ? { lightningAddress: input, amountSats }
146
- : { lnurl: input, amountSats };
147
- }
148
208
  function withTimeout(p, ms, label) {
149
209
  let timer;
150
210
  const timeout = new Promise((_, reject) => {
@@ -1 +1 @@
1
- {"version":3,"file":"escrow-client.js","sourceRoot":"","sources":["../src/escrow-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"escrow-client.js","sourceRoot":"","sources":["../src/escrow-client.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "@satora/escrow";
2
+ export { classifyDestination, type DestinationKind } from "./destination.js";
2
3
  export * from "./escrow-client.js";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAC;AAE/B,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EAAE,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE7E,cAAc,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  // One-stop import: re-export all escrow primitives so consumers need only
2
2
  // `@satora/escrow-client` (plus the swap Client they already run).
3
3
  export * from "@satora/escrow";
4
+ // Destination classification used by the smart `withdraw` (useful for routing
5
+ // or labelling a destination in a UI before calling it).
6
+ export { classifyDestination } from "./destination.js";
4
7
  // High-level escrow flows (EscrowClient).
5
8
  export * from "./escrow-client.js";
6
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,mEAAmE;AACnE,cAAc,gBAAgB,CAAC;AAC/B,0CAA0C;AAC1C,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,mEAAmE;AACnE,cAAc,gBAAgB,CAAC;AAC/B,8EAA8E;AAC9E,yDAAyD;AACzD,OAAO,EAAE,mBAAmB,EAAwB,MAAM,kBAAkB,CAAC;AAC7E,0CAA0C;AAC1C,cAAc,oBAAoB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@satora/escrow-client",
3
- "version": "0.0.1-alpha.2",
3
+ "version": "0.0.1-alpha.4",
4
4
  "description": "High-level escrow flows (funding/withdrawing) bundling @satora/escrow with an injected swap client",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -27,6 +27,7 @@
27
27
  "@arkade-os/sdk": "^0.4.32",
28
28
  "@biomejs/biome": "2.3.15",
29
29
  "typescript": "^5.7.0",
30
+ "vitest": "^3.0.0",
30
31
  "@satora/swap": "0.0.1-alpha.1"
31
32
  },
32
33
  "license": "MIT",
@@ -36,6 +37,8 @@
36
37
  "scripts": {
37
38
  "build": "tsc -p tsconfig.build.json",
38
39
  "check-types": "tsc -p tsconfig.json --noEmit",
40
+ "test": "vitest",
41
+ "test:run": "vitest run",
39
42
  "lint": "biome check .",
40
43
  "lint:fix": "biome check --write .",
41
44
  "clean": "rm -rf dist"