@argonprotocol/testing 1.4.3-dev.8dfc7f36 → 1.4.3-dev.8e7d7af7
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/ethereum-contracts/ArgonToken.json +419 -0
- package/lib/ethereum-contracts/ArgonotToken.json +419 -0
- package/lib/ethereum-contracts/MintingGateway.json +538 -0
- package/lib/ethereum-contracts/ProxyAdmin.json +135 -0
- package/lib/ethereum-contracts/TransparentUpgradeableProxy.json +131 -0
- package/lib/index.cjs +520 -17
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +96 -3
- package/lib/index.d.ts +96 -3
- package/lib/index.js +519 -17
- package/lib/index.js.map +1 -1
- package/package.json +5 -6
- /package/lib/{docker-compose.yml → dev.docker-compose.yml} +0 -0
package/lib/index.cjs
CHANGED
|
@@ -32,16 +32,19 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
SKIP_E2E: () => SKIP_E2E,
|
|
34
34
|
TestBitcoinCli: () => TestBitcoinCli,
|
|
35
|
+
TestEthereum: () => TestEthereum,
|
|
35
36
|
TestMainchain: () => TestMainchain,
|
|
36
37
|
TestNotary: () => TestNotary,
|
|
37
38
|
TestOracle: () => TestOracle,
|
|
38
39
|
activateNotary: () => activateNotary,
|
|
39
40
|
addTeardown: () => addTeardown,
|
|
41
|
+
argonTokenArtifact: () => argonTokenArtifact,
|
|
40
42
|
cleanHostForDocker: () => cleanHostForDocker,
|
|
41
43
|
closeOnTeardown: () => closeOnTeardown,
|
|
42
44
|
disconnectOnTeardown: () => disconnectOnTeardown,
|
|
43
45
|
getDockerPortMapping: () => getDockerPortMapping,
|
|
44
46
|
getProxy: () => getProxy,
|
|
47
|
+
mintingGatewayArtifact: () => mintingGatewayArtifact,
|
|
45
48
|
projectRoot: () => projectRoot,
|
|
46
49
|
runOnTeardown: () => runOnTeardown,
|
|
47
50
|
runTestScript: () => runTestScript,
|
|
@@ -51,13 +54,19 @@ __export(index_exports, {
|
|
|
51
54
|
teardown: () => teardown
|
|
52
55
|
});
|
|
53
56
|
module.exports = __toCommonJS(index_exports);
|
|
57
|
+
|
|
58
|
+
// node_modules/tsup/assets/cjs_shims.js
|
|
59
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
|
|
60
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
61
|
+
|
|
62
|
+
// src/index.ts
|
|
54
63
|
var import_mainchain4 = require("@argonprotocol/mainchain");
|
|
55
64
|
var process4 = __toESM(require("process"), 1);
|
|
56
65
|
var import_http_proxy = __toESM(require("http-proxy"), 1);
|
|
57
66
|
var child_process4 = __toESM(require("child_process"), 1);
|
|
58
|
-
var
|
|
67
|
+
var http2 = __toESM(require("http"), 1);
|
|
59
68
|
var url = __toESM(require("url"), 1);
|
|
60
|
-
var
|
|
69
|
+
var Path7 = __toESM(require("path"), 1);
|
|
61
70
|
|
|
62
71
|
// src/TestNotary.ts
|
|
63
72
|
var import_nanoid = require("nanoid");
|
|
@@ -246,7 +255,6 @@ var Path2 = __toESM(require("path"), 1);
|
|
|
246
255
|
var readline2 = __toESM(require("readline"), 1);
|
|
247
256
|
var import_detect_port = require("detect-port");
|
|
248
257
|
var import_nanoid2 = require("nanoid");
|
|
249
|
-
var import_bitcoin_core = __toESM(require("bitcoin-core"), 1);
|
|
250
258
|
var lockfile = __toESM(require("proper-lockfile"), 1);
|
|
251
259
|
var import_mainchain2 = require("@argonprotocol/mainchain");
|
|
252
260
|
var nanoid2 = (0, import_nanoid2.customAlphabet)("0123456789abcdefghijklmnopqrstuvwxyz", 4);
|
|
@@ -282,11 +290,7 @@ var TestMainchain = class {
|
|
|
282
290
|
addTeardown(this);
|
|
283
291
|
}
|
|
284
292
|
getBitcoinClient() {
|
|
285
|
-
return new
|
|
286
|
-
username: "bitcoin",
|
|
287
|
-
password: "bitcoin",
|
|
288
|
-
host: `http://localhost:${this.bitcoinPort}`
|
|
289
|
-
});
|
|
293
|
+
return new BitcoinRpcClient(`http://localhost:${this.bitcoinPort}`, "bitcoin", "bitcoin");
|
|
290
294
|
}
|
|
291
295
|
/**
|
|
292
296
|
* Launch and return the localhost url. NOTE: this url will not work cross-docker. You need to use the containerAddress property
|
|
@@ -376,9 +380,20 @@ var TestMainchain = class {
|
|
|
376
380
|
return this.address;
|
|
377
381
|
}
|
|
378
382
|
async client() {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
383
|
+
let lastError;
|
|
384
|
+
for (let attempt = 0; attempt < 20; attempt += 1) {
|
|
385
|
+
try {
|
|
386
|
+
const client = await (0, import_mainchain2.getClient)(this.address);
|
|
387
|
+
disconnectOnTeardown(client);
|
|
388
|
+
return client;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
lastError = error;
|
|
391
|
+
await new Promise((resolve3) => setTimeout(resolve3, 250));
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
throw new Error(`Unable to connect to mainchain client at ${this.address}`, {
|
|
395
|
+
cause: lastError instanceof Error ? lastError : void 0
|
|
396
|
+
});
|
|
382
397
|
}
|
|
383
398
|
async bootAddress() {
|
|
384
399
|
const client = await this.client();
|
|
@@ -469,6 +484,51 @@ var TestMainchain = class {
|
|
|
469
484
|
return cleanHostForDocker(`http://bitcoin:bitcoin@localhost:${rpcPort}`);
|
|
470
485
|
}
|
|
471
486
|
};
|
|
487
|
+
var BitcoinRpcClient = class {
|
|
488
|
+
#rpcUrl;
|
|
489
|
+
#authorization;
|
|
490
|
+
constructor(rpcUrl, username, password) {
|
|
491
|
+
this.#rpcUrl = rpcUrl;
|
|
492
|
+
this.#authorization = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
|
|
493
|
+
}
|
|
494
|
+
async command(method, ...params) {
|
|
495
|
+
const response = await fetch(this.#rpcUrl, {
|
|
496
|
+
method: "POST",
|
|
497
|
+
headers: {
|
|
498
|
+
authorization: this.#authorization,
|
|
499
|
+
"content-type": "application/json"
|
|
500
|
+
},
|
|
501
|
+
body: JSON.stringify({
|
|
502
|
+
jsonrpc: "1.0",
|
|
503
|
+
id: `${method}-${Date.now()}`,
|
|
504
|
+
method,
|
|
505
|
+
params
|
|
506
|
+
})
|
|
507
|
+
});
|
|
508
|
+
const body = await response.text();
|
|
509
|
+
let payload;
|
|
510
|
+
if (body) {
|
|
511
|
+
try {
|
|
512
|
+
payload = JSON.parse(body);
|
|
513
|
+
} catch {
|
|
514
|
+
payload = void 0;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (payload?.error) {
|
|
518
|
+
const httpStatus = response.ok ? "" : ` with HTTP ${response.status}`;
|
|
519
|
+
throw new Error(
|
|
520
|
+
`Bitcoin RPC ${method} failed${httpStatus} (${payload.error.code}): ${payload.error.message}`
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
if (!response.ok) {
|
|
524
|
+
throw new Error(`Bitcoin RPC ${method} failed with HTTP ${response.status}`);
|
|
525
|
+
}
|
|
526
|
+
if (!payload) {
|
|
527
|
+
throw new Error(`Bitcoin RPC ${method} returned an invalid JSON response`);
|
|
528
|
+
}
|
|
529
|
+
return payload.result;
|
|
530
|
+
}
|
|
531
|
+
};
|
|
472
532
|
|
|
473
533
|
// src/TestBitcoinCli.ts
|
|
474
534
|
var child_process2 = __toESM(require("child_process"), 1);
|
|
@@ -546,11 +606,451 @@ var TestOracle = class _TestOracle {
|
|
|
546
606
|
}
|
|
547
607
|
};
|
|
548
608
|
|
|
609
|
+
// src/TestEthereum.ts
|
|
610
|
+
var fs4 = __toESM(require("fs/promises"), 1);
|
|
611
|
+
var os = __toESM(require("os"), 1);
|
|
612
|
+
var Path5 = __toESM(require("path"), 1);
|
|
613
|
+
var import_node_child_process2 = require("child_process");
|
|
614
|
+
var import_detect_port2 = require("detect-port");
|
|
615
|
+
|
|
616
|
+
// src/ethereumContracts.ts
|
|
617
|
+
var import_node_fs = require("fs");
|
|
618
|
+
function loadArtifact(fileName) {
|
|
619
|
+
return JSON.parse(
|
|
620
|
+
(0, import_node_fs.readFileSync)(new URL(`./ethereum-contracts/${fileName}`, importMetaUrl), "utf8")
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
var argonTokenArtifact = loadArtifact("ArgonToken.json");
|
|
624
|
+
var argonotTokenArtifact = loadArtifact("ArgonotToken.json");
|
|
625
|
+
var mintingGatewayArtifact = loadArtifact("MintingGateway.json");
|
|
626
|
+
var proxyAdminArtifact = loadArtifact("ProxyAdmin.json");
|
|
627
|
+
var transparentUpgradeableProxyArtifact = loadArtifact("TransparentUpgradeableProxy.json");
|
|
628
|
+
|
|
629
|
+
// src/TestEthereum.ts
|
|
630
|
+
var import_accounts = require("viem/accounts");
|
|
631
|
+
var import_viem = require("viem");
|
|
632
|
+
var DEFAULT_KURTOSIS_BIN = "kurtosis";
|
|
633
|
+
var DEFAULT_ETHEREUM_PACKAGE = "github.com/ethpandaops/ethereum-package";
|
|
634
|
+
var DEFAULT_EL_PORT_START = 32e3;
|
|
635
|
+
var DEFAULT_CL_PORT_START = 33e3;
|
|
636
|
+
var PORT_RANGE_SIZE = 32;
|
|
637
|
+
var ENCLAVE_NAME_PREFIX = "argon-eth-";
|
|
638
|
+
var PROBE_INTERVAL_MS = 1e3;
|
|
639
|
+
var PROBE_TIMEOUT_MS = 6e4;
|
|
640
|
+
var LIGHT_CLIENT_READY_TIMEOUT_MS = 5 * 6e4;
|
|
641
|
+
var KURTOSIS_RUN_TIMEOUT_MS = 20 * 6e4;
|
|
642
|
+
var DEFAULT_SEED_ARGON_AMOUNT_BASE_UNITS = 1000000000n;
|
|
643
|
+
var ERC1967_ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
|
|
644
|
+
var TestEthereum = class {
|
|
645
|
+
enclaveName;
|
|
646
|
+
kurtosisBin;
|
|
647
|
+
packageRef;
|
|
648
|
+
executionRpcUrl;
|
|
649
|
+
beaconApiUrl;
|
|
650
|
+
chainId;
|
|
651
|
+
#argsDir;
|
|
652
|
+
constructor(enclaveName = `${ENCLAVE_NAME_PREFIX}${Math.random().toString(36).slice(2, 8)}`, kurtosisBin = DEFAULT_KURTOSIS_BIN, packageRef = DEFAULT_ETHEREUM_PACKAGE) {
|
|
653
|
+
this.enclaveName = enclaveName;
|
|
654
|
+
this.kurtosisBin = kurtosisBin;
|
|
655
|
+
this.packageRef = packageRef;
|
|
656
|
+
addTeardown(this);
|
|
657
|
+
}
|
|
658
|
+
static isInstalled(kurtosisBin = DEFAULT_KURTOSIS_BIN) {
|
|
659
|
+
return (0, import_node_child_process2.spawnSync)(kurtosisBin, ["version"], { stdio: "ignore" }).status === 0;
|
|
660
|
+
}
|
|
661
|
+
async launch(options) {
|
|
662
|
+
const {
|
|
663
|
+
consensusClient = "lighthouse",
|
|
664
|
+
preset = "mainnet",
|
|
665
|
+
secondsPerSlot,
|
|
666
|
+
waitForFinalization = true,
|
|
667
|
+
prefundedAccounts
|
|
668
|
+
} = options ?? {};
|
|
669
|
+
const elPublicPortStart = await findFreePortRange(DEFAULT_EL_PORT_START, PORT_RANGE_SIZE);
|
|
670
|
+
const clPublicPortStart = await findFreePortRange(DEFAULT_CL_PORT_START, PORT_RANGE_SIZE);
|
|
671
|
+
this.#argsDir = await fs4.mkdtemp(Path5.join(os.tmpdir(), "argon-ethereum-devnet-"));
|
|
672
|
+
const argsFile = Path5.join(this.#argsDir, "network-params.yaml");
|
|
673
|
+
await fs4.writeFile(
|
|
674
|
+
argsFile,
|
|
675
|
+
renderEthereumArgs(
|
|
676
|
+
elPublicPortStart,
|
|
677
|
+
clPublicPortStart,
|
|
678
|
+
consensusClient,
|
|
679
|
+
preset,
|
|
680
|
+
secondsPerSlot,
|
|
681
|
+
waitForFinalization,
|
|
682
|
+
prefundedAccounts
|
|
683
|
+
)
|
|
684
|
+
);
|
|
685
|
+
await runCommand(
|
|
686
|
+
this.kurtosisBin,
|
|
687
|
+
["run", "--enclave", this.enclaveName, this.packageRef, "--args-file", argsFile],
|
|
688
|
+
KURTOSIS_RUN_TIMEOUT_MS
|
|
689
|
+
);
|
|
690
|
+
const executionRpc = await waitForProbe(
|
|
691
|
+
() => findExecutionRpcUrl(elPublicPortStart, PORT_RANGE_SIZE),
|
|
692
|
+
PROBE_TIMEOUT_MS
|
|
693
|
+
);
|
|
694
|
+
const beaconApi = await waitForProbe(
|
|
695
|
+
() => findBeaconApiUrl(clPublicPortStart, PORT_RANGE_SIZE),
|
|
696
|
+
PROBE_TIMEOUT_MS
|
|
697
|
+
);
|
|
698
|
+
this.executionRpcUrl = executionRpc.url;
|
|
699
|
+
this.beaconApiUrl = beaconApi.url;
|
|
700
|
+
this.chainId = executionRpc.chainId;
|
|
701
|
+
await waitForProbe(
|
|
702
|
+
() => this.getBeacon("/eth/v1/beacon/genesis"),
|
|
703
|
+
LIGHT_CLIENT_READY_TIMEOUT_MS
|
|
704
|
+
);
|
|
705
|
+
return {
|
|
706
|
+
executionRpcUrl: this.executionRpcUrl,
|
|
707
|
+
beaconApiUrl: this.beaconApiUrl,
|
|
708
|
+
chainId: this.chainId
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
async callExecution(method, params = []) {
|
|
712
|
+
const executionRpcUrl = this.executionRpcUrl;
|
|
713
|
+
if (!executionRpcUrl) {
|
|
714
|
+
throw new Error("Execution RPC URL is not available before launch");
|
|
715
|
+
}
|
|
716
|
+
const response = await fetch(executionRpcUrl, {
|
|
717
|
+
method: "POST",
|
|
718
|
+
headers: { "content-type": "application/json" },
|
|
719
|
+
body: JSON.stringify({
|
|
720
|
+
id: 1,
|
|
721
|
+
jsonrpc: "2.0",
|
|
722
|
+
method,
|
|
723
|
+
params
|
|
724
|
+
}),
|
|
725
|
+
signal: AbortSignal.timeout(1e4)
|
|
726
|
+
});
|
|
727
|
+
if (!response.ok) {
|
|
728
|
+
throw new Error(`Execution RPC request failed for ${method}: ${response.status}`);
|
|
729
|
+
}
|
|
730
|
+
const body = await response.json();
|
|
731
|
+
if (body.error) {
|
|
732
|
+
throw new Error(
|
|
733
|
+
`Execution RPC ${method} failed (${body.error.code ?? "unknown"}): ${body.error.message ?? "unknown error"}`
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
return body.result;
|
|
737
|
+
}
|
|
738
|
+
async getBeacon(path) {
|
|
739
|
+
const beaconApiUrl = this.beaconApiUrl;
|
|
740
|
+
if (!beaconApiUrl) {
|
|
741
|
+
throw new Error("Beacon API URL is not available before launch");
|
|
742
|
+
}
|
|
743
|
+
const response = await fetch(new URL(path, `${beaconApiUrl}/`), {
|
|
744
|
+
signal: AbortSignal.timeout(1e4)
|
|
745
|
+
});
|
|
746
|
+
if (!response.ok) {
|
|
747
|
+
throw new Error(`Beacon API request failed for ${path}: ${response.status}`);
|
|
748
|
+
}
|
|
749
|
+
return await response.json();
|
|
750
|
+
}
|
|
751
|
+
async deployMintingGatewayFixture(options) {
|
|
752
|
+
const { executionRpcUrl, chainId } = this;
|
|
753
|
+
if (!executionRpcUrl || !chainId) {
|
|
754
|
+
throw new Error("Ethereum devnet must be launched before deploying MintingGateway fixtures");
|
|
755
|
+
}
|
|
756
|
+
const account = (0, import_accounts.privateKeyToAccount)(options.deployerPrivateKey);
|
|
757
|
+
const adminSafe = options.adminSafe ?? account.address;
|
|
758
|
+
const guardianSafe = options.guardianSafe ?? adminSafe;
|
|
759
|
+
const chain = createExecutionChain(chainId, executionRpcUrl);
|
|
760
|
+
const publicClient = (0, import_viem.createPublicClient)({
|
|
761
|
+
chain,
|
|
762
|
+
transport: (0, import_viem.http)(executionRpcUrl)
|
|
763
|
+
});
|
|
764
|
+
const walletClient = (0, import_viem.createWalletClient)({
|
|
765
|
+
account,
|
|
766
|
+
chain,
|
|
767
|
+
transport: (0, import_viem.http)(executionRpcUrl)
|
|
768
|
+
});
|
|
769
|
+
const bootstrapImplementationAddress = await deployContract(walletClient, publicClient, {
|
|
770
|
+
abi: mintingGatewayArtifact.abi,
|
|
771
|
+
bytecode: mintingGatewayArtifact.bytecode,
|
|
772
|
+
args: [import_viem.zeroAddress, import_viem.zeroAddress]
|
|
773
|
+
});
|
|
774
|
+
const initializeData = (0, import_viem.encodeFunctionData)({
|
|
775
|
+
abi: mintingGatewayArtifact.abi,
|
|
776
|
+
functionName: "initialize",
|
|
777
|
+
args: [adminSafe, guardianSafe]
|
|
778
|
+
});
|
|
779
|
+
const gatewayAddress = await deployContract(walletClient, publicClient, {
|
|
780
|
+
abi: transparentUpgradeableProxyArtifact.abi,
|
|
781
|
+
bytecode: transparentUpgradeableProxyArtifact.bytecode,
|
|
782
|
+
args: [bootstrapImplementationAddress, adminSafe, initializeData]
|
|
783
|
+
});
|
|
784
|
+
const proxyAdminAddress = getAddressFromStorage(
|
|
785
|
+
await publicClient.getStorageAt({
|
|
786
|
+
address: gatewayAddress,
|
|
787
|
+
slot: ERC1967_ADMIN_SLOT
|
|
788
|
+
})
|
|
789
|
+
);
|
|
790
|
+
const argonTokenAddress = await deployContract(walletClient, publicClient, {
|
|
791
|
+
abi: argonTokenArtifact.abi,
|
|
792
|
+
bytecode: argonTokenArtifact.bytecode,
|
|
793
|
+
args: [gatewayAddress]
|
|
794
|
+
});
|
|
795
|
+
const argonotTokenAddress = await deployContract(walletClient, publicClient, {
|
|
796
|
+
abi: argonotTokenArtifact.abi,
|
|
797
|
+
bytecode: argonotTokenArtifact.bytecode,
|
|
798
|
+
args: [gatewayAddress]
|
|
799
|
+
});
|
|
800
|
+
const finalImplementationAddress = await deployContract(walletClient, publicClient, {
|
|
801
|
+
abi: mintingGatewayArtifact.abi,
|
|
802
|
+
bytecode: mintingGatewayArtifact.bytecode,
|
|
803
|
+
args: [argonTokenAddress, argonotTokenAddress]
|
|
804
|
+
});
|
|
805
|
+
const upgradeHash = await walletClient.sendTransaction({
|
|
806
|
+
to: proxyAdminAddress,
|
|
807
|
+
data: (0, import_viem.encodeFunctionData)({
|
|
808
|
+
abi: proxyAdminArtifact.abi,
|
|
809
|
+
functionName: "upgradeAndCall",
|
|
810
|
+
args: [gatewayAddress, finalImplementationAddress, "0x"]
|
|
811
|
+
})
|
|
812
|
+
});
|
|
813
|
+
const upgradeReceipt = await waitForExecutionReceipt(publicClient, upgradeHash);
|
|
814
|
+
if (upgradeReceipt.status !== "success") {
|
|
815
|
+
throw new Error("MintingGateway proxy upgrade failed");
|
|
816
|
+
}
|
|
817
|
+
if (options.seedArgonRecipient) {
|
|
818
|
+
const mintHash = await walletClient.sendTransaction({
|
|
819
|
+
to: gatewayAddress,
|
|
820
|
+
data: (0, import_viem.encodeFunctionData)({
|
|
821
|
+
abi: mintingGatewayArtifact.abi,
|
|
822
|
+
functionName: "adminMintBatch",
|
|
823
|
+
args: [
|
|
824
|
+
argonTokenAddress,
|
|
825
|
+
[options.seedArgonRecipient],
|
|
826
|
+
[options.seedArgonAmountBaseUnits ?? DEFAULT_SEED_ARGON_AMOUNT_BASE_UNITS]
|
|
827
|
+
]
|
|
828
|
+
})
|
|
829
|
+
});
|
|
830
|
+
const mintReceipt = await waitForExecutionReceipt(publicClient, mintHash);
|
|
831
|
+
if (mintReceipt.status !== "success") {
|
|
832
|
+
throw new Error("MintingGateway admin mint failed");
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
return {
|
|
836
|
+
argonTokenAddress,
|
|
837
|
+
argonotTokenAddress,
|
|
838
|
+
gatewayAddress
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
async teardown() {
|
|
842
|
+
if (this.#argsDir) {
|
|
843
|
+
await fs4.rm(this.#argsDir, { recursive: true, force: true });
|
|
844
|
+
this.#argsDir = void 0;
|
|
845
|
+
}
|
|
846
|
+
await runCommand(this.kurtosisBin, ["enclave", "rm", "-f", this.enclaveName], 6e4, true);
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
async function deployContract(walletClient, publicClient, request) {
|
|
850
|
+
const hash = await walletClient.deployContract({
|
|
851
|
+
...request,
|
|
852
|
+
account: walletClient.account,
|
|
853
|
+
chain: walletClient.chain
|
|
854
|
+
});
|
|
855
|
+
const receipt = await waitForExecutionReceipt(publicClient, hash);
|
|
856
|
+
if (receipt.status !== "success" || !receipt.contractAddress) {
|
|
857
|
+
throw new Error(`Contract deployment failed for ${request.bytecode.slice(0, 10)}`);
|
|
858
|
+
}
|
|
859
|
+
return receipt.contractAddress;
|
|
860
|
+
}
|
|
861
|
+
function getAddressFromStorage(value) {
|
|
862
|
+
if (!value || value === "0x") {
|
|
863
|
+
throw new Error("Missing proxy admin address in ERC1967 admin slot");
|
|
864
|
+
}
|
|
865
|
+
return (0, import_viem.getAddress)(`0x${value.slice(-40)}`);
|
|
866
|
+
}
|
|
867
|
+
function renderEthereumArgs(elPublicPortStart, clPublicPortStart, consensusClient, preset, secondsPerSlot, waitForFinalization, prefundedAccounts) {
|
|
868
|
+
const lines = [
|
|
869
|
+
"participants:",
|
|
870
|
+
" - el_type: geth",
|
|
871
|
+
` cl_type: ${consensusClient}`,
|
|
872
|
+
"network_params:",
|
|
873
|
+
" network: kurtosis",
|
|
874
|
+
` preset: ${preset}`,
|
|
875
|
+
...secondsPerSlot ? [` seconds_per_slot: ${secondsPerSlot}`] : [],
|
|
876
|
+
...prefundedAccounts && Object.keys(prefundedAccounts).length > 0 ? [` prefunded_accounts: '${JSON.stringify(prefundedAccounts)}'`] : [],
|
|
877
|
+
"additional_services: []",
|
|
878
|
+
`wait_for_finalization: ${waitForFinalization ? "true" : "false"}`,
|
|
879
|
+
"global_log_level: warn",
|
|
880
|
+
"port_publisher:",
|
|
881
|
+
" el:",
|
|
882
|
+
" enabled: true",
|
|
883
|
+
` public_port_start: ${elPublicPortStart}`,
|
|
884
|
+
" cl:",
|
|
885
|
+
" enabled: true",
|
|
886
|
+
` public_port_start: ${clPublicPortStart}`
|
|
887
|
+
];
|
|
888
|
+
lines.push("");
|
|
889
|
+
return lines.join("\n");
|
|
890
|
+
}
|
|
891
|
+
async function findExecutionRpcUrl(portStart, rangeSize) {
|
|
892
|
+
for (let port2 = portStart; port2 < portStart + rangeSize; port2 += 1) {
|
|
893
|
+
const url2 = `http://127.0.0.1:${port2}`;
|
|
894
|
+
const response = await fetchJsonRpc(url2, "eth_chainId");
|
|
895
|
+
if (typeof response === "string") {
|
|
896
|
+
return { url: url2, chainId: response };
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
throw new Error(
|
|
900
|
+
`Unable to find an execution RPC endpoint in ${portStart}-${portStart + rangeSize - 1}`
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
async function findBeaconApiUrl(portStart, rangeSize) {
|
|
904
|
+
for (let port2 = portStart; port2 < portStart + rangeSize; port2 += 1) {
|
|
905
|
+
const url2 = `http://127.0.0.1:${port2}`;
|
|
906
|
+
try {
|
|
907
|
+
const response = await fetch(new URL("/eth/v1/node/version", `${url2}/`), {
|
|
908
|
+
signal: AbortSignal.timeout(2e3)
|
|
909
|
+
});
|
|
910
|
+
if (!response.ok) {
|
|
911
|
+
continue;
|
|
912
|
+
}
|
|
913
|
+
const body = await response.json();
|
|
914
|
+
if (body.data?.version) {
|
|
915
|
+
return { url: url2 };
|
|
916
|
+
}
|
|
917
|
+
} catch {
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
throw new Error(
|
|
921
|
+
`Unable to find a Beacon API endpoint in ${portStart}-${portStart + rangeSize - 1}`
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
async function fetchJsonRpc(url2, method) {
|
|
925
|
+
try {
|
|
926
|
+
const response = await fetch(url2, {
|
|
927
|
+
method: "POST",
|
|
928
|
+
headers: { "content-type": "application/json" },
|
|
929
|
+
body: JSON.stringify({
|
|
930
|
+
id: 1,
|
|
931
|
+
jsonrpc: "2.0",
|
|
932
|
+
method,
|
|
933
|
+
params: []
|
|
934
|
+
}),
|
|
935
|
+
signal: AbortSignal.timeout(2e3)
|
|
936
|
+
});
|
|
937
|
+
if (!response.ok) {
|
|
938
|
+
return null;
|
|
939
|
+
}
|
|
940
|
+
const body = await response.json();
|
|
941
|
+
return body.result ?? null;
|
|
942
|
+
} catch {
|
|
943
|
+
return null;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
function createExecutionChain(chainId, executionRpcUrl) {
|
|
947
|
+
return (0, import_viem.defineChain)({
|
|
948
|
+
id: Number.parseInt(chainId, 16),
|
|
949
|
+
name: "argon-test-ethereum",
|
|
950
|
+
nativeCurrency: {
|
|
951
|
+
name: "Ether",
|
|
952
|
+
symbol: "ETH",
|
|
953
|
+
decimals: 18
|
|
954
|
+
},
|
|
955
|
+
rpcUrls: {
|
|
956
|
+
default: {
|
|
957
|
+
http: [executionRpcUrl]
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
async function findFreePortRange(start, size) {
|
|
963
|
+
for (let candidate = start; candidate < start + 1e3; candidate += size) {
|
|
964
|
+
const ports = Array.from({ length: size }, (_, index) => candidate + index);
|
|
965
|
+
const results = await Promise.all(ports.map((port2) => (0, import_detect_port2.detectPort)(port2)));
|
|
966
|
+
if (results.every((resolvedPort, index) => resolvedPort === ports[index])) {
|
|
967
|
+
return candidate;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
throw new Error(`Unable to find a free port range starting near ${start}`);
|
|
971
|
+
}
|
|
972
|
+
async function waitForProbe(probe, timeoutMs) {
|
|
973
|
+
const start = Date.now();
|
|
974
|
+
let lastError;
|
|
975
|
+
while (Date.now() - start < timeoutMs) {
|
|
976
|
+
try {
|
|
977
|
+
return await probe();
|
|
978
|
+
} catch (error) {
|
|
979
|
+
lastError = error;
|
|
980
|
+
await delay(PROBE_INTERVAL_MS);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
throw lastError instanceof Error ? lastError : new Error("Timed out waiting for probe");
|
|
984
|
+
}
|
|
985
|
+
async function waitForExecutionReceipt(publicClient, hash) {
|
|
986
|
+
const start = Date.now();
|
|
987
|
+
let lastError;
|
|
988
|
+
while (Date.now() - start < 12e4) {
|
|
989
|
+
try {
|
|
990
|
+
const receipt = await publicClient.getTransactionReceipt({ hash });
|
|
991
|
+
if (receipt) {
|
|
992
|
+
return receipt;
|
|
993
|
+
}
|
|
994
|
+
} catch (error) {
|
|
995
|
+
const errorText = error instanceof Error ? [
|
|
996
|
+
error.message,
|
|
997
|
+
"details" in error && typeof error.details === "string" ? error.details : void 0
|
|
998
|
+
].filter(Boolean).join(" ") : String(error);
|
|
999
|
+
if (!errorText.includes("indexing is in progress") && !errorText.includes("Transaction receipt with hash") && !errorText.includes("could not be found")) {
|
|
1000
|
+
throw error;
|
|
1001
|
+
}
|
|
1002
|
+
lastError = error instanceof Error ? error : new Error(errorText);
|
|
1003
|
+
}
|
|
1004
|
+
await delay(500);
|
|
1005
|
+
}
|
|
1006
|
+
throw lastError ?? new Error(`Timed out waiting for execution receipt ${hash}`);
|
|
1007
|
+
}
|
|
1008
|
+
async function runCommand(command, args, timeoutMs, allowFailure = false) {
|
|
1009
|
+
await new Promise((resolve3, reject) => {
|
|
1010
|
+
const child = (0, import_node_child_process2.spawn)(command, args, {
|
|
1011
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1012
|
+
});
|
|
1013
|
+
let stdout = "";
|
|
1014
|
+
let stderr = "";
|
|
1015
|
+
const timeout = setTimeout(() => {
|
|
1016
|
+
child.kill("SIGTERM");
|
|
1017
|
+
reject(new Error(`Command timed out: ${command} ${args.join(" ")}`));
|
|
1018
|
+
}, timeoutMs);
|
|
1019
|
+
child.stdout?.setEncoding("utf8");
|
|
1020
|
+
child.stderr?.setEncoding("utf8");
|
|
1021
|
+
child.stdout?.on("data", (chunk) => {
|
|
1022
|
+
stdout += chunk;
|
|
1023
|
+
});
|
|
1024
|
+
child.stderr?.on("data", (chunk) => {
|
|
1025
|
+
stderr += chunk;
|
|
1026
|
+
});
|
|
1027
|
+
child.on("error", (error) => {
|
|
1028
|
+
clearTimeout(timeout);
|
|
1029
|
+
reject(error);
|
|
1030
|
+
});
|
|
1031
|
+
child.on("exit", (code) => {
|
|
1032
|
+
clearTimeout(timeout);
|
|
1033
|
+
if (code === 0 || allowFailure) {
|
|
1034
|
+
resolve3();
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
reject(
|
|
1038
|
+
new Error(
|
|
1039
|
+
[`Command failed: ${command} ${args.join(" ")}`, stdout.trim(), stderr.trim()].filter(Boolean).join("\n")
|
|
1040
|
+
)
|
|
1041
|
+
);
|
|
1042
|
+
});
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
async function delay(ms) {
|
|
1046
|
+
await new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
1047
|
+
}
|
|
1048
|
+
|
|
549
1049
|
// src/TestNetwork.ts
|
|
550
1050
|
var docker = __toESM(require("docker-compose"), 1);
|
|
551
|
-
var
|
|
1051
|
+
var Path6 = __toESM(require("path"), 1);
|
|
552
1052
|
async function startNetwork(testName, options) {
|
|
553
|
-
const config =
|
|
1053
|
+
const config = Path6.join(__dirname, `dev.docker-compose.yml`);
|
|
554
1054
|
const env4 = {
|
|
555
1055
|
VERSION: "dev",
|
|
556
1056
|
ARGON_CHAIN: "dev-docker",
|
|
@@ -595,7 +1095,7 @@ async function getProxy() {
|
|
|
595
1095
|
autoRewrite: true
|
|
596
1096
|
});
|
|
597
1097
|
proxy.on("error", () => null);
|
|
598
|
-
proxyServer =
|
|
1098
|
+
proxyServer = http2.createServer(function(req, res) {
|
|
599
1099
|
const queryData = url.parse(req.url, true).query;
|
|
600
1100
|
if (!queryData.target) {
|
|
601
1101
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
@@ -645,12 +1145,12 @@ function stringifyExt(obj) {
|
|
|
645
1145
|
}
|
|
646
1146
|
function projectRoot() {
|
|
647
1147
|
if (process4.env.ARGON_PROJECT_ROOT) {
|
|
648
|
-
return
|
|
1148
|
+
return Path7.join(process4.env.ARGON_PROJECT_ROOT);
|
|
649
1149
|
}
|
|
650
|
-
return
|
|
1150
|
+
return Path7.join(__dirname, `../../..`);
|
|
651
1151
|
}
|
|
652
1152
|
async function runTestScript(relativePath) {
|
|
653
|
-
const scriptPath =
|
|
1153
|
+
const scriptPath = Path7.resolve(projectRoot(), relativePath);
|
|
654
1154
|
return child_process4.execSync(scriptPath, { encoding: "utf8" }).trim();
|
|
655
1155
|
}
|
|
656
1156
|
async function getDockerPortMapping(containerName, port2) {
|
|
@@ -701,16 +1201,19 @@ async function activateNotary(sudo2, client, notary) {
|
|
|
701
1201
|
0 && (module.exports = {
|
|
702
1202
|
SKIP_E2E,
|
|
703
1203
|
TestBitcoinCli,
|
|
1204
|
+
TestEthereum,
|
|
704
1205
|
TestMainchain,
|
|
705
1206
|
TestNotary,
|
|
706
1207
|
TestOracle,
|
|
707
1208
|
activateNotary,
|
|
708
1209
|
addTeardown,
|
|
1210
|
+
argonTokenArtifact,
|
|
709
1211
|
cleanHostForDocker,
|
|
710
1212
|
closeOnTeardown,
|
|
711
1213
|
disconnectOnTeardown,
|
|
712
1214
|
getDockerPortMapping,
|
|
713
1215
|
getProxy,
|
|
1216
|
+
mintingGatewayArtifact,
|
|
714
1217
|
projectRoot,
|
|
715
1218
|
runOnTeardown,
|
|
716
1219
|
runTestScript,
|