Hardhat vs Foundry for a Multi-Chain Deployment
A team of four developers is starting a DeFi protocol that will deploy to Ethereum mainnet, an L2, and a testnet. Two developers prefer JavaScript, two prefer Solidity. They need deterministic deployments, scripted verification, fork testing against mainnet state, and CI that runs in under 10 minutes. Their current repo uses Hardhat with ethers and a plugin for verification, but fork tests are slow and flaky because they hit a public RPC. They are debating a rewrite in Foundry. The deadline is eight weeks, and the protocol has three contracts with upgradeable proxies.
1. Recommend a tooling strategy. Justify it against the stated requirements rather than picking a favorite.
Read the worked answer
The requirements are deterministic deployments, scripted verification, fork testing, and fast CI. Both Hardhat and Foundry can do all four, so the decision should hinge on team skills, migration risk, and CI performance.
Foundry is strong on fork testing speed and Solidity-native tests, which suits the two Solidity-preferring developers and directly addresses the flaky fork tests. Hardhat is strong on JavaScript tooling, plugin ecosystem, and scripted verification, which suits the two JS developers and the existing repo. A full rewrite in eight weeks with upgradeable proxies adds risk: proxy deployment and upgrade scripts need careful re-testing, and the team loses institutional knowledge encoded in the current scripts.
The pragmatic recommendation is a hybrid: keep Hardhat for deployment scripts and verification, and add Foundry for unit and fork tests. Foundry tests run fast and can pin a fork block number, which fixes flakiness. The flakiness itself is an RPC problem, not a framework problem - pin the block, cache the fork, or run a local node in CI. That change alone may bring CI under 10 minutes without a rewrite. If the team later wants to consolidate, do it after launch. The exam point is to diagnose the flakiness as an RPC/pinning issue and to weigh migration cost, not to declare one tool universally better.
2. How should they make deployments deterministic and verifiable across three networks?
Read the worked answer
Determinism comes from controlling the deployer address, nonce, and constructor arguments. Use a deterministic deployer such as CREATE2 with a fixed salt, or a deployment framework that records nonces and replays them. The same deployer key and same nonce sequence on each chain yields the same addresses, which makes verification and cross-chain references predictable.
Store deployment artifacts per network: contract address, constructor arguments, compiler version and settings, and the exact source. Verification depends on byte-for-byte reproducibility, so pin the solc version, pin optimizer runs, and avoid metadata that varies by build path. Commit a lockfile and use the same toolchain in CI.
For upgradeable proxies, deploy the implementation and the proxy separately, record both addresses, and verify the implementation. Confirm the proxy admin and initializer are set correctly on each network, and that the initializer cannot be called twice. Run a post-deploy check script that reads back the proxy's implementation slot and the owner, and fail the pipeline if they do not match expectations. Keep a per-network config file for RPC endpoints and addresses so the same scripts run everywhere. Finally, document the deployment order and require a dry run on the testnet before mainnet, with the fork test asserting the resulting state.