@dusk-network/app-core 0.1.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to this package are listed here. It follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/).
4
4
 
5
+ ## [0.2.0]
6
+
7
+ ### Added
8
+
9
+ - `/bridge`: `depositArrivals`, `migrationPayouts` and `serviceArrivals`, where a deposit to DuskEVM, a migration and a transfer out to BNB Smart Chain arrived, each credit paying one transfer, in order
10
+
5
11
  ## [0.1.0]
6
12
 
7
13
  ### Added
package/README.md CHANGED
@@ -30,6 +30,7 @@ The entry points are the same on both, under each registry's name: `@dusk-networ
30
30
  | `@dusk-network/app-core/history` | A public account's history from the Dusk archive, synced by block height into the app's store (`createHistory`), through the archive's GraphQL (`createArchive`, `historyArchiveUrl`); its entries as facts (`parseHistoryEntry`, `historyEntry`); a range of heights (`historyRange`); a transaction's details (`fetchTxDetails`, `fetchTxNonce`); and the heights a history covers (`addCoverage`, `topGap`, `shownDownTo`) |
31
31
  | `@dusk-network/app-core/shielded` | A profile's shielded history from the notes its shielded sync keeps, each block asked for among kept decoys (`shieldedHistory`); its entries as facts (`shieldedEntries`); the blocks at the notes' heights (`fetchShieldedBlocks`); the note tree's heights and the decoys drawn from them (`noteTreeHeights`, `readNoteHeights`, `createLeafHeightTap`, `pickHeights`, `leafInfo`) |
32
32
  | `@dusk-network/app-core/activity` | An account's activity as rows of facts, one per transaction, newest first, from its public and shielded history and the wallet's own sends (`activityRows`), and the sends the chain's rows now say all of (`settleSends`) |
33
+ | `@dusk-network/app-core/bridge` | The other side of the bridge's routes: where a deposit to DuskEVM arrived (`depositArrivals`), a migration's payout on Dusk (`migrationPayouts`), and where a transfer out to BNB Smart Chain arrived (`serviceArrivals`); the history's entries as those transfers (`depositOf`, `migrationPayoutOf`, `serviceTransferOf`); and the arrivals as `/activity` takes them (`arrivalsOf`) |
33
34
 
34
35
  Every entry point has its `.d.ts`. The one runtime dependency is `@dusk-network/networks`.
35
36
 
@@ -181,6 +182,34 @@ const { drop, keep } = settleSends({ public: entries, shielded, pending: sends }
181
182
 
182
183
  By default a send adds the name typed for its recipient, or a shielded send's recipient or memo, which the shielded history doesn't have; `keeps(send)` says what else does. A failed send that tried to move an amount is always kept: the chain's row says it moved nothing.
183
184
 
185
+ ## Bridge
186
+
187
+ ```js
188
+ import { arrivalsOf, depositArrivals, depositOf } from "@dusk-network/app-core/bridge";
189
+
190
+ const { arrivals } = await depositArrivals({
191
+ network: chainId,
192
+ deposits: entries.map((entry) => depositOf(entry, account)).filter(Boolean), // `/history`'s entries
193
+ taken: keptArrivals, // the DuskEVM transactions the app's other deposits arrived with
194
+ fetch,
195
+ });
196
+ // arrivals.get(hash): { state: "arrived", hash: "0x029e…", at: 1793080333000, amount: 500000000n, block: 3951755 }
197
+ arrivalsOf(arrivals); // Map { hash => { hash: "0x029e…", at: 1793080333000 } }: `/activity`'s `arrivals`
198
+ ```
199
+
200
+ - Each credit pays one transfer. Equal transfers (the same route, recipient and payout) are paid in the order they were sent: the oldest takes the first credit after it, from 2 minutes before its block, as the chains' clocks differ. The app passes the transfers it still waits for, and the credits its others arrived with (`taken`): none of those pays a waiting one, though an earlier transfer read from the chain takes its own back, as one given but not looked for does.
201
+ - A transfer's time is its Dusk block's, never the device's clock. One without it yet isn't looked for. One sent more than a week ago (`waitMs`) is unknown, and isn't asked about.
202
+ - A deposit is followed on DuskEVM's explorer (`via: "explorer"`, the default): the recipient's incoming calls, newest first, read once for all its deposits, back past the oldest, 5 pages at most. Those calls don't say who deposited, so a payment is a deposit's only when it can't be another's: within 2 minutes either side of its block, once those minutes are over, with no other payment of its amount there (a failed one counts) that isn't another given deposit's. Nothing is asked before then.
203
+ - On DuskEVM's RPC (`via: "rpc"`), a deposit is found by DuskEVM's bridge event from its sender's DuskEVM address. With `/history`'s archive, each sender's equal deposits in the hours before its own are read from its history and paid first; a history too long to read, or a deposit there whose call can't be read, leaves the order unclear. Without it, the RPC's credits are taken as the explorer's are. A deposit given without its sender takes no credit from the sender of another equal one given.
204
+ - A migration is paid by a transfer to the account from its route's payout account, with the migration's transaction hash as the memo, of exactly its amount: from the account's entries, or from the archive's memo index, which gives each payout's own amount. One from that account of another amount leaves it unsure, not waiting: an entry's value holds any gas refund paid to the account. With `entries`, the payouts there of migrations the app didn't list come too (`unlisted`).
205
+ - A transfer out is read from the chain: what the route's account received, the address its memo gives as the route's bridge reads it (0x and 40 hex digits, any case, nothing around them), and its block. It arrives with the DUSK token's `Transfer` from its route's payout address to that address, of what the account received less the fee. The account's history lists every transfer that named the same address, in any case: equal ones in the hours before (a given one's by its own fee) are paid first, and one that can't be read, or a history cut short, leaves the order unclear. One that pays nothing out is `no-payout`, with its `problem`. `serviceTransferOf` gives what left the account (`sent`), and what the account received (`amount`) only where no gas was left to refund: an entry's value holds any refund paid to another account.
206
+ - A route without its payout account or address in the network's file pays out nothing that can be told apart: `no-route`.
207
+ - An RPC search starts at a block from before the transfer, estimated from the chain's pace and checked by its time, and reads 8 windows of 5,000 blocks at most, narrower where the RPC asks for it. A result that isn't arrived says where the next search starts, with what it searched for and the credits found so far (`scan`): the app keeps it with the arrivals it was made with, and passes both back. A search for another sender or amount starts afresh.
208
+
209
+ A result is facts: `arrived`, with the other side's transaction, its block's time, the lux it paid and its block; `waiting`; or `unknown`, with why: `unsure` (a credit could be another's), `late` (none came in its window), `beyond` (the explorer's pages don't reach it), `searching` (carry on from `scan`), `expired`, `no-route`, `no-payout` or `error`. The words are the app's.
210
+
211
+ `activityRows` of `/activity` takes the deposits that arrived as its `arrivals`: `arrivalsOf` gives them by the deposit's hash, the DuskEVM transaction that paid it and when, and the deposit's row says where it arrived. Its `claims` are DuskEVM withdrawals', which this entry point doesn't read.
212
+
184
213
  ## License
185
214
 
186
215
  MPL-2.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dusk-network/app-core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Shared logic for the Dusk apps: public and shielded history, activity rows, bridge arrivals and DuskEVM withdrawals.",
5
5
  "license": "MPL-2.0",
6
6
  "type": "module",
@@ -21,6 +21,10 @@
21
21
  "types": "./src/activity.d.ts",
22
22
  "default": "./src/activity.js"
23
23
  },
24
+ "./bridge": {
25
+ "types": "./src/bridge.d.ts",
26
+ "default": "./src/bridge.js"
27
+ },
24
28
  "./package.json": "./package.json"
25
29
  },
26
30
  "files": [
@@ -35,7 +39,8 @@
35
39
  "typecheck": "npx --yes --package=typescript@5.9.3 -- tsc -p test-types",
36
40
  "check:versions": "node scripts/check-versions.js",
37
41
  "check:jsr": "npx --yes jsr@0.14.3 publish --dry-run --allow-dirty",
38
- "smoke:history": "node scripts/smoke-history.js"
42
+ "smoke:history": "node scripts/smoke-history.js",
43
+ "smoke:bridge": "node scripts/smoke-bridge.js"
39
44
  },
40
45
  "dependencies": {
41
46
  "@dusk-network/networks": "0.3.0"
@@ -0,0 +1,402 @@
1
+ /**
2
+ * The other side of the bridge's routes, as facts, for the Dusk apps:
3
+ * whether a deposit to DuskEVM arrived there, whether a migration from BNB
4
+ * Smart Chain or Ethereum was paid out on Dusk, and whether a transfer out
5
+ * to another chain (Dusk to BNB Smart Chain) arrived there.
6
+ *
7
+ * - Each credit pays one transfer. Equal transfers (the same route,
8
+ * recipient and payout) are paid in the order they were sent: the oldest
9
+ * takes the first credit after it. The app passes the transfers it still
10
+ * waits for, and the credits its others arrived with (`taken`): none of
11
+ * those pays a waiting one, though an earlier transfer read from the
12
+ * chain takes its own back, as one given but not looked for does.
13
+ * - A credit counts from 2 minutes before its transfer's block: Dusk's
14
+ * clock and the other chain's can differ a little. A transfer's time is
15
+ * its Dusk block's, never the device's clock; one without it yet isn't
16
+ * looked for.
17
+ * - Where the credits don't say who sent the transfer (DuskEVM's explorer),
18
+ * or the transfers that could have made them aren't all known, a credit
19
+ * is a transfer's only when it can't be another's: within 2 minutes
20
+ * either side of its block, once those minutes are over, and alone there
21
+ * but for the credits of the other transfers given, a payment that
22
+ * failed counting too. Otherwise the transfer is unsure.
23
+ * - A migration is paid by a transfer to the account from its route's
24
+ * payout account, with the migration's transaction hash as the memo, of
25
+ * exactly its amount. A transfer out arrives with the DUSK token's
26
+ * `Transfer` from its route's payout address to the address its memo
27
+ * gives, of what the route's account received less the bridge's fee, as
28
+ * the transfer's own transaction says. A route without its payout account
29
+ * or address in the network's file pays out nothing that can be told
30
+ * apart. Facts that can't be read leave a transfer unsure, never paid.
31
+ * - Results are facts: arrived, with the other side's transaction, its
32
+ * time, its amount in lux and its block; waiting; or unknown, and why.
33
+ * The words are the app's.
34
+ * - The app owns all I/O and storage: it passes `fetch`, the URLs (the
35
+ * network's file's by default), `/history`'s archive for the Dusk side,
36
+ * and its own caches: the credits it gave other transfers, where the last
37
+ * search stopped, and the chain's block times. Nothing here keeps state
38
+ * outside the calls, so it runs in an extension's service worker as well
39
+ * as in a page.
40
+ *
41
+ * @example
42
+ * ```js
43
+ * import { arrivalsOf, depositArrivals, depositOf } from "@dusk/app-core/bridge";
44
+ *
45
+ * const { arrivals } = await depositArrivals({
46
+ * network: chainId,
47
+ * deposits: entries.map((entry) => depositOf(entry, account)).filter(Boolean),
48
+ * taken: keptArrivals.map((arrival) => arrival.hash), // the DuskEVM transactions other deposits arrived with
49
+ * fetch,
50
+ * });
51
+ * arrivals.get(hash); // { state: "arrived", hash: "0x029e…", at: 1793080333000, amount: 500000000n, block: 3951755 }
52
+ * arrivalsOf(arrivals); // `/activity`'s `arrivals`: the DuskEVM transaction that paid each deposit, and when
53
+ * ```
54
+ *
55
+ * @module
56
+ */
57
+
58
+ import type { Account, EvmAddress, NetworkRef } from "@dusk-network/networks";
59
+ import type { Archive, Direction, EntryKind } from "./history.js";
60
+
61
+ /** How long before its transfer's block a credit still counts: Dusk's clock and the other chain's can differ. 2 minutes, in milliseconds. */
62
+ export declare const CLOCK_SLACK_MS: 120000;
63
+
64
+ /**
65
+ * How long either side of its block a transfer's credit must come, where
66
+ * the credits can't otherwise be told apart: 2 minutes, in milliseconds.
67
+ */
68
+ export declare const CREDIT_WINDOW_MS: 120000;
69
+
70
+ /** How long a transfer is waited for by default before it is unknown: 7 days, in milliseconds. */
71
+ export declare const WAIT_MS: 604800000;
72
+
73
+ /** Pages of an address's incoming calls on DuskEVM's explorer read at most, by default. */
74
+ export declare const EXPLORER_PAGES: 5;
75
+
76
+ /** Blocks one log search asks for at once; narrower where the RPC asks for it. */
77
+ export declare const LOG_WINDOW: 5000;
78
+
79
+ /** Log searches one call makes for a group of equal transfers, by default. */
80
+ export declare const LOG_WINDOWS: 8;
81
+
82
+ /** Equal deposits sent within this of each other are paid in their order: 2 hours, in milliseconds. */
83
+ export declare const DEPOSIT_HORIZON_MS: 7200000;
84
+
85
+ /** Equal transfers out sent within this of each other are paid in their order, or 4 times the route's usual time: 12 hours, in milliseconds. */
86
+ export declare const SERVICE_HORIZON_MS: 43200000;
87
+
88
+ /** Pages of a sender's history read for its earlier equal deposits. */
89
+ export declare const HISTORY_PAGES: 4;
90
+
91
+ /** `Transfer(address,address,uint256)`: the DUSK token's transfer that pays a transfer out. */
92
+ export declare const TRANSFER_TOPIC: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
93
+
94
+ /** `ETHBridgeFinalized(address,address,uint256,bytes)`: DuskEVM's bridge paying a deposit, from the depositor's DuskEVM address. */
95
+ export declare const ETH_BRIDGE_FINALIZED_TOPIC: "0x31b2166ff604fc5672ea5df08a78081d2bc6d746cadce880747f3643d819e83d";
96
+
97
+ /**
98
+ * Where a search stopped: the block the next one starts at, the time of the
99
+ * transfer it began from, the logs it searched for (`search`), and the
100
+ * credits it found before (`seen`), which the next one counts again. A
101
+ * search for other logs, as for another sender or amount, starts afresh.
102
+ * Kept by the app with the credits it was made with, and passed back as it
103
+ * is.
104
+ */
105
+ export type Scan = { from: string; basis: number; search: string; seen?: ReadonlyArray<{ hash: string; block: string; at: number; sender: string | null }> };
106
+
107
+ /**
108
+ * Why a transfer's credit is unknown:
109
+ * - "unsure": a credit could be another transfer's;
110
+ * - "late": its window closed without a credit, and one coming later can't be told apart;
111
+ * - "beyond": the explorer's pages don't reach back to it;
112
+ * - "searching": the search used its windows before it read all it needs; it carries on from `scan`;
113
+ * - "expired": sent longer ago than it's waited for;
114
+ * - "no-route": the network has no such route, or the route's payout account or address isn't known;
115
+ * - "no-payout": a transfer out pays nothing out, as the chain shows it (`problem`);
116
+ * - "error": a read failed (`error`).
117
+ */
118
+ export type UnknownReason = "unsure" | "late" | "beyond" | "searching" | "expired" | "no-route" | "no-payout" | "error";
119
+
120
+ /**
121
+ * Why a transfer out pays nothing out, as the chain shows it: it "failed"
122
+ * on Dusk, went "elsewhere" than the route's account, paid it no more than
123
+ * the bridge's fee ("under-fee"), or has a memo that isn't an address as
124
+ * the route's bridge reads it ("no-address").
125
+ */
126
+ export type NoPayout = "failed" | "elsewhere" | "under-fee" | "no-address";
127
+
128
+ /**
129
+ * What became of a transfer on the other side: "arrived", with the
130
+ * transaction there that paid it (an EVM transaction's hash, lower case, or
131
+ * a Dusk one's for a migration's payout), its block's time in milliseconds
132
+ * (null for a payout whose details aren't read yet), the lux it paid and its
133
+ * block; "waiting" for it; or "unknown", and why. `scan` is where the next
134
+ * search starts.
135
+ */
136
+ export type Arrival =
137
+ | { state: "arrived"; hash: string; at: number | null; amount: bigint; block: number | null }
138
+ | { state: "waiting"; scan?: Scan }
139
+ | { state: "unknown"; reason: UnknownReason; error?: string; problem?: NoPayout; scan?: Scan };
140
+
141
+ /** A `fetch`, as these reads use it: a GET of the explorer's JSON, or a POST of JSON-RPC, and the answer's status and text. */
142
+ export type FetchLike = (
143
+ input: string,
144
+ init: { method: "GET" | "POST"; headers: Record<string, string>; body?: string; signal: AbortSignal }
145
+ ) => Promise<{ ok: boolean; status: number; text(): Promise<string> }>;
146
+
147
+ /** The app's cache of a chain's block times, in milliseconds, by number, as a `Map` is. */
148
+ export type BlockTimes = {
149
+ get(block: number): number | undefined;
150
+ set(block: number, at: number): unknown;
151
+ };
152
+
153
+ /** A deposit to DuskEVM that went through on Dusk (`depositOf`). Amounts in lux. */
154
+ export type Deposit = {
155
+ /** Its Dusk transaction's hash. */
156
+ hash: string;
157
+ amount: bigint | number | string;
158
+ /** The DuskEVM address it pays. */
159
+ to: string;
160
+ /** Its Dusk block's time, in milliseconds; null until the node gave it: it isn't looked for until then. */
161
+ at: number | null;
162
+ /** The Dusk account that sent it: on the RPC, its credit is found by that account's DuskEVM address. */
163
+ sender?: string | null;
164
+ /** Its Dusk block's height: where the sender's history is read back from. */
165
+ height?: number | null;
166
+ /** A DuskEVM block its credit can't be before: the head the app read before sending it. */
167
+ notBefore?: bigint | number | string | null;
168
+ /** Where the last search for it stopped, as its result gave it. */
169
+ scan?: Scan | null;
170
+ };
171
+
172
+ /** What `depositArrivals` takes. */
173
+ export type DepositArrivalOptions = {
174
+ /** The Dusk network, or its chain ID: its DuskEVM, and its URLs. */
175
+ network: NetworkRef;
176
+ /** The deposits waited for: each once, by hash. */
177
+ deposits: Iterable<Deposit>;
178
+ /**
179
+ * Where the credits are read: "explorer", the recipients' incoming calls
180
+ * on DuskEVM's explorer (its Blockscout API), the default; or "rpc",
181
+ * DuskEVM's bridge events on its RPC, by the sender's DuskEVM address.
182
+ */
183
+ via?: "explorer" | "rpc";
184
+ /** The `fetch` to send requests with; `globalThis.fetch` when not given. */
185
+ fetch?: FetchLike;
186
+ /** DuskEVM's explorer API; the network's by default. */
187
+ explorerUrl?: string;
188
+ /** DuskEVM's RPC; the network's by default. */
189
+ rpcUrl?: string;
190
+ /**
191
+ * `/history`'s archive, for "rpc": each sender's equal deposits in the
192
+ * hours before its own are read from its history, those given but not
193
+ * looked for too, and paid first.
194
+ * Without it, or for a deposit without its sender and height, its credit
195
+ * is a deposit's only as where they can't be told apart.
196
+ */
197
+ archive?: Archive;
198
+ /**
199
+ * DuskEVM transactions the app's other deposits arrived with: pass those
200
+ * deposits through these alone, not among `deposits`. No deposit looked
201
+ * for takes them; one read from a sender's history may, as its own.
202
+ */
203
+ taken?: Iterable<string>;
204
+ /** DuskEVM's block times the app keeps, for "rpc". */
205
+ blockTimes?: BlockTimes;
206
+ /** The clock, in milliseconds. */
207
+ now?: number;
208
+ /** How long a deposit is waited for; `WAIT_MS` by default. */
209
+ waitMs?: number;
210
+ /** `CREDIT_WINDOW_MS` by default. */
211
+ windowMs?: number;
212
+ /** `EXPLORER_PAGES` by default. */
213
+ maxPages?: number;
214
+ /** `LOG_WINDOWS` by default. */
215
+ maxWindows?: number;
216
+ /** How long one request may take, in milliseconds: 8,000 by default. */
217
+ timeoutMs?: number;
218
+ };
219
+
220
+ /**
221
+ * Where each deposit arrived on DuskEVM, by its Dusk transaction's hash
222
+ * (lower case), in the order given, and the requests it took. Each credit
223
+ * pays one deposit, in the order they were sent.
224
+ *
225
+ * On the explorer, the recipient's incoming calls are read once for all its
226
+ * deposits, newest first, back past the oldest one waited for, at most
227
+ * `maxPages` pages; none is asked while every deposit's window is still
228
+ * open. On the RPC, a group of equal deposits from one sender is searched
229
+ * from about when the first was sent, `maxWindows` windows at most.
230
+ * A network without DuskEVM asks nothing. Throws a TypeError for a deposit
231
+ * that isn't one, and for a network there's no file for.
232
+ */
233
+ export declare function depositArrivals(options: DepositArrivalOptions): Promise<{ arrivals: Map<string, Arrival>; requests: number }>;
234
+
235
+ /**
236
+ * A transfer out to another chain on a service route, sent to the route's
237
+ * account on Dusk (`serviceTransferOf`). What it paid that account, the
238
+ * address its memo gives, and its block's height and time are read from
239
+ * the chain.
240
+ */
241
+ export type ServiceTransfer = {
242
+ /** Its Dusk transaction's hash. */
243
+ hash: string;
244
+ /** Its route's ID, as "dusk-to-bsc". */
245
+ route: string;
246
+ /** The bridge's fee, in lux; the route's by default. */
247
+ fee?: bigint | number | string | null;
248
+ /** A block of the other chain its payout can't be before: the head the app read before sending it. */
249
+ notBefore?: bigint | number | string | null;
250
+ scan?: Scan | null;
251
+ };
252
+
253
+ /** What `serviceArrivals` takes. */
254
+ export type ServiceArrivalOptions = {
255
+ network: NetworkRef;
256
+ transfers: Iterable<ServiceTransfer>;
257
+ /** `/history`'s archive: each transfer, and the route's account's history, which lists the equal ones paid before. */
258
+ archive: Archive;
259
+ fetch?: FetchLike;
260
+ /** The other chain's RPC; the route's by default. */
261
+ rpcUrl?: string;
262
+ /** Transactions on the other chain that paid the app's other transfers, which aren't among `transfers`. */
263
+ taken?: Iterable<string>;
264
+ /** That chain's block times the app keeps. */
265
+ blockTimes?: BlockTimes;
266
+ now?: number;
267
+ waitMs?: number;
268
+ maxWindows?: number;
269
+ timeoutMs?: number;
270
+ };
271
+
272
+ /**
273
+ * Where each transfer out arrived on its chain, by its Dusk transaction's
274
+ * hash, in the order given, and the requests it took: the DUSK token's
275
+ * `Transfer` from the route's payout address to the address the memo gives,
276
+ * of what the route's account received less the fee. Each transfer is read
277
+ * from the chain, in one request: one the archive doesn't have yet is
278
+ * waiting, and one that pays nothing out is `no-payout`. The transfers the
279
+ * route's account received in the hours before that named the same address,
280
+ * in any case, and pay out the same are paid first: its history lists them,
281
+ * and their own transactions say what each received (one given but not
282
+ * looked for pays out what its own fee leaves). One that can't be
283
+ * read, or a history cut short, leaves the order unclear: unsure. Throws a
284
+ * TypeError without an archive, and for a network there's no file for.
285
+ */
286
+ export declare function serviceArrivals(options: ServiceArrivalOptions): Promise<{ arrivals: Map<string, Arrival>; requests: number }>;
287
+
288
+ /** A migration into Dusk, as its chain shows it. */
289
+ export type Migration = {
290
+ /** Its transaction's hash on its chain. */
291
+ hash: string;
292
+ /** Its route's ID, as "bsc-to-dusk". */
293
+ route: string;
294
+ /** The DUSK it migrates, in lux. */
295
+ amount: bigint | number | string;
296
+ /** When it was sent, in milliseconds: it's waited for `waitMs` from then. */
297
+ at?: number | null;
298
+ };
299
+
300
+ /** A payout of a migration, as the account's history has it (`migrationPayoutOf`). */
301
+ export type MigrationPayout = {
302
+ /** The migration's transaction hash, from the memo, lower case. */
303
+ hash: `0x${string}`;
304
+ route: string;
305
+ /** What it paid, in lux. */
306
+ amount: bigint;
307
+ /** The payout's Dusk transaction. */
308
+ payout: string;
309
+ /** Its block's time, in milliseconds; null before its details are read. */
310
+ at: number | null;
311
+ /** Its block's height. */
312
+ block: number;
313
+ };
314
+
315
+ /** What `migrationPayouts` takes: the account's entries, or the archive and the account. */
316
+ export type MigrationPayoutOptions = {
317
+ network: NetworkRef;
318
+ migrations: Iterable<Migration>;
319
+ /** The account's public history, as `/history` reads or keeps it. */
320
+ entries?: Iterable<HistoryLike>;
321
+ /** Without `entries`: the archive's memo index is asked for each migration's payout, in one request. */
322
+ archive?: Archive;
323
+ /** The account the migrations pay, which the archive is read for. */
324
+ account?: string;
325
+ /** Payouts other migrations have. */
326
+ taken?: Iterable<string>;
327
+ now?: number;
328
+ waitMs?: number;
329
+ };
330
+
331
+ /**
332
+ * Each migration's payout on Dusk, by the migration's hash (lower case), in
333
+ * the order given; with `entries`, the payouts there of migrations not given
334
+ * (`unlisted`: sent from another device, or before); and the requests it
335
+ * took. Each payout pays one migration. A payout of the migration of another
336
+ * amount leaves it unsure, not waiting: an entry's value holds any gas
337
+ * refund paid to the account; the memo index gives each payout's own.
338
+ */
339
+ export declare function migrationPayouts(
340
+ options: MigrationPayoutOptions
341
+ ): Promise<{ payouts: Map<string, Arrival>; unlisted: MigrationPayout[]; requests: number }>;
342
+
343
+ /** An entry of an account's public history, as `/history` reads or keeps it: amounts as bigints or decimal strings. */
344
+ export type HistoryLike = {
345
+ hash: string;
346
+ blockHeight: number;
347
+ direction: Direction;
348
+ kind: EntryKind;
349
+ counterparty: string | null;
350
+ value: bigint | string;
351
+ memo: string;
352
+ payer: boolean;
353
+ timestamp?: number | null;
354
+ success?: boolean | null;
355
+ bridge?: { kind: string; amount?: string; to?: string } | null;
356
+ [field: string]: unknown;
357
+ };
358
+
359
+ /**
360
+ * A deposit to DuskEVM the account sent, from its entry, once its details
361
+ * read its call: its amount and DuskEVM address, its block's time and
362
+ * height, and `account` as its sender. Null for any other entry, and for one
363
+ * that failed.
364
+ */
365
+ export declare function depositOf(entry: HistoryLike, account?: Account): (Deposit & { amount: bigint; to: EvmAddress }) | null;
366
+
367
+ /** A transfer to a service route's account, and why it pays nothing out, if it doesn't. */
368
+ export type ServiceTransferFacts = {
369
+ hash: string;
370
+ route: string;
371
+ /** What left the account: the transfer, and any gas refund it paid another account, which the entry doesn't tell apart. */
372
+ sent: bigint;
373
+ /** What the route's account received: known only where no gas was left to refund; null otherwise. */
374
+ amount: bigint | null;
375
+ fee: bigint;
376
+ /** The address its memo gives, exactly as the bridge reads it; null when it isn't one. */
377
+ to: string | null;
378
+ at: number | null;
379
+ height: number | null;
380
+ /** "failed" on Dusk; "under-fee": no more than the fee left the account; "no-address": a memo that isn't an address; null when none is known. */
381
+ problem: "failed" | "under-fee" | "no-address" | null;
382
+ };
383
+
384
+ /**
385
+ * A transfer the account sent to a service route's account, as its entry
386
+ * says it; null for any other entry. The memo is read as the route's bridge
387
+ * reads it: 0x and 40 hex digits, any case, nothing around them.
388
+ */
389
+ export declare function serviceTransferOf(entry: HistoryLike, network: NetworkRef): ServiceTransferFacts | null;
390
+
391
+ /**
392
+ * A payout of a migration, from its entry: a transfer the account received
393
+ * from a migration route's payout account, with a transaction hash as the
394
+ * memo. Null for any other entry, and on a route without its payout account.
395
+ */
396
+ export declare function migrationPayoutOf(entry: HistoryLike, network: NetworkRef): MigrationPayout | null;
397
+
398
+ /**
399
+ * The deposits that arrived, as `/activity`'s `arrivals` takes them: by the
400
+ * deposit's hash, the DuskEVM transaction that paid it and when.
401
+ */
402
+ export declare function arrivalsOf(arrivals: ReadonlyMap<string, Arrival>): Map<string, { hash: string; at: number | null }>;