@dusk-network/app-core 0.2.0 → 0.3.1
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/CHANGELOG.md +22 -0
- package/README.md +53 -6
- package/package.json +19 -2
- package/src/bridge.d.ts +55 -14
- package/src/bridge.js +439 -199
- package/src/duskevm-withdrawals.d.ts +535 -0
- package/src/duskevm-withdrawals.js +2429 -0
- package/src/history.d.ts +11 -2
- package/src/history.js +14 -6
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A DuskEVM → Dusk withdrawal's whole life, for the Dusk apps, signing
|
|
3
|
+
* aside: the call that starts it on DuskEVM, finding an account's
|
|
4
|
+
* withdrawals again, where each one is (waiting for a dispute game,
|
|
5
|
+
* provable, proved, claimable from a date, claimed), the game a proof goes
|
|
6
|
+
* against and the proof itself, and the proof's and the claim's calls on
|
|
7
|
+
* Dusk, ready for the app's wallet to sign.
|
|
8
|
+
*
|
|
9
|
+
* - Only DUSK withdrawals on the bridge's route count, as Dusk's L1 bridge
|
|
10
|
+
* pays them out (`decodeWithdrawal` of `@dusk-network/networks/duskevm`):
|
|
11
|
+
* from DuskEVM's messenger to Dusk's, relaying DuskEVM's bridge to
|
|
12
|
+
* Dusk's, paying a Dusk account, or a contract only whole lux at the
|
|
13
|
+
* address DuskEVM gives it, and no one past a u64 of lux. Any other
|
|
14
|
+
* message is refused, for its status, its proof and its claim.
|
|
15
|
+
* - A proof goes against a game that covers the withdrawal and has already
|
|
16
|
+
* resolved for its proposal, where the Portal would take it (the anchor
|
|
17
|
+
* state registry calls it proper and respected), so its claim date is
|
|
18
|
+
* exact when it's made; otherwise against the newest game that covers
|
|
19
|
+
* it and that the Portal takes a proof against. A claim date is worked
|
|
20
|
+
* out as the Portal checks a claim (`claimFrom`), and a claim is ready
|
|
21
|
+
* once the Portal takes it, its game has resolved for the defender, and
|
|
22
|
+
* its date has come: all of it read, never on the Portal's check alone.
|
|
23
|
+
* - A proof or a claim is encoded by the Portal's own data driver, which
|
|
24
|
+
* the app loads, and read back before it's handed over: its arguments
|
|
25
|
+
* must say exactly the withdrawal, the game, the output root proof and
|
|
26
|
+
* the proof's nodes they were built from, as Dusk Wallet reads them, or
|
|
27
|
+
* nothing is given to sign. It sends no DUSK along, and its gas limit is
|
|
28
|
+
* 50M and the withdrawal's own gas, at least 1M (`withdrawalGasLimit`),
|
|
29
|
+
* refused over the app's bound.
|
|
30
|
+
* - The app owns all I/O, storage, wallets and words: it passes its own
|
|
31
|
+
* clients (DuskEVM's RPC as a viem client or a URL and `fetch`, the Dusk
|
|
32
|
+
* node's URL with its `fetch`, its Multicall for Dusk batcher), the data
|
|
33
|
+
* drivers it loaded, and its caches. Results are facts; the words are
|
|
34
|
+
* the app's.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```js
|
|
38
|
+
* import { createWithdrawals } from "@dusk/app-core/duskevm-withdrawals";
|
|
39
|
+
*
|
|
40
|
+
* const withdrawals = createWithdrawals({
|
|
41
|
+
* network: chainId,
|
|
42
|
+
* nodeUrl,
|
|
43
|
+
* fetch: createMulticallFetch({ nodeUrl, multicallId }), // the reads one task starts, in one query
|
|
44
|
+
* drivers: { optimismPortal: () => loadDriver(portalUrl), disputeGameFactory: () => loadDriver(factoryUrl) },
|
|
45
|
+
* duskEvm: publicClient, // or { url: rpcUrl, fetch }
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* const status = await withdrawals.status(txHash, { submitter: account });
|
|
49
|
+
* // { stage: "proven_waiting", reason: "game-in-progress", readyAt: 1793589639n, readyAtExact: false, … }
|
|
50
|
+
* const prepared = await withdrawals.prepareProof(txHash, { submitter: account });
|
|
51
|
+
* prepared.claim; // when it can be claimed if proved now: { at, exact, overdue }
|
|
52
|
+
* prepared.call; // { contractId, fnName: "proveWithdrawalTransaction", fnArgs, deposit: 0n, gasLimit: 51_000_000n, … }
|
|
53
|
+
* const claim = await withdrawals.claimCall(txHash, { submitter: account }); // once it's ready
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @module
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
import type { Account, ContractId, EvmAddress, Network, NetworkRef } from "@dusk-network/networks";
|
|
60
|
+
import type { ClaimCall, ClaimDate, DuskTip, ProveCall, WithdrawalFacts } from "@dusk-network/networks/duskevm";
|
|
61
|
+
|
|
62
|
+
/** How many of the newest games a proof is looked for among, by default. */
|
|
63
|
+
export declare const GAME_SEARCH_DEPTH: 64;
|
|
64
|
+
|
|
65
|
+
/** Games one search for a resolved game reads at once. */
|
|
66
|
+
export declare const RESOLVED_PAGE: 32;
|
|
67
|
+
|
|
68
|
+
/** Pages of games a search for a resolved game reads at most. */
|
|
69
|
+
export declare const RESOLVED_PAGES: 3;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* How long past its clock running out a game's resolver is usually done:
|
|
73
|
+
* an hour, in seconds. A game is old enough to have resolved once both
|
|
74
|
+
* have passed.
|
|
75
|
+
*/
|
|
76
|
+
export declare const RESOLVER_LAG_SECONDS: 3600;
|
|
77
|
+
|
|
78
|
+
/** Reads one query holds by default, as Multicall for Dusk's batcher sends them; each game checked takes 4. */
|
|
79
|
+
export declare const MAX_BATCH: 32;
|
|
80
|
+
|
|
81
|
+
/** The gas limit a proof or a claim is refused over by default: 1,000,000,000, the apps' bound. */
|
|
82
|
+
export declare const GAS_LIMIT_UPPER: 1000000000n;
|
|
83
|
+
|
|
84
|
+
/** The gas a withdrawal's start leaves its message on Dusk: 200,000, as OP Stack bridges use. */
|
|
85
|
+
export declare const WITHDRAWAL_MIN_GAS_LIMIT: 200000;
|
|
86
|
+
|
|
87
|
+
/** DuskEVM blocks one log search asks for at once: 100,000, about 2.3 days. */
|
|
88
|
+
export declare const L2_WINDOW: 100000;
|
|
89
|
+
|
|
90
|
+
/** Log searches one run of `syncWithdrawals` makes, the head's included, by default. */
|
|
91
|
+
export declare const L2_RUN_REQUESTS: 8;
|
|
92
|
+
|
|
93
|
+
/** DuskEVM blocks under the head counted as final where the RPC has no "finalized" block: about an hour. */
|
|
94
|
+
export declare const UNFINALIZED_MARGIN: 1800;
|
|
95
|
+
|
|
96
|
+
/** Pages of an address's transactions `explorerWithdrawals` reads at most, by default. */
|
|
97
|
+
export declare const EXPLORER_PAGES: 10;
|
|
98
|
+
|
|
99
|
+
/** Withdrawals `explorerWithdrawals` gives at most, by default. */
|
|
100
|
+
export declare const EXPLORER_ITEMS: 12;
|
|
101
|
+
|
|
102
|
+
/** `MessagePassed(uint256,address,address,uint256,uint256,bytes,bytes32)`: DuskEVM's message passer recording a withdrawal. */
|
|
103
|
+
export declare const MESSAGE_PASSED_TOPIC: "0x02a52367d10742d8032712c1bb8e0144ff1ec5ffda1ed7d70bb05a2744955054";
|
|
104
|
+
|
|
105
|
+
/** `ETHBridgeInitiated(address,address,uint256,bytes)`: DuskEVM's bridge starting a DUSK withdrawal, from its sender. */
|
|
106
|
+
export declare const ETH_BRIDGE_INITIATED_TOPIC: "0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5";
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Where a withdrawal is on Dusk, for the account whose proof counts:
|
|
110
|
+
* waiting for a dispute game to cover it, ready to prove, proved and
|
|
111
|
+
* waiting for its claim date, ready to claim, or claimed.
|
|
112
|
+
*/
|
|
113
|
+
export type WithdrawalStage = "waiting_for_output" | "ready_to_prove" | "proven_waiting" | "ready_to_finalize" | "finalized";
|
|
114
|
+
|
|
115
|
+
/** The stages, by name. */
|
|
116
|
+
export declare const STAGE: Readonly<{
|
|
117
|
+
WAITING_FOR_OUTPUT: "waiting_for_output";
|
|
118
|
+
READY_TO_PROVE: "ready_to_prove";
|
|
119
|
+
PROVEN_WAITING: "proven_waiting";
|
|
120
|
+
READY_TO_FINALIZE: "ready_to_finalize";
|
|
121
|
+
FINALIZED: "finalized";
|
|
122
|
+
}>;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Why a withdrawal waits, or must be proved again:
|
|
126
|
+
* - "no-games": no dispute game has been proposed yet;
|
|
127
|
+
* - "no-output": no game the Portal takes a proof against covers it yet (`error` says what couldn't be read while
|
|
128
|
+
* looking, if anything);
|
|
129
|
+
* - "proof-rejected": the account's proof can't be claimed, as the Portal refuses its game (blacklisted, retired, no
|
|
130
|
+
* longer respected, or won by the challenger), whatever its own check says: it's ready to prove again against
|
|
131
|
+
* another game the Portal takes, or waits for one;
|
|
132
|
+
* - "game-unreadable": the proof's game, or whether the Portal still takes it, can't be read now: no date, and nothing
|
|
133
|
+
* to claim;
|
|
134
|
+
* - "portal-refuses": the claim's date has passed and the Portal still refuses the claim;
|
|
135
|
+
* - "game-in-progress": the proof's game hasn't resolved;
|
|
136
|
+
* - "game-not-final": its game has resolved, and the proof or the game isn't final yet.
|
|
137
|
+
*/
|
|
138
|
+
export type WaitReason =
|
|
139
|
+
| "no-games"
|
|
140
|
+
| "no-output"
|
|
141
|
+
| "proof-rejected"
|
|
142
|
+
| "game-unreadable"
|
|
143
|
+
| "portal-refuses"
|
|
144
|
+
| "game-in-progress"
|
|
145
|
+
| "game-not-final";
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Why the package refuses:
|
|
149
|
+
* - "bad-hash": not a DuskEVM transaction hash;
|
|
150
|
+
* - "not-found": DuskEVM has no receipt of it (yet);
|
|
151
|
+
* - "failed": it failed on DuskEVM;
|
|
152
|
+
* - "not-a-withdrawal": it records no DUSK withdrawal on the bridge's route that Dusk's L1 bridge pays out;
|
|
153
|
+
* - "gas": its proof or claim needs more gas than the bound;
|
|
154
|
+
* - "claimed": it's claimed already, so a proof does nothing;
|
|
155
|
+
* - "proven": the account has a proof of it that stands, and another would cost its fee for nothing;
|
|
156
|
+
* - "no-proof": no game covers it yet (`reason`);
|
|
157
|
+
* - "not-ready": it isn't ready to claim for the account (`status`);
|
|
158
|
+
* - "bad-call": the call its driver encoded doesn't read back as what it was built from.
|
|
159
|
+
*/
|
|
160
|
+
export type WithdrawalErrorCode =
|
|
161
|
+
| "bad-hash"
|
|
162
|
+
| "not-found"
|
|
163
|
+
| "failed"
|
|
164
|
+
| "not-a-withdrawal"
|
|
165
|
+
| "gas"
|
|
166
|
+
| "claimed"
|
|
167
|
+
| "proven"
|
|
168
|
+
| "no-proof"
|
|
169
|
+
| "not-ready"
|
|
170
|
+
| "bad-call";
|
|
171
|
+
|
|
172
|
+
/** A refusal, by its code, with the withdrawal's status where one was read. */
|
|
173
|
+
export declare class WithdrawalError extends Error {
|
|
174
|
+
constructor(
|
|
175
|
+
code: WithdrawalErrorCode,
|
|
176
|
+
message?: string,
|
|
177
|
+
options?: { status?: WithdrawalStatus | null; reason?: WaitReason | null; cause?: unknown }
|
|
178
|
+
);
|
|
179
|
+
readonly code: WithdrawalErrorCode;
|
|
180
|
+
/** The withdrawal's status, for "claimed", "proven" and "not-ready". */
|
|
181
|
+
readonly status: WithdrawalStatus | null;
|
|
182
|
+
/** Why it waits: the status's, or for "no-proof", "no-games" or "no-output". */
|
|
183
|
+
readonly reason: WaitReason | null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** A withdrawal as DuskEVM's message passer recorded it. */
|
|
187
|
+
export type L2Withdrawal = {
|
|
188
|
+
nonce: bigint;
|
|
189
|
+
/** DuskEVM's messenger, with its checksum. */
|
|
190
|
+
sender: EvmAddress;
|
|
191
|
+
/** Dusk's messenger, as DuskEVM names it, with its checksum. */
|
|
192
|
+
target: EvmAddress;
|
|
193
|
+
/** In DuskEVM's 18 decimals. */
|
|
194
|
+
value: bigint;
|
|
195
|
+
/** The gas its own call asks for, which a proof's and a claim's limit add. */
|
|
196
|
+
gasLimit: bigint;
|
|
197
|
+
/** The relayed message, lower-case hex. */
|
|
198
|
+
data: `0x${string}`;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/** A DuskEVM transaction's withdrawal: where DuskEVM recorded it, and what it does. */
|
|
202
|
+
export type ReceiptWithdrawal = {
|
|
203
|
+
/** The DuskEVM transaction, lower case. */
|
|
204
|
+
transactionHash: `0x${string}`;
|
|
205
|
+
/** Its DuskEVM block: a game must cover it. */
|
|
206
|
+
blockNumber: bigint;
|
|
207
|
+
/** The hash the Portal keys its proofs and its claim by, lower case. */
|
|
208
|
+
withdrawalHash: `0x${string}`;
|
|
209
|
+
withdrawal: L2Withdrawal;
|
|
210
|
+
/** What it pays, whom, from whom: `decodeWithdrawal`'s. */
|
|
211
|
+
facts: WithdrawalFacts;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/** Where a withdrawal is, as the chain says, for the account whose proof counts (`proofSubmitter`). */
|
|
215
|
+
export type WithdrawalStatus = ReceiptWithdrawal & {
|
|
216
|
+
stage: WithdrawalStage;
|
|
217
|
+
/** Why it waits; null when it doesn't. */
|
|
218
|
+
reason: WaitReason | null;
|
|
219
|
+
/** For "no-output": the last read that failed while a game was looked for. */
|
|
220
|
+
error?: Error;
|
|
221
|
+
/**
|
|
222
|
+
* The Portal's address of the account whose proof the stage is, lower
|
|
223
|
+
* case: the one asked for, else the recipient's own when it's an
|
|
224
|
+
* account; null for neither.
|
|
225
|
+
*/
|
|
226
|
+
proofSubmitter: `0x${string}` | null;
|
|
227
|
+
/** How many accounts have proved it. */
|
|
228
|
+
proofSubmitterCount: bigint;
|
|
229
|
+
/** Whether the account's proof can't be claimed and must be made again. */
|
|
230
|
+
proofRejected: boolean;
|
|
231
|
+
/** For "ready_to_prove": another account holds a proof that stands, which this account can't claim with. */
|
|
232
|
+
provenByOther?: boolean;
|
|
233
|
+
/**
|
|
234
|
+
* For "ready_to_prove": the game a proof would go against now, the newest
|
|
235
|
+
* that covers it and that the Portal takes a proof against, else one
|
|
236
|
+
* that has resolved, as `prepareProof` finds it; and the DuskEVM block it
|
|
237
|
+
* covers.
|
|
238
|
+
*/
|
|
239
|
+
disputeGameIndex?: bigint;
|
|
240
|
+
proofL2BlockNumber?: bigint;
|
|
241
|
+
/** Once proved: the game the account's proof went against, lower case. */
|
|
242
|
+
disputeGameProxy?: `0x${string}`;
|
|
243
|
+
/** Once proved: when, in seconds of wall-clock time, from the contracts' own clock. */
|
|
244
|
+
provenAt?: bigint;
|
|
245
|
+
/**
|
|
246
|
+
* When it can be claimed, in seconds; null when there's no date (a proof
|
|
247
|
+
* to make again, or a date past while the Portal still refuses). Absent
|
|
248
|
+
* when it couldn't be worked out now, as when the proof's game can't be
|
|
249
|
+
* read: the date known so far stands.
|
|
250
|
+
*/
|
|
251
|
+
readyAt?: bigint | null;
|
|
252
|
+
/** Whether `readyAt` is exact: its game has resolved. */
|
|
253
|
+
readyAtExact?: boolean;
|
|
254
|
+
/** Whether its game is more than an hour late to resolve. */
|
|
255
|
+
claimOverdue?: boolean;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* When a proved withdrawal can be claimed (`ClaimDate`), whether it's
|
|
260
|
+
* claimed, whether it can be claimed now (its game read and resolved for
|
|
261
|
+
* the defender, the Portal taking the claim, its date come), and whether
|
|
262
|
+
* its proof must be made again (the Portal refuses its game: blacklisted,
|
|
263
|
+
* retired, no longer respected, or won by the challenger), with no date
|
|
264
|
+
* then. Fits `/activity`'s `claims`.
|
|
265
|
+
*/
|
|
266
|
+
export type WithdrawalClaim = ClaimDate & { claimed: boolean; ready: boolean; reprove: boolean };
|
|
267
|
+
|
|
268
|
+
/** How long a withdrawal takes on the network, as the Portal and the games say. */
|
|
269
|
+
export type WithdrawalTiming = {
|
|
270
|
+
/** The Portal's proof maturity delay, in seconds. */
|
|
271
|
+
maturitySeconds: number;
|
|
272
|
+
/** The Portal's dispute game finality delay, in seconds. */
|
|
273
|
+
finalitySeconds: number;
|
|
274
|
+
/** How often outputs come: the middle gap between the latest games, in the contracts' seconds; null without two games. */
|
|
275
|
+
outputSeconds: number | null;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/** The game a proof goes against, and the proof. */
|
|
279
|
+
export type OutputProof = {
|
|
280
|
+
/** The game's index in the factory. */
|
|
281
|
+
disputeGameIndex: bigint;
|
|
282
|
+
/** The game's address, lower case. */
|
|
283
|
+
disputeGameProxy: `0x${string}`;
|
|
284
|
+
/** The DuskEVM block the game's output is of. */
|
|
285
|
+
l2BlockNumber: bigint;
|
|
286
|
+
/** The output's root, the game's root claim. */
|
|
287
|
+
outputRoot: `0x${string}`;
|
|
288
|
+
outputRootProof: {
|
|
289
|
+
version: `0x${string}`;
|
|
290
|
+
stateRoot: `0x${string}`;
|
|
291
|
+
messagePasserStorageRoot: `0x${string}`;
|
|
292
|
+
latestBlockhash: `0x${string}`;
|
|
293
|
+
};
|
|
294
|
+
/** The message passer's storage proof of the withdrawal, its nodes as RLP. */
|
|
295
|
+
withdrawalProof: `0x${string}`[];
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/** A proof's or a claim's call on Dusk, for the app's wallet to sign. */
|
|
299
|
+
export type PortalCall = {
|
|
300
|
+
/** The network's Portal. */
|
|
301
|
+
contractId: ContractId;
|
|
302
|
+
fnName: "proveWithdrawalTransaction" | "finalizeWithdrawalTransaction";
|
|
303
|
+
/** The arguments, as the Portal's data driver encoded `args`. */
|
|
304
|
+
fnArgs: Uint8Array;
|
|
305
|
+
/** The driver's input, as JSON takes it: bytes as arrays of numbers. */
|
|
306
|
+
args: unknown;
|
|
307
|
+
/** DUSK sent along: none. */
|
|
308
|
+
deposit: 0n;
|
|
309
|
+
/** 50M and the withdrawal's own gas, at least 1M. */
|
|
310
|
+
gasLimit: bigint;
|
|
311
|
+
/** What the call does, as `decodeBridgeCall` reads its `fnArgs`: what Dusk Wallet shows. */
|
|
312
|
+
decoded: ProveCall | ClaimCall;
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* A proof, ready to sign: the withdrawal, the game and its proof, when it
|
|
317
|
+
* can be claimed if proved now (null when that can't be read), and the
|
|
318
|
+
* call. `at` is when it was prepared: the app decides how long it sends it
|
|
319
|
+
* as is.
|
|
320
|
+
*/
|
|
321
|
+
export type PreparedProof = {
|
|
322
|
+
at: number;
|
|
323
|
+
receipt: ReceiptWithdrawal;
|
|
324
|
+
proof: OutputProof;
|
|
325
|
+
claim: ClaimDate | null;
|
|
326
|
+
call: PortalCall;
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
/** A data driver, as the app loaded it: JSON in, rkyv out, and back. */
|
|
330
|
+
export type DataDriver = {
|
|
331
|
+
encodeInputFn(fnName: string, json: string): Uint8Array;
|
|
332
|
+
decodeOutputFn(fnName: string, bytes: Uint8Array): unknown;
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
/** A driver, a promise of one, or what loads one, once, and again after it failed. */
|
|
336
|
+
export type DriverSource = DataDriver | PromiseLike<DataDriver> | (() => DataDriver | PromiseLike<DataDriver>);
|
|
337
|
+
|
|
338
|
+
/** DuskEVM's JSON-RPC: a viem client (its `request`), or a URL and the `fetch` to post to it. */
|
|
339
|
+
export type DuskEvmClient = { request(args: { method: string; params?: unknown }): Promise<unknown> } | { url: string; fetch?: typeof fetch };
|
|
340
|
+
|
|
341
|
+
/** The app's cache of what a deployment doesn't change, as text: a Map does. */
|
|
342
|
+
export type FactCache = { get(key: string): string | null | undefined; set(key: string, value: string): unknown };
|
|
343
|
+
|
|
344
|
+
/** What `createWithdrawals` takes. */
|
|
345
|
+
export type WithdrawalsOptions = {
|
|
346
|
+
/** The network, or its chain ID: its file names the Portal, the factory, the registry and the bridge's route. */
|
|
347
|
+
network: NetworkRef;
|
|
348
|
+
/** The Dusk node the Portal and the games are read on. */
|
|
349
|
+
nodeUrl: string;
|
|
350
|
+
/** The `fetch` the reads go through: the app's Multicall for Dusk batcher sends those one task starts in one query. */
|
|
351
|
+
fetch?: typeof fetch;
|
|
352
|
+
/** The Portal's and the dispute game factory's data drivers, as the network's file names and pins them. */
|
|
353
|
+
drivers: { optimismPortal: DriverSource; disputeGameFactory: DriverSource };
|
|
354
|
+
/** DuskEVM's RPC; the network file's, by `fetch`, by default. */
|
|
355
|
+
duskEvm?: DuskEvmClient;
|
|
356
|
+
/** Dusk's latest block, which contract times count from; read from the node by default. */
|
|
357
|
+
latestBlock?: () => Promise<DuskTip>;
|
|
358
|
+
/** Reads one query holds: 32 by default. */
|
|
359
|
+
maxBatch?: number;
|
|
360
|
+
/** How many of the newest games a proof is looked for among: 64 by default, and for anything but a positive whole number. */
|
|
361
|
+
gameSearchDepth?: number | bigint;
|
|
362
|
+
/** Where the deployment's fixed facts are kept: each game's hub, each game type's hub, each hub's clock limit. */
|
|
363
|
+
cache?: FactCache;
|
|
364
|
+
/** The clock, in milliseconds. */
|
|
365
|
+
now?: () => number;
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
/** A network's withdrawals, read on its Dusk node and DuskEVM. */
|
|
369
|
+
export type Withdrawals = {
|
|
370
|
+
readonly network: Network;
|
|
371
|
+
/** A DuskEVM transaction's withdrawal, from its receipt; refuses as `parseWithdrawalReceipt` does. */
|
|
372
|
+
receipt(txHash: string): Promise<ReceiptWithdrawal>;
|
|
373
|
+
/**
|
|
374
|
+
* Where a withdrawal is, for `submitter` (a Dusk account, or its
|
|
375
|
+
* Portal address), or else its recipient's account. `proofGame`, the game
|
|
376
|
+
* the last check found the proof against, puts that game's reads in the
|
|
377
|
+
* same query as the Portal's.
|
|
378
|
+
*/
|
|
379
|
+
status(txHash: string, options?: { submitter?: string | null; proofGame?: string | null }): Promise<WithdrawalStatus>;
|
|
380
|
+
/**
|
|
381
|
+
* When the withdrawals `submitter` proved can be claimed, by their hashes
|
|
382
|
+
* (lower case keys): claimed, ready, a date, none, or to prove again.
|
|
383
|
+
* Each one's record and the Portal's check go in one query, their games
|
|
384
|
+
* in the next.
|
|
385
|
+
*/
|
|
386
|
+
claims(hashes: ReadonlyArray<string>, options: { submitter: string }): Promise<Map<string, WithdrawalClaim>>;
|
|
387
|
+
/** How long a withdrawal takes: the Portal's delays with the game count in one query, then the latest games. */
|
|
388
|
+
timing(): Promise<WithdrawalTiming>;
|
|
389
|
+
/**
|
|
390
|
+
* The proof `submitter` signs: against a resolved game where one covers
|
|
391
|
+
* the withdrawal, else the newest that covers it that the Portal takes a
|
|
392
|
+
* proof against. Refused ("claimed",
|
|
393
|
+
* "proven", "gas", "no-proof", "not-a-withdrawal") where it would do
|
|
394
|
+
* nothing or can't be made.
|
|
395
|
+
*/
|
|
396
|
+
prepareProof(txHash: string, options: { submitter: string; gasLimitUpper?: bigint | number }): Promise<PreparedProof>;
|
|
397
|
+
/** The claim `submitter` signs, once its status is ready to claim; refused ("not-ready", "gas") before. */
|
|
398
|
+
claimCall(
|
|
399
|
+
txHash: string,
|
|
400
|
+
options: { submitter: string; gasLimitUpper?: bigint | number; proofGame?: string | null }
|
|
401
|
+
): Promise<PortalCall>;
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
/** A network's withdrawals: the reads go through the app's clients, and nothing is kept outside the object. */
|
|
405
|
+
export declare function createWithdrawals(options: WithdrawalsOptions): Withdrawals;
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* The withdrawal a DuskEVM receipt records: its message passer's
|
|
409
|
+
* `MessagePassed`, whose hash must be its own, on the network's bridge
|
|
410
|
+
* route, as Dusk's L1 bridge pays it out. Throws a WithdrawalError:
|
|
411
|
+
* "not-found" without a receipt, "failed" for a reverted one,
|
|
412
|
+
* "not-a-withdrawal" for anything else.
|
|
413
|
+
*/
|
|
414
|
+
export declare function parseWithdrawalReceipt(network: NetworkRef, receipt: unknown): ReceiptWithdrawal;
|
|
415
|
+
|
|
416
|
+
/** What `withdrawalCall` takes. */
|
|
417
|
+
export type WithdrawalCallInput = {
|
|
418
|
+
/** What it moves, in DuskEVM's 18 decimals: whole lux, more than 0, at most a u64 of lux. */
|
|
419
|
+
amountWei: bigint | number | string;
|
|
420
|
+
/** The Dusk account it pays. */
|
|
421
|
+
to: Account;
|
|
422
|
+
/** The DuskEVM address that sends it, which its message names as its recipient address. */
|
|
423
|
+
sender: string;
|
|
424
|
+
/** The gas it leaves its message on Dusk: `WITHDRAWAL_MIN_GAS_LIMIT` by default. */
|
|
425
|
+
minGasLimit?: number | bigint;
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* A DUSK withdrawal's start on DuskEVM, for the app's EVM wallet to send:
|
|
430
|
+
* DuskEVM's bridge's `bridgeETHTo`, the Dusk account in its extra data,
|
|
431
|
+
* the amount as its value. Throws a RangeError for an amount that isn't
|
|
432
|
+
* whole lux, is 0, or is past a u64 of lux, and a TypeError for a
|
|
433
|
+
* recipient that isn't a Dusk account or a sender that isn't an address.
|
|
434
|
+
*/
|
|
435
|
+
export declare function withdrawalCall(
|
|
436
|
+
network: NetworkRef,
|
|
437
|
+
withdrawal: WithdrawalCallInput
|
|
438
|
+
): { to: EvmAddress; data: `0x${string}`; value: bigint };
|
|
439
|
+
|
|
440
|
+
/** A withdrawal found in DuskEVM's bridge's logs. */
|
|
441
|
+
export type FoundWithdrawal = {
|
|
442
|
+
/** Its DuskEVM transaction, lower case. */
|
|
443
|
+
hash: `0x${string}`;
|
|
444
|
+
blockNumber: number;
|
|
445
|
+
/** What it moves, in DuskEVM's 18 decimals, as text. */
|
|
446
|
+
amountWei: string;
|
|
447
|
+
/** Whom it pays on Dusk, as its extra data says: an account, a contract's ID, or null for neither. */
|
|
448
|
+
destination: string | null;
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
/** Where `syncWithdrawals` got to, kept by the app and passed back as it is. */
|
|
452
|
+
export type WithdrawalScan = {
|
|
453
|
+
/** The final blocks covered, as ranges, highest first. */
|
|
454
|
+
covered: number[][];
|
|
455
|
+
/** What was found, by hash. */
|
|
456
|
+
entries: Record<string, FoundWithdrawal>;
|
|
457
|
+
/** The final head the last run read under. */
|
|
458
|
+
target: number | null;
|
|
459
|
+
/** The blocks one search asks for. */
|
|
460
|
+
window: number;
|
|
461
|
+
updatedAt?: number;
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* One run over an address's withdrawals, from the bridge's own event
|
|
466
|
+
* (`ETHBridgeInitiated`, by its sender), the newest final blocks first, a
|
|
467
|
+
* window at a time, narrower where the RPC asks for it, within
|
|
468
|
+
* `maxRequests`. Only final blocks count as covered: those above can still
|
|
469
|
+
* be reorged away. The next run carries on below and reads only what is
|
|
470
|
+
* new above; under a final head lower than the last run's, what was
|
|
471
|
+
* covered and found above it is dropped, and read again.
|
|
472
|
+
*/
|
|
473
|
+
export declare function syncWithdrawals(options: {
|
|
474
|
+
/** The DuskEVM address that sent them. */
|
|
475
|
+
address: string;
|
|
476
|
+
duskEvm: DuskEvmClient;
|
|
477
|
+
/** The network, for its bridge on DuskEVM; or the bridge's address. */
|
|
478
|
+
network?: NetworkRef;
|
|
479
|
+
bridge?: string;
|
|
480
|
+
state?: WithdrawalScan | null;
|
|
481
|
+
maxRequests?: number;
|
|
482
|
+
now?: () => number;
|
|
483
|
+
}): Promise<{ found: FoundWithdrawal[]; requests: number; state: WithdrawalScan }>;
|
|
484
|
+
|
|
485
|
+
/** A withdrawal as DuskEVM's explorer lists it. */
|
|
486
|
+
export type ExplorerWithdrawal = {
|
|
487
|
+
/** Its DuskEVM transaction, lower case. */
|
|
488
|
+
hash: `0x${string}`;
|
|
489
|
+
/** Who sent it, lower case. */
|
|
490
|
+
from: `0x${string}` | null;
|
|
491
|
+
/** Its DuskEVM block, as text; null where the list doesn't say. */
|
|
492
|
+
blockNumber: string | null;
|
|
493
|
+
/** In DuskEVM's 18 decimals, as text. */
|
|
494
|
+
amountWei: string | null;
|
|
495
|
+
/** Whom it pays on Dusk, as its call says: an account, a contract's ID, or null. */
|
|
496
|
+
destination: string | null;
|
|
497
|
+
/** When it was sent, ISO; null where the explorer doesn't say. */
|
|
498
|
+
timestamp: string | null;
|
|
499
|
+
/** The explorer's own word for where it is ("Ready to prove"); see `explorerStage`. */
|
|
500
|
+
explorerStatus: string | null;
|
|
501
|
+
/** Its claim's transaction, where the explorer knows it. */
|
|
502
|
+
l1TransactionHash: `0x${string}` | null;
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* An address's withdrawals, from DuskEVM's explorer: its own calls to the
|
|
507
|
+
* bridge's `bridgeETHTo` that didn't fail, newest first, up to `maxItems`,
|
|
508
|
+
* each with what the explorer says of it.
|
|
509
|
+
*/
|
|
510
|
+
export declare function explorerWithdrawals(options: {
|
|
511
|
+
network: NetworkRef;
|
|
512
|
+
address: string;
|
|
513
|
+
fetch?: typeof fetch;
|
|
514
|
+
/** The explorer's API: the network file's by default. */
|
|
515
|
+
url?: string;
|
|
516
|
+
maxPages?: number;
|
|
517
|
+
maxItems?: number;
|
|
518
|
+
}): Promise<ExplorerWithdrawal[]>;
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* The DuskEVM transactions of withdrawals known by their nonces, as their
|
|
522
|
+
* proofs and claims on Dusk carry them, from the explorer's list of all
|
|
523
|
+
* withdrawals: newest first, never past the oldest asked for, by nonce as
|
|
524
|
+
* decimal text. However a withdrawal was sent, the list has it.
|
|
525
|
+
*/
|
|
526
|
+
export declare function withdrawalsByNonce(options: {
|
|
527
|
+
network: NetworkRef;
|
|
528
|
+
nonces: ReadonlyArray<bigint>;
|
|
529
|
+
fetch?: typeof fetch;
|
|
530
|
+
url?: string;
|
|
531
|
+
maxPages?: number;
|
|
532
|
+
}): Promise<Map<string, ExplorerWithdrawal>>;
|
|
533
|
+
|
|
534
|
+
/** The stage the explorer's word for a withdrawal stands for; null for one it doesn't have yet. */
|
|
535
|
+
export declare function explorerStage(status: string | null | undefined): WithdrawalStage | null;
|