@dusk-network/networks 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 +7 -0
- package/README.md +10 -0
- package/networks/testnet.json +1 -0
- package/package.json +5 -1
- package/schema.json +5 -1
- package/src/duskevm.d.ts +144 -0
- package/src/duskevm.js +170 -0
- package/src/index.d.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
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
|
+
- `/duskevm`: when a DuskEVM withdrawal can be claimed, whether it can be claimed now, and which dispute games a proof can go against
|
|
10
|
+
- `duskEvm.l1AdapterUrl`: the DuskEVM adapter's RPC beside DuskEVM's own
|
|
11
|
+
|
|
5
12
|
## [0.1.0]
|
|
6
13
|
|
|
7
14
|
### Added
|
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ The entry points are the same on both, under each registry's name: `@dusk-networ
|
|
|
28
28
|
| `@dusk-network/networks` | `networks`, `networkFor(chainId)`, `labelFor(net, id)`, `isBlocked(net, account)`, `blockedReason(net, account)`, `routes(net)`, `bridgeLink(net, { route, to })` |
|
|
29
29
|
| `@dusk-network/networks/sozu` | Sozu's fee, stDUSK and minimum rules, its gas, the hub's argument bytes, the reply decoders and `readSozuStatus` |
|
|
30
30
|
| `@dusk-network/networks/rates` | `nativeRateEstimate` and `sozuRateEstimate`, as yearly fractions |
|
|
31
|
+
| `@dusk-network/networks/duskevm` | When a DuskEVM withdrawal can be claimed (`claimFrom`), whether it can be claimed now (`claimReadiness`), the games a proof can go against (`isEligibleGame`), and the contracts' clock |
|
|
31
32
|
| `@dusk-network/networks/format` | `formatDusk`, `formatDuskPlain`, `formatTime`, `formatContractId`, `shortAccount`, `formatEvmAddress` |
|
|
32
33
|
| `@dusk-network/networks/networks/<name>.json` | `mainnet`, `testnet` or `devnet` as data |
|
|
33
34
|
| `@dusk-network/networks/schema.json` | The files' JSON Schema |
|
|
@@ -71,6 +72,15 @@ const call = sozuCall(status.contracts.pool, SOZU_FN.STAKE, amount); // { contra
|
|
|
71
72
|
const { limit, minimum } = SOZU_GAS[call.fnName]; // warn while typing under the minimum
|
|
72
73
|
```
|
|
73
74
|
|
|
75
|
+
A DuskEVM withdrawal's claim date comes from the chain: the app reads the proof's dispute game on its hub, the Portal's two delays and Dusk's latest block, and `/duskevm` works out the date as the Portal checks a claim:
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
import { claimFrom, claimReadiness } from "@dusk-network/networks/duskevm";
|
|
79
|
+
|
|
80
|
+
const claim = claimFrom({ provenAt, game, portal, tip }); // { at, exact, overdue }: "about" until the game resolves
|
|
81
|
+
claimReadiness({ claim, portalAccepts, tip }).ready; // the Portal's yes counts from the date only
|
|
82
|
+
```
|
|
83
|
+
|
|
74
84
|
The bridge takes a route and a Dusk recipient in its link. `bridgeLink` builds it, and gives null while the network's bridge has no published address:
|
|
75
85
|
|
|
76
86
|
```js
|
package/networks/testnet.json
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"symbol": "DUSK"
|
|
45
45
|
},
|
|
46
46
|
"rpcUrl": "https://rpc.testnet.evm.dusk.network",
|
|
47
|
+
"l1AdapterUrl": "https://rpc.testnet.evm.dusk.network/l1",
|
|
47
48
|
"explorerUrl": "https://explorer.testnet.evm.dusk.network",
|
|
48
49
|
"blockscoutApiUrl": "https://explorer.testnet.evm.dusk.network/api/v2",
|
|
49
50
|
"predeploys": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dusk-network/networks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Dusk's networks for the Dusk apps: endpoints, contracts, routes and labels, with Sozu's rules, reward estimates and shared formats.",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
"types": "./src/format.d.ts",
|
|
26
26
|
"default": "./src/format.js"
|
|
27
27
|
},
|
|
28
|
+
"./duskevm": {
|
|
29
|
+
"types": "./src/duskevm.d.ts",
|
|
30
|
+
"default": "./src/duskevm.js"
|
|
31
|
+
},
|
|
28
32
|
"./networks/*.json": {
|
|
29
33
|
"types": "./src/network-file.d.ts",
|
|
30
34
|
"default": "./networks/*.json"
|
package/schema.json
CHANGED
|
@@ -250,12 +250,16 @@
|
|
|
250
250
|
"duskEvm": {
|
|
251
251
|
"type": "object",
|
|
252
252
|
"additionalProperties": false,
|
|
253
|
-
"required": ["name", "chainId", "currency", "rpcUrl", "explorerUrl", "blockscoutApiUrl", "predeploys", "drivers", "contracts", "source"],
|
|
253
|
+
"required": ["name", "chainId", "currency", "rpcUrl", "l1AdapterUrl", "explorerUrl", "blockscoutApiUrl", "predeploys", "drivers", "contracts", "source"],
|
|
254
254
|
"properties": {
|
|
255
255
|
"name": { "description": "The chain's name as wallets list it.", "type": "string", "minLength": 1 },
|
|
256
256
|
"chainId": { "type": "integer", "minimum": 1 },
|
|
257
257
|
"currency": { "$ref": "#/$defs/currency" },
|
|
258
258
|
"rpcUrl": { "$ref": "#/$defs/url" },
|
|
259
|
+
"l1AdapterUrl": {
|
|
260
|
+
"description": "The DuskEVM adapter's RPC beside the chain's own. It answers for DuskEVM (its chain ID); the bridge asks it which DuskEVM deposit a Dusk transaction made.",
|
|
261
|
+
"$ref": "#/$defs/url"
|
|
262
|
+
},
|
|
259
263
|
"explorerUrl": { "$ref": "#/$defs/url" },
|
|
260
264
|
"blockscoutApiUrl": { "$ref": "#/$defs/url" },
|
|
261
265
|
"predeploys": {
|
package/src/duskevm.d.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When a DuskEVM withdrawal can be claimed on Dusk, worked out the way the
|
|
3
|
+
* Portal checks a claim: from the later of the proof's maturity
|
|
4
|
+
* (`proofMaturityDelaySeconds` after it was made) and its dispute game's
|
|
5
|
+
* finality (`disputeGameFinalityDelaySeconds` after the game resolved).
|
|
6
|
+
* Exact once the game has resolved; before that, the earliest it can be,
|
|
7
|
+
* from the game's clock (`maxClockDuration`). Pure: each app reads the
|
|
8
|
+
* game, the Portal and Dusk's latest block itself.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```js
|
|
12
|
+
* import { claimFrom, claimReadiness } from "@dusk/networks/duskevm";
|
|
13
|
+
*
|
|
14
|
+
* const claim = claimFrom({
|
|
15
|
+
* provenAt: 46_877_440n, // the Portal's proof time
|
|
16
|
+
* game: { createdAt: 46_876_050n, resolvedAt: 0n, status: 0, maxClockDuration: 302_400n },
|
|
17
|
+
* portal: { proofMaturityDelaySeconds: 604_800n, disputeGameFinalityDelaySeconds: 302_400n },
|
|
18
|
+
* tip: { height: 4_704_959n, timestamp: 1_793_156_989n }, // Dusk's latest block
|
|
19
|
+
* });
|
|
20
|
+
* // { at: Date.UTC(2026, 10, 2, 3, 20, 39), exact: false, overdue: false }: "about Mon 2 Nov, 04:20 CET"
|
|
21
|
+
* claimReadiness({ claim, portalAccepts: false, tip }); // { ready: false, readyAt: 1793589639n, … }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** Dusk's latest block: its height, and its time in seconds. */
|
|
28
|
+
export type DuskTip = { height: bigint | number; timestamp: bigint | number };
|
|
29
|
+
|
|
30
|
+
/** What a deployment's contracts count: Dusk block height × 10 (testnet), or block time. */
|
|
31
|
+
export type ContractClock = "height" | "timestamp";
|
|
32
|
+
|
|
33
|
+
/** A dispute game as its hub gives it, with the hub's clock limit. */
|
|
34
|
+
export type ClaimGame = {
|
|
35
|
+
createdAt: bigint | number;
|
|
36
|
+
resolvedAt: bigint | number;
|
|
37
|
+
status: number;
|
|
38
|
+
maxClockDuration: bigint | number;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** The Portal's two delays, in the contracts' seconds. */
|
|
42
|
+
export type PortalDelays = {
|
|
43
|
+
proofMaturityDelaySeconds: bigint | number;
|
|
44
|
+
disputeGameFinalityDelaySeconds: bigint | number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** What `claimFrom` takes. */
|
|
48
|
+
export type ClaimInput = {
|
|
49
|
+
/** The Portal's proof time, in the contracts' time; none for a proof made now. */
|
|
50
|
+
provenAt?: bigint | number | null;
|
|
51
|
+
/** The proof's dispute game; none when it couldn't be read. */
|
|
52
|
+
game: ClaimGame | null | undefined;
|
|
53
|
+
portal: PortalDelays;
|
|
54
|
+
tip: DuskTip;
|
|
55
|
+
/** The deployment's clock; read from the game's own time when not given. */
|
|
56
|
+
clock?: ContractClock;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* When a withdrawal can be claimed: `at` in milliseconds, `exact` once the
|
|
61
|
+
* game has resolved (else "about"), `overdue` when the game is more than
|
|
62
|
+
* an hour late to resolve. `at` is null when the challenger won, or the hub
|
|
63
|
+
* doesn't know the game.
|
|
64
|
+
*/
|
|
65
|
+
export type ClaimDate = { at: number | null; exact: boolean; overdue: boolean };
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* What a claim date means now: `ready` to claim, from when (`readyAt`, in
|
|
69
|
+
* seconds), and `refused` when the date has passed while the Portal still
|
|
70
|
+
* refuses the claim, so the date says nothing more.
|
|
71
|
+
*/
|
|
72
|
+
export type ClaimReadiness = {
|
|
73
|
+
ready: boolean;
|
|
74
|
+
readyAt: bigint | null;
|
|
75
|
+
readyAtExact: boolean;
|
|
76
|
+
claimOverdue: boolean;
|
|
77
|
+
refused: boolean;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** What decides which games a proof can go against. */
|
|
81
|
+
export type GameRules = {
|
|
82
|
+
/** The anchor state registry's `respectedGameTypeUpdatedAt`: games created then or before are retired. */
|
|
83
|
+
respectedGameTypeUpdatedAt: bigint | number;
|
|
84
|
+
/** The L2 block of the withdrawal: a game must cover it. */
|
|
85
|
+
withdrawalBlockNumber: bigint | number;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/** A game with its hub's status and the registry's answers; null where one couldn't be read. */
|
|
89
|
+
export type GameCheck = {
|
|
90
|
+
createdAt: bigint | number;
|
|
91
|
+
l2BlockNumber: bigint | number;
|
|
92
|
+
status: number | null;
|
|
93
|
+
proper: boolean | null;
|
|
94
|
+
respected: boolean | null;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** A dispute game's status, as its hub gives it. */
|
|
98
|
+
export declare const GAME_STATUS: Readonly<{ IN_PROGRESS: 0; CHALLENGER_WINS: 1; DEFENDER_WINS: 2 }>;
|
|
99
|
+
|
|
100
|
+
/** A game still unresolved this long past the earliest it could resolve is overdue: an hour. */
|
|
101
|
+
export declare const OVERDUE_SECONDS: bigint;
|
|
102
|
+
|
|
103
|
+
/** The clock a deployment's contracts keep, read from one of their times and the tip. */
|
|
104
|
+
export declare function contractClock(sample: bigint | number, tip: DuskTip): ContractClock;
|
|
105
|
+
|
|
106
|
+
/** The contracts' time at the tip. */
|
|
107
|
+
export declare function contractNow(clock: ContractClock, tip: DuskTip): bigint;
|
|
108
|
+
|
|
109
|
+
/** A contract time as wall-clock milliseconds. */
|
|
110
|
+
export declare function wallTime(seconds: bigint | number, clock: ContractClock, tip: DuskTip): number;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* When a withdrawal can be claimed: from max(proof + maturity, game
|
|
114
|
+
* resolved + finality), exact once the game has resolved, the earliest
|
|
115
|
+
* before.
|
|
116
|
+
*/
|
|
117
|
+
export declare function claimFrom(input: ClaimInput): ClaimDate;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Whether a proven withdrawal can be claimed now: once the Portal's check
|
|
121
|
+
* passes and its date has come, not before.
|
|
122
|
+
*/
|
|
123
|
+
export declare function claimReadiness(input: {
|
|
124
|
+
claim: ClaimDate | null | undefined;
|
|
125
|
+
portalAccepts: boolean;
|
|
126
|
+
tip: DuskTip;
|
|
127
|
+
}): ClaimReadiness;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Whether a game is worth checking for a proof, before its status and the
|
|
131
|
+
* registry are read: it covers the withdrawal, and it was created after the
|
|
132
|
+
* respected game type last changed.
|
|
133
|
+
*/
|
|
134
|
+
export declare function isCandidateGame(
|
|
135
|
+
game: { createdAt: bigint | number; l2BlockNumber: bigint | number },
|
|
136
|
+
rules: GameRules
|
|
137
|
+
): boolean;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Whether a proof can go against a game and be claimed exactly its maturity
|
|
141
|
+
* delay later: a candidate that has resolved for its proposal (the defender
|
|
142
|
+
* won), and that the registry calls proper and respected.
|
|
143
|
+
*/
|
|
144
|
+
export declare function isEligibleGame(game: GameCheck, rules: GameRules): boolean;
|
package/src/duskevm.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/* @ts-self-types="./duskevm.d.ts" */
|
|
2
|
+
/**
|
|
3
|
+
* When a DuskEVM withdrawal can be claimed on Dusk, worked out the way the
|
|
4
|
+
* Portal checks a claim:
|
|
5
|
+
* - the proof has matured: `proofMaturityDelaySeconds` after it was made;
|
|
6
|
+
* - its dispute game has resolved for its proposal and is final:
|
|
7
|
+
* `disputeGameFinalityDelaySeconds` after it resolved.
|
|
8
|
+
* It's exact once the game has resolved. Before that, the game resolves no
|
|
9
|
+
* sooner than its clock runs out (`maxClockDuration` after it was created),
|
|
10
|
+
* which gives the earliest date, an estimate.
|
|
11
|
+
*
|
|
12
|
+
* The times are the contracts' own. The deployed testnet contracts count
|
|
13
|
+
* Dusk block height × 10; the others count block time and compare
|
|
14
|
+
* strictly, so a claim there comes a second later. Pure: each app reads the
|
|
15
|
+
* game, the Portal and Dusk's latest block itself, and passes them in.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** @typedef {import("./duskevm.js").DuskTip} DuskTip */
|
|
21
|
+
/** @typedef {import("./duskevm.js").ContractClock} ContractClock */
|
|
22
|
+
/** @typedef {import("./duskevm.js").ClaimDate} ClaimDate */
|
|
23
|
+
|
|
24
|
+
/** A dispute game's status, as its hub gives it. */
|
|
25
|
+
export const GAME_STATUS = Object.freeze({
|
|
26
|
+
CHALLENGER_WINS: 1,
|
|
27
|
+
DEFENDER_WINS: 2,
|
|
28
|
+
IN_PROGRESS: 0,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/** A game still unresolved this long past the earliest it could resolve is overdue. */
|
|
32
|
+
export const OVERDUE_SECONDS = 3_600n;
|
|
33
|
+
|
|
34
|
+
/** @type {ClaimDate} */
|
|
35
|
+
const NO_DATE = Object.freeze({ at: null, exact: false, overdue: false });
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {bigint} a
|
|
39
|
+
* @param {bigint} b
|
|
40
|
+
*/
|
|
41
|
+
const distance = (a, b) => (a > b ? a - b : b - a);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {bigint} a
|
|
45
|
+
* @param {bigint} b
|
|
46
|
+
*/
|
|
47
|
+
const later = (a, b) => (a > b ? a : b);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* At the tip the two clocks are decades apart, so a time is on whichever
|
|
51
|
+
* it's nearer.
|
|
52
|
+
*
|
|
53
|
+
* @param {bigint | number} sample
|
|
54
|
+
* @param {DuskTip} tip
|
|
55
|
+
* @returns {ContractClock}
|
|
56
|
+
*/
|
|
57
|
+
export function contractClock(sample, tip) {
|
|
58
|
+
const time = BigInt(sample);
|
|
59
|
+
|
|
60
|
+
return distance(time, 10n * BigInt(tip.height)) < distance(time, BigInt(tip.timestamp))
|
|
61
|
+
? "height"
|
|
62
|
+
: "timestamp";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {ContractClock} clock
|
|
67
|
+
* @param {DuskTip} tip
|
|
68
|
+
* @returns {bigint}
|
|
69
|
+
*/
|
|
70
|
+
export const contractNow = (clock, tip) =>
|
|
71
|
+
clock === "height" ? 10n * BigInt(tip.height) : BigInt(tip.timestamp);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* On the height clock a time is counted from the tip, at Dusk's 10 seconds
|
|
75
|
+
* a block.
|
|
76
|
+
*
|
|
77
|
+
* @param {bigint | number} seconds
|
|
78
|
+
* @param {ContractClock} clock
|
|
79
|
+
* @param {DuskTip} tip
|
|
80
|
+
* @returns {number}
|
|
81
|
+
*/
|
|
82
|
+
export function wallTime(seconds, clock, tip) {
|
|
83
|
+
const time = BigInt(seconds);
|
|
84
|
+
const wall = clock === "height" ? BigInt(tip.timestamp) + time - 10n * BigInt(tip.height) : time;
|
|
85
|
+
|
|
86
|
+
return Number(wall) * 1_000;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {import("./duskevm.js").ClaimInput} input
|
|
91
|
+
* @returns {ClaimDate}
|
|
92
|
+
*/
|
|
93
|
+
export function claimFrom({ clock, game, portal, provenAt = null, tip }) {
|
|
94
|
+
if (!game) {
|
|
95
|
+
return NO_DATE;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const created = BigInt(game.createdAt);
|
|
99
|
+
const status = Number(game.status);
|
|
100
|
+
|
|
101
|
+
if (created === 0n || status === GAME_STATUS.CHALLENGER_WINS) {
|
|
102
|
+
return NO_DATE;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const counted = clock ?? contractClock(created, tip);
|
|
106
|
+
const now = contractNow(counted, tip);
|
|
107
|
+
// A block-time deployment compares strictly: a second after the delay.
|
|
108
|
+
const strict = counted === "height" ? 0n : 1n;
|
|
109
|
+
const resolved = status === GAME_STATUS.DEFENDER_WINS;
|
|
110
|
+
// The earliest the game resolves: once its clock has run out, and not before now.
|
|
111
|
+
const settles = created + BigInt(game.maxClockDuration);
|
|
112
|
+
const resolvedAt = resolved ? BigInt(game.resolvedAt) : later(now, settles);
|
|
113
|
+
const matured = (provenAt ? BigInt(provenAt) : now) + BigInt(portal.proofMaturityDelaySeconds);
|
|
114
|
+
const final = resolvedAt + BigInt(portal.disputeGameFinalityDelaySeconds);
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
at: wallTime(later(matured, final) + strict, counted, tip),
|
|
118
|
+
exact: resolved,
|
|
119
|
+
overdue: !resolved && now > settles + OVERDUE_SECONDS,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* A claim is ready from its date only: a Portal whose check takes just the
|
|
125
|
+
* proof and its game says yes before it, and refuses the claim itself. A
|
|
126
|
+
* date that has passed while the Portal still refuses the claim says
|
|
127
|
+
* nothing more.
|
|
128
|
+
*
|
|
129
|
+
* @param {{ claim: ClaimDate | null | undefined, portalAccepts: boolean, tip: DuskTip }} input
|
|
130
|
+
* @returns {import("./duskevm.js").ClaimReadiness}
|
|
131
|
+
*/
|
|
132
|
+
export function claimReadiness({ claim, portalAccepts, tip }) {
|
|
133
|
+
const readyAt = claim?.at == null ? null : BigInt(Math.floor(claim.at / 1_000));
|
|
134
|
+
const due = readyAt === null || readyAt <= BigInt(tip.timestamp);
|
|
135
|
+
|
|
136
|
+
if (portalAccepts && due) {
|
|
137
|
+
return { claimOverdue: false, ready: true, readyAt, readyAtExact: Boolean(claim?.exact), refused: false };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const refused = !portalAccepts && readyAt !== null && due;
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
claimOverdue: Boolean(claim?.overdue),
|
|
144
|
+
ready: false,
|
|
145
|
+
readyAt: refused ? null : readyAt,
|
|
146
|
+
readyAtExact: refused ? false : Boolean(claim?.exact),
|
|
147
|
+
refused,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @param {{ createdAt: bigint | number, l2BlockNumber: bigint | number }} game
|
|
153
|
+
* @param {import("./duskevm.js").GameRules} rules
|
|
154
|
+
* @returns {boolean}
|
|
155
|
+
*/
|
|
156
|
+
export const isCandidateGame = (game, { respectedGameTypeUpdatedAt, withdrawalBlockNumber }) =>
|
|
157
|
+
BigInt(game.l2BlockNumber) >= BigInt(withdrawalBlockNumber) &&
|
|
158
|
+
BigInt(game.createdAt) > BigInt(respectedGameTypeUpdatedAt);
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @param {import("./duskevm.js").GameCheck} game
|
|
162
|
+
* @param {import("./duskevm.js").GameRules} rules
|
|
163
|
+
* @returns {boolean}
|
|
164
|
+
*/
|
|
165
|
+
export const isEligibleGame = (game, rules) =>
|
|
166
|
+
isCandidateGame(game, rules) &&
|
|
167
|
+
game.status != null &&
|
|
168
|
+
Number(game.status) === GAME_STATUS.DEFENDER_WINS &&
|
|
169
|
+
game.proper === true &&
|
|
170
|
+
game.respected === true;
|
package/src/index.d.ts
CHANGED
|
@@ -56,6 +56,8 @@ export type DuskEvm = ChainFields &
|
|
|
56
56
|
Readonly<{
|
|
57
57
|
/** The chain's name as wallets list it. */
|
|
58
58
|
name: string;
|
|
59
|
+
/** The DuskEVM adapter's RPC beside the chain's own, which the bridge asks which DuskEVM deposit a Dusk transaction made. */
|
|
60
|
+
l1AdapterUrl: string;
|
|
59
61
|
blockscoutApiUrl: string;
|
|
60
62
|
predeploys: Readonly<{
|
|
61
63
|
l1Block: EvmAddress;
|