Migrating Solidity to Polygon zkEVM: EVM‑Equivalence, Tooling, and Practical Trade‑offs
Polygon zkEVM lets you run unmodified Solidity on a zk‑rollup with near‑zero‑gas proofs. This guide walks through a real migration, shows how to estimate costs, and explains the central sequencer risk and 7‑day withdrawal delay that shape your architecture.
14 Aug 2026, 03:38 UTC

Concrete Problem: “Can I deploy my existing Solidity contract on Polygon zkEVM without rewriting or recompiling?”
Polygon zkEVM was designed to be EVM‑equivalent: the same bytecode that runs on Ethereum L1 runs unchanged on the zk‑rollup. That means you can take a contract that already compiles with Hardhat or Foundry, deploy it to zkEVM, and have it behave exactly as on L1, provided you respect the few opcode differences and precompile variations.
Thesis: “Migrating is a matter of tooling and cost estimation, not code rewrites.”
The migration workflow is almost identical to an Ethereum mainnet deployment, but you must account for the L1‑to‑L2 bridge, proof generation, and the 7‑day forced‑exit window. Below is a step‑by‑step example that shows how to prepare, estimate, deploy, and verify a simple ERC‑20 contract on the Polygon zkEVM testnet.
1️⃣ Set Up the Development Environment
Use the hardhat-zkevm plugin, which forks the zkEVM testnet and exposes the same JSON‑RPC interface as Ethereum. Install the plugin and its peer dependencies:
npm install --save-dev hardhat hardhat-zkevm @nomiclabs/hardhat-ethers ethers
Configure hardhat.config.js to point to the zkEVM testnet (chain ID 1442) and the dedicated RPC endpoint:
module.exports = {
solidity: "0.8.20",
networks: {
zkevm_testnet: {
url: "https://zkevm-rpc.com", // public zkEVM RPC
chainId: 1442,
accounts: [process.env.PRIVATE_KEY]
}
}
};
Make sure PRIVATE_KEY is set in your environment. The RPC endpoint is read‑only; for write operations you need a private key with testnet ETH.
2️⃣ Write a Minimal ERC‑20 Contract
Below is a contract that compiles on any Solidity 0.8.x compiler. No changes are needed for zkEVM.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TestToken is ERC20 {
constructor(uint256 initialSupply) ERC20("TestToken", "TT") {
_mint(msg.sender, initialSupply);
}
}
3️⃣ Estimate Gas Before Deployment
Polygon zkEVM’s gas cost is a mix of L2 execution gas and L1 calldata cost. Use the public estimator API to get a realistic estimate that includes the base fee and calldata compression overhead:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{"from":"0xYourAddress","to":"0xContractAddress","data":"0x..."}],"id":1}' \
https://api-zkevm.polygonscan.com/api?module=proxy&action=eth_estimateGas
Replace 0xContractAddress with the contract’s bytecode hash (you can obtain it from a local Hardhat build). The response will include the gas limit and a cost estimate in ETH. A typical ERC‑20 deployment costs ~150 k gas on L2, but the L1 calldata cost can push the final fee to 0.02 ETH during a congestion spike.
4️⃣ Deploy the Contract
Deploy using Hardhat’s run script. The plugin automatically submits the transaction to the zkEVM testnet and waits for L2 confirmation. After the transaction is included in a batch, the prover generates a STARK proof, which is then aggregated into a SNARK and posted to L1 for verification.
npx hardhat run scripts/deploy.js --network zkevm_testnet
Sample deploy.js:
const hre = require("hardhat");
async function main() {
const [deployer] = await hre.ethers.getSigners();
console.log("Deploying from", deployer.address);
const Token = await hre.ethers.getContractFactory("TestToken");
const token = await Token.deploy(hre.ethers.parseUnits("1000000", 18));
await token.waitForDeployment();
console.log("Token deployed to", await token.getAddress());
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
After deployment, verify the contract on Polygon zkEVM explorer by submitting the source code.
5️⃣ Verify State and Finality
Once the transaction is confirmed on L2, the prover will submit a batch to L1. The L1 contract posts a GlobalExitRoot that signals batch finality. To check that the contract is fully finalized, query the PolygonZkEVMGlobalExitRoot contract or use the explorer’s “Batch” view. A soft finality occurs within ~2 seconds (sequencer confirmation), but the contract is only hard‑finalized after the batch proof is verified on L1 (≈10–30 minutes).
6️⃣ Understand the Trade‑offs
- Centralized sequencer: Current zkEVM sequencer is operated by Polygon Labs. This introduces a MEV extraction risk and potential censorship. A forced‑exit mechanism allows users to submit exit transactions directly to the rollup contract, but the 7‑day challenge window can delay urgent withdrawals.
- Gas cost volatility: L1 calldata cost dominates the total fee. During Ethereum congestion, the base fee can spike, making fee estimation uncertain. Batch compression mitigates but does not eliminate the impact.
- Precompile differences: zkEVM’s precompiles (e.g., BLS12‑381) differ from L1. If your contract calls a precompile, test the function on testnet before mainnet deployment.
- Archive access: Beyond 128 blocks, public RPC providers require a paid plan. If you need full history, consider running a self‑hosted archive node with
polygon-zkevm-erigon, which demands ~4 TB SSD storage.
7️⃣ Actionable Checklist for Developers
- Fork your existing Hardhat/Foundry setup with
hardhat-zkevm. - Run
npx hardhat test --network zkevm_testnetto ensure all tests pass on zkEVM. - Estimate gas with the public estimator API; adjust your deployment parameters if the cost is too high.
- Deploy to testnet, monitor the batch submission, and confirm hard finality via the explorer.
- Validate bridge flows: deposit to zkEVM via the official bridge UI, then withdraw after 7 days to confirm the forced‑exit path works.
- Plan for future decentralization: keep an eye on the CDK shared‑sequencer roadmap and be ready to switch if you need lower MEV risk.
Conclusion
Polygon zkEVM offers a near‑zero‑change path for Solidity developers, backed by a proven EVM‑equivalent execution engine and a robust proving pipeline. The main engineering decisions you’ll face are around cost estimation, finality expectations, and the centralized sequencer risk. By following the workflow above, you can prototype, test, and deploy on zkEVM with confidence, while staying aware of the trade‑offs that shape the user experience.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.