ckb-session-kit 0.0.0-stage → 2.0.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.
@@ -0,0 +1,451 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { type SessionLockDeployment } from "./lock.js";
3
+ import { type Session } from "./session.js";
4
+ /**
5
+ * Sessions enforced by the on-chain session lock.
6
+ *
7
+ * - `openSession` — the owner (any CCC signer: a wallet) funds a session cell under
8
+ * the session lock and a key cell under the session key's own lock. One signature.
9
+ * - `spendInSession` — the session key alone spends from the session cell; the key
10
+ * cell pays the fee. No wallet involved; the network enforces the scope. With
11
+ * `topUp`, it adds to the recipient's anyone-can-pay cell instead of creating a
12
+ * new one, so a payment can be any size (a new cell needs at least 61 CKB).
13
+ * - `closeSession` — the key cell goes back to the owner (session key signs), then
14
+ * the owner sweeps the session cells (one wallet signature).
15
+ * - `recoverSessions` — the device holding the session key is gone: the owner's
16
+ * wallet alone finds every session it opened and sweeps them back.
17
+ *
18
+ * A token session (`openSession(..., { token })`) holds an xUDT token as well as
19
+ * CKB; `spendInSession(..., { to, token })` pays in it, and the lock caps the
20
+ * units per spend as it caps shannons. Sweeps return the tokens to the owner.
21
+ */
22
+ /** What the browser must remember, besides the key, to find and spend the session. */
23
+ export type OnChainBinding = NonNullable<Session["onchain"]>;
24
+ export interface SessionCells {
25
+ lock: ccc.Script;
26
+ keyLock: ccc.Script;
27
+ sessionCells: ccc.Cell[];
28
+ keyCells: ccc.Cell[];
29
+ /** Spendable balance of the session cells, in shannons. */
30
+ balance: bigint;
31
+ /** Fee budget left in the key cells, in shannons. */
32
+ feeBalance: bigint;
33
+ /** Token units in the session cells (token sessions; 0 otherwise). */
34
+ tokenBalance: bigint;
35
+ }
36
+ /**
37
+ * Why a `SessionBalanceError` was thrown, where a caller may need to tell it apart
38
+ * without matching the message (which may change):
39
+ * - `no-fee-cell`: the paying key (a session's key cell, a subscription's charger)
40
+ * has no cell that can pay the fee.
41
+ * - `no-payout-cell`: the recipient (`payTo`) has no cell to top up.
42
+ * - `payout-busy`: every payout cell checked is being spent by a transaction in
43
+ * the node's pool (other payers at the same moment). Nothing was sent; try
44
+ * again after a block, or give the recipient more cells (`createPayoutCells`).
45
+ *
46
+ * Neither is about the session's or the subscription's own balance or timing: the
47
+ * missing cells belong to the key's holder or the recipient (in a subscription,
48
+ * both are the creator's). Other balance errors have no `reason`.
49
+ */
50
+ export type SessionBalanceReason = "no-fee-cell" | "no-payout-cell" | "payout-busy";
51
+ export declare class SessionBalanceError extends Error {
52
+ readonly reason?: SessionBalanceReason;
53
+ constructor(message: string, reason?: SessionBalanceReason);
54
+ }
55
+ /**
56
+ * Something about a session's terms that the lock will enforce as written but that
57
+ * the owner may not have meant. `openSession` reports it before anything is signed
58
+ * (`opts.onWarning`, or `console.warn` without one).
59
+ * - `no-rate-limit`: `minInterval` is 0 (or 1, almost the same: review W6 I3). Each
60
+ * spend is held to `maxPerTx`, but the change of one spend can be spent again in
61
+ * the next block (with 1, a block later), so a leaked key can repeat spends until the
62
+ * session is empty.
63
+ */
64
+ export interface SessionWarning {
65
+ code: "no-rate-limit";
66
+ message: string;
67
+ }
68
+ /**
69
+ * The smallest key cell that can still be returned to the owner: a cell under the
70
+ * owner's lock (63 CKB for JoyID or Omnilock, whose args are 22 bytes), and never
71
+ * below a key cell's own 61 CKB.
72
+ */
73
+ export declare function keyCellFloor(ownerLock: ccc.ScriptLike): bigint;
74
+ /**
75
+ * A send failed and the node could not then be asked whether it has the
76
+ * transaction (review W6 L4): it may have been taken and committed. Never
77
+ * retried; `txHash` is the transaction to look for, and `cause` the send's own
78
+ * error. Its message never repeats the cause's, so nothing reads it as a
79
+ * refusal for a spent input.
80
+ */
81
+ export declare class SendOutcomeUnknownError extends Error {
82
+ readonly txHash: ccc.Hex;
83
+ constructor(txHash: ccc.Hex, cause: unknown);
84
+ }
85
+ /**
86
+ * Signs `tx`, hands its final hash to `beforeSend`, then sends it. The hash is
87
+ * known before anything leaves, so a caller can record the payment or the key
88
+ * against it first. If the send throws but the node did take the transaction (a
89
+ * timeout on the reply, say), the hash is returned all the same. If the send
90
+ * throws and the status lookup fails too, a `SendOutcomeUnknownError` is thrown
91
+ * instead of the send's error, which `rebuildOnDeadInputs` never retries.
92
+ */
93
+ export declare function signAndSend(signer: ccc.Signer, tx: ccc.Transaction, beforeSend?: (txHash: ccc.Hex) => Promise<void>): Promise<ccc.Hex>;
94
+ export declare function keyLockOf(session: Session, client: ccc.Client): Promise<ccc.Script>;
95
+ /** The xUDT amount in a cell's data (RFC 0052: u128 LE in the first 16 bytes). */
96
+ export declare function tokenAmount(data: ccc.HexLike): bigint;
97
+ export declare const tokenData: (amount: bigint, rest?: Uint8Array) => `0x${string}`;
98
+ /** A cell's data is exactly a 16-byte amount: what the session lock accepts as token change. */
99
+ export declare const plainTokenCell: (cell: ccc.Cell, type: ccc.Script) => boolean;
100
+ export declare function sessionLockOf(session: Session, client: ccc.Client, deployment: SessionLockDeployment, binding: OnChainBinding): Promise<ccc.Script>;
101
+ /**
102
+ * Whether a session-lock cell was created by a transaction its owner or its
103
+ * session key took part in (an input under the lock hash in args bytes 0..32 or
104
+ * 32..64). Nobody else can sign for those, so a planted cell never passes.
105
+ */
106
+ export declare function ownOrigin(client: ccc.Client, cell: ccc.Cell): Promise<boolean>;
107
+ /**
108
+ * `cells` less those whose token amounts would overflow a u128, per token type.
109
+ * Anyone can plant a cell holding 2^128-1 units of a free token under a session
110
+ * lock, and xUDT refuses a transaction whose inputs overflow, so taking every
111
+ * cell would block spends, closes, recovery, charges and cancels (review, 27 and
112
+ * 28 Oct). Which cells stay does not depend on indexer order: cells of the
113
+ * owner's or the key's own making first, then the smallest amounts. Without an
114
+ * overflow nothing is looked up and every cell stays, in order.
115
+ */
116
+ export declare function withinU128(client: ccc.Client, cells: ccc.Cell[]): Promise<ccc.Cell[]>;
117
+ /** One of `cells` at random: payers or chargers at once then rarely compete for the same cell. */
118
+ export declare const randomPick: <T>(cells: T[]) => T | undefined;
119
+ /** Whether `lock` is this network's anyone-can-pay lock (RFC 0026). */
120
+ export declare function isAnyoneCanPay(lock: ccc.Script, client: ccc.Client): Promise<boolean>;
121
+ /** The most cells of a recipient read when picking one to top up: any of them will do. */
122
+ export declare const MAX_PAYOUT_CELLS = 64;
123
+ /** The most payout cells a pick asks the node about (`get_live_cell` with the pool), all at once. */
124
+ export declare const MAX_POOL_CHECKS = 4;
125
+ /**
126
+ * Which of `cells` (the recipient's anyone-can-pay cells) to top up, so payers at
127
+ * the same moment rarely take the same one (mentor review, 2 Nov):
128
+ *
129
+ * - confirmed cells first (listed by the indexer), then this client's own
130
+ * outputs still pending (only CCC's cache lists them), each group shuffled;
131
+ * - `avoid` (out points a node rejection named as spent) left out;
132
+ * - the first `MAX_POOL_CHECKS` asked at once whether a transaction in the
133
+ * node's pool spends them (`get_live_cell` with `include_tx_pool`: a cell a
134
+ * pool transaction consumes is dead); the first free one is taken.
135
+ *
136
+ * If the node cannot be asked, an unchecked cell is taken (a rejected send is
137
+ * retried). If every cell checked is spent in the pool, an unchecked one is taken
138
+ * if any is left; otherwise a `SessionBalanceError` "payout-busy" is thrown and
139
+ * nothing is sent. Undefined when `cells` is empty.
140
+ */
141
+ export declare function pickPayoutCell(client: ccc.Client, lock: ccc.Script, cells: ccc.Cell[], avoid?: ReadonlySet<string>): Promise<ccc.Cell | undefined>;
142
+ /**
143
+ * Tops up one cell under the anyone-can-pay `lock` in `tx`: one input, and one
144
+ * output holding `ckb` shannons more, or with `token`, `units` more of it in a
145
+ * cell of that token. The cell is chosen by `pickPayoutCell`, never one in
146
+ * `avoid`. Returns the cell, or undefined when `lock` has none to add to.
147
+ */
148
+ export declare function addTopUp(tx: ccc.Transaction, client: ccc.Client, lock: ccc.Script, add: {
149
+ ckb?: bigint;
150
+ token?: ccc.Script;
151
+ units?: bigint;
152
+ }, avoid?: ReadonlySet<string>): Promise<ccc.Cell | undefined>;
153
+ /** Plain cells under `lock`; with `token`, also cells holding exactly that token. */
154
+ export declare function collect(client: ccc.Client, lock: ccc.Script, token?: ccc.Script): Promise<ccc.Cell[]>;
155
+ /**
156
+ * `cells` (found under `lock`) less those only CCC's client cache vouches for
157
+ * that are gone. The cache lists the outputs of every transaction this client
158
+ * sent as live, ahead of the indexer's cells, and never drops them: once another
159
+ * tab, device or server instance spends them, every transaction built here on
160
+ * them would be rejected until a reload (audit, 31 Oct). A cached cell is kept
161
+ * while the transaction that made it is pending or proposed (a chain of
162
+ * payments faster than the indexer needs it), or once committed while the node
163
+ * says it is still live; it is dropped once the node no longer knows that
164
+ * transaction, or says the cell is spent. When the node cannot be asked, it is kept.
165
+ */
166
+ export declare function withoutDeadCached(client: ccc.Client, lock: ccc.Script, cells: ccc.Cell[]): Promise<ccc.Cell[]>;
167
+ /** Whether a send was rejected because an input is spent or unknown to the node. */
168
+ export declare function deadInputs(e: unknown): boolean;
169
+ /**
170
+ * Whether a send was rejected because an input is already spent by a
171
+ * transaction in the node's pool, on a node with replace-by-fee on: CKB then
172
+ * runs its RBF checks instead of answering `Dead`, and refuses the newcomer
173
+ * (`PoolRejectedRBF`, -1111) unless it pays enough more to replace the other.
174
+ */
175
+ export declare function poolConflict(e: unknown): boolean;
176
+ /** How often, and how patiently, a payment or a charge is built again after a refusal for a spent cell. */
177
+ export interface RetryOptions {
178
+ /** Attempts in all, the first included (default 3; 1 never retries). */
179
+ attempts?: number;
180
+ /** The wait before the second attempt, in ms (default 1000); it doubles each time, with jitter of +-50%. */
181
+ delayMs?: number;
182
+ }
183
+ export declare const DEFAULT_RETRY: Readonly<Required<RetryOptions>>;
184
+ /**
185
+ * Runs `build` (which builds and sends a transaction). If the node definitely
186
+ * refused it because an input was already spent (`Dead`, `Unknown`, or an RBF
187
+ * refusal for a conflict in its pool), or `build` sent nothing because every
188
+ * payout cell was busy ("payout-busy"), clears the client's cache, waits, and
189
+ * runs it again, up to `retry.attempts` in all (audit, 31 Oct; mentor review,
190
+ * 2 Nov). `build` is given the out points rejections named, so a payout cell
191
+ * the node called spent is not picked again. The wait is `retry.delayMs`,
192
+ * doubling each time, times a random 0.5 to 1.5, so payers that collided do
193
+ * not retry in step.
194
+ *
195
+ * Any other error is thrown at once. That includes a send whose outcome is
196
+ * unknown (a timeout, a lost reply): `signAndSend` returns the hash when the
197
+ * node did take the transaction, and otherwise throws the send's own error,
198
+ * which is never retried, so nothing is ever paid twice. When the node cannot
199
+ * be asked either, a refusal for a spent input may only mean the first send
200
+ * committed (CCC retries a send on a fallback node): `signAndSend` then throws
201
+ * `SendOutcomeUnknownError`, never retried (review W6 L4). A `beforeSend` inside
202
+ * runs again with each new transaction's hash: a refused one never commits.
203
+ */
204
+ export declare function rebuildOnDeadInputs<T>(client: ccc.Client, build: (avoid: ReadonlySet<string>) => Promise<T>, retry?: RetryOptions): Promise<T>;
205
+ export declare function findSessionCells(session: Session, client: ccc.Client, deployment: SessionLockDeployment, binding: OnChainBinding): Promise<SessionCells>;
206
+ /**
207
+ * The recipient the session lock will enforce, taken from the session's own scope
208
+ * so the browser and the chain cannot disagree. The lock holds one recipient, so a
209
+ * scope listing several cannot be enforced on-chain and is refused.
210
+ */
211
+ export declare function onchainRecipient(session: Session): string | undefined;
212
+ /** Options for {@link assertSigningLock}. */
213
+ export type SigningLockOptions = {
214
+ /**
215
+ * Let a lock this kit has not reviewed own a session, with a `console.warn`.
216
+ * Use it only after checking yourself that the lock cannot be unlocked without
217
+ * the owner's signature. A lock known to unlock without it is refused anyway
218
+ * (the deployed anyone-can-pay, PW-Lock and always-success code, under any
219
+ * hash_type; see `assertSigningLock`).
220
+ */
221
+ allowUnreviewedOwnerLock?: boolean;
222
+ };
223
+ /**
224
+ * Throws `SessionPolicyError` unless `lock` is a reviewed configuration of a lock
225
+ * that needs the owner's signature over the whole transaction. The session lock
226
+ * grants owner mode to any transaction with an input under the owner's lock, so
227
+ * that lock is the only thing standing between a stranger and every session.
228
+ * An allowlist, not a blocklist (code review, 14 Oct; mentor review, 2 Nov):
229
+ *
230
+ * Reviewed, accepted:
231
+ * - secp256k1-blake160 (20-byte args); secp256k1 multisig, v1 and v2 (20 bytes,
232
+ * or 28 with a since, which only delays);
233
+ * - Omnilock with a signature auth flag (0x00-0x06: CKB, Ethereum, EOS, Tron,
234
+ * Bitcoin, Dogecoin, multisig; 0x12: Ethereum with the message displayed), and
235
+ * no mode other than time-lock or supply;
236
+ * - Nostr lock in signing mode (args[0] = 0, 21-byte args);
237
+ * - JoyID (closed source: reviewed from its documentation only).
238
+ *
239
+ * Known to unlock without the owner's signature, refused always (reason
240
+ * `"owner-lock-unsafe"`): anyone-can-pay, PW-Lock, always-success (by their
241
+ * type id, or by the data hash of their deployed binaries under any data
242
+ * hash_type), Omnilock in anyone-can-pay or administrator mode, Nostr lock in
243
+ * PoW mode (args[0] != 0). Another build of those locks (a binary with a
244
+ * different data hash) is not recognised: it is refused as unreviewed.
245
+ *
246
+ * Anything else (Omnilock auth 0xFC-0xFE, which hand the decision to another lock
247
+ * or to other code; the proxy locks; unknown locks; args the lock's code would
248
+ * not accept) is refused with reason `"owner-lock-unreviewed"`, unless
249
+ * `allowUnreviewedOwnerLock` is set: then it passes with a warning.
250
+ *
251
+ * The owner must also never sign a partial (open) transaction with this lock.
252
+ */
253
+ export declare function assertSigningLock(lock: ccc.Script, client: ccc.Client, opts?: SigningLockOptions): Promise<void>;
254
+ /** Whose lock `checkSigningLock` checks, for its messages, and the opt-in that lets an unreviewed one through. */
255
+ export type SigningRole = {
256
+ whose: string;
257
+ can: string;
258
+ optIn: string;
259
+ };
260
+ /** `assertSigningLock` for any role: a subscription's charger lock is checked the same way (review M2), with its own opt-in. */
261
+ export declare function checkSigningLock(lock: ccc.Script, client: ccc.Client, allowUnreviewed: boolean, role: SigningRole): Promise<void>;
262
+ /**
263
+ * Owner funds the session: one transaction, one signature from `owner`.
264
+ * The on-chain recipient comes from `session.policy.scope.recipients`.
265
+ *
266
+ * `beforeSend` runs once the transaction is signed and before it is sent: save the
267
+ * session there (`store.save({ ...session, onchain: binding })`). Saved after
268
+ * sending, a failed save would leave funds under a key that exists nowhere. The
269
+ * binding then carries `openTx`, the funding transaction's hash, which
270
+ * `closeSession` checks before reporting that nothing is left.
271
+ *
272
+ * The key cell (`feeBudget`) must be able to return to the owner at the end: by
273
+ * default it is the size of a cell under the owner's lock plus 1 CKB for fees.
274
+ */
275
+ export declare function openSession(owner: ccc.Signer, session: Session, deployment: SessionLockDeployment, opts: {
276
+ budget: bigint;
277
+ feeBudget?: bigint;
278
+ minInterval?: bigint;
279
+ /** A token session: put `amount` units of the xUDT `type` in it, and let one spend move at most `maxPerTx`. */
280
+ token?: {
281
+ type: ccc.ScriptLike;
282
+ amount: bigint;
283
+ maxPerTx: bigint;
284
+ };
285
+ beforeSend?: (binding: OnChainBinding) => Promise<void>;
286
+ /**
287
+ * Called before anything is signed, once per `SessionWarning`; throw to stop the
288
+ * opening. Without it, warnings go to `console.warn`.
289
+ */
290
+ onWarning?: (warning: SessionWarning) => void | Promise<void>;
291
+ } & SigningLockOptions): Promise<{
292
+ txHash: ccc.Hex;
293
+ binding: OnChainBinding;
294
+ }>;
295
+ /**
296
+ * Throws unless `type` is a plain xUDT (RFC 0052) on this network: the session
297
+ * lock reads amounts as xUDT stores them, and an xUDT with any flag set in its
298
+ * args either runs extension scripts the owner did not choose on every spend, or
299
+ * widens who may mint (owner mode by input or output type, code review 14 Oct).
300
+ */
301
+ export declare function assertPlainXudt(type: ccc.Script, client: ccc.Client): Promise<void>;
302
+ /** The network's xUDT code: what `client.getKnownScript(ccc.KnownScript.XUdt)` returns. */
303
+ type XudtCode = {
304
+ codeHash: ccc.Hex;
305
+ hashType: ccc.HashType;
306
+ };
307
+ /** Why `type` is not a plain xUDT under the network's xUDT script `xudt`, or undefined if it is. */
308
+ export declare function plainXudtFault(type: ccc.Script, xudt: XudtCode): string | undefined;
309
+ /**
310
+ * The session key pays `to`: `amount` shannons, or in a token session `token`
311
+ * units of its xUDT. The scope is checked here first, then the network checks it
312
+ * again in the session lock. No wallet is involved.
313
+ *
314
+ * `topUp: true` pays into an existing cell of `to` instead of creating one. `to`
315
+ * must be an anyone-can-pay address with at least one live cell to add to (plain
316
+ * for CKB, holding the session's token for `token`); that cell is consumed and
317
+ * recreated holding more, which the anyone-can-pay lock allows without the
318
+ * recipient's signature. A token paid without `topUp` goes in a new cell, whose
319
+ * capacity (about 142 CKB) the session also pays and must fit in `maxPerTx`.
320
+ *
321
+ * In a token session, tokens always stay in the change: a CKB payment from a
322
+ * cell holding tokens returns them, never burns them.
323
+ *
324
+ * `memo` is recorded in the witness of the session key's own input, which that
325
+ * key's signature covers: the payment commits to it (see `verifyAccess`).
326
+ *
327
+ * With `topUp`, the recipient's cell is a confirmed one that no transaction in
328
+ * the node's pool spends, where the node can tell (`pickPayoutCell`): readers
329
+ * paying at the same moment compete for those cells.
330
+ *
331
+ * If the node rejects the payment because an input is already spent (another
332
+ * tab, device or payer took it first) or unknown, the client's cache is cleared
333
+ * and the payment is built again from the live cells, with another payout
334
+ * cell, after a short wait: up to `retry.attempts` in all (default 3), waiting
335
+ * `retry.delayMs` (default 1000) doubling each time. `beforeSend` runs again
336
+ * with each new hash (`rebuildOnDeadInputs`). A send whose outcome is unknown
337
+ * is never retried.
338
+ */
339
+ export declare function spendInSession(session: Session, client: ccc.Client, deployment: SessionLockDeployment, binding: OnChainBinding, request: SpendRequest, now?: Date): Promise<ccc.Hex>;
340
+ type SpendCommon = {
341
+ to: string;
342
+ topUp?: boolean;
343
+ memo?: ccc.HexLike;
344
+ beforeSend?: (txHash: ccc.Hex) => Promise<void>;
345
+ retry?: RetryOptions;
346
+ };
347
+ type SpendRequest = SpendCommon & ({
348
+ amount: bigint;
349
+ token?: undefined;
350
+ } | {
351
+ token: bigint;
352
+ amount?: undefined;
353
+ });
354
+ /**
355
+ * `completeFeeChangeToOutput` into the last output, with CCC's "Insufficient CKB"
356
+ * (the paying cell holds its floor but not the fee too) as a
357
+ * `SessionBalanceError` with reason `no-fee-cell` (audit round 2, 31 Oct).
358
+ */
359
+ export declare function completeFeeOrNoFeeCell(tx: ccc.Transaction, signer: ccc.Signer, message: string): Promise<void>;
360
+ /** The cells created at least `blocks` blocks before the tip: those a relative `since` of `blocks` can spend. */
361
+ export declare function matureCells(client: ccc.Client, cells: ccc.Cell[], blocks: bigint): Promise<ccc.Cell[]>;
362
+ /**
363
+ * Ends the session: the owner sweeps the session cells (one wallet signature),
364
+ * then the key cell returns to the owner (session key signs, no wallet).
365
+ *
366
+ * The sweep goes first because it is what matters: a key cell too small to pay
367
+ * for the owner's lock (some wallets' locks need more than 61 CKB) must not block
368
+ * it. A key-cell failure is reported in `keyError`; the key stays usable for a retry.
369
+ *
370
+ * `nothingFound` means no cell is left under the session or the key: the key can
371
+ * be forgotten. If the funding transaction (`binding.openTx`) is still in flight,
372
+ * or committed with an output under the session or the key the node still holds
373
+ * live (not indexed yet), this throws instead, so the key is never forgotten
374
+ * before the funds it controls arrive. Once the funding is committed and every
375
+ * one of those outputs is spent (a close whose reply was lost, another tab's
376
+ * close), it is `nothingFound` (audit, 31 Oct).
377
+ *
378
+ * `owner` must be the wallet that opened the session (its lock is
379
+ * `binding.ownerLock`): any other is refused with a `SessionPolicyError` before
380
+ * it is asked to sign anything.
381
+ */
382
+ export declare function closeSession(owner: ccc.Signer, session: Session, deployment: SessionLockDeployment, binding: OnChainBinding): Promise<{
383
+ keyTx?: ccc.Hex;
384
+ sweepTx?: ccc.Hex;
385
+ keyError?: string;
386
+ nothingFound?: true;
387
+ }>;
388
+ /**
389
+ * Every live session cell this owner opened, found without any session key.
390
+ *
391
+ * Session-lock args begin with the owner's lock hash, so an indexer prefix search
392
+ * on the args finds them all. Only well-formed args (80 or 112 bytes; 128 or 160
393
+ * for a token session) are kept: a cell with malformed args would fail the lock
394
+ * even in owner mode, and anyone can create one with this owner's hash as a prefix
395
+ * to block a sweep. Likewise a typed cell is kept only if it holds the session's
396
+ * own token, a plain xUDT, in exactly 16 bytes of data; anything else could make
397
+ * the sweep fail. Cells
398
+ * whose tokens would overflow a u128 together are left out (`withinU128`).
399
+ *
400
+ * Pass several deployments (`[TESTNET_DEPLOYMENT, ...TESTNET_LEGACY_DEPLOYMENTS]`)
401
+ * to find sessions opened under earlier versions of the lock as well.
402
+ */
403
+ export declare function findOwnedSessionCells(owner: ccc.Signer, deployments: SessionLockDeployment | SessionLockDeployment[]): Promise<ccc.Cell[]>;
404
+ /**
405
+ * Device-loss recovery: sweeps every session this owner opened back to the owner,
406
+ * in one transaction and one wallet signature. Needs nothing from the lost device.
407
+ *
408
+ * Anyone can create a cell under a session lock carrying this owner's hash and
409
+ * their own key, and spend it before the sweep lands, which would make a single
410
+ * sweep fail. So if the one transaction is refused, each session (cells under one
411
+ * session lock) is swept on its own, one signature each: a cell someone else can
412
+ * spend fails alone, and `failed` counts the sessions not recovered. A fault no
413
+ * retry can fix (the owner holds no plain cell to prove ownership) is thrown.
414
+ *
415
+ * The key cell (the fee budget) is under the session key's own lock and cannot be
416
+ * recovered without that key; keep it small.
417
+ */
418
+ export declare function recoverSessions(owner: ccc.Signer, deployments: SessionLockDeployment | SessionLockDeployment[]): Promise<{
419
+ txHashes: ccc.Hex[];
420
+ recovered: bigint;
421
+ cells: number;
422
+ failed: number;
423
+ }>;
424
+ /**
425
+ * Spends `cells` in owner mode: everything returns to the owner. Tokens go back
426
+ * in one cell per token type (xUDT would let a sweep burn them otherwise).
427
+ * `memo` goes in the witness (`input_type`) of the owner's own input, which the
428
+ * owner's signature covers: what the sweep is for (`CLEAR_PLANTED_MEMO`).
429
+ */
430
+ export declare function ownerSweep(owner: ccc.Signer, deployments: SessionLockDeployment | SessionLockDeployment[], cells: ccc.Cell[], opts?: {
431
+ memo?: ccc.Hex;
432
+ }): Promise<ccc.Hex>;
433
+ /**
434
+ * Gives an anyone-can-pay address (a creator's `payTo`) `count` more cells to be
435
+ * topped up, paid by `funder`, in one transaction. Each top-up consumes one of
436
+ * these cells, so readers paying at the same moment compete for them; with more
437
+ * cells they rarely pick the same one (mentor review, 2 Nov). Anyone can be the
438
+ * funder: the anyone-can-pay lock needs no signature to receive a new cell.
439
+ *
440
+ * Each cell is as small as a cell under `payTo` can be (61 CKB for a 20-byte
441
+ * args address) unless `capacity` is given. With `token`, each is a cell of that
442
+ * token holding 0 units (about 142 CKB), for token payments. `count` is 1 to
443
+ * `MAX_PAYOUT_CELLS`: a payment reads no more than that many.
444
+ */
445
+ export declare function createPayoutCells(funder: ccc.Signer, payTo: string, opts: {
446
+ count: number;
447
+ capacity?: bigint;
448
+ token?: ccc.ScriptLike;
449
+ beforeSend?: (txHash: ccc.Hex) => Promise<void>;
450
+ }): Promise<ccc.Hex>;
451
+ export {};