Skip to content

Commit e446c37

Browse files
authored
fix(test-suite): add resilient smoke runner for inputFlow (release) (#1921)
fix(test-suite): add resilient smoke runner for inputFlow (#1840) * fix(test-suite): add smoke runner hardening * fix(test-suite): document smoke env setup * fix(test-suite): simplify env handling + post-success cleanup - Simplify RPC URL warning conditions (redundant checks removed) - Refactor cancelBacklog to reuse sendWithRetries for resilience - Add post-success cleanup to clear backlogs on unclean signers * style: apply prettier formatting * feat(test-suite): add BetterStack heartbeat integration - Ping BETTERSTACK_HEARTBEAT_URL on success - Report failure status with error message - Document in README * fix(test-suite): use receipt.contractAddress instead of computing it More reliable: reads the actual deployed address from the receipt rather than computing it from nonce, eliminating potential mismatch. * fix(test-suite): doc and deprecated API cleanup - README: correct SMOKE_CANCEL_BACKLOG default from '1' to 'true' - smoke-inputflow: remove deprecated provider.getGasPrice() call, use MIN_PRIORITY_FEE as last-resort fallback instead * fix(test-suite): remove unnecessary hardhat chainId check and redundant casts - E2ECoprocessorConfigLocal.sol: remove 31337 (hardhat) from chainId check, smoke tests target real networks only - instance.ts: remove redundant Number() casts, values are already numbers after Number.isFinite() validation * fix(test-suite): add robustness for mainnet API key, decryption timeouts, and gas estimation - instance.ts: enforce ZAMA_FHEVM_API_KEY on mainnet to fail fast - smoke-inputflow.ts: add withTimeout wrapper for decryption operations (default 120s, configurable via SMOKE_DECRYPT_TIMEOUT_SECS) - smoke-inputflow.ts: wrap gas estimation in try/catch with clear error messages - README.md: document SMOKE_DECRYPT_TIMEOUT_SECS env var * fix(test-suite): log full error on gas estimation failure for debugging Add console.error logging before re-throwing in gas estimation catch blocks to preserve full error details (stack trace, ethers properties) for debugging purposes. * refactor(test-suite): delegate coprocessor config entirely to ZamaConfig ZamaConfig.getEthereumCoprocessorConfig() already handles chainId checks internally for mainnet (1), Sepolia (11155111), and local (31337), returning appropriate addresses for each. Remove redundant chainId check and hardcoded fallback addresses. * refactor(test-suite): simplify RPC URL config and require network-specific URLs - staging/zwsDev: use RPC_URL with localhost fallback - sepolia: require SEPOLIA_ETH_RPC_URL explicitly (fail if not set) - mainnet: require MAINNET_ETH_RPC_URL explicitly (fail if not set) Removes verbose RPC_URL fallback chains - if targeting a specific network, set its specific env var. Clearer and less error-prone. * refactor(test-suite): simplify instance.ts config - remove unnecessary vars Only ZAMA_FHEVM_API_KEY is a secret that benefits from hardhat vars. Contract addresses, chain IDs, and URLs can use simple env || defaults. Removes verbose chaining and string↔number conversions. * refactor(test-suite): use BetterStack /fail endpoint for failure reporting Simpler than encoding error messages in query params. Error details are already logged to console. * refactor(test-suite): simplify env var parsing in smoke runner - Remove unnecessary Math.trunc() calls - Use simple boolean coercion for allowCancel and forceDeploy - Drop intermediate variables (cancelRaw, forceRaw) * refactor(test-suite): address PR feedback for smoke runner - Rename SMOKE_FORCE_DEPLOY → SMOKE_DEPLOY_CONTRACT (defaults to 1) - Add SMOKE_RUN_TESTS to allow deploy-only mode (set to 0) - Add strict boolean parsing for env vars (only 0/1, fail fast on invalid) - Send error details to BetterStack /1 endpoint instead of /fail * feat(test-suite): add timing breakdown to smoke heartbeat - Track deploy, encrypt, tx, and decrypt phases separately - Send timing report to BetterStack on success - Align timing boundaries with TransferBench (decrypt excludes handle fetch) * fix(test-suite): lazy validation for network RPC URLs Only throw error for missing SEPOLIA_ETH_RPC_URL / MAINNET_ETH_RPC_URL when actually targeting that network, not during compile/build. Fixes Docker build failure. * feat(test-suite): add RPC_URL fallback for sepolia/mainnet For pod deployments, just set RPC_URL - it works for all networks. Keeps network-specific vars (SEPOLIA_ETH_RPC_URL, MAINNET_ETH_RPC_URL) for local dev convenience. * docs(test-suite): clarify env setup for sepolia/mainnet/devnet - sepolia/mainnet: SDK provides defaults, only need RPC_URL + MNEMONIC - devnet: use pre-configured .env.devnet - other networks: set all vars manually * fix(test-suite): provide placeholder URLs for sepolia/mainnet during compile When not targeting sepolia/mainnet, provide placeholder public RPC URLs to satisfy Hardhat's config validation. The actual RPC URL is still required when targeting these networks. * refactor(test-suite): move TestInput.sol to contracts/smoke/ Allows faster container startup with: npx hardhat compile:specific --contract contracts/smoke * feat(test-suite): improve smoke signer handling and observability - Default to 3 signers (0,1,2) for automatic failover - Dynamic balance threshold based on current gas prices - Show all available signers at startup with balances - Add LOW_BALANCE warning for signers < 0.1 ETH - Fix withTimeout to clear timer on success (prevents zombie timers) - Update README with signer funding guidance * fix(test-suite): log warning when failure heartbeat fails Add consistent warning behavior for the failure heartbeat to match the success heartbeat logging. * revert(test-suite): restore hardcoded addresses in E2ECoprocessorConfigLocal The ZamaConfig approach doesn't work for devnet/staging which uses different contract addresses than production Sepolia despite sharing the same chainId. * feat(test-suite): inject coprocessor config via constructor for smoke tests - TestInput.sol now accepts (acl, coprocessor, kmsVerifier) in constructor - instance.ts exports addresses with SDK defaults for sepolia/mainnet - smoke-inputflow.ts passes addresses when deploying This allows smoke tests to work on: - Sepolia/mainnet: uses SDK defaults - Devnet: uses env vars (FHEVM_EXECUTOR_CONTRACT_ADDRESS, etc.) Other E2E tests still use sed-patched E2ECoprocessorConfigLocal.sol. * refactor(test-suite): split SmokeTestInput from TestInput to avoid E2E regression - Create SmokeTestInput.sol with constructor-based config injection for smoke tests - Revert TestInput.sol to use E2ECoprocessorConfig inheritance for Pierre's E2E tests - Update smoke-inputflow.ts to use SmokeTestInput with proper TypeScript typing This avoids breaking existing E2E tests (inputFlow.ts, pausedHost.ts, pausedGateway.ts) that deploy TestInput without constructor arguments. * fix(test-suite): handle late tx confirmation in retry loop When a tx times out and we attempt to send a replacement, the original tx might get mined in that window. This caused false failure reports because the replacement send would fail with "nonce already used" and we'd exhaust retries without recognizing the original tx succeeded. Fix: Track all sent tx hashes and check for late receipts when: - A send fails (might be because previous tx just got mined) - After exhausting all retries (final safety check) * refactor(test-suite): use tx.wait() with TRANSACTION_REPLACED handling Replace manual polling (waitForReceipt) and hash tracking (sentTxHashes) with ethers v6 native tx.wait() which handles replacement detection via TRANSACTION_REPLACED error code. This simplifies the retry logic: - Remove waitForReceipt function (ethers polls internally) - Remove sentTxHashes tracking (ethers tracks replacements) - Remove checkPreviousTxs helper (ethers throws TRANSACTION_REPLACED) - Catch TRANSACTION_REPLACED and return replacement receipt if successful Co-authored-by: maxnovawind * fix(test-suite): handle ethers v6 tx.wait() errors correctly - Handle CALL_EXCEPTION explicitly (reverts are terminal, don't retry) - Handle TIMEOUT explicitly (retry with bumped fees) - Refresh signer states before cleanup to avoid stale nonce issues * fix(test-suite): add retry logic for hardhat compile in Docker build * Revert "fix(test-suite): add retry logic for hardhat compile in Docker build" This reverts commit 452d29c. * fix(test-suite): make API key authentication optional Internal smoke tests don't go through Kong, so the API key requirement on mainnet was blocking internal testing workflows. * fix(test-suite): use network-suggested priority fee instead of 2 gwei floor Remove the hardcoded 2 gwei minimum priority fee and use the network's recommended value instead. Falls back to 0.1 gwei only if network returns null. This reduces priority fees from ~2 gwei to ~0.0001 gwei on mainnet, significantly lowering transaction costs during normal network conditions. * fix(test-suite): improve smoke logging and gas caps * fix(test-suite): address PR review feedback - Fix timer leak in withTimeout by using .finally() instead of .then() - Remove unused extendProvider import from hardhat.config.ts - Fetch fresh balance after backlog cancellation to fix stale log output - Upgrade heartbeat and cleanup failure logs from warn to error * fix(test-suite): responder-friendly smoke failure payload
1 parent 98c0881 commit e446c37

File tree

11 files changed

+1210
-52
lines changed

11 files changed

+1210
-52
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ logs/
3232
.env.*
3333
!.env.example
3434
!.env.sample
35+
# Allow shared env templates in subprojects
36+
!test-suite/e2e/.env.devnet
3537
# If you have .env files specific to subprojects, e.g. subproject/.env,
3638
# the .env rule above will catch them.
3739

test-suite/e2e/.env.devnet

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#
2+
# CONTRACT ADDRESS OVERRIDE CONFIGURATION
3+
#
4+
# If the runtime Hardhat network selected via the --network flag (e.g., 'devnet')
5+
# matches the value defined here, all contract addresses and URLs below
6+
# will OVERRIDE any default or previously loaded configuration.
7+
FHEVM_HARDHAT_NETWORK="devnet"
8+
9+
# Gateway
10+
INPUT_VERIFICATION_ADDRESS="0xf091D9B4C2da7ecd11858cDD1F4515a8a767D755"
11+
DECRYPTION_ADDRESS="0xA4dc265D54D25D41565c60d36097E8955B03decD"
12+
# Host
13+
ACL_CONTRACT_ADDRESS="0xBCA6F8De823a399Dc431930FD5EE550Bf1C0013e"
14+
KMS_VERIFIER_CONTRACT_ADDRESS="0x3F3819BeBE4bD0EFEf8078Df6f9B574ADa80CCA4"
15+
INPUT_VERIFIER_CONTRACT_ADDRESS="0x6B32f47E39B0F8bE8bEAD5B8990F62E3e28ac08d"
16+
FHEVM_EXECUTOR_CONTRACT_ADDRESS="0x5cc8c5A366E733d4f1e677B2A9C08Bc2ea49b302"
17+
HCU_LIMIT_CONTRACT_ADDRESS="0xb8E70273De41498aAF047fd73ae1F3025D8709f8"
18+
RELAYER_URL="https://relayer.dev.zama.cloud"
19+
20+
# Hardhat account seed (used for hardhat/anvil/sepolia)
21+
MNEMONIC="test test test test test test test test test test test junk"
22+
23+
# Provider keys
24+
INFURA_API_KEY=""
25+
ETHERSCAN_API_KEY=""
26+
27+
# Required: authorized caller addresses for Numeric deploy (comma-separated list)
28+
AUTHORIZED_CALLER_ADDRESSES=""
29+
30+
# Optional: set a specific payment token for SimplifiedAuction deploys
31+
SIMPLIFIED_AUCTION_PAYMENT_TOKEN=""

test-suite/e2e/.env.example

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
MNEMONIC="adapt mosquito move limb mobile illegal tree voyage juice mosquito burger raise father hope layer"
2+
RPC_URL=""
3+
SEPOLIA_ETH_RPC_URL=""
4+
MAINNET_ETH_RPC_URL=""
5+
RELAYER_URL=""
6+
ZAMA_FHEVM_API_KEY=""
27
# Gateway
38
CHAIN_ID_GATEWAY="54321"
49
CHAIN_ID_HOST="12345"
@@ -9,5 +14,15 @@ ACL_CONTRACT_ADDRESS="0x05fD9B5EFE0a996095f42Ed7e77c390810CF660c"
914
KMS_VERIFIER_CONTRACT_ADDRESS="0xcCAe95fF1d11656358E782570dF0418F59fA40e1"
1015
INPUT_VERIFIER_CONTRACT_ADDRESS="0xa1880e99d86F081E8D3868A8C4732C8f65dfdB11"
1116
FHEVM_EXECUTOR_CONTRACT_ADDRESS="0x12B064FB845C1cc05e9493856a1D637a73e944bE"
17+
TEST_INPUT_CONTRACT_ADDRESS=""
1218

1319
HARDHAT_NETWORK="staging"
20+
21+
# Smoke runner (optional)
22+
BETTERSTACK_HEARTBEAT_URL=""
23+
# SMOKE_DEPLOY_CONTRACT=1
24+
# SMOKE_RUN_TESTS=1
25+
# SMOKE_TX_TIMEOUT_SECS=48
26+
# SMOKE_MAX_FEE_GWEI= # unset = no cap
27+
# SMOKE_MAX_PRIORITY_FEE_GWEI= # unset = no cap
28+
# SMOKE_DECRYPT_TIMEOUT_SECS=300

test-suite/e2e/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,81 @@ REPORT_GAS=true npx hardhat test
1111
npx hardhat node
1212
npx hardhat ignition deploy ./ignition/modules/Lock.ts
1313
```
14+
15+
## Smoke runner (inputFlow)
16+
17+
Runs a single on-chain smoke flow (input + add42 + decrypt) using Hardhat as a runtime
18+
and hardened transaction handling.
19+
20+
### Prereqs
21+
22+
**For sepolia/mainnet**, most config is auto-populated from the SDK (`SepoliaConfig`/`MainnetConfig`).
23+
You only need:
24+
25+
- `RPC_URL` (or `SEPOLIA_ETH_RPC_URL` / `MAINNET_ETH_RPC_URL`)
26+
- `MNEMONIC`
27+
- `ZAMA_FHEVM_API_KEY` (mainnet only)
28+
29+
**For devnet**, use the pre-configured `.env.devnet` (all addresses included):
30+
31+
```shell
32+
DOTENV_CONFIG_PATH=./.env.devnet npx hardhat run --network devnet scripts/smoke-inputflow.ts
33+
```
34+
35+
**For other networks** (staging, custom), set all variables manually - see `.env.example`.
36+
37+
Network-specific RPC URLs:
38+
39+
- staging/zwsDev: `RPC_URL` (defaults to localhost:8545)
40+
- sepolia: `SEPOLIA_ETH_RPC_URL` (falls back to `RPC_URL`)
41+
- mainnet: `MAINNET_ETH_RPC_URL` (falls back to `RPC_URL`)
42+
43+
For pod deployments, just set `RPC_URL` - it works for all networks.
44+
45+
Set `TEST_INPUT_CONTRACT_ADDRESS` to reuse an existing contract (requires `SMOKE_DEPLOY_CONTRACT=0`).
46+
47+
Hardhat loads env from `test-suite/e2e/.env` by default; override with `DOTENV_CONFIG_PATH`.
48+
You can also store secrets with Hardhat vars, e.g. `npx hardhat vars set SEPOLIA_ETH_RPC_URL` (it will prompt for the value).
49+
For devnet, `test-suite/e2e/.env.devnet` provides a ready baseline (use `DOTENV_CONFIG_PATH=./.env.devnet`).
50+
51+
### Signer configuration
52+
53+
The smoke runner uses HD wallet signers derived from `MNEMONIC`. By default, it uses indices `0,1,2`
54+
for automatic failover - if one signer has a stuck transaction, it falls back to another.
55+
56+
**Important:** All configured signers should be funded for maximum resilience. The script logs all
57+
available signers at startup with their balances and warns if any have low balance (< 0.005 ETH).
58+
Post-success cleanup will attempt to cancel any remaining pending transactions, but failures in that
59+
cleanup step do not fail the smoke run.
60+
61+
To derive signer addresses from a mnemonic (for funding):
62+
```shell
63+
# Using Foundry's cast
64+
cast wallet address --mnemonic "your mnemonic here" --mnemonic-index 0
65+
cast wallet address --mnemonic "your mnemonic here" --mnemonic-index 1
66+
cast wallet address --mnemonic "your mnemonic here" --mnemonic-index 2
67+
```
68+
69+
### Smoke-specific knobs (defaults in parentheses)
70+
71+
- `SMOKE_SIGNER_INDICES` (`0,1,2`) - comma-separated list of signer indices to use for failover
72+
- `SMOKE_TX_TIMEOUT_SECS` (`48`)
73+
- `SMOKE_TX_MAX_RETRIES` (`2`)
74+
- `SMOKE_FEE_BUMP` (`1.125^4`)
75+
- `SMOKE_MAX_FEE_GWEI` (optional) - fail fast if maxFeePerGas exceeds this cap (unset = no cap)
76+
- `SMOKE_MAX_PRIORITY_FEE_GWEI` (optional) - fail fast if maxPriorityFeePerGas exceeds this cap (unset = no cap)
77+
- `SMOKE_MAX_BACKLOG` (`3`)
78+
- `SMOKE_CANCEL_BACKLOG` (`1`) - set to `0` to disable auto-cancel of pending transactions
79+
- `SMOKE_DEPLOY_CONTRACT` (`1`) - set to `0` to attach to existing contract via `TEST_INPUT_CONTRACT_ADDRESS`
80+
- `SMOKE_RUN_TESTS` (`1`) - set to `0` to deploy contract only without running tests
81+
- `SMOKE_DECRYPT_TIMEOUT_SECS` (`300`) - timeout for decryption operations
82+
- `BETTERSTACK_HEARTBEAT_URL` (optional) - if set, pings BetterStack on success; reports error with exit code on failure
83+
84+
### Run
85+
86+
```shell
87+
cd test-suite/e2e
88+
npx hardhat run --network zwsDev scripts/smoke-inputflow.ts
89+
npx hardhat run --network sepolia scripts/smoke-inputflow.ts
90+
npx hardhat run --network mainnet scripts/smoke-inputflow.ts
91+
```

test-suite/e2e/contracts/E2ECoprocessorConfigLocal.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ pragma solidity ^0.8.24;
44
import {CoprocessorConfig, FHE} from "@fhevm/solidity/lib/FHE.sol";
55

66
library DefaultCoprocessorConfig {
7+
/// @dev These addresses are placeholders. They are patched at runtime via sed
8+
/// in the E2E test runner script with the actual deployment addresses.
79
function getConfig() internal pure returns (CoprocessorConfig memory) {
810
return
911
CoprocessorConfig({
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: BSD-3-Clause-Clear
2+
3+
pragma solidity ^0.8.24;
4+
5+
import "@fhevm/solidity/lib/FHE.sol";
6+
import {CoprocessorConfig} from "@fhevm/solidity/lib/Impl.sol";
7+
8+
/// @notice Smoke test contract with constructor-based coprocessor config injection.
9+
/// @dev Unlike TestInput.sol which uses E2ECoprocessorConfig (sed-patched at runtime),
10+
/// this contract receives addresses at deploy time, enabling smoke tests to run on
11+
/// devnet, sepolia, and mainnet without sed patching.
12+
contract SmokeTestInput {
13+
euint64 public resUint64;
14+
15+
constructor(address aclAddress, address coprocessorAddress, address kmsVerifierAddress) {
16+
FHE.setCoprocessor(
17+
CoprocessorConfig({
18+
ACLAddress: aclAddress,
19+
CoprocessorAddress: coprocessorAddress,
20+
KMSVerifierAddress: kmsVerifierAddress
21+
})
22+
);
23+
}
24+
25+
function requestUint64NonTrivial(externalEuint64 inputHandle, bytes calldata inputProof) public {
26+
resUint64 = FHE.fromExternal(inputHandle, inputProof);
27+
FHE.allowThis(resUint64);
28+
}
29+
30+
// Adds a trivially-encrypted 42 to the user-provided encrypted uint64 input.
31+
function add42ToInput64(externalEuint64 inputHandle, bytes calldata inputProof) public {
32+
euint64 input = FHE.fromExternal(inputHandle, inputProof);
33+
euint64 trivial42 = FHE.asEuint64(42);
34+
resUint64 = FHE.add(input, trivial42);
35+
FHE.allowThis(resUint64);
36+
FHE.allow(resUint64, msg.sender);
37+
FHE.makePubliclyDecryptable(resUint64);
38+
}
39+
}

test-suite/e2e/contracts/TestInput.sol renamed to test-suite/e2e/contracts/smoke/TestInput.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pragma solidity ^0.8.24;
44

55
import "@fhevm/solidity/lib/FHE.sol";
6-
import {E2ECoprocessorConfig} from "./E2ECoprocessorConfigLocal.sol";
6+
import {E2ECoprocessorConfig} from "../E2ECoprocessorConfigLocal.sol";
77

88
contract TestInput is E2ECoprocessorConfig {
99
euint64 public resUint64;

test-suite/e2e/hardhat.config.ts

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import '@nomicfoundation/hardhat-toolbox';
22
import dotenv from 'dotenv';
3-
import type { HardhatUserConfig, extendProvider } from 'hardhat/config';
4-
import { task } from 'hardhat/config';
3+
import type { HardhatUserConfig } from 'hardhat/config';
4+
import { task, vars } from 'hardhat/config';
55
import type { NetworkUserConfig } from 'hardhat/types';
66
import { resolve } from 'path';
77

88
const NUM_ACCOUNTS = 120;
9+
const DEFAULT_NETWORK = 'staging';
910

1011
task('compile:specific', 'Compiles only the specified contract')
1112
.addParam('contract', "The contract's path")
@@ -19,11 +20,9 @@ task('compile:specific', 'Compiles only the specified contract')
1920
const dotenvConfigPath: string = process.env.DOTENV_CONFIG_PATH || './.env';
2021
dotenv.config({ path: resolve(__dirname, dotenvConfigPath) });
2122

22-
// Ensure that we have all the environment variables we need.
23-
let mnemonic: string | undefined = process.env.MNEMONIC;
24-
if (!mnemonic) {
25-
mnemonic = 'adapt mosquito move limb mobile illegal tree voyage juice mosquito burger raise father hope layer'; // default mnemonic in case it is undefined (needed to avoid panicking when deploying on real network)
26-
}
23+
const defaultMnemonic =
24+
'adapt mosquito move limb mobile illegal tree voyage juice mosquito burger raise father hope layer';
25+
const mnemonic: string = process.env.MNEMONIC ?? vars.get('MNEMONIC', defaultMnemonic);
2726

2827
task('coverage').setAction(async (taskArgs, hre, runSuper) => {
2928
hre.config.networks.hardhat.allowUnlimitedContractSize = true;
@@ -90,38 +89,39 @@ const chainIds = {
9089
function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig {
9190
let jsonRpcUrl: string;
9291
const defaultRpcUrl = 'http://localhost:8545';
92+
const requestedNetwork = (() => {
93+
const idx = process.argv.indexOf('--network');
94+
if (idx !== -1 && process.argv[idx + 1] && !process.argv[idx + 1].startsWith('-')) {
95+
return process.argv[idx + 1];
96+
}
97+
return process.env.HARDHAT_NETWORK;
98+
})();
99+
const shouldWarn = requestedNetwork ? requestedNetwork === chain : chain === DEFAULT_NETWORK;
93100

94101
switch (chain) {
95102
case 'staging':
96-
jsonRpcUrl = process.env.RPC_URL || defaultRpcUrl;
97-
if (jsonRpcUrl === defaultRpcUrl && !process.env.RPC_URL) {
98-
console.warn(
99-
`WARN: RPC_URL environment variable not set for network '${chain}'. Using default: ${defaultRpcUrl}`,
100-
);
101-
}
102-
break;
103103
case 'zwsDev':
104-
jsonRpcUrl = process.env.RPC_URL || defaultRpcUrl;
105-
if (jsonRpcUrl === defaultRpcUrl && !process.env.RPC_URL) {
106-
console.warn(
107-
`WARN: RPC_URL environment variable not set for network '${chain}'. Using default: ${defaultRpcUrl}`,
108-
);
104+
jsonRpcUrl = process.env.RPC_URL ?? vars.get('RPC_URL', defaultRpcUrl);
105+
if (shouldWarn && jsonRpcUrl === defaultRpcUrl) {
106+
console.warn(`WARN: RPC_URL not set for network '${chain}'. Using default: ${defaultRpcUrl}`);
109107
}
110108
break;
111109
case 'sepolia':
112-
jsonRpcUrl = process.env.RPC_URL || defaultRpcUrl;
113-
if (jsonRpcUrl === defaultRpcUrl && !process.env.RPC_URL) {
114-
console.warn(
115-
`WARN: RPC_URL environment variable not set for network '${chain}'. Using default: ${defaultRpcUrl}`,
116-
);
110+
jsonRpcUrl = process.env.SEPOLIA_ETH_RPC_URL || vars.get('SEPOLIA_ETH_RPC_URL', '') || process.env.RPC_URL;
111+
if (!jsonRpcUrl) {
112+
if (shouldWarn) {
113+
throw new Error('SEPOLIA_ETH_RPC_URL (or RPC_URL) is required for sepolia network');
114+
}
115+
jsonRpcUrl = 'https://rpc.sepolia.org'; // placeholder for config validation
117116
}
118117
break;
119118
case 'mainnet':
120-
jsonRpcUrl = process.env.RPC_URL || defaultRpcUrl;
121-
if (jsonRpcUrl === defaultRpcUrl && !process.env.RPC_URL) {
122-
console.warn(
123-
`WARN: RPC_URL environment variable not set for network '${chain}'. Using default: ${defaultRpcUrl}`,
124-
);
119+
jsonRpcUrl = process.env.MAINNET_ETH_RPC_URL || vars.get('MAINNET_ETH_RPC_URL', '') || process.env.RPC_URL;
120+
if (!jsonRpcUrl) {
121+
if (shouldWarn) {
122+
throw new Error('MAINNET_ETH_RPC_URL (or RPC_URL) is required for mainnet network');
123+
}
124+
jsonRpcUrl = 'https://eth.llamarpc.com'; // placeholder for config validation
125125
}
126126
break;
127127
case 'localCoprocessor':
@@ -162,7 +162,7 @@ function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig {
162162
const config: HardhatUserConfig = {
163163
// workaround a hardhat bug with --parallel --network
164164
// https://github.com/NomicFoundation/hardhat/issues/2756
165-
defaultNetwork: 'staging',
165+
defaultNetwork: DEFAULT_NETWORK,
166166
mocha: {
167167
timeout: 300000,
168168
},

0 commit comments

Comments
 (0)