@argonprotocol/testing 1.4.3 → 1.4.4-dev.abb08dac
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/lib/index.cjs +1713 -132
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +339 -25
- package/lib/index.d.ts +339 -25
- package/lib/index.js +1736 -131
- package/lib/index.js.map +1 -1
- package/package.json +6 -7
- /package/lib/{docker-compose.yml → dev.docker-compose.yml} +0 -0
package/lib/index.cjs
CHANGED
|
@@ -30,9 +30,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
EthereumProofE2eHarness: () => EthereumProofE2eHarness,
|
|
33
34
|
SKIP_E2E: () => SKIP_E2E,
|
|
34
35
|
TestBitcoinCli: () => TestBitcoinCli,
|
|
36
|
+
TestEthereum: () => TestEthereum,
|
|
35
37
|
TestMainchain: () => TestMainchain,
|
|
38
|
+
TestMintingAuthorityActor: () => TestMintingAuthorityActor,
|
|
39
|
+
TestMintingGateway: () => TestMintingGateway,
|
|
36
40
|
TestNotary: () => TestNotary,
|
|
37
41
|
TestOracle: () => TestOracle,
|
|
38
42
|
activateNotary: () => activateNotary,
|
|
@@ -42,32 +46,131 @@ __export(index_exports, {
|
|
|
42
46
|
disconnectOnTeardown: () => disconnectOnTeardown,
|
|
43
47
|
getDockerPortMapping: () => getDockerPortMapping,
|
|
44
48
|
getProxy: () => getProxy,
|
|
49
|
+
getReadyEthereumGatewayUpdates: () => getReadyEthereumGatewayUpdates,
|
|
50
|
+
mineLaterExecutionAnchorReceipt: () => mineLaterExecutionAnchorReceipt,
|
|
45
51
|
projectRoot: () => projectRoot,
|
|
46
52
|
runOnTeardown: () => runOnTeardown,
|
|
47
53
|
runTestScript: () => runTestScript,
|
|
54
|
+
signGatewayPermit: () => signGatewayPermit,
|
|
48
55
|
startNetwork: () => startNetwork,
|
|
49
56
|
stringifyExt: () => stringifyExt,
|
|
50
57
|
sudo: () => sudo,
|
|
51
|
-
|
|
58
|
+
syncEthereumVerifierUntilAnchorCovers: () => syncEthereumVerifierUntilAnchorCovers,
|
|
59
|
+
teardown: () => teardown,
|
|
60
|
+
toArgonKeccakSignature: () => toArgonKeccakSignature,
|
|
61
|
+
toEvmRecoverableSignature: () => toEvmRecoverableSignature,
|
|
62
|
+
waitForExecutionReceipt: () => waitForExecutionReceipt2,
|
|
63
|
+
waitForFinalizedBeaconExecutionAtOrAbove: () => waitForFinalizedBeaconExecutionAtOrAbove
|
|
52
64
|
});
|
|
53
65
|
module.exports = __toCommonJS(index_exports);
|
|
54
|
-
var
|
|
55
|
-
var process4 = __toESM(require("process"), 1);
|
|
56
|
-
var import_http_proxy = __toESM(require("http-proxy"), 1);
|
|
57
|
-
var child_process4 = __toESM(require("child_process"), 1);
|
|
58
|
-
var http = __toESM(require("http"), 1);
|
|
59
|
-
var url = __toESM(require("url"), 1);
|
|
60
|
-
var Path6 = __toESM(require("path"), 1);
|
|
66
|
+
var import_mainchain8 = require("@argonprotocol/mainchain");
|
|
61
67
|
|
|
62
68
|
// src/TestNotary.ts
|
|
63
69
|
var import_nanoid = require("nanoid");
|
|
64
70
|
var import_pg = __toESM(require("pg"), 1);
|
|
65
|
-
var
|
|
71
|
+
var child_process2 = __toESM(require("child_process"), 1);
|
|
66
72
|
var import_mainchain = require("@argonprotocol/mainchain");
|
|
67
73
|
var fs = __toESM(require("fs"), 1);
|
|
68
74
|
var readline = __toESM(require("readline"), 1);
|
|
75
|
+
|
|
76
|
+
// src/support.ts
|
|
69
77
|
var process2 = __toESM(require("process"), 1);
|
|
78
|
+
var import_http_proxy = __toESM(require("http-proxy"), 1);
|
|
79
|
+
var child_process = __toESM(require("child_process"), 1);
|
|
80
|
+
var http = __toESM(require("http"), 1);
|
|
81
|
+
var url = __toESM(require("url"), 1);
|
|
70
82
|
var Path = __toESM(require("path"), 1);
|
|
83
|
+
var toTeardown = [];
|
|
84
|
+
var proxy = null;
|
|
85
|
+
var proxyServer = null;
|
|
86
|
+
var SKIP_E2E = process2.env.SKIP_E2E === "true" || process2.env.SKIP_E2E === "1";
|
|
87
|
+
async function getProxy() {
|
|
88
|
+
if (!proxy) {
|
|
89
|
+
proxy = import_http_proxy.default.createProxyServer({
|
|
90
|
+
changeOrigin: true,
|
|
91
|
+
ws: true,
|
|
92
|
+
autoRewrite: true
|
|
93
|
+
});
|
|
94
|
+
proxy.on("error", () => null);
|
|
95
|
+
proxyServer = http.createServer(function(req, res) {
|
|
96
|
+
const queryData = url.parse(req.url, true).query;
|
|
97
|
+
if (!queryData.target) {
|
|
98
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
99
|
+
res.end("Target parameter is required");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
console.log("Proxying http request", queryData.target);
|
|
103
|
+
proxy?.web(req, res, { target: queryData.target });
|
|
104
|
+
});
|
|
105
|
+
proxyServer.on("upgrade", function(req, clientSocket, head) {
|
|
106
|
+
const queryData = url.parse(req.url, true).query;
|
|
107
|
+
const target = url.parse(queryData.target);
|
|
108
|
+
proxy?.ws(req, clientSocket, head, {
|
|
109
|
+
target: target.href,
|
|
110
|
+
ws: true
|
|
111
|
+
});
|
|
112
|
+
clientSocket.on("error", console.error);
|
|
113
|
+
});
|
|
114
|
+
await new Promise((resolve3) => proxyServer.listen(0, resolve3));
|
|
115
|
+
toTeardown.push({
|
|
116
|
+
teardown: () => new Promise((resolve3) => {
|
|
117
|
+
proxy?.close();
|
|
118
|
+
proxyServer?.close((_) => null);
|
|
119
|
+
proxy = null;
|
|
120
|
+
proxyServer = null;
|
|
121
|
+
resolve3();
|
|
122
|
+
})
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const port2 = proxyServer.address().port;
|
|
126
|
+
return `ws://host.docker.internal:${port2}`;
|
|
127
|
+
}
|
|
128
|
+
function projectRoot() {
|
|
129
|
+
if (process2.env.ARGON_PROJECT_ROOT) {
|
|
130
|
+
return Path.join(process2.env.ARGON_PROJECT_ROOT);
|
|
131
|
+
}
|
|
132
|
+
return Path.join(__dirname, `../../..`);
|
|
133
|
+
}
|
|
134
|
+
async function runTestScript(relativePath) {
|
|
135
|
+
const scriptPath = Path.resolve(projectRoot(), relativePath);
|
|
136
|
+
return child_process.execSync(scriptPath, { encoding: "utf8" }).trim();
|
|
137
|
+
}
|
|
138
|
+
async function getDockerPortMapping(containerName, port2) {
|
|
139
|
+
return child_process.execSync(`docker port ${containerName} ${port2}`, { encoding: "utf8" }).trim().split(":").pop();
|
|
140
|
+
}
|
|
141
|
+
async function teardown() {
|
|
142
|
+
for (const t of toTeardown) {
|
|
143
|
+
try {
|
|
144
|
+
await t.teardown().catch(console.error);
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
toTeardown.length = 0;
|
|
149
|
+
}
|
|
150
|
+
function cleanHostForDocker(host, replacer = "host.docker.internal") {
|
|
151
|
+
if (process2.env.ARGON_USE_DOCKER_BINS) {
|
|
152
|
+
return host.replace("localhost", replacer).replace("127.0.0.1", replacer).replace("0.0.0.0", replacer);
|
|
153
|
+
}
|
|
154
|
+
return host;
|
|
155
|
+
}
|
|
156
|
+
function addTeardown(teardownable) {
|
|
157
|
+
toTeardown.push(teardownable);
|
|
158
|
+
}
|
|
159
|
+
function runOnTeardown(teardown2) {
|
|
160
|
+
addTeardown({ teardown: teardown2 });
|
|
161
|
+
}
|
|
162
|
+
function closeOnTeardown(closeable) {
|
|
163
|
+
addTeardown({ teardown: () => closeable.close() });
|
|
164
|
+
return closeable;
|
|
165
|
+
}
|
|
166
|
+
function disconnectOnTeardown(closeable) {
|
|
167
|
+
addTeardown({ teardown: () => closeable.disconnect() });
|
|
168
|
+
return closeable;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/TestNotary.ts
|
|
172
|
+
var process3 = __toESM(require("process"), 1);
|
|
173
|
+
var Path2 = __toESM(require("path"), 1);
|
|
71
174
|
var { Client: PgClient } = import_pg.default;
|
|
72
175
|
var nanoid = (0, import_nanoid.customAlphabet)("0123456789abcdefghijklmnopqrstuvwxyz", 4);
|
|
73
176
|
function createUid() {
|
|
@@ -93,7 +196,7 @@ var TestNotary = class {
|
|
|
93
196
|
return `ws://${this.ip}:${this.port}`;
|
|
94
197
|
}
|
|
95
198
|
constructor(dbConnectionString) {
|
|
96
|
-
this.#dbConnectionString = dbConnectionString ??
|
|
199
|
+
this.#dbConnectionString = dbConnectionString ?? process3.env.NOTARY_DB_URL ?? "postgres://postgres:postgres@localhost:5432";
|
|
97
200
|
addTeardown(this);
|
|
98
201
|
}
|
|
99
202
|
/**
|
|
@@ -105,10 +208,10 @@ var TestNotary = class {
|
|
|
105
208
|
this.registeredPublicKey = new import_mainchain.Keyring({ type: "ed25519" }).createFromUri(
|
|
106
209
|
"//Ferdie//notary"
|
|
107
210
|
).publicKey;
|
|
108
|
-
let notaryPath = pathToNotaryBin ??
|
|
109
|
-
if (
|
|
211
|
+
let notaryPath = pathToNotaryBin ?? Path2.join(projectRoot(), "target/debug/argon-notary");
|
|
212
|
+
if (process3.env.ARGON_USE_DOCKER_BINS) {
|
|
110
213
|
this.containerName = "notary_" + uuid;
|
|
111
|
-
const addHost =
|
|
214
|
+
const addHost = process3.env.ADD_DOCKER_HOST ? ` --add-host=host.docker.internal:host-gateway` : "";
|
|
112
215
|
notaryPath = `docker run --rm -p=0:9925${addHost} --name=${this.containerName} -e RUST_LOG=warn ghcr.io/argonprotocol/argon-notary:dev`;
|
|
113
216
|
this.#dbConnectionString = cleanHostForDocker(this.#dbConnectionString);
|
|
114
217
|
} else if (!fs.existsSync(notaryPath)) {
|
|
@@ -131,7 +234,7 @@ var TestNotary = class {
|
|
|
131
234
|
} finally {
|
|
132
235
|
await client.end();
|
|
133
236
|
}
|
|
134
|
-
const result =
|
|
237
|
+
const result = child_process2.execSync(
|
|
135
238
|
`${notaryPath} migrate --db-url ${this.#dbConnectionString}/${this.#dbName}`,
|
|
136
239
|
{
|
|
137
240
|
encoding: "utf-8"
|
|
@@ -154,18 +257,18 @@ var TestNotary = class {
|
|
|
154
257
|
`--archive-bucket=${bucketName}`,
|
|
155
258
|
`--operator-address=${this.operator.address}`
|
|
156
259
|
];
|
|
157
|
-
if (
|
|
158
|
-
|
|
260
|
+
if (process3.env.ARGON_USE_DOCKER_BINS) {
|
|
261
|
+
process3.env.AWS_S3_ENDPOINT = "http://host.docker.internal:9000";
|
|
159
262
|
execArgs.unshift(...notaryPath.replace("docker run", "run").split(" "));
|
|
160
263
|
execArgs.push("-b=0.0.0.0:9925");
|
|
161
264
|
notaryPath = "docker";
|
|
162
265
|
}
|
|
163
|
-
if (
|
|
164
|
-
execArgs.push(`--archive-endpoint=${
|
|
266
|
+
if (process3.env.AWS_S3_ENDPOINT) {
|
|
267
|
+
execArgs.push(`--archive-endpoint=${process3.env.AWS_S3_ENDPOINT}`);
|
|
165
268
|
}
|
|
166
|
-
this.#childProcess =
|
|
269
|
+
this.#childProcess = child_process2.spawn(notaryPath, execArgs, {
|
|
167
270
|
stdio: ["ignore", "pipe", "pipe"],
|
|
168
|
-
env: { ...
|
|
271
|
+
env: { ...process3.env, RUST_LOG: "warn" }
|
|
169
272
|
});
|
|
170
273
|
this.#childProcess.stdout.setEncoding("utf8");
|
|
171
274
|
this.#childProcess.stderr.setEncoding("utf8");
|
|
@@ -222,7 +325,7 @@ var TestNotary = class {
|
|
|
222
325
|
}
|
|
223
326
|
if (this.containerName) {
|
|
224
327
|
try {
|
|
225
|
-
|
|
328
|
+
child_process2.execSync(`docker rm -f ${this.containerName}`);
|
|
226
329
|
} catch {
|
|
227
330
|
}
|
|
228
331
|
}
|
|
@@ -242,15 +345,14 @@ var TestNotary = class {
|
|
|
242
345
|
// src/TestMainchain.ts
|
|
243
346
|
var fs2 = __toESM(require("fs"), 1);
|
|
244
347
|
var import_node_child_process = require("child_process");
|
|
245
|
-
var
|
|
348
|
+
var Path3 = __toESM(require("path"), 1);
|
|
246
349
|
var readline2 = __toESM(require("readline"), 1);
|
|
247
350
|
var import_detect_port = require("detect-port");
|
|
248
351
|
var import_nanoid2 = require("nanoid");
|
|
249
|
-
var import_bitcoin_core = __toESM(require("bitcoin-core"), 1);
|
|
250
352
|
var lockfile = __toESM(require("proper-lockfile"), 1);
|
|
251
353
|
var import_mainchain2 = require("@argonprotocol/mainchain");
|
|
252
354
|
var nanoid2 = (0, import_nanoid2.customAlphabet)("0123456789abcdefghijklmnopqrstuvwxyz", 4);
|
|
253
|
-
var lockPath =
|
|
355
|
+
var lockPath = Path3.join(process.cwd(), ".port-lock");
|
|
254
356
|
var TestMainchain = class {
|
|
255
357
|
ip = "127.0.0.1";
|
|
256
358
|
port;
|
|
@@ -273,8 +375,8 @@ var TestMainchain = class {
|
|
|
273
375
|
return `ws://${this.ip}:${this.port}`;
|
|
274
376
|
}
|
|
275
377
|
constructor(binPath) {
|
|
276
|
-
this.#binPath = binPath ??
|
|
277
|
-
this.#binPath =
|
|
378
|
+
this.#binPath = binPath ?? Path3.join(projectRoot(), `target/debug/argon-node`);
|
|
379
|
+
this.#binPath = Path3.resolve(this.#binPath);
|
|
278
380
|
if (!process.env.ARGON_USE_DOCKER_BINS && !fs2.existsSync(this.#binPath)) {
|
|
279
381
|
throw new Error(`Mainchain binary not found at ${this.#binPath}`);
|
|
280
382
|
}
|
|
@@ -282,11 +384,7 @@ var TestMainchain = class {
|
|
|
282
384
|
addTeardown(this);
|
|
283
385
|
}
|
|
284
386
|
getBitcoinClient() {
|
|
285
|
-
return new
|
|
286
|
-
username: "bitcoin",
|
|
287
|
-
password: "bitcoin",
|
|
288
|
-
host: `http://localhost:${this.bitcoinPort}`
|
|
289
|
-
});
|
|
387
|
+
return new BitcoinRpcClient(`http://localhost:${this.bitcoinPort}`, "bitcoin", "bitcoin");
|
|
290
388
|
}
|
|
291
389
|
/**
|
|
292
390
|
* Launch and return the localhost url. NOTE: this url will not work cross-docker. You need to use the containerAddress property
|
|
@@ -376,9 +474,20 @@ var TestMainchain = class {
|
|
|
376
474
|
return this.address;
|
|
377
475
|
}
|
|
378
476
|
async client() {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
477
|
+
let lastError;
|
|
478
|
+
for (let attempt = 0; attempt < 20; attempt += 1) {
|
|
479
|
+
try {
|
|
480
|
+
const client = await (0, import_mainchain2.getClient)(this.address);
|
|
481
|
+
disconnectOnTeardown(client);
|
|
482
|
+
return client;
|
|
483
|
+
} catch (error) {
|
|
484
|
+
lastError = error;
|
|
485
|
+
await new Promise((resolve3) => setTimeout(resolve3, 250));
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
throw new Error(`Unable to connect to mainchain client at ${this.address}`, {
|
|
489
|
+
cause: lastError instanceof Error ? lastError : void 0
|
|
490
|
+
});
|
|
382
491
|
}
|
|
383
492
|
async bootAddress() {
|
|
384
493
|
const client = await this.client();
|
|
@@ -428,7 +537,7 @@ var TestMainchain = class {
|
|
|
428
537
|
const release = await lockfile.lock(lockPath, { retries: 10 });
|
|
429
538
|
try {
|
|
430
539
|
rpcPort = await (0, import_detect_port.detectPort)();
|
|
431
|
-
const path = (0, import_node_child_process.execSync)(
|
|
540
|
+
const path = (0, import_node_child_process.execSync)(Path3.join(projectRoot(), `target/debug/argon-testing-bitcoin`), {
|
|
432
541
|
encoding: "utf8"
|
|
433
542
|
}).trim();
|
|
434
543
|
const tmpDir = fs2.mkdtempSync("/tmp/argon-bitcoin-" + this.uuid);
|
|
@@ -469,18 +578,63 @@ var TestMainchain = class {
|
|
|
469
578
|
return cleanHostForDocker(`http://bitcoin:bitcoin@localhost:${rpcPort}`);
|
|
470
579
|
}
|
|
471
580
|
};
|
|
581
|
+
var BitcoinRpcClient = class {
|
|
582
|
+
#rpcUrl;
|
|
583
|
+
#authorization;
|
|
584
|
+
constructor(rpcUrl, username, password) {
|
|
585
|
+
this.#rpcUrl = rpcUrl;
|
|
586
|
+
this.#authorization = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
|
|
587
|
+
}
|
|
588
|
+
async command(method, ...params) {
|
|
589
|
+
const response = await fetch(this.#rpcUrl, {
|
|
590
|
+
method: "POST",
|
|
591
|
+
headers: {
|
|
592
|
+
authorization: this.#authorization,
|
|
593
|
+
"content-type": "application/json"
|
|
594
|
+
},
|
|
595
|
+
body: JSON.stringify({
|
|
596
|
+
jsonrpc: "1.0",
|
|
597
|
+
id: `${method}-${Date.now()}`,
|
|
598
|
+
method,
|
|
599
|
+
params
|
|
600
|
+
})
|
|
601
|
+
});
|
|
602
|
+
const body = await response.text();
|
|
603
|
+
let payload;
|
|
604
|
+
if (body) {
|
|
605
|
+
try {
|
|
606
|
+
payload = JSON.parse(body);
|
|
607
|
+
} catch {
|
|
608
|
+
payload = void 0;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (payload?.error) {
|
|
612
|
+
const httpStatus = response.ok ? "" : ` with HTTP ${response.status}`;
|
|
613
|
+
throw new Error(
|
|
614
|
+
`Bitcoin RPC ${method} failed${httpStatus} (${payload.error.code}): ${payload.error.message}`
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
if (!response.ok) {
|
|
618
|
+
throw new Error(`Bitcoin RPC ${method} failed with HTTP ${response.status}`);
|
|
619
|
+
}
|
|
620
|
+
if (!payload) {
|
|
621
|
+
throw new Error(`Bitcoin RPC ${method} returned an invalid JSON response`);
|
|
622
|
+
}
|
|
623
|
+
return payload.result;
|
|
624
|
+
}
|
|
625
|
+
};
|
|
472
626
|
|
|
473
627
|
// src/TestBitcoinCli.ts
|
|
474
|
-
var
|
|
475
|
-
var
|
|
628
|
+
var child_process3 = __toESM(require("child_process"), 1);
|
|
629
|
+
var Path4 = __toESM(require("path"), 1);
|
|
476
630
|
var TestBitcoinCli = class {
|
|
477
631
|
/**
|
|
478
632
|
* Returns the localhost address of the notary (NOTE: not accessible from containers)
|
|
479
633
|
*/
|
|
480
634
|
static run(command) {
|
|
481
|
-
const binPath =
|
|
635
|
+
const binPath = Path4.join(`${projectRoot()}`, "target/debug/argon-bitcoin-cli");
|
|
482
636
|
try {
|
|
483
|
-
return
|
|
637
|
+
return child_process3.execSync(`${binPath} ${command}`, {
|
|
484
638
|
encoding: "utf8"
|
|
485
639
|
}).trim();
|
|
486
640
|
} catch (e) {
|
|
@@ -492,12 +646,12 @@ var TestBitcoinCli = class {
|
|
|
492
646
|
};
|
|
493
647
|
|
|
494
648
|
// src/TestOracle.ts
|
|
495
|
-
var
|
|
649
|
+
var child_process4 = __toESM(require("child_process"), 1);
|
|
496
650
|
var import_mainchain3 = require("@argonprotocol/mainchain");
|
|
497
651
|
var fs3 = __toESM(require("fs"), 1);
|
|
498
652
|
var readline3 = __toESM(require("readline"), 1);
|
|
499
|
-
var
|
|
500
|
-
var
|
|
653
|
+
var process4 = __toESM(require("process"), 1);
|
|
654
|
+
var Path5 = __toESM(require("path"), 1);
|
|
501
655
|
var TestOracle = class _TestOracle {
|
|
502
656
|
static BitcoinOperator = "//Dave";
|
|
503
657
|
static PriceIndexOperator = "//Eve";
|
|
@@ -512,7 +666,7 @@ var TestOracle = class _TestOracle {
|
|
|
512
666
|
const { pathToBin, mainchainUrl, bitcoinRpcUrl } = options;
|
|
513
667
|
const operatorSuri = service == "bitcoin" ? _TestOracle.BitcoinOperator : _TestOracle.PriceIndexOperator;
|
|
514
668
|
this.operator = new import_mainchain3.Keyring({ type: "sr25519" }).createFromUri(operatorSuri);
|
|
515
|
-
const binPath = pathToBin ??
|
|
669
|
+
const binPath = pathToBin ?? Path5.join(projectRoot(), "target/debug/argon-oracle");
|
|
516
670
|
if (!fs3.existsSync(binPath)) {
|
|
517
671
|
throw new Error(`Oracle binary not found at ${binPath}`);
|
|
518
672
|
}
|
|
@@ -524,9 +678,9 @@ var TestOracle = class _TestOracle {
|
|
|
524
678
|
}
|
|
525
679
|
execArgs.push("--bitcoin-rpc-url", bitcoinRpcUrl);
|
|
526
680
|
}
|
|
527
|
-
this.#childProcess =
|
|
681
|
+
this.#childProcess = child_process4.spawn(binPath, execArgs, {
|
|
528
682
|
stdio: ["ignore", "pipe", "pipe"],
|
|
529
|
-
env: { ...
|
|
683
|
+
env: { ...process4.env, RUST_LOG: "info", ...options.env }
|
|
530
684
|
});
|
|
531
685
|
this.#childProcess.stdout.setEncoding("utf8");
|
|
532
686
|
this.#childProcess.stderr.setEncoding("utf8");
|
|
@@ -546,11 +700,467 @@ var TestOracle = class _TestOracle {
|
|
|
546
700
|
}
|
|
547
701
|
};
|
|
548
702
|
|
|
703
|
+
// src/TestEthereum.ts
|
|
704
|
+
var fs4 = __toESM(require("fs/promises"), 1);
|
|
705
|
+
var os = __toESM(require("os"), 1);
|
|
706
|
+
var Path6 = __toESM(require("path"), 1);
|
|
707
|
+
var import_node_child_process2 = require("child_process");
|
|
708
|
+
var import_detect_port2 = require("detect-port");
|
|
709
|
+
var import_mainchain4 = require("@argonprotocol/mainchain");
|
|
710
|
+
var import_accounts = require("viem/accounts");
|
|
711
|
+
var import_viem = require("viem");
|
|
712
|
+
var {
|
|
713
|
+
argonTokenArtifact,
|
|
714
|
+
argonotTokenArtifact,
|
|
715
|
+
hashMintingGatewayGlobalIssuanceCouncil,
|
|
716
|
+
mintingGatewayArtifact,
|
|
717
|
+
proxyAdminArtifact,
|
|
718
|
+
transparentUpgradeableProxyArtifact
|
|
719
|
+
} = import_mainchain4.EvmContracts;
|
|
720
|
+
var DEFAULT_KURTOSIS_BIN = "kurtosis";
|
|
721
|
+
var DEFAULT_ETHEREUM_PACKAGE = "github.com/ethpandaops/ethereum-package";
|
|
722
|
+
var DEFAULT_EL_PORT_START = 32e3;
|
|
723
|
+
var DEFAULT_CL_PORT_START = 33e3;
|
|
724
|
+
var PORT_RANGE_SIZE = 32;
|
|
725
|
+
var ENCLAVE_NAME_PREFIX = "argon-eth-";
|
|
726
|
+
var PROBE_INTERVAL_MS = 1e3;
|
|
727
|
+
var PROBE_TIMEOUT_MS = 6e4;
|
|
728
|
+
var LIGHT_CLIENT_READY_TIMEOUT_MS = 5 * 6e4;
|
|
729
|
+
var KURTOSIS_RUN_TIMEOUT_MS = 20 * 6e4;
|
|
730
|
+
var DEFAULT_SEED_ARGON_AMOUNT_BASE_UNITS = 1000000000n;
|
|
731
|
+
var DEFAULT_INITIAL_MICROGONS_PER_ARGONOT = 1000000n;
|
|
732
|
+
var ERC1967_ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
|
|
733
|
+
var TestEthereum = class {
|
|
734
|
+
enclaveName;
|
|
735
|
+
kurtosisBin;
|
|
736
|
+
packageRef;
|
|
737
|
+
executionRpcUrl;
|
|
738
|
+
beaconApiUrl;
|
|
739
|
+
chainId;
|
|
740
|
+
#argsDir;
|
|
741
|
+
constructor(enclaveName = `${ENCLAVE_NAME_PREFIX}${Math.random().toString(36).slice(2, 8)}`, kurtosisBin = DEFAULT_KURTOSIS_BIN, packageRef = DEFAULT_ETHEREUM_PACKAGE) {
|
|
742
|
+
this.enclaveName = enclaveName;
|
|
743
|
+
this.kurtosisBin = kurtosisBin;
|
|
744
|
+
this.packageRef = packageRef;
|
|
745
|
+
addTeardown(this);
|
|
746
|
+
}
|
|
747
|
+
static isInstalled(kurtosisBin = DEFAULT_KURTOSIS_BIN) {
|
|
748
|
+
return (0, import_node_child_process2.spawnSync)(kurtosisBin, ["version"], { stdio: "ignore" }).status === 0;
|
|
749
|
+
}
|
|
750
|
+
async launch(options) {
|
|
751
|
+
const {
|
|
752
|
+
consensusClient = "lighthouse",
|
|
753
|
+
preset = "mainnet",
|
|
754
|
+
secondsPerSlot,
|
|
755
|
+
waitForFinalization = true,
|
|
756
|
+
prefundedAccounts
|
|
757
|
+
} = options ?? {};
|
|
758
|
+
const elPublicPortStart = await findFreePortRange(DEFAULT_EL_PORT_START, PORT_RANGE_SIZE);
|
|
759
|
+
const clPublicPortStart = await findFreePortRange(DEFAULT_CL_PORT_START, PORT_RANGE_SIZE);
|
|
760
|
+
this.#argsDir = await fs4.mkdtemp(Path6.join(os.tmpdir(), "argon-ethereum-devnet-"));
|
|
761
|
+
const argsFile = Path6.join(this.#argsDir, "network-params.yaml");
|
|
762
|
+
await fs4.writeFile(
|
|
763
|
+
argsFile,
|
|
764
|
+
renderEthereumArgs(
|
|
765
|
+
elPublicPortStart,
|
|
766
|
+
clPublicPortStart,
|
|
767
|
+
consensusClient,
|
|
768
|
+
preset,
|
|
769
|
+
secondsPerSlot,
|
|
770
|
+
waitForFinalization,
|
|
771
|
+
prefundedAccounts
|
|
772
|
+
)
|
|
773
|
+
);
|
|
774
|
+
await runCommand(
|
|
775
|
+
this.kurtosisBin,
|
|
776
|
+
["run", "--enclave", this.enclaveName, this.packageRef, "--args-file", argsFile],
|
|
777
|
+
KURTOSIS_RUN_TIMEOUT_MS
|
|
778
|
+
);
|
|
779
|
+
const executionRpc = await waitForProbe(
|
|
780
|
+
() => findExecutionRpcUrl(elPublicPortStart, PORT_RANGE_SIZE),
|
|
781
|
+
PROBE_TIMEOUT_MS
|
|
782
|
+
);
|
|
783
|
+
const beaconApi = await waitForProbe(
|
|
784
|
+
() => findBeaconApiUrl(clPublicPortStart, PORT_RANGE_SIZE),
|
|
785
|
+
PROBE_TIMEOUT_MS
|
|
786
|
+
);
|
|
787
|
+
this.executionRpcUrl = executionRpc.url;
|
|
788
|
+
this.beaconApiUrl = beaconApi.url;
|
|
789
|
+
this.chainId = executionRpc.chainId;
|
|
790
|
+
await waitForProbe(
|
|
791
|
+
() => this.getBeacon("/eth/v1/beacon/genesis"),
|
|
792
|
+
LIGHT_CLIENT_READY_TIMEOUT_MS
|
|
793
|
+
);
|
|
794
|
+
return {
|
|
795
|
+
executionRpcUrl: this.executionRpcUrl,
|
|
796
|
+
beaconApiUrl: this.beaconApiUrl,
|
|
797
|
+
chainId: this.chainId
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
async callExecution(method, params = []) {
|
|
801
|
+
const executionRpcUrl = this.executionRpcUrl;
|
|
802
|
+
if (!executionRpcUrl) {
|
|
803
|
+
throw new Error("Execution RPC URL is not available before launch");
|
|
804
|
+
}
|
|
805
|
+
const response = await fetch(executionRpcUrl, {
|
|
806
|
+
method: "POST",
|
|
807
|
+
headers: { "content-type": "application/json" },
|
|
808
|
+
body: JSON.stringify({
|
|
809
|
+
id: 1,
|
|
810
|
+
jsonrpc: "2.0",
|
|
811
|
+
method,
|
|
812
|
+
params
|
|
813
|
+
}),
|
|
814
|
+
signal: AbortSignal.timeout(1e4)
|
|
815
|
+
});
|
|
816
|
+
if (!response.ok) {
|
|
817
|
+
throw new Error(`Execution RPC request failed for ${method}: ${response.status}`);
|
|
818
|
+
}
|
|
819
|
+
const body = await response.json();
|
|
820
|
+
if (body.error) {
|
|
821
|
+
throw new Error(
|
|
822
|
+
`Execution RPC ${method} failed (${body.error.code ?? "unknown"}): ${body.error.message ?? "unknown error"}`
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
return body.result;
|
|
826
|
+
}
|
|
827
|
+
async getBeacon(path) {
|
|
828
|
+
const beaconApiUrl = this.beaconApiUrl;
|
|
829
|
+
if (!beaconApiUrl) {
|
|
830
|
+
throw new Error("Beacon API URL is not available before launch");
|
|
831
|
+
}
|
|
832
|
+
const response = await fetch(new URL(path, `${beaconApiUrl}/`), {
|
|
833
|
+
signal: AbortSignal.timeout(1e4)
|
|
834
|
+
});
|
|
835
|
+
if (!response.ok) {
|
|
836
|
+
throw new Error(`Beacon API request failed for ${path}: ${response.status}`);
|
|
837
|
+
}
|
|
838
|
+
return await response.json();
|
|
839
|
+
}
|
|
840
|
+
async deployMintingGatewayFixture(options) {
|
|
841
|
+
const { executionRpcUrl, chainId } = this;
|
|
842
|
+
if (!executionRpcUrl || !chainId) {
|
|
843
|
+
throw new Error("Ethereum devnet must be launched before deploying MintingGateway fixtures");
|
|
844
|
+
}
|
|
845
|
+
const account = (0, import_accounts.privateKeyToAccount)(options.deployerPrivateKey);
|
|
846
|
+
const adminSafe = options.adminSafe ?? account.address;
|
|
847
|
+
const guardianSafe = options.guardianSafe ?? adminSafe;
|
|
848
|
+
const chain = createExecutionChain(chainId, executionRpcUrl);
|
|
849
|
+
const publicClient = (0, import_viem.createPublicClient)({
|
|
850
|
+
chain,
|
|
851
|
+
transport: (0, import_viem.http)(executionRpcUrl)
|
|
852
|
+
});
|
|
853
|
+
const walletClient = (0, import_viem.createWalletClient)({
|
|
854
|
+
account,
|
|
855
|
+
chain,
|
|
856
|
+
transport: (0, import_viem.http)(executionRpcUrl)
|
|
857
|
+
});
|
|
858
|
+
const bootstrapCouncil = {
|
|
859
|
+
signers: [adminSafe],
|
|
860
|
+
weights: [1n]
|
|
861
|
+
};
|
|
862
|
+
const initialMicrogonsPerArgonot = options.initialMicrogonsPerArgonot ?? DEFAULT_INITIAL_MICROGONS_PER_ARGONOT;
|
|
863
|
+
const bootstrapCouncilHash = hashMintingGatewayGlobalIssuanceCouncil({
|
|
864
|
+
...bootstrapCouncil,
|
|
865
|
+
epochMicrogonsPerArgonot: initialMicrogonsPerArgonot
|
|
866
|
+
});
|
|
867
|
+
const bootstrapImplementationAddress = await deployContract(walletClient, publicClient, {
|
|
868
|
+
abi: mintingGatewayArtifact.abi,
|
|
869
|
+
bytecode: mintingGatewayArtifact.bytecode,
|
|
870
|
+
args: [import_viem.zeroAddress, import_viem.zeroAddress]
|
|
871
|
+
});
|
|
872
|
+
const initializeData = (0, import_viem.encodeFunctionData)({
|
|
873
|
+
abi: mintingGatewayArtifact.abi,
|
|
874
|
+
functionName: "initialize",
|
|
875
|
+
args: [
|
|
876
|
+
adminSafe,
|
|
877
|
+
guardianSafe,
|
|
878
|
+
bootstrapCouncilHash,
|
|
879
|
+
BigInt(bootstrapCouncil.signers.length),
|
|
880
|
+
1n,
|
|
881
|
+
initialMicrogonsPerArgonot
|
|
882
|
+
]
|
|
883
|
+
});
|
|
884
|
+
const gatewayAddress = await deployContract(walletClient, publicClient, {
|
|
885
|
+
abi: transparentUpgradeableProxyArtifact.abi,
|
|
886
|
+
bytecode: transparentUpgradeableProxyArtifact.bytecode,
|
|
887
|
+
args: [bootstrapImplementationAddress, adminSafe, initializeData]
|
|
888
|
+
});
|
|
889
|
+
const proxyAdminAddress = getAddressFromStorage(
|
|
890
|
+
await publicClient.getStorageAt({
|
|
891
|
+
address: gatewayAddress,
|
|
892
|
+
slot: ERC1967_ADMIN_SLOT
|
|
893
|
+
})
|
|
894
|
+
);
|
|
895
|
+
const argonTokenAddress = await deployContract(walletClient, publicClient, {
|
|
896
|
+
abi: argonTokenArtifact.abi,
|
|
897
|
+
bytecode: argonTokenArtifact.bytecode,
|
|
898
|
+
args: [gatewayAddress]
|
|
899
|
+
});
|
|
900
|
+
const argonotTokenAddress = await deployContract(walletClient, publicClient, {
|
|
901
|
+
abi: argonotTokenArtifact.abi,
|
|
902
|
+
bytecode: argonotTokenArtifact.bytecode,
|
|
903
|
+
args: [gatewayAddress]
|
|
904
|
+
});
|
|
905
|
+
const finalImplementationAddress = await deployContract(walletClient, publicClient, {
|
|
906
|
+
abi: mintingGatewayArtifact.abi,
|
|
907
|
+
bytecode: mintingGatewayArtifact.bytecode,
|
|
908
|
+
args: [argonTokenAddress, argonotTokenAddress]
|
|
909
|
+
});
|
|
910
|
+
const upgradeHash = await walletClient.sendTransaction({
|
|
911
|
+
to: proxyAdminAddress,
|
|
912
|
+
data: (0, import_viem.encodeFunctionData)({
|
|
913
|
+
abi: proxyAdminArtifact.abi,
|
|
914
|
+
functionName: "upgradeAndCall",
|
|
915
|
+
args: [gatewayAddress, finalImplementationAddress, "0x"]
|
|
916
|
+
})
|
|
917
|
+
});
|
|
918
|
+
const upgradeReceipt = await waitForExecutionReceipt(publicClient, upgradeHash);
|
|
919
|
+
if (upgradeReceipt.status !== "success") {
|
|
920
|
+
throw new Error("MintingGateway proxy upgrade failed");
|
|
921
|
+
}
|
|
922
|
+
if (options.seedArgonRecipient) {
|
|
923
|
+
const mintHash = await walletClient.sendTransaction({
|
|
924
|
+
to: gatewayAddress,
|
|
925
|
+
data: (0, import_viem.encodeFunctionData)({
|
|
926
|
+
abi: mintingGatewayArtifact.abi,
|
|
927
|
+
functionName: "migrate",
|
|
928
|
+
args: [
|
|
929
|
+
{
|
|
930
|
+
recipients: [options.seedArgonRecipient],
|
|
931
|
+
amounts: [options.seedArgonAmountBaseUnits ?? DEFAULT_SEED_ARGON_AMOUNT_BASE_UNITS]
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
recipients: [],
|
|
935
|
+
amounts: []
|
|
936
|
+
}
|
|
937
|
+
]
|
|
938
|
+
})
|
|
939
|
+
});
|
|
940
|
+
const mintReceipt = await waitForExecutionReceipt(publicClient, mintHash);
|
|
941
|
+
if (mintReceipt.status !== "success") {
|
|
942
|
+
throw new Error("MintingGateway migrate failed");
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
return {
|
|
946
|
+
argonTokenAddress,
|
|
947
|
+
argonotTokenAddress,
|
|
948
|
+
gatewayAddress
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
async teardown() {
|
|
952
|
+
if (this.#argsDir) {
|
|
953
|
+
await fs4.rm(this.#argsDir, { recursive: true, force: true });
|
|
954
|
+
this.#argsDir = void 0;
|
|
955
|
+
}
|
|
956
|
+
await runCommand(this.kurtosisBin, ["enclave", "rm", "-f", this.enclaveName], 6e4, true);
|
|
957
|
+
}
|
|
958
|
+
};
|
|
959
|
+
async function deployContract(walletClient, publicClient, request) {
|
|
960
|
+
const hash = await walletClient.deployContract({
|
|
961
|
+
...request,
|
|
962
|
+
account: walletClient.account,
|
|
963
|
+
chain: walletClient.chain
|
|
964
|
+
});
|
|
965
|
+
const receipt = await waitForExecutionReceipt(publicClient, hash);
|
|
966
|
+
if (receipt.status !== "success" || !receipt.contractAddress) {
|
|
967
|
+
throw new Error(`Contract deployment failed for ${request.bytecode.slice(0, 10)}`);
|
|
968
|
+
}
|
|
969
|
+
return receipt.contractAddress;
|
|
970
|
+
}
|
|
971
|
+
function getAddressFromStorage(value) {
|
|
972
|
+
if (!value || value === "0x") {
|
|
973
|
+
throw new Error("Missing proxy admin address in ERC1967 admin slot");
|
|
974
|
+
}
|
|
975
|
+
return (0, import_viem.getAddress)(`0x${value.slice(-40)}`);
|
|
976
|
+
}
|
|
977
|
+
function renderEthereumArgs(elPublicPortStart, clPublicPortStart, consensusClient, preset, secondsPerSlot, waitForFinalization, prefundedAccounts) {
|
|
978
|
+
const lines = [
|
|
979
|
+
"participants:",
|
|
980
|
+
" - el_type: geth",
|
|
981
|
+
` cl_type: ${consensusClient}`,
|
|
982
|
+
"network_params:",
|
|
983
|
+
" network: kurtosis",
|
|
984
|
+
` preset: ${preset}`,
|
|
985
|
+
...secondsPerSlot ? [` seconds_per_slot: ${secondsPerSlot}`] : [],
|
|
986
|
+
...prefundedAccounts && Object.keys(prefundedAccounts).length > 0 ? [` prefunded_accounts: '${JSON.stringify(prefundedAccounts)}'`] : [],
|
|
987
|
+
"additional_services: []",
|
|
988
|
+
`wait_for_finalization: ${waitForFinalization ? "true" : "false"}`,
|
|
989
|
+
"global_log_level: warn",
|
|
990
|
+
"port_publisher:",
|
|
991
|
+
" el:",
|
|
992
|
+
" enabled: true",
|
|
993
|
+
` public_port_start: ${elPublicPortStart}`,
|
|
994
|
+
" cl:",
|
|
995
|
+
" enabled: true",
|
|
996
|
+
` public_port_start: ${clPublicPortStart}`
|
|
997
|
+
];
|
|
998
|
+
lines.push("");
|
|
999
|
+
return lines.join("\n");
|
|
1000
|
+
}
|
|
1001
|
+
async function findExecutionRpcUrl(portStart, rangeSize) {
|
|
1002
|
+
for (let port2 = portStart; port2 < portStart + rangeSize; port2 += 1) {
|
|
1003
|
+
const url2 = `http://127.0.0.1:${port2}`;
|
|
1004
|
+
const response = await fetchJsonRpc(url2, "eth_chainId");
|
|
1005
|
+
if (typeof response === "string") {
|
|
1006
|
+
return { url: url2, chainId: response };
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
throw new Error(
|
|
1010
|
+
`Unable to find an execution RPC endpoint in ${portStart}-${portStart + rangeSize - 1}`
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
async function findBeaconApiUrl(portStart, rangeSize) {
|
|
1014
|
+
for (let port2 = portStart; port2 < portStart + rangeSize; port2 += 1) {
|
|
1015
|
+
const url2 = `http://127.0.0.1:${port2}`;
|
|
1016
|
+
try {
|
|
1017
|
+
const response = await fetch(new URL("/eth/v1/node/version", `${url2}/`), {
|
|
1018
|
+
signal: AbortSignal.timeout(2e3)
|
|
1019
|
+
});
|
|
1020
|
+
if (!response.ok) {
|
|
1021
|
+
continue;
|
|
1022
|
+
}
|
|
1023
|
+
const body = await response.json();
|
|
1024
|
+
if (body.data?.version) {
|
|
1025
|
+
return { url: url2 };
|
|
1026
|
+
}
|
|
1027
|
+
} catch {
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
throw new Error(
|
|
1031
|
+
`Unable to find a Beacon API endpoint in ${portStart}-${portStart + rangeSize - 1}`
|
|
1032
|
+
);
|
|
1033
|
+
}
|
|
1034
|
+
async function fetchJsonRpc(url2, method) {
|
|
1035
|
+
try {
|
|
1036
|
+
const response = await fetch(url2, {
|
|
1037
|
+
method: "POST",
|
|
1038
|
+
headers: { "content-type": "application/json" },
|
|
1039
|
+
body: JSON.stringify({
|
|
1040
|
+
id: 1,
|
|
1041
|
+
jsonrpc: "2.0",
|
|
1042
|
+
method,
|
|
1043
|
+
params: []
|
|
1044
|
+
}),
|
|
1045
|
+
signal: AbortSignal.timeout(2e3)
|
|
1046
|
+
});
|
|
1047
|
+
if (!response.ok) {
|
|
1048
|
+
return null;
|
|
1049
|
+
}
|
|
1050
|
+
const body = await response.json();
|
|
1051
|
+
return body.result ?? null;
|
|
1052
|
+
} catch {
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
function createExecutionChain(chainId, executionRpcUrl) {
|
|
1057
|
+
return (0, import_viem.defineChain)({
|
|
1058
|
+
id: Number.parseInt(chainId, 16),
|
|
1059
|
+
name: "argon-test-ethereum",
|
|
1060
|
+
nativeCurrency: {
|
|
1061
|
+
name: "Ether",
|
|
1062
|
+
symbol: "ETH",
|
|
1063
|
+
decimals: 18
|
|
1064
|
+
},
|
|
1065
|
+
rpcUrls: {
|
|
1066
|
+
default: {
|
|
1067
|
+
http: [executionRpcUrl]
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
async function findFreePortRange(start, size) {
|
|
1073
|
+
for (let candidate = start; candidate < start + 1e3; candidate += size) {
|
|
1074
|
+
const ports = Array.from({ length: size }, (_, index) => candidate + index);
|
|
1075
|
+
const results = await Promise.all(ports.map((port2) => (0, import_detect_port2.detectPort)(port2)));
|
|
1076
|
+
if (results.every((resolvedPort, index) => resolvedPort === ports[index])) {
|
|
1077
|
+
return candidate;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
throw new Error(`Unable to find a free port range starting near ${start}`);
|
|
1081
|
+
}
|
|
1082
|
+
async function waitForProbe(probe, timeoutMs) {
|
|
1083
|
+
const start = Date.now();
|
|
1084
|
+
let lastError;
|
|
1085
|
+
while (Date.now() - start < timeoutMs) {
|
|
1086
|
+
try {
|
|
1087
|
+
return await probe();
|
|
1088
|
+
} catch (error) {
|
|
1089
|
+
lastError = error;
|
|
1090
|
+
await delay(PROBE_INTERVAL_MS);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
throw lastError instanceof Error ? lastError : new Error("Timed out waiting for probe");
|
|
1094
|
+
}
|
|
1095
|
+
async function waitForExecutionReceipt(publicClient, hash) {
|
|
1096
|
+
const start = Date.now();
|
|
1097
|
+
let lastError;
|
|
1098
|
+
while (Date.now() - start < 12e4) {
|
|
1099
|
+
try {
|
|
1100
|
+
const receipt = await publicClient.getTransactionReceipt({ hash });
|
|
1101
|
+
if (receipt) {
|
|
1102
|
+
return receipt;
|
|
1103
|
+
}
|
|
1104
|
+
} catch (error) {
|
|
1105
|
+
const errorText = error instanceof Error ? [
|
|
1106
|
+
error.message,
|
|
1107
|
+
"details" in error && typeof error.details === "string" ? error.details : void 0
|
|
1108
|
+
].filter(Boolean).join(" ") : String(error);
|
|
1109
|
+
if (!errorText.includes("indexing is in progress") && !errorText.includes("Transaction receipt with hash") && !errorText.includes("could not be found")) {
|
|
1110
|
+
throw error;
|
|
1111
|
+
}
|
|
1112
|
+
lastError = error instanceof Error ? error : new Error(errorText);
|
|
1113
|
+
}
|
|
1114
|
+
await delay(500);
|
|
1115
|
+
}
|
|
1116
|
+
throw lastError ?? new Error(`Timed out waiting for execution receipt ${hash}`);
|
|
1117
|
+
}
|
|
1118
|
+
async function runCommand(command, args, timeoutMs, allowFailure = false) {
|
|
1119
|
+
await new Promise((resolve3, reject) => {
|
|
1120
|
+
const child = (0, import_node_child_process2.spawn)(command, args, {
|
|
1121
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1122
|
+
});
|
|
1123
|
+
let stdout = "";
|
|
1124
|
+
let stderr = "";
|
|
1125
|
+
const timeout = setTimeout(() => {
|
|
1126
|
+
child.kill("SIGTERM");
|
|
1127
|
+
reject(new Error(`Command timed out: ${command} ${args.join(" ")}`));
|
|
1128
|
+
}, timeoutMs);
|
|
1129
|
+
child.stdout?.setEncoding("utf8");
|
|
1130
|
+
child.stderr?.setEncoding("utf8");
|
|
1131
|
+
child.stdout?.on("data", (chunk) => {
|
|
1132
|
+
stdout += chunk;
|
|
1133
|
+
});
|
|
1134
|
+
child.stderr?.on("data", (chunk) => {
|
|
1135
|
+
stderr += chunk;
|
|
1136
|
+
});
|
|
1137
|
+
child.on("error", (error) => {
|
|
1138
|
+
clearTimeout(timeout);
|
|
1139
|
+
reject(error);
|
|
1140
|
+
});
|
|
1141
|
+
child.on("exit", (code) => {
|
|
1142
|
+
clearTimeout(timeout);
|
|
1143
|
+
if (code === 0 || allowFailure) {
|
|
1144
|
+
resolve3();
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
reject(
|
|
1148
|
+
new Error(
|
|
1149
|
+
[`Command failed: ${command} ${args.join(" ")}`, stdout.trim(), stderr.trim()].filter(Boolean).join("\n")
|
|
1150
|
+
)
|
|
1151
|
+
);
|
|
1152
|
+
});
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
async function delay(ms) {
|
|
1156
|
+
await new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
1157
|
+
}
|
|
1158
|
+
|
|
549
1159
|
// src/TestNetwork.ts
|
|
550
1160
|
var docker = __toESM(require("docker-compose"), 1);
|
|
551
|
-
var
|
|
1161
|
+
var Path7 = __toESM(require("path"), 1);
|
|
552
1162
|
async function startNetwork(testName, options) {
|
|
553
|
-
const config =
|
|
1163
|
+
const config = Path7.join(__dirname, `dev.docker-compose.yml`);
|
|
554
1164
|
const env4 = {
|
|
555
1165
|
VERSION: "dev",
|
|
556
1166
|
ARGON_CHAIN: "dev-docker",
|
|
@@ -582,115 +1192,1074 @@ async function startNetwork(testName, options) {
|
|
|
582
1192
|
};
|
|
583
1193
|
}
|
|
584
1194
|
|
|
585
|
-
// src/
|
|
586
|
-
var
|
|
587
|
-
var
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
1195
|
+
// src/EthereumE2eUtils.ts
|
|
1196
|
+
var import_mainchain5 = require("@argonprotocol/mainchain");
|
|
1197
|
+
var import_viem2 = require("viem");
|
|
1198
|
+
async function signGatewayPermit(args) {
|
|
1199
|
+
const signature = (0, import_viem2.parseSignature)(
|
|
1200
|
+
await args.account.signTypedData({
|
|
1201
|
+
domain: {
|
|
1202
|
+
name: "Argon",
|
|
1203
|
+
version: "1",
|
|
1204
|
+
chainId: args.chainId,
|
|
1205
|
+
verifyingContract: args.tokenAddress
|
|
1206
|
+
},
|
|
1207
|
+
types: {
|
|
1208
|
+
Permit: [
|
|
1209
|
+
{ name: "owner", type: "address" },
|
|
1210
|
+
{ name: "spender", type: "address" },
|
|
1211
|
+
{ name: "value", type: "uint256" },
|
|
1212
|
+
{ name: "nonce", type: "uint256" },
|
|
1213
|
+
{ name: "deadline", type: "uint256" }
|
|
1214
|
+
]
|
|
1215
|
+
},
|
|
1216
|
+
primaryType: "Permit",
|
|
1217
|
+
message: {
|
|
1218
|
+
owner: args.owner,
|
|
1219
|
+
spender: args.gatewayAddress,
|
|
1220
|
+
value: args.value,
|
|
1221
|
+
nonce: args.nonce,
|
|
1222
|
+
deadline: args.deadline
|
|
604
1223
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
1224
|
+
})
|
|
1225
|
+
);
|
|
1226
|
+
return {
|
|
1227
|
+
v: Number(signature.v),
|
|
1228
|
+
r: signature.r,
|
|
1229
|
+
s: signature.s
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
async function waitForFinalizedBeaconExecutionAtOrAbove(ethereum, minimumExecutionBlockNumber, options = {}) {
|
|
1233
|
+
const startedAt = Date.now();
|
|
1234
|
+
const minimumFinalizedSlot = options.minimumFinalizedSlot ?? 0n;
|
|
1235
|
+
let lastSeenExecutionBlockNumber = 0n;
|
|
1236
|
+
let lastSeenHeadSlot = 0n;
|
|
1237
|
+
let lastSeenFinalizedSlot = 0n;
|
|
1238
|
+
let lastError;
|
|
1239
|
+
while (Date.now() - startedAt < 3e5) {
|
|
1240
|
+
try {
|
|
1241
|
+
const [headHeader, finalizedHeader] = await Promise.all([
|
|
1242
|
+
ethereum.getBeacon("/eth/v1/beacon/headers/head"),
|
|
1243
|
+
ethereum.getBeacon("/eth/v1/beacon/headers/finalized")
|
|
1244
|
+
]);
|
|
1245
|
+
lastSeenHeadSlot = BigInt(headHeader.data.header.message.slot);
|
|
1246
|
+
lastSeenFinalizedSlot = BigInt(finalizedHeader.data.header.message.slot);
|
|
1247
|
+
const block = await ethereum.getBeacon(
|
|
1248
|
+
`/eth/v2/beacon/blocks/${finalizedHeader.data.root}`
|
|
1249
|
+
);
|
|
1250
|
+
const executionBlockNumber = BigInt(block.data.message.body.execution_payload.block_number);
|
|
1251
|
+
lastSeenExecutionBlockNumber = executionBlockNumber;
|
|
1252
|
+
lastError = void 0;
|
|
1253
|
+
if (executionBlockNumber >= minimumExecutionBlockNumber && lastSeenFinalizedSlot >= minimumFinalizedSlot) {
|
|
1254
|
+
return { header: finalizedHeader, block };
|
|
1255
|
+
}
|
|
1256
|
+
} catch (error) {
|
|
1257
|
+
if (!(error instanceof Error)) {
|
|
1258
|
+
throw error;
|
|
1259
|
+
}
|
|
1260
|
+
lastError = error;
|
|
1261
|
+
}
|
|
1262
|
+
await delay2(1e3);
|
|
1263
|
+
}
|
|
1264
|
+
const lastErrorSuffix = lastError ? `; last beacon error was: ${lastError.message}` : "";
|
|
1265
|
+
throw new Error(
|
|
1266
|
+
`Timed out waiting for finalized beacon execution block at or above ${minimumExecutionBlockNumber} and finalized slot at or above ${minimumFinalizedSlot}; last seen head slot was ${lastSeenHeadSlot}, finalized slot was ${lastSeenFinalizedSlot}, and finalized execution block was ${lastSeenExecutionBlockNumber}${lastErrorSuffix}`
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
async function mineLaterExecutionAnchorReceipt(walletClient, chain, ethereum, account, minimumBlockNumber) {
|
|
1270
|
+
while (true) {
|
|
1271
|
+
const transactionHash = await walletClient.sendTransaction({
|
|
1272
|
+
account,
|
|
1273
|
+
chain,
|
|
1274
|
+
to: account.address,
|
|
1275
|
+
value: 0n
|
|
626
1276
|
});
|
|
1277
|
+
const receipt = await waitForExecutionReceipt2(ethereum, transactionHash);
|
|
1278
|
+
if (BigInt(receipt.blockNumber) > minimumBlockNumber) {
|
|
1279
|
+
return receipt;
|
|
1280
|
+
}
|
|
627
1281
|
}
|
|
628
|
-
const port2 = proxyServer.address().port;
|
|
629
|
-
return `ws://host.docker.internal:${port2}`;
|
|
630
1282
|
}
|
|
631
|
-
function
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
1283
|
+
async function waitForExecutionReceipt2(ethereum, transactionHash) {
|
|
1284
|
+
const startedAt = Date.now();
|
|
1285
|
+
while (Date.now() - startedAt < 12e4) {
|
|
1286
|
+
try {
|
|
1287
|
+
const receipt = await ethereum.callExecution(
|
|
1288
|
+
"eth_getTransactionReceipt",
|
|
1289
|
+
[transactionHash]
|
|
1290
|
+
);
|
|
1291
|
+
if (receipt) {
|
|
1292
|
+
return receipt;
|
|
637
1293
|
}
|
|
638
|
-
|
|
639
|
-
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
const errorText = error instanceof Error ? [
|
|
1296
|
+
error.message,
|
|
1297
|
+
"details" in error && typeof error.details === "string" ? error.details : void 0
|
|
1298
|
+
].filter(Boolean).join(" ") : String(error);
|
|
1299
|
+
if (!errorText.includes("indexing is in progress")) {
|
|
1300
|
+
throw error;
|
|
640
1301
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
1302
|
+
}
|
|
1303
|
+
await delay2(500);
|
|
1304
|
+
}
|
|
1305
|
+
throw new Error(`Timed out waiting for execution receipt ${transactionHash}`);
|
|
1306
|
+
}
|
|
1307
|
+
async function syncEthereumVerifierUntilAnchorCovers(mainchainClient, relayer, beaconApiUrl, minimumExecutionBlockNumber) {
|
|
1308
|
+
const startedAt = Date.now();
|
|
1309
|
+
const timeoutMs = 5 * 6e4;
|
|
1310
|
+
let lastRetryableError;
|
|
1311
|
+
let lastAnchorBlockNumber;
|
|
1312
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
1313
|
+
try {
|
|
1314
|
+
const anchor = await (0, import_mainchain5.getLatestArgonFinalizedExecutionHeader)(mainchainClient);
|
|
1315
|
+
lastAnchorBlockNumber = anchor.blockNumber;
|
|
1316
|
+
if (anchor.blockNumber >= minimumExecutionBlockNumber) {
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
} catch {
|
|
1320
|
+
}
|
|
1321
|
+
const txs = await (0, import_mainchain5.getNextEthereumBeaconSyncTxs)(mainchainClient, beaconApiUrl);
|
|
1322
|
+
if (txs.length === 0) {
|
|
1323
|
+
await delay2(500);
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
let shouldRetry = false;
|
|
1327
|
+
for (const tx of txs) {
|
|
1328
|
+
try {
|
|
1329
|
+
const result = await new import_mainchain5.TxSubmitter(mainchainClient, tx, relayer).submit();
|
|
1330
|
+
await result.waitForInFirstBlock;
|
|
1331
|
+
lastRetryableError = void 0;
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
if (isRetryableEthereumVerifierSyncError(error)) {
|
|
1334
|
+
lastRetryableError = error instanceof Error ? error : new Error(String(error));
|
|
1335
|
+
shouldRetry = true;
|
|
1336
|
+
break;
|
|
1337
|
+
}
|
|
1338
|
+
throw error;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
if (shouldRetry) {
|
|
1342
|
+
await delay2(500);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
throw lastRetryableError ?? new Error(
|
|
1346
|
+
`Ethereum verifier did not retain an anchor at or above execution block ${minimumExecutionBlockNumber} within ${Math.floor(timeoutMs / 1e3)}s; last seen anchor was ${lastAnchorBlockNumber ?? "unavailable"}`
|
|
644
1347
|
);
|
|
645
1348
|
}
|
|
646
|
-
function
|
|
647
|
-
|
|
648
|
-
|
|
1349
|
+
function toArgonKeccakSignature(signature) {
|
|
1350
|
+
const bytes = (0, import_mainchain5.hexToU8a)(signature);
|
|
1351
|
+
if (bytes.length !== 65) {
|
|
1352
|
+
throw new Error(`Expected 65-byte ECDSA signature, received ${bytes.length} bytes`);
|
|
1353
|
+
}
|
|
1354
|
+
if (bytes[64] >= 27) {
|
|
1355
|
+
bytes[64] -= 27;
|
|
649
1356
|
}
|
|
650
|
-
return
|
|
1357
|
+
return (0, import_mainchain5.u8aToHex)(bytes);
|
|
651
1358
|
}
|
|
652
|
-
|
|
653
|
-
const
|
|
654
|
-
|
|
1359
|
+
function toEvmRecoverableSignature(signature) {
|
|
1360
|
+
const bytes = (0, import_mainchain5.hexToU8a)(signature);
|
|
1361
|
+
if (bytes.length !== 65) {
|
|
1362
|
+
throw new Error(`Expected 65-byte ECDSA signature, received ${bytes.length} bytes`);
|
|
1363
|
+
}
|
|
1364
|
+
if (bytes[64] <= 1) {
|
|
1365
|
+
bytes[64] += 27;
|
|
1366
|
+
}
|
|
1367
|
+
return (0, import_mainchain5.u8aToHex)(bytes);
|
|
655
1368
|
}
|
|
656
|
-
|
|
657
|
-
|
|
1369
|
+
function isRetryableEthereumVerifierSyncError(error) {
|
|
1370
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1371
|
+
return (0, import_mainchain5.isOutdatedTransactionError)(error) || message.includes("ethereumVerifier.InvalidHeaderMerkleProof");
|
|
658
1372
|
}
|
|
659
|
-
async function
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
1373
|
+
async function delay2(ms) {
|
|
1374
|
+
await new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
// src/EthereumGatewayQueue.ts
|
|
1378
|
+
var import_mainchain6 = require("@argonprotocol/mainchain");
|
|
1379
|
+
var import_viem3 = require("viem");
|
|
1380
|
+
var {
|
|
1381
|
+
encodeMintingGatewayMintingAuthorityActivationTarget,
|
|
1382
|
+
encodeMintingGatewayMintingAuthorityDeactivateTarget,
|
|
1383
|
+
hashMintingGatewayActivateMintingAuthority,
|
|
1384
|
+
hashMintingGatewayGatewayUpdateApproval,
|
|
1385
|
+
hashMintingGatewayMintingAuthorityDeactivation,
|
|
1386
|
+
mintingGatewayAbi,
|
|
1387
|
+
MINTING_GATEWAY_UPDATE_KINDS
|
|
1388
|
+
} = import_mainchain6.EvmContracts;
|
|
1389
|
+
async function getReadyEthereumGatewayUpdates(client, gatewayClient, options = {}) {
|
|
1390
|
+
const destinationChain = options.destinationChain ?? "Ethereum";
|
|
1391
|
+
const maxQueueEntries = options.maxQueueEntries ?? 100;
|
|
1392
|
+
if (maxQueueEntries < 1) {
|
|
1393
|
+
throw new Error(`maxQueueEntries must be at least 1, received ${maxQueueEntries}`);
|
|
1394
|
+
}
|
|
1395
|
+
const chainConfigOption = await client.query.crosschainTransfer.chainConfigBySourceChain(destinationChain);
|
|
1396
|
+
if (chainConfigOption.isNone) {
|
|
1397
|
+
throw new Error(`Crosschain config not found for ${destinationChain}`);
|
|
1398
|
+
}
|
|
1399
|
+
const chainConfig = chainConfigOption.unwrap();
|
|
1400
|
+
if (!chainConfig.isEvm) {
|
|
1401
|
+
throw new Error(`Chain config for ${destinationChain} is not EVM-shaped`);
|
|
1402
|
+
}
|
|
1403
|
+
const gatewayAddress = (0, import_viem3.getAddress)(toHexValue(chainConfig.asEvm.gateway));
|
|
1404
|
+
const chainId = chainConfig.asEvm.chainId.toBigInt();
|
|
1405
|
+
const hashContext = { chainId, gatewayAddress };
|
|
1406
|
+
const currentCouncilHashOption = await client.query.crosschainTransfer.activeGlobalIssuanceCouncilByDestinationChain(
|
|
1407
|
+
destinationChain
|
|
1408
|
+
);
|
|
1409
|
+
if (currentCouncilHashOption.isNone) {
|
|
1410
|
+
throw new Error(`Active GlobalIssuanceCouncil not found for ${destinationChain}`);
|
|
1411
|
+
}
|
|
1412
|
+
const currentCouncilHash = toHexValue(currentCouncilHashOption.unwrap());
|
|
1413
|
+
const councilCache = /* @__PURE__ */ new Map();
|
|
1414
|
+
const currentCouncil = councilToSnapshot(
|
|
1415
|
+
await loadCouncilByHash(client, currentCouncilHash, councilCache)
|
|
1416
|
+
);
|
|
1417
|
+
const [rawArgonApprovalsNonce, rawArgonApprovalsHash, rawPaused] = await Promise.all([
|
|
1418
|
+
gatewayClient.readContract({
|
|
1419
|
+
abi: mintingGatewayAbi,
|
|
1420
|
+
address: gatewayAddress,
|
|
1421
|
+
functionName: "argonApprovalsNonce"
|
|
1422
|
+
}),
|
|
1423
|
+
gatewayClient.readContract({
|
|
1424
|
+
abi: mintingGatewayAbi,
|
|
1425
|
+
address: gatewayAddress,
|
|
1426
|
+
functionName: "argonApprovalsHash"
|
|
1427
|
+
}),
|
|
1428
|
+
gatewayClient.readContract({
|
|
1429
|
+
abi: mintingGatewayAbi,
|
|
1430
|
+
address: gatewayAddress,
|
|
1431
|
+
functionName: "paused"
|
|
1432
|
+
})
|
|
1433
|
+
]);
|
|
1434
|
+
const argonApprovalsNonce = rawArgonApprovalsNonce;
|
|
1435
|
+
const argonApprovalsHash = rawArgonApprovalsHash;
|
|
1436
|
+
const paused = rawPaused;
|
|
1437
|
+
const pendingClearOutQueueNonces = [];
|
|
1438
|
+
const candidateUpdates = [];
|
|
1439
|
+
let expectedPreviousApprovalHash = argonApprovalsHash;
|
|
1440
|
+
let readyQueueEntriesScanned = 0;
|
|
1441
|
+
if (!paused) {
|
|
1442
|
+
for (let queueNonce = argonApprovalsNonce + 1n; readyQueueEntriesScanned < maxQueueEntries; queueNonce += 1n) {
|
|
1443
|
+
const entryOption = await client.query.crosschainTransfer.councilApprovalQueueByDestinationChainAndNonce(
|
|
1444
|
+
destinationChain,
|
|
1445
|
+
queueNonce
|
|
1446
|
+
);
|
|
1447
|
+
if (entryOption.isNone) {
|
|
1448
|
+
break;
|
|
1449
|
+
}
|
|
1450
|
+
const entry = entryOption.unwrap();
|
|
1451
|
+
const approvingCouncilHash = toHexValue(entry.approvingCouncilHash);
|
|
1452
|
+
if (!await queueEntryIsReady(
|
|
1453
|
+
client,
|
|
1454
|
+
entry,
|
|
1455
|
+
approvingCouncilHash,
|
|
1456
|
+
councilCache,
|
|
1457
|
+
hashContext,
|
|
1458
|
+
queueNonce
|
|
1459
|
+
)) {
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
readyQueueEntriesScanned += 1;
|
|
1463
|
+
if (toHexValue(entry.previousApprovalHash) !== expectedPreviousApprovalHash) {
|
|
1464
|
+
throw new Error(
|
|
1465
|
+
`Queue nonce ${queueNonce} expected previous approval hash ${expectedPreviousApprovalHash}, received ${toHexValue(entry.previousApprovalHash)}`
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
const update = await buildGatewayUpdate(client, destinationChain, hashContext, queueNonce, {
|
|
1469
|
+
entry,
|
|
1470
|
+
approvingCouncilHash
|
|
1471
|
+
});
|
|
1472
|
+
candidateUpdates.push(update);
|
|
1473
|
+
expectedPreviousApprovalHash = toHexValue(entry.approvalHash);
|
|
664
1474
|
}
|
|
665
1475
|
}
|
|
666
|
-
|
|
1476
|
+
while (candidateUpdates.length > 0 && candidateUpdates[candidateUpdates.length - 1]?.kind === MINTING_GATEWAY_UPDATE_KINDS.mintingAuthorityDeactivate) {
|
|
1477
|
+
pendingClearOutQueueNonces.unshift(candidateUpdates.pop().queueNonce);
|
|
1478
|
+
}
|
|
1479
|
+
const updates = candidateUpdates;
|
|
1480
|
+
const firstQueueNonce = updates[0]?.queueNonce;
|
|
1481
|
+
const lastQueueNonce = updates[updates.length - 1]?.queueNonce;
|
|
1482
|
+
return {
|
|
1483
|
+
destinationChain,
|
|
1484
|
+
chainId,
|
|
1485
|
+
gatewayAddress,
|
|
1486
|
+
currentCouncilHash,
|
|
1487
|
+
currentCouncil,
|
|
1488
|
+
argonApprovalsNonce,
|
|
1489
|
+
argonApprovalsHash,
|
|
1490
|
+
paused,
|
|
1491
|
+
pendingClearOutQueueNonces,
|
|
1492
|
+
...firstQueueNonce !== void 0 ? { firstQueueNonce, lastQueueNonce } : {},
|
|
1493
|
+
updates
|
|
1494
|
+
};
|
|
667
1495
|
}
|
|
668
|
-
function
|
|
669
|
-
|
|
670
|
-
|
|
1496
|
+
async function buildGatewayUpdate(client, destinationChain, hashContext, queueNonce, queueItem) {
|
|
1497
|
+
const { entry, approvingCouncilHash } = queueItem;
|
|
1498
|
+
if (entry.target.isMintingAuthorityActivation) {
|
|
1499
|
+
const signatures = getSortedSignatures(entry.signatures);
|
|
1500
|
+
const signingKey = (0, import_viem3.getAddress)(toHexValue(entry.target.asMintingAuthorityActivation));
|
|
1501
|
+
const authorityOption = await client.query.crosschainTransfer.mintingAuthoritiesBySigner(signingKey);
|
|
1502
|
+
if (authorityOption.isNone) {
|
|
1503
|
+
throw new Error(
|
|
1504
|
+
`Minting authority activation ${signingKey} not found for queue nonce ${queueNonce}`
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
const authority = authorityOption.unwrap();
|
|
1508
|
+
if (authority.destinationChain.type !== destinationChain) {
|
|
1509
|
+
throw new Error(
|
|
1510
|
+
`Minting authority ${signingKey} belongs to ${String(authority.destinationChain.type)}, expected ${String(destinationChain)}`
|
|
1511
|
+
);
|
|
1512
|
+
}
|
|
1513
|
+
const target = {
|
|
1514
|
+
microgonCollateral: authority.gatewayRemainingMicrogonCollateral.toBigInt(),
|
|
1515
|
+
micronotCollateral: authority.gatewayRemainingMicronotCollateral.toBigInt(),
|
|
1516
|
+
signingKey
|
|
1517
|
+
};
|
|
1518
|
+
const payload = encodeMintingGatewayMintingAuthorityActivationTarget(target);
|
|
1519
|
+
const targetPayloadHash = payloadHashFromActivationPayload(hashContext, target);
|
|
1520
|
+
const approvalHash = hashMintingGatewayGatewayUpdateApproval(hashContext, {
|
|
1521
|
+
queueNonce,
|
|
1522
|
+
approvingCouncilHash,
|
|
1523
|
+
kind: MINTING_GATEWAY_UPDATE_KINDS.mintingAuthorityActivate,
|
|
1524
|
+
targetId: `0x${signingKey.slice(2).padStart(64, "0").toLowerCase()}`,
|
|
1525
|
+
targetPayloadHash,
|
|
1526
|
+
previousUpdateHash: toHexValue(entry.previousApprovalHash)
|
|
1527
|
+
});
|
|
1528
|
+
if (toHexValue(entry.targetPayloadHash) !== targetPayloadHash) {
|
|
1529
|
+
throw new Error(`Queue nonce ${queueNonce} target payload hash does not match authority`);
|
|
1530
|
+
}
|
|
1531
|
+
if (toHexValue(entry.approvalHash) !== approvalHash) {
|
|
1532
|
+
throw new Error(
|
|
1533
|
+
`Queue nonce ${queueNonce} approval hash does not match authority: actual=${toHexValue(entry.approvalHash)} expected=${approvalHash} previous=${toHexValue(entry.previousApprovalHash)} council=${approvingCouncilHash} targetPayload=${toHexValue(entry.targetPayloadHash)}`
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
return {
|
|
1537
|
+
queueNonce,
|
|
1538
|
+
kind: MINTING_GATEWAY_UPDATE_KINDS.mintingAuthorityActivate,
|
|
1539
|
+
payload,
|
|
1540
|
+
signatures
|
|
1541
|
+
};
|
|
671
1542
|
}
|
|
672
|
-
|
|
1543
|
+
if (entry.target.isMintingAuthorityDeactivation) {
|
|
1544
|
+
const { payload, signatures } = validateDeactivationEntry(
|
|
1545
|
+
hashContext,
|
|
1546
|
+
queueNonce,
|
|
1547
|
+
entry,
|
|
1548
|
+
approvingCouncilHash
|
|
1549
|
+
);
|
|
1550
|
+
return {
|
|
1551
|
+
queueNonce,
|
|
1552
|
+
kind: MINTING_GATEWAY_UPDATE_KINDS.mintingAuthorityDeactivate,
|
|
1553
|
+
payload,
|
|
1554
|
+
signatures
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
throw new Error(`Unsupported approval queue target ${entry.target.type}`);
|
|
673
1558
|
}
|
|
674
|
-
function
|
|
675
|
-
|
|
1559
|
+
async function loadCouncilByHash(client, councilHash, cache) {
|
|
1560
|
+
const cached = cache.get(councilHash);
|
|
1561
|
+
if (cached) {
|
|
1562
|
+
return cached;
|
|
1563
|
+
}
|
|
1564
|
+
const councilOption = await client.query.crosschainTransfer.globalIssuanceCouncilByHash(councilHash);
|
|
1565
|
+
if (councilOption.isNone) {
|
|
1566
|
+
throw new Error(`GlobalIssuanceCouncil ${councilHash} not found`);
|
|
1567
|
+
}
|
|
1568
|
+
const council = councilOption.unwrap();
|
|
1569
|
+
const loaded = {
|
|
1570
|
+
totalWeight: council.totalWeight.toBigInt(),
|
|
1571
|
+
members: [...council.members.entries()].map(([signer, member]) => ({
|
|
1572
|
+
signer: (0, import_viem3.getAddress)(toHexValue(signer)),
|
|
1573
|
+
weight: member.weight.toBigInt()
|
|
1574
|
+
})).sort((left, right) => left.signer.localeCompare(right.signer))
|
|
1575
|
+
};
|
|
1576
|
+
cache.set(councilHash, loaded);
|
|
1577
|
+
return loaded;
|
|
676
1578
|
}
|
|
677
|
-
function
|
|
678
|
-
|
|
1579
|
+
function queueEntryHasQuorum(entry, council) {
|
|
1580
|
+
const signedWeight = [...entry.signatures.entries()].reduce((total, [signer]) => {
|
|
1581
|
+
const signerAddress = (0, import_viem3.getAddress)(toHexValue(signer));
|
|
1582
|
+
const member = council.members.find((x) => x.signer === signerAddress);
|
|
1583
|
+
if (!member) {
|
|
1584
|
+
throw new Error(`Signature submitted by ${signerAddress}, which is not in the council`);
|
|
1585
|
+
}
|
|
1586
|
+
return total + member.weight;
|
|
1587
|
+
}, 0n);
|
|
1588
|
+
return signedWeight * 2n > council.totalWeight;
|
|
679
1589
|
}
|
|
680
|
-
function
|
|
681
|
-
|
|
682
|
-
|
|
1590
|
+
async function queueEntryIsReady(client, entry, approvingCouncilHash, councilCache, hashContext, queueNonce) {
|
|
1591
|
+
if (entry.target.isMintingAuthorityDeactivation) {
|
|
1592
|
+
validateDeactivationEntry(hashContext, queueNonce, entry, approvingCouncilHash);
|
|
1593
|
+
return true;
|
|
1594
|
+
}
|
|
1595
|
+
const approvingCouncil = await loadCouncilByHash(client, approvingCouncilHash, councilCache);
|
|
1596
|
+
return queueEntryHasQuorum(entry, approvingCouncil);
|
|
683
1597
|
}
|
|
684
|
-
function
|
|
685
|
-
|
|
686
|
-
|
|
1598
|
+
function councilToSnapshot(council) {
|
|
1599
|
+
return {
|
|
1600
|
+
signers: council.members.map((member) => member.signer),
|
|
1601
|
+
weights: council.members.map((member) => member.weight)
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
function payloadHashFromActivationPayload(hashContext, target) {
|
|
1605
|
+
return hashMintingGatewayActivateMintingAuthority(hashContext, target);
|
|
1606
|
+
}
|
|
1607
|
+
function payloadHashFromDeactivationPayload(target) {
|
|
1608
|
+
return (0, import_viem3.keccak256)(encodeMintingGatewayMintingAuthorityDeactivateTarget(target));
|
|
1609
|
+
}
|
|
1610
|
+
function validateDeactivationEntry(hashContext, queueNonce, entry, approvingCouncilHash) {
|
|
1611
|
+
const signingKey = (0, import_viem3.getAddress)(toHexValue(entry.target.asMintingAuthorityDeactivation));
|
|
1612
|
+
const target = { signingKey };
|
|
1613
|
+
const payload = encodeMintingGatewayMintingAuthorityDeactivateTarget(target);
|
|
1614
|
+
const targetPayloadHash = payloadHashFromDeactivationPayload(target);
|
|
1615
|
+
const approvalHash = hashMintingGatewayMintingAuthorityDeactivation(hashContext, {
|
|
1616
|
+
queueNonce,
|
|
1617
|
+
target,
|
|
1618
|
+
previousUpdateHash: toHexValue(entry.previousApprovalHash)
|
|
1619
|
+
});
|
|
1620
|
+
if (toHexValue(entry.targetPayloadHash) !== targetPayloadHash) {
|
|
1621
|
+
throw new Error(`Queue nonce ${queueNonce} target payload hash does not match deactivation`);
|
|
1622
|
+
}
|
|
1623
|
+
if (toHexValue(entry.approvalHash) !== approvalHash) {
|
|
1624
|
+
throw new Error(
|
|
1625
|
+
`Queue nonce ${queueNonce} approval hash does not match deactivation: actual=${toHexValue(entry.approvalHash)} expected=${approvalHash} previous=${toHexValue(entry.previousApprovalHash)} council=${approvingCouncilHash}`
|
|
1626
|
+
);
|
|
1627
|
+
}
|
|
1628
|
+
const deactivationSignatures = [...entry.signatures.entries()];
|
|
1629
|
+
if (deactivationSignatures.length !== 1) {
|
|
1630
|
+
throw new Error(
|
|
1631
|
+
`Queue nonce ${queueNonce} expected exactly one deactivation signature, received ${deactivationSignatures.length}`
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
const [signer] = deactivationSignatures[0];
|
|
1635
|
+
if ((0, import_viem3.getAddress)(toHexValue(signer)) !== signingKey) {
|
|
1636
|
+
throw new Error(
|
|
1637
|
+
`Queue nonce ${queueNonce} deactivation signature was submitted by ${(0, import_viem3.getAddress)(toHexValue(signer))}, expected ${signingKey}`
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
return {
|
|
1641
|
+
payload,
|
|
1642
|
+
signatures: getSortedSignatures(entry.signatures)
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
function getSortedSignatures(signatures) {
|
|
1646
|
+
return [...signatures.entries()].sort(
|
|
1647
|
+
([leftSigner], [rightSigner]) => toHexValue(leftSigner).localeCompare(toHexValue(rightSigner))
|
|
1648
|
+
).map(([, signature]) => toEvmRecoverableSignature(toHexValue(signature)));
|
|
1649
|
+
}
|
|
1650
|
+
function toHexValue(value) {
|
|
1651
|
+
return value.toHex();
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// src/TestEthereumProofActors.ts
|
|
1655
|
+
var import_mainchain7 = require("@argonprotocol/mainchain");
|
|
1656
|
+
var import_accounts2 = require("viem/accounts");
|
|
1657
|
+
var import_viem4 = require("viem");
|
|
1658
|
+
var { argonTokenAbi, mintingGatewayAbi: mintingGatewayAbi2, MINTING_GATEWAY_RUNTIME_TO_ERC20_SCALE } = import_mainchain7.EvmContracts;
|
|
1659
|
+
var MINIMAL_BOOTSTRAP_FINALIZED_SLOT = 64n;
|
|
1660
|
+
var EthereumProofE2eHarness = class _EthereumProofE2eHarness {
|
|
1661
|
+
constructor(ethereum, endpoints, mainchain, mainchainClient, deployerPrivateKey, proofRelayerUri) {
|
|
1662
|
+
this.ethereum = ethereum;
|
|
1663
|
+
this.endpoints = endpoints;
|
|
1664
|
+
this.mainchain = mainchain;
|
|
1665
|
+
this.mainchainClient = mainchainClient;
|
|
1666
|
+
this.deployer = (0, import_accounts2.privateKeyToAccount)(deployerPrivateKey);
|
|
1667
|
+
this.chain = (0, import_viem4.defineChain)({
|
|
1668
|
+
id: Number.parseInt(endpoints.chainId, 16),
|
|
1669
|
+
name: "argon-test-ethereum",
|
|
1670
|
+
nativeCurrency: {
|
|
1671
|
+
name: "Ether",
|
|
1672
|
+
symbol: "ETH",
|
|
1673
|
+
decimals: 18
|
|
1674
|
+
},
|
|
1675
|
+
rpcUrls: {
|
|
1676
|
+
default: {
|
|
1677
|
+
http: [endpoints.executionRpcUrl]
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
this.publicClient = (0, import_viem4.createPublicClient)({
|
|
1682
|
+
chain: this.chain,
|
|
1683
|
+
transport: (0, import_viem4.http)(endpoints.executionRpcUrl)
|
|
1684
|
+
});
|
|
1685
|
+
this.walletClient = (0, import_viem4.createWalletClient)({
|
|
1686
|
+
account: this.deployer,
|
|
1687
|
+
chain: this.chain,
|
|
1688
|
+
transport: (0, import_viem4.http)(endpoints.executionRpcUrl)
|
|
1689
|
+
});
|
|
1690
|
+
this.proofRelayer = new import_mainchain7.Keyring({ type: "sr25519" }).createFromUri(proofRelayerUri);
|
|
1691
|
+
}
|
|
1692
|
+
sudoSigner = new import_mainchain7.Keyring({ type: "sr25519" }).createFromUri("//Alice");
|
|
1693
|
+
deployer;
|
|
1694
|
+
chain;
|
|
1695
|
+
publicClient;
|
|
1696
|
+
walletClient;
|
|
1697
|
+
mainchainClient;
|
|
1698
|
+
proofRelayer;
|
|
1699
|
+
static async launch(args) {
|
|
1700
|
+
const ethereum = new TestEthereum();
|
|
1701
|
+
const endpoints = await ethereum.launch({
|
|
1702
|
+
consensusClient: "lodestar",
|
|
1703
|
+
preset: "minimal",
|
|
1704
|
+
secondsPerSlot: 1,
|
|
1705
|
+
prefundedAccounts: {
|
|
1706
|
+
[args.testAccount.address]: {
|
|
1707
|
+
balance: args.testAccount.balance
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
const mainchain = new TestMainchain();
|
|
1712
|
+
await mainchain.launch();
|
|
1713
|
+
const mainchainClient = await mainchain.client();
|
|
1714
|
+
return new _EthereumProofE2eHarness(
|
|
1715
|
+
ethereum,
|
|
1716
|
+
endpoints,
|
|
1717
|
+
mainchain,
|
|
1718
|
+
mainchainClient,
|
|
1719
|
+
args.testAccount.privateKey,
|
|
1720
|
+
args.proofRelayerUri
|
|
1721
|
+
);
|
|
1722
|
+
}
|
|
1723
|
+
async submit(tx, signer) {
|
|
1724
|
+
const result = await new import_mainchain7.TxSubmitter(this.mainchainClient, tx, signer).submit();
|
|
1725
|
+
await result.waitForInFirstBlock;
|
|
1726
|
+
return result;
|
|
1727
|
+
}
|
|
1728
|
+
async sudoSubmit(tx) {
|
|
1729
|
+
const result = await this.submit(
|
|
1730
|
+
this.mainchainClient.tx.sudo.sudo(tx),
|
|
1731
|
+
this.sudoSigner
|
|
1732
|
+
);
|
|
1733
|
+
const sudoEvent = result.events.find((event) => this.mainchainClient.events.sudo.Sudid.is(event));
|
|
1734
|
+
if (!sudoEvent || !this.mainchainClient.events.sudo.Sudid.is(sudoEvent)) {
|
|
1735
|
+
throw new Error("sudo did not emit sudo.Sudid");
|
|
1736
|
+
}
|
|
1737
|
+
const sudoResult = sudoEvent.data[0];
|
|
1738
|
+
if (sudoResult.isErr) {
|
|
1739
|
+
throw new Error(
|
|
1740
|
+
`sudo failed: ${(0, import_mainchain7.dispatchErrorToString)(this.mainchainClient, sudoResult.asErr)}`
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
return result;
|
|
1744
|
+
}
|
|
1745
|
+
async syncVerifierThrough(minimumExecutionBlockNumber) {
|
|
1746
|
+
await syncEthereumVerifierUntilAnchorCovers(
|
|
1747
|
+
this.mainchainClient,
|
|
1748
|
+
this.sudoSigner,
|
|
1749
|
+
this.endpoints.beaconApiUrl,
|
|
1750
|
+
minimumExecutionBlockNumber
|
|
1751
|
+
);
|
|
1752
|
+
}
|
|
1753
|
+
async proveGatewayActivity(gatewayAddress, throughExecutionBlockNumber) {
|
|
1754
|
+
const payload = await (0, import_mainchain7.buildGatewayActivityProofPayload)(this.mainchainClient, {
|
|
1755
|
+
executionRpcUrl: this.endpoints.executionRpcUrl,
|
|
1756
|
+
gatewayAddress,
|
|
1757
|
+
throughExecutionBlockNumber
|
|
1758
|
+
});
|
|
1759
|
+
if (!payload) {
|
|
1760
|
+
throw new Error("Expected uncovered gateway activity to prove");
|
|
1761
|
+
}
|
|
1762
|
+
const result = await this.submit(
|
|
1763
|
+
this.mainchainClient.tx.crosschainTransfer.proveGatewayActivity(
|
|
1764
|
+
"Ethereum",
|
|
1765
|
+
payload.previousGatewayActivityNonce,
|
|
1766
|
+
payload.proof
|
|
1767
|
+
),
|
|
1768
|
+
this.proofRelayer
|
|
1769
|
+
);
|
|
1770
|
+
return { payload, result };
|
|
1771
|
+
}
|
|
1772
|
+
async configureEthereumRuntime(gateway, mode) {
|
|
1773
|
+
const calls = [
|
|
1774
|
+
this.mainchainClient.tx.crosschainTransfer.setChainConfig("Ethereum", {
|
|
1775
|
+
Evm: {
|
|
1776
|
+
chainId: BigInt(this.chain.id).toString(),
|
|
1777
|
+
gateway: gateway.gatewayAddress,
|
|
1778
|
+
argonToken: gateway.argonTokenAddress,
|
|
1779
|
+
argonotToken: gateway.argonotTokenAddress
|
|
1780
|
+
}
|
|
1781
|
+
})
|
|
1782
|
+
];
|
|
1783
|
+
if (mode.kind === "outbound") {
|
|
1784
|
+
const activationPricing = {
|
|
1785
|
+
activationGasCost: BigInt(mode.activationPricing.activationGasCost),
|
|
1786
|
+
signatureGasCost: BigInt(mode.activationPricing.signatureGasCost),
|
|
1787
|
+
estimatedWeiPerGas: BigInt(mode.activationPricing.estimatedWeiPerGas),
|
|
1788
|
+
estimatedMicrogonsPerEth: BigInt(mode.activationPricing.estimatedMicrogonsPerEth)
|
|
1789
|
+
};
|
|
1790
|
+
calls.push(
|
|
1791
|
+
this.mainchainClient.tx.crosschainTransfer.setMintingAuthorityActivationRepaymentPricing(
|
|
1792
|
+
"Ethereum",
|
|
1793
|
+
{
|
|
1794
|
+
activationGasCost: activationPricing.activationGasCost.toString(),
|
|
1795
|
+
signatureGasCost: activationPricing.signatureGasCost.toString(),
|
|
1796
|
+
estimatedWeiPerGas: activationPricing.estimatedWeiPerGas.toString(),
|
|
1797
|
+
estimatedMicrogonsPerEth: activationPricing.estimatedMicrogonsPerEth.toString()
|
|
1798
|
+
}
|
|
1799
|
+
)
|
|
1800
|
+
);
|
|
1801
|
+
if (mode.minimumMintingAuthorityValue !== void 0) {
|
|
1802
|
+
calls.push(
|
|
1803
|
+
this.mainchainClient.tx.crosschainTransfer.setMinimumMintingAuthorityValue(
|
|
1804
|
+
"Ethereum",
|
|
1805
|
+
mode.minimumMintingAuthorityValue.toString()
|
|
1806
|
+
)
|
|
1807
|
+
);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
calls.push(
|
|
1811
|
+
await (0, import_mainchain7.getEthereumBeaconSyncBootstrapTx)(this.mainchainClient, this.endpoints.beaconApiUrl)
|
|
1812
|
+
);
|
|
1813
|
+
const result = await this.sudoSubmit(this.mainchainClient.tx.utility.batchAll(calls));
|
|
1814
|
+
return { result };
|
|
1815
|
+
}
|
|
1816
|
+
async fundBurnAccount(amount) {
|
|
1817
|
+
const burnAccount = this.mainchainClient.consts.crosschainTransfer.ethereumBurnAccount.toString();
|
|
1818
|
+
return this.forceSetBalance(burnAccount, amount);
|
|
1819
|
+
}
|
|
1820
|
+
async fundProofRelayer(amount = this.mainchainClient.consts.balances.existentialDeposit.toBigInt() + 1000000n) {
|
|
1821
|
+
return this.submit(
|
|
1822
|
+
this.mainchainClient.tx.balances.transferAllowDeath(this.proofRelayer.address, amount),
|
|
1823
|
+
this.sudoSigner
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
async forceSetBalance(address, amount) {
|
|
1827
|
+
return this.sudoSubmit(this.mainchainClient.tx.balances.forceSetBalance(address, amount));
|
|
1828
|
+
}
|
|
1829
|
+
async forceSetOwnership(address, amount) {
|
|
1830
|
+
return this.sudoSubmit(this.mainchainClient.tx.ownership.forceSetBalance(address, amount));
|
|
1831
|
+
}
|
|
1832
|
+
async waitForExecutionFinalizedAfter(minimumExecutionBlockNumber) {
|
|
1833
|
+
const laterReceipt = await mineLaterExecutionAnchorReceipt(
|
|
1834
|
+
this.walletClient,
|
|
1835
|
+
this.chain,
|
|
1836
|
+
this.ethereum,
|
|
1837
|
+
this.deployer,
|
|
1838
|
+
minimumExecutionBlockNumber
|
|
1839
|
+
);
|
|
1840
|
+
await waitForFinalizedBeaconExecutionAtOrAbove(
|
|
1841
|
+
this.ethereum,
|
|
1842
|
+
BigInt(laterReceipt.blockNumber),
|
|
1843
|
+
{
|
|
1844
|
+
// Matches the apps/pr/gateway-proof bootstrap guard for minimal devnets.
|
|
1845
|
+
minimumFinalizedSlot: MINIMAL_BOOTSTRAP_FINALIZED_SLOT
|
|
1846
|
+
}
|
|
1847
|
+
);
|
|
1848
|
+
return laterReceipt;
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
var TestMintingGateway = class _TestMintingGateway {
|
|
1852
|
+
constructor(harness, deployment) {
|
|
1853
|
+
this.harness = harness;
|
|
1854
|
+
this.deployment = deployment;
|
|
1855
|
+
}
|
|
1856
|
+
static async deploy(harness, options) {
|
|
1857
|
+
const deployment = await harness.ethereum.deployMintingGatewayFixture(options);
|
|
1858
|
+
return new _TestMintingGateway(harness, deployment);
|
|
1859
|
+
}
|
|
1860
|
+
get gatewayAddress() {
|
|
1861
|
+
return this.deployment.gatewayAddress;
|
|
1862
|
+
}
|
|
1863
|
+
get argonTokenAddress() {
|
|
1864
|
+
return this.deployment.argonTokenAddress;
|
|
1865
|
+
}
|
|
1866
|
+
get argonotTokenAddress() {
|
|
1867
|
+
return this.deployment.argonotTokenAddress;
|
|
1868
|
+
}
|
|
1869
|
+
async startTransferToArgon(args) {
|
|
1870
|
+
const permitDeadline = (await this.harness.publicClient.getBlock()).timestamp + 3600n;
|
|
1871
|
+
const permitNonce = await this.harness.publicClient.readContract({
|
|
1872
|
+
address: this.argonTokenAddress,
|
|
1873
|
+
abi: argonTokenAbi,
|
|
1874
|
+
functionName: "nonces",
|
|
1875
|
+
args: [args.account.address]
|
|
1876
|
+
});
|
|
1877
|
+
const permitSignature = await signGatewayPermit({
|
|
1878
|
+
account: args.account,
|
|
1879
|
+
chainId: this.harness.chain.id,
|
|
1880
|
+
tokenAddress: this.argonTokenAddress,
|
|
1881
|
+
gatewayAddress: this.gatewayAddress,
|
|
1882
|
+
owner: args.account.address,
|
|
1883
|
+
value: args.amountRuntimeUnits * MINTING_GATEWAY_RUNTIME_TO_ERC20_SCALE,
|
|
1884
|
+
nonce: permitNonce,
|
|
1885
|
+
deadline: permitDeadline
|
|
1886
|
+
});
|
|
1887
|
+
const transactionHash = await (0, import_viem4.createWalletClient)({
|
|
1888
|
+
account: args.account,
|
|
1889
|
+
chain: this.harness.chain,
|
|
1890
|
+
transport: (0, import_viem4.http)(this.harness.endpoints.executionRpcUrl)
|
|
1891
|
+
}).sendTransaction({
|
|
1892
|
+
account: args.account,
|
|
1893
|
+
chain: this.harness.chain,
|
|
1894
|
+
to: this.gatewayAddress,
|
|
1895
|
+
data: (0, import_viem4.encodeFunctionData)({
|
|
1896
|
+
abi: mintingGatewayAbi2,
|
|
1897
|
+
functionName: "startTransferToArgon",
|
|
1898
|
+
args: [
|
|
1899
|
+
this.argonTokenAddress,
|
|
1900
|
+
args.amountRuntimeUnits,
|
|
1901
|
+
args.recipientArgonAddress,
|
|
1902
|
+
permitDeadline,
|
|
1903
|
+
permitSignature.v,
|
|
1904
|
+
permitSignature.r,
|
|
1905
|
+
permitSignature.s
|
|
1906
|
+
]
|
|
1907
|
+
})
|
|
1908
|
+
});
|
|
1909
|
+
return waitForExecutionReceipt2(this.harness.ethereum, transactionHash);
|
|
1910
|
+
}
|
|
1911
|
+
async forceUpdateActiveCouncil(replacementCouncil, nextMicrogonsPerArgonot) {
|
|
1912
|
+
return this.harness.publicClient.waitForTransactionReceipt({
|
|
1913
|
+
hash: await this.harness.walletClient.writeContract({
|
|
1914
|
+
account: this.harness.deployer,
|
|
1915
|
+
chain: this.harness.chain,
|
|
1916
|
+
address: this.gatewayAddress,
|
|
1917
|
+
abi: mintingGatewayAbi2,
|
|
1918
|
+
functionName: "forceUpdateActiveCouncil",
|
|
1919
|
+
args: [replacementCouncil, nextMicrogonsPerArgonot]
|
|
1920
|
+
})
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
async relayReadyApprovals(batch, operatorAddress) {
|
|
1924
|
+
return this.harness.publicClient.waitForTransactionReceipt({
|
|
1925
|
+
hash: await this.harness.walletClient.writeContract({
|
|
1926
|
+
account: this.harness.deployer,
|
|
1927
|
+
chain: this.harness.chain,
|
|
1928
|
+
address: this.gatewayAddress,
|
|
1929
|
+
abi: mintingGatewayAbi2,
|
|
1930
|
+
functionName: "applyGatewayUpdates",
|
|
1931
|
+
args: [
|
|
1932
|
+
batch.currentCouncil,
|
|
1933
|
+
batch.updates,
|
|
1934
|
+
(0, import_viem4.toHex)((0, import_mainchain7.decodeAddress)(operatorAddress), { size: 32 })
|
|
1935
|
+
]
|
|
1936
|
+
})
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1939
|
+
async argonApprovalsNonce() {
|
|
1940
|
+
return await this.harness.publicClient.readContract({
|
|
1941
|
+
address: this.gatewayAddress,
|
|
1942
|
+
abi: mintingGatewayAbi2,
|
|
1943
|
+
functionName: "argonApprovalsNonce"
|
|
1944
|
+
});
|
|
1945
|
+
}
|
|
1946
|
+
async globalIssuanceCouncil() {
|
|
1947
|
+
return await this.harness.publicClient.readContract({
|
|
1948
|
+
address: this.gatewayAddress,
|
|
1949
|
+
abi: mintingGatewayAbi2,
|
|
1950
|
+
functionName: "globalIssuanceCouncil"
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
async authorityCollateral(signingKey) {
|
|
1954
|
+
return await this.harness.publicClient.readContract({
|
|
1955
|
+
address: this.gatewayAddress,
|
|
1956
|
+
abi: mintingGatewayAbi2,
|
|
1957
|
+
functionName: "mintingAuthorityCollateralRemaining",
|
|
1958
|
+
args: [signingKey]
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1961
|
+
async finalizeTransferOut(args) {
|
|
1962
|
+
return this.harness.publicClient.waitForTransactionReceipt({
|
|
1963
|
+
hash: await this.harness.walletClient.writeContract({
|
|
1964
|
+
account: this.harness.deployer,
|
|
1965
|
+
chain: this.harness.chain,
|
|
1966
|
+
address: this.gatewayAddress,
|
|
1967
|
+
abi: mintingGatewayAbi2,
|
|
1968
|
+
functionName: "finalizeTransferOutOfArgon",
|
|
1969
|
+
args: [
|
|
1970
|
+
args.transferRequest,
|
|
1971
|
+
{
|
|
1972
|
+
authorizations: [
|
|
1973
|
+
{
|
|
1974
|
+
microgonCollateral: 0n,
|
|
1975
|
+
micronotCollateral: args.micronotCollateral,
|
|
1976
|
+
signature: args.collateralizationSignature
|
|
1977
|
+
}
|
|
1978
|
+
]
|
|
1979
|
+
}
|
|
1980
|
+
]
|
|
1981
|
+
})
|
|
1982
|
+
});
|
|
1983
|
+
}
|
|
1984
|
+
async isFinalizedTransferOut(transferRequest) {
|
|
1985
|
+
return await this.harness.publicClient.readContract({
|
|
1986
|
+
address: this.gatewayAddress,
|
|
1987
|
+
abi: mintingGatewayAbi2,
|
|
1988
|
+
functionName: "finalizedTransferOutOfArgonIds",
|
|
1989
|
+
args: [import_mainchain7.EvmContracts.hashMintingGatewayTransferOutOfArgonRequest(transferRequest)]
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
async argonBalance(address) {
|
|
1993
|
+
return await this.harness.publicClient.readContract({
|
|
1994
|
+
address: this.argonTokenAddress,
|
|
1995
|
+
abi: argonTokenAbi,
|
|
1996
|
+
functionName: "balanceOf",
|
|
1997
|
+
args: [address]
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
async fundExecutionAccount(address, value) {
|
|
2001
|
+
return this.harness.publicClient.waitForTransactionReceipt({
|
|
2002
|
+
hash: await this.harness.walletClient.sendTransaction({
|
|
2003
|
+
account: this.harness.deployer,
|
|
2004
|
+
chain: this.harness.chain,
|
|
2005
|
+
to: address,
|
|
2006
|
+
value
|
|
2007
|
+
})
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
2011
|
+
var TestMintingAuthorityActor = class {
|
|
2012
|
+
constructor(harness, args) {
|
|
2013
|
+
this.harness = harness;
|
|
2014
|
+
this.operator = new import_mainchain7.Keyring({ type: "sr25519" }).createFromUri(args.operatorUri);
|
|
2015
|
+
this.councilSigner = (0, import_accounts2.privateKeyToAccount)(args.councilPrivateKey);
|
|
2016
|
+
this.authoritySigner = (0, import_accounts2.privateKeyToAccount)(args.authorityPrivateKey);
|
|
2017
|
+
}
|
|
2018
|
+
operator;
|
|
2019
|
+
councilSigner;
|
|
2020
|
+
authoritySigner;
|
|
2021
|
+
gateway;
|
|
2022
|
+
attachGateway(gateway) {
|
|
2023
|
+
this.gateway = gateway;
|
|
2024
|
+
}
|
|
2025
|
+
async prepareOperator(args) {
|
|
2026
|
+
await this.harness.forceSetBalance(this.operator.address, args.freeBalance);
|
|
2027
|
+
await this.harness.forceSetOwnership(this.operator.address, args.ownershipBalance);
|
|
2028
|
+
const vault = await import_mainchain7.Vault.create(this.harness.mainchainClient, this.operator, {
|
|
2029
|
+
securitization: 1000000000n,
|
|
2030
|
+
securitizationRatio: 1,
|
|
2031
|
+
annualPercentRate: 0.05,
|
|
2032
|
+
baseFee: 0n,
|
|
2033
|
+
bitcoinXpub: args.bitcoinXpub,
|
|
2034
|
+
treasuryProfitSharing: 0
|
|
2035
|
+
});
|
|
2036
|
+
await vault.getVault();
|
|
2037
|
+
await this.harness.sudoSubmit(
|
|
2038
|
+
this.harness.mainchainClient.tx.priceIndex.setOperator(this.operator.address)
|
|
2039
|
+
);
|
|
2040
|
+
const currentTick = await this.harness.mainchainClient.query.ticks.currentTick();
|
|
2041
|
+
await this.harness.submit(
|
|
2042
|
+
this.harness.mainchainClient.tx.priceIndex.submit({
|
|
2043
|
+
btcUsdPrice: (0, import_mainchain7.toFixedNumber)(6e4, 18),
|
|
2044
|
+
argonotUsdPrice: (0, import_mainchain7.toFixedNumber)(1, 18),
|
|
2045
|
+
argonUsdPrice: (0, import_mainchain7.toFixedNumber)(1, 18),
|
|
2046
|
+
argonUsdTargetPrice: (0, import_mainchain7.toFixedNumber)(1, 18),
|
|
2047
|
+
argonTimeWeightedAverageLiquidity: (0, import_mainchain7.toFixedNumber)(1e6, 18),
|
|
2048
|
+
tick: currentTick.toBigInt()
|
|
2049
|
+
}),
|
|
2050
|
+
this.operator
|
|
2051
|
+
);
|
|
2052
|
+
await this.harness.submit(
|
|
2053
|
+
this.harness.mainchainClient.tx.vaults.setCommittedArgonots(args.committedArgonots),
|
|
2054
|
+
this.operator
|
|
2055
|
+
);
|
|
2056
|
+
}
|
|
2057
|
+
async registerCouncilSigner() {
|
|
2058
|
+
return this.harness.submit(
|
|
2059
|
+
this.harness.mainchainClient.tx.crosschainTransfer.registerCouncilSigner(
|
|
2060
|
+
"Ethereum",
|
|
2061
|
+
this.councilSigner.address,
|
|
2062
|
+
toArgonKeccakSignature(
|
|
2063
|
+
await this.councilSigner.signMessage({
|
|
2064
|
+
message: { raw: (0, import_viem4.toHex)(this.registrationMessage("argon/council-signer/v2")) }
|
|
2065
|
+
})
|
|
2066
|
+
)
|
|
2067
|
+
),
|
|
2068
|
+
this.operator
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
async forceSingleMemberCouncil() {
|
|
2072
|
+
await this.harness.sudoSubmit(
|
|
2073
|
+
this.harness.mainchainClient.tx.crosschainTransfer.forceSetGlobalIssuanceCouncil(
|
|
2074
|
+
"Ethereum",
|
|
2075
|
+
0,
|
|
2076
|
+
[this.operator.address]
|
|
2077
|
+
)
|
|
2078
|
+
);
|
|
2079
|
+
const activeCouncilHashOption = await this.harness.mainchainClient.query.crosschainTransfer.activeGlobalIssuanceCouncilByDestinationChain(
|
|
2080
|
+
"Ethereum"
|
|
2081
|
+
);
|
|
2082
|
+
if (activeCouncilHashOption.isNone) {
|
|
2083
|
+
throw new Error("Expected active Ethereum council hash");
|
|
2084
|
+
}
|
|
2085
|
+
const activeCouncilOption = await this.harness.mainchainClient.query.crosschainTransfer.globalIssuanceCouncilByHash(
|
|
2086
|
+
activeCouncilHashOption.unwrap()
|
|
2087
|
+
);
|
|
2088
|
+
if (activeCouncilOption.isNone) {
|
|
2089
|
+
throw new Error("Expected active Ethereum council");
|
|
2090
|
+
}
|
|
2091
|
+
const activeCouncil = activeCouncilOption.unwrap();
|
|
2092
|
+
const currentCouncil = [...activeCouncil.members.entries()].map(([signer, member]) => ({
|
|
2093
|
+
signer: signer.toHex(),
|
|
2094
|
+
weight: member.weight.toBigInt()
|
|
2095
|
+
})).sort((left, right) => left.signer.localeCompare(right.signer));
|
|
2096
|
+
return {
|
|
2097
|
+
activeCouncilHash: activeCouncilHashOption.unwrap().toHex(),
|
|
2098
|
+
activeCouncil,
|
|
2099
|
+
currentCouncil: {
|
|
2100
|
+
signers: currentCouncil.map((member) => member.signer),
|
|
2101
|
+
weights: currentCouncil.map((member) => member.weight)
|
|
2102
|
+
}
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2105
|
+
async registerMintingAuthority(micronotCollateral) {
|
|
2106
|
+
return this.harness.submit(
|
|
2107
|
+
this.harness.mainchainClient.tx.crosschainTransfer.registerMintingAuthority(
|
|
2108
|
+
"Ethereum",
|
|
2109
|
+
this.authoritySigner.address,
|
|
2110
|
+
toArgonKeccakSignature(
|
|
2111
|
+
await this.authoritySigner.signMessage({
|
|
2112
|
+
message: {
|
|
2113
|
+
raw: (0, import_viem4.toHex)(this.registrationMessage("argon/minting-authority-signer/v2"))
|
|
2114
|
+
}
|
|
2115
|
+
})
|
|
2116
|
+
),
|
|
2117
|
+
0n,
|
|
2118
|
+
micronotCollateral
|
|
2119
|
+
),
|
|
2120
|
+
this.operator
|
|
2121
|
+
);
|
|
2122
|
+
}
|
|
2123
|
+
async approveActivationQueueEntry(queueNonce = 1n) {
|
|
2124
|
+
const approvalQueueEntry = await this.harness.mainchainClient.query.crosschainTransfer.councilApprovalQueueByDestinationChainAndNonce(
|
|
2125
|
+
"Ethereum",
|
|
2126
|
+
queueNonce
|
|
2127
|
+
);
|
|
2128
|
+
if (approvalQueueEntry.isNone) {
|
|
2129
|
+
throw new Error(`Expected queue nonce ${queueNonce} to exist`);
|
|
2130
|
+
}
|
|
2131
|
+
const councilApprovalSignature = await this.councilSigner.signMessage({
|
|
2132
|
+
message: {
|
|
2133
|
+
raw: approvalQueueEntry.unwrap().approvalHash.toHex()
|
|
2134
|
+
}
|
|
2135
|
+
});
|
|
2136
|
+
await this.harness.submit(
|
|
2137
|
+
this.harness.mainchainClient.tx.crosschainTransfer.approveQueueEntries(
|
|
2138
|
+
"Ethereum",
|
|
2139
|
+
new import_mainchain7.Vec(this.harness.mainchainClient.registry, import_mainchain7.U8aFixed.with(520), [
|
|
2140
|
+
new import_mainchain7.U8aFixed(
|
|
2141
|
+
this.harness.mainchainClient.registry,
|
|
2142
|
+
toArgonKeccakSignature(councilApprovalSignature),
|
|
2143
|
+
520
|
|
2144
|
+
)
|
|
2145
|
+
])
|
|
2146
|
+
),
|
|
2147
|
+
this.operator
|
|
2148
|
+
);
|
|
2149
|
+
const batch = await getReadyEthereumGatewayUpdates(
|
|
2150
|
+
this.harness.mainchainClient,
|
|
2151
|
+
this.harness.publicClient
|
|
2152
|
+
);
|
|
2153
|
+
return {
|
|
2154
|
+
approvalQueueEntry,
|
|
2155
|
+
councilApprovalSignature,
|
|
2156
|
+
batch
|
|
2157
|
+
};
|
|
2158
|
+
}
|
|
2159
|
+
async collateralizeFirstPendingTransferOut() {
|
|
2160
|
+
const gateway = this.requireGateway();
|
|
2161
|
+
const pendingRequests = await this.harness.mainchainClient.query.crosschainTransfer.pendingCollateralizationRequestsByChain(
|
|
2162
|
+
"Ethereum"
|
|
2163
|
+
);
|
|
2164
|
+
if (pendingRequests.length === 0) {
|
|
2165
|
+
throw new Error("Expected a pending collateralization request");
|
|
2166
|
+
}
|
|
2167
|
+
const pendingRequest = pendingRequests[0];
|
|
2168
|
+
const transferId = pendingRequest.transferId.toHex();
|
|
2169
|
+
const transferOption = await this.harness.mainchainClient.query.crosschainTransfer.transferOutById(transferId);
|
|
2170
|
+
if (transferOption.isNone) {
|
|
2171
|
+
throw new Error(`Expected transfer out ${transferId} to exist`);
|
|
2172
|
+
}
|
|
2173
|
+
const transfer = transferOption.unwrap();
|
|
2174
|
+
const transferRequest = {
|
|
2175
|
+
argonAccountId: transfer.argonAccountId.toHex(),
|
|
2176
|
+
argonTransferNonce: transfer.argonTransferNonce.toBigInt(),
|
|
2177
|
+
chainId: BigInt(this.harness.chain.id),
|
|
2178
|
+
microgonsPerArgonot: transfer.microgonsPerArgonot.toBigInt(),
|
|
2179
|
+
recipient: transfer.destinationAccount.toHex(),
|
|
2180
|
+
validUntilBlock: transfer.validUntilEthereumBlock.toBigInt(),
|
|
2181
|
+
token: gateway.argonTokenAddress,
|
|
2182
|
+
amount: transfer.amount.toBigInt(),
|
|
2183
|
+
mintingAuthorityTip: transfer.mintingAuthorityTip.toBigInt()
|
|
2184
|
+
};
|
|
2185
|
+
const micronotCollateral = transfer.amount.toBigInt();
|
|
2186
|
+
const collateralizationHash = import_mainchain7.EvmContracts.hashMintingGatewayMintingAuthorization(
|
|
2187
|
+
{ chainId: BigInt(this.harness.chain.id), gatewayAddress: gateway.gatewayAddress },
|
|
2188
|
+
{
|
|
2189
|
+
request: transferRequest,
|
|
2190
|
+
microgonCollateral: 0n,
|
|
2191
|
+
micronotCollateral
|
|
2192
|
+
}
|
|
2193
|
+
);
|
|
2194
|
+
const collateralizationSignature = await this.authoritySigner.signMessage({
|
|
2195
|
+
message: {
|
|
2196
|
+
raw: collateralizationHash
|
|
2197
|
+
}
|
|
2198
|
+
});
|
|
2199
|
+
const result = await this.harness.submit(
|
|
2200
|
+
this.harness.mainchainClient.tx.crosschainTransfer.collateralizeTransfer(
|
|
2201
|
+
transferId,
|
|
2202
|
+
toArgonKeccakSignature(collateralizationSignature),
|
|
2203
|
+
0n,
|
|
2204
|
+
micronotCollateral
|
|
2205
|
+
),
|
|
2206
|
+
this.operator
|
|
2207
|
+
);
|
|
2208
|
+
return {
|
|
2209
|
+
pendingRequest,
|
|
2210
|
+
transferId,
|
|
2211
|
+
transferRequest,
|
|
2212
|
+
micronotCollateral,
|
|
2213
|
+
collateralizationSignature,
|
|
2214
|
+
result
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
registrationMessage(prefix) {
|
|
2218
|
+
const prefixBytes = this.harness.mainchainClient.registry.createType("Bytes", prefix).toU8a();
|
|
2219
|
+
const destinationChainBytes = this.harness.mainchainClient.registry.createType("PalletCrosschainTransferSourceChain", "Ethereum").toU8a();
|
|
2220
|
+
const operatorAccountIdBytes = this.harness.mainchainClient.registry.createType("AccountId32", this.operator.address).toU8a();
|
|
2221
|
+
return concatBytes(prefixBytes, destinationChainBytes, operatorAccountIdBytes);
|
|
2222
|
+
}
|
|
2223
|
+
requireGateway() {
|
|
2224
|
+
if (!this.gateway) {
|
|
2225
|
+
throw new Error("Minting authority actor requires an attached TestMintingGateway");
|
|
2226
|
+
}
|
|
2227
|
+
return this.gateway;
|
|
2228
|
+
}
|
|
2229
|
+
};
|
|
2230
|
+
function concatBytes(...parts) {
|
|
2231
|
+
const totalLength = parts.reduce((sum, part) => sum + part.length, 0);
|
|
2232
|
+
const bytes = new Uint8Array(totalLength);
|
|
2233
|
+
let offset = 0;
|
|
2234
|
+
for (const part of parts) {
|
|
2235
|
+
bytes.set(part, offset);
|
|
2236
|
+
offset += part.length;
|
|
2237
|
+
}
|
|
2238
|
+
return bytes;
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
// src/index.ts
|
|
2242
|
+
function stringifyExt(obj) {
|
|
2243
|
+
return JSON.stringify(
|
|
2244
|
+
obj,
|
|
2245
|
+
(_key, value) => {
|
|
2246
|
+
if (typeof value === "bigint") {
|
|
2247
|
+
return value.toString() + "n";
|
|
2248
|
+
}
|
|
2249
|
+
if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
2250
|
+
return `0x${Buffer.from(value).toString("hex")}`;
|
|
2251
|
+
}
|
|
2252
|
+
return value;
|
|
2253
|
+
},
|
|
2254
|
+
2
|
|
2255
|
+
);
|
|
687
2256
|
}
|
|
688
2257
|
function sudo() {
|
|
689
|
-
return new
|
|
2258
|
+
return new import_mainchain8.Keyring({ type: "sr25519" }).createFromUri("//Alice");
|
|
690
2259
|
}
|
|
691
2260
|
async function activateNotary(sudo2, client, notary) {
|
|
692
2261
|
await notary.register(client);
|
|
693
|
-
const txResult = await new
|
|
2262
|
+
const txResult = await new import_mainchain8.TxSubmitter(
|
|
694
2263
|
client,
|
|
695
2264
|
client.tx.sudo.sudo(client.tx.notaries.activate(notary.operator.publicKey)),
|
|
696
2265
|
sudo2
|
|
@@ -699,9 +2268,13 @@ async function activateNotary(sudo2, client, notary) {
|
|
|
699
2268
|
}
|
|
700
2269
|
// Annotate the CommonJS export names for ESM import in node:
|
|
701
2270
|
0 && (module.exports = {
|
|
2271
|
+
EthereumProofE2eHarness,
|
|
702
2272
|
SKIP_E2E,
|
|
703
2273
|
TestBitcoinCli,
|
|
2274
|
+
TestEthereum,
|
|
704
2275
|
TestMainchain,
|
|
2276
|
+
TestMintingAuthorityActor,
|
|
2277
|
+
TestMintingGateway,
|
|
705
2278
|
TestNotary,
|
|
706
2279
|
TestOracle,
|
|
707
2280
|
activateNotary,
|
|
@@ -711,12 +2284,20 @@ async function activateNotary(sudo2, client, notary) {
|
|
|
711
2284
|
disconnectOnTeardown,
|
|
712
2285
|
getDockerPortMapping,
|
|
713
2286
|
getProxy,
|
|
2287
|
+
getReadyEthereumGatewayUpdates,
|
|
2288
|
+
mineLaterExecutionAnchorReceipt,
|
|
714
2289
|
projectRoot,
|
|
715
2290
|
runOnTeardown,
|
|
716
2291
|
runTestScript,
|
|
2292
|
+
signGatewayPermit,
|
|
717
2293
|
startNetwork,
|
|
718
2294
|
stringifyExt,
|
|
719
2295
|
sudo,
|
|
720
|
-
|
|
2296
|
+
syncEthereumVerifierUntilAnchorCovers,
|
|
2297
|
+
teardown,
|
|
2298
|
+
toArgonKeccakSignature,
|
|
2299
|
+
toEvmRecoverableSignature,
|
|
2300
|
+
waitForExecutionReceipt,
|
|
2301
|
+
waitForFinalizedBeaconExecutionAtOrAbove
|
|
721
2302
|
});
|
|
722
2303
|
//# sourceMappingURL=index.cjs.map
|