Polygon Ecosystem Development
Build on Polygon's multi-chain ecosystem: PoS sidechain for low-cost EVM transactions, zkEVM for Ethereum-equivalent ZK rollups, and AggLayer for unified cross-chain interop.
What You Probably Got Wrong
- Polygon PoS is not an L2 -- it is a commit chain (sidechain) with its own validator set that checkpoints to Ethereum. It does NOT inherit Ethereum security for individual transactions.
- MATIC is being replaced by POL -- POL (0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6 on Ethereum) is the new native gas and staking token. MATIC holders must migrate via the migration contract.
- zkEVM and PoS are completely different chains -- different chain IDs, different RPCs, different bridge contracts. Code that works on PoS does not automatically work on zkEVM without verifying opcode compatibility.
- zkEVM finality depends on proof generation -- transactions are "trusted" quickly but only final on Ethereum after a ZK proof is submitted and verified (~30 min to hours).
- Gas on PoS uses POL (formerly MATIC), gas on zkEVM uses ETH -- do not confuse the native gas tokens between chains.
Quick Start
Install Dependencies
# viem for TypeScript interaction
npm install viem
# Foundry for Solidity deployment
curl -L https://foundry.paradigm.xyz | bash
foundryup
Environment Setup
# .env
PRIVATE_KEY=your_private_key_here
POLYGONSCAN_API_KEY=your_polygonscan_key
POLYGON_RPC_URL=https://polygon-rpc.com
ZKEVM_RPC_URL=https://zkevm-rpc.com
Chain Configuration
Polygon PoS
| Property | Value |
|---|---|
| Chain ID | 137 |
| Currency | POL (18 decimals) |
| EVM Version | Shanghai |
| Block Time | ~2 seconds |
| Consensus | PoS + Heimdall (Tendermint BFT) |
| Checkpointing | Every ~30 min to Ethereum |
| Block Gas Limit | 30M |
RPC Endpoints (PoS Mainnet)
| URL | Provider | Notes |
|---|---|---|
https://polygon-rpc.com |
Polygon Labs | Default public |
https://rpc.ankr.com/polygon |
Ankr | Public, rate limited |
https://polygon.llamarpc.com |
LlamaNodes | Public |
https://polygon-mainnet.g.alchemy.com/v2/<KEY> |
Alchemy | Authenticated |
https://polygon-mainnet.infura.io/v3/<KEY> |
Infura | Authenticated |
Block Explorers (PoS)
| Explorer | URL |
|---|---|
| Polygonscan | https://polygonscan.com |
| Blockscout | https://polygon.blockscout.com |
| OKLink | https://www.oklink.com/polygon |
Polygon zkEVM
| Property | Value |
|---|---|
| Chain ID | 1101 |
| Currency | ETH (18 decimals) |
| ZK Type | Type-2 ZK-EVM |
| Block Time | Variable (~5-10 seconds) |
| Proof Time | ~30 min to finalize on L1 |
| Sequencer | Centralized (Polygon Labs) |
RPC Endpoints (zkEVM Mainnet)
| URL | Provider | Notes |
|---|---|---|
https://zkevm-rpc.com |
Polygon Labs | Default public |
https://rpc.ankr.com/polygon_zkevm |
Ankr | Public |
https://polygonzkevm-mainnet.g.alchemy.com/v2/<KEY> |
Alchemy | Authenticated |
Block Explorers (zkEVM)
| Explorer | URL |
|---|---|
| zkEVM Explorer | https://zkevm.polygonscan.com |
| Blockscout | https://zkevm.blockscout.com |
Testnets
| Network | Chain ID | Currency | Faucet |
|---|---|---|---|
| Amoy (PoS testnet) | 80002 | POL | https://faucet.polygon.technology |
| Cardona (zkEVM testnet) | 2442 | ETH | https://faucet.polygon.technology |
Testnet RPCs
| Network | URL |
|---|---|
| Amoy | https://rpc-amoy.polygon.technology |
| Cardona | https://rpc.cardona.zkevm-rpc.com |
Deployment
Foundry (Polygon PoS)
# Deploy to Polygon PoS mainnet
forge create src/MyContract.sol:MyContract \
--rpc-url https://polygon-rpc.com \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--verifier-url https://api.polygonscan.com/api \
--etherscan-api-key $POLYGONSCAN_API_KEY
# Deploy to Amoy testnet
forge create src/MyContract.sol:MyContract \
--rpc-url https://rpc-amoy.polygon.technology \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--verifier-url https://api-amoy.polygonscan.com/api \
--etherscan-api-key $POLYGONSCAN_API_KEY
Foundry (Polygon zkEVM)
# Deploy to zkEVM mainnet
forge create src/MyContract.sol:MyContract \
--rpc-url https://zkevm-rpc.com \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--verifier-url https://api-zkevm.polygonscan.com/api \
--etherscan-api-key $POLYGONSCAN_API_KEY
Hardhat Configuration
// hardhat.config.ts
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
const config: HardhatUserConfig = {
solidity: "0.8.24",
networks: {
polygon: {
url: process.env.POLYGON_RPC_URL || "https://polygon-rpc.com",
accounts: [process.env.PRIVATE_KEY!],
chainId: 137,
},
amoy: {
url: "https://rpc-amoy.polygon.technology",
accounts: [process.env.PRIVATE_KEY!],
chainId: 80002,
},
zkevm: {
url: process.env.ZKEVM_RPC_URL || "https://zkevm-rpc.com",
accounts: [process.env.PRIVATE_KEY!],
chainId: 1101,
},
cardona: {
url: "https://rpc.cardona.zkevm-rpc.com",
accounts: [process.env.PRIVATE_KEY!],
chainId: 2442,
},
},
etherscan: {
apiKey: {
polygon: process.env.POLYGONSCAN_API_KEY!,
polygonAmoy: process.env.POLYGONSCAN_API_KEY!,
polygonZkEVM: process.env.POLYGONSCAN_API_KEY!,
},
},
};
export default config;
Verification
# Verify on Polygonscan (PoS)
forge verify-contract <ADDRESS> src/MyContract.sol:MyContract \
--chain-id 137 \
--verifier-url https://api.polygonscan.com/api \
--etherscan-api-key $POLYGONSCAN_API_KEY
# Verify on zkEVM explorer
forge verify-contract <ADDRESS> src/MyContract.sol:MyContract \
--chain-id 1101 \
--verifier-url https://api-zkevm.polygonscan.com/api \
--etherscan-api-key $POLYGONSCAN_API_KEY
Polygon PoS Architecture
Polygon PoS is a commit chain (sidechain) with its own validator set:
- Bor: Block production layer (modified Geth). Validators take turns producing blocks in "spans" (~6400 blocks).
- Heimdall: Consensus and checkpoint layer (Tendermint BFT). Selects block producers, validates blocks, and submits checkpoints to Ethereum.
- Checkpoints: State roots submitted to Ethereum
RootChaincontract every ~30 minutes. This provides data availability, NOT execution validity. - Validator Set: ~100 validators with POL staking. Delegators can stake via
ValidatorSharecontracts.
PoS Key Contracts (Ethereum L1)
| Contract | Address | Purpose |
|---|---|---|
| RootChain | 0x86E4Dc95c7FBdBf52e33D563BbDB00823894C287 |
Checkpoint submission |
| StateSender | 0x28e4F3a7f651294B9564800b2D01f35189A5bFbE |
L1 -> L2 state sync |
| StakeManager | 0x5e3Ef299fDDf15eAa0432E6e66473ace8c13D908 |
Validator staking |
| RootChainManager | 0xA0c68C638235ee32657e8f720a23ceC1bFc77C77 |
Bridge deposits |
| POL Token | 0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6 |
Native token (Ethereum) |
| MATIC Token | 0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0 |
Legacy token (Ethereum) |
Last verified: 2025-12-01
PoS Key Contracts (Polygon Chain)
| Contract | Address | Purpose |
|---|---|---|
| ChildChainManager | 0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa |
Bridge withdrawals |
| WPOL (Wrapped POL) | 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270 |
Wrapped native token |
| WETH | 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619 |
Wrapped Ether |
| USDC | 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 |
Native USDC |
| USDC.e | 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 |
Bridged USDC |
Last verified: 2025-12-01
Polygon zkEVM
Polygon zkEVM is a Type-2 ZK-EVM rollup. It aims for full EVM equivalence, meaning standard Solidity contracts deploy without modification in most cases.
How It Works
- Sequencer receives transactions and produces L2 batches.
- Aggregator generates ZK proofs for batches.
- Proofs are verified on Ethereum via the
PolygonZkEVMcontract. - State transitions become final on L1 once proof is accepted (~30 min to hours).
Transaction States on zkEVM
| State | Meaning | Time |
|---|---|---|
| Trusted | Sequencer included it | Seconds |
| Virtual | Batch posted to L1 | Minutes |
| Consolidated | ZK proof verified on L1 | ~30 min to hours |
EVM Compatibility Notes
zkEVM targets full EVM equivalence but some edge cases differ:
DIFFICULTY/PREVRANDAOopcode returns0(no randomness source like Ethereum beacon chain)SELFDESTRUCTis disabled (per EIP-6049 deprecation)- Precompiled contracts:
ecAdd,ecMul,ecPairingbehave identically;modexpmay have higher gas costs BLOCKHASHonly returns hashes for the last 256 blocks (same as Ethereum spec, but be aware proof timing may affect behavior)- Gas costs for some operations differ slightly due to proof generation overhead
zkEVM Gas Model
Gas on zkEVM is paid in ETH. The cost includes:
- L2 execution gas: Similar to Ethereum gas pricing
- L1 data availability cost: Posting batch data to Ethereum
- Proof overhead: Indirectly amortized across all transactions in a batch
import { createPublicClient, http } from "viem";
import { polygonZkEvm } from "viem/chains";
const zkEvmClient = createPublicClient({
chain: polygonZkEvm,
transport: http("https://zkevm-rpc.com"),
});
const gasPrice = await zkEvmClient.getGasPrice();
const estimatedGas = await zkEvmClient.estimateGas({
account: "0xYourAddress",
to: "0xRecipient",
value: 0n,
data: "0x...",
});
const totalCostWei = gasPrice * estimatedGas;
POL Token
POL replaced MATIC as Polygon's native token via a migration contract on Ethereum.
Migration (MATIC to POL)
The migration is 1:1. Call the migration contract on Ethereum:
import { createWalletClient, http, parseAbi } from "viem";
import { mainnet } from "viem/chains";
// Migration contract on Ethereum
// Converts MATIC -> POL at 1:1 ratio
const MIGRATION_CONTRACT = "0x29e7DF7b6c1264C3F63e2E7bB27143EeB8A05fe3" as const;
const migrationAbi = parseAbi([
"function migrate(uint256 amount) external",
"function unmigrate(uint256 amount) external",
]);
const MATIC_TOKEN = "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0" as const;
const POL_TOKEN = "0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6" as const;
// Step 1: Approve MATIC spend
// Step 2: Call migrate()
POL Staking
POL is staked on Ethereum via the StakeManager contract. Delegators use ValidatorShare contracts:
import { parseAbi } from "viem";
const validatorShareAbi = parseAbi([
"function buyVoucher(uint256 _amount, uint256 _minSharesToMint) external returns (uint256)",
"function sellVoucher_new(uint256 claimAmount, uint256 maximumSharesToBurn) external",
"function restake() external returns (uint256, uint256)",
"function withdrawRewards() external",
"function getLiquidRewards(address user) external view returns (uint256)",
"function getTotalStake(address user) external view returns (uint256, uint256)",
]);
AggLayer
AggLayer (Aggregation Layer) is Polygon's vision for unifying multiple chains under a single ZK-proven interop layer.
Core Concepts
- Unified Bridge: Single bridge contract on Ethereum shared by all AggLayer-connected chains. Each chain gets a unique
networkId. - Pessimistic Proofs: AggLayer validates cross-chain claims using pessimistic proofs -- it assumes the worst case and only releases funds if the proof confirms solvency.
- Chain Interop: Chains connected to AggLayer can transfer assets without going through Ethereum L1 as intermediary. Assets move via the LxLy bridge with AggLayer verification.
- Shared Liquidity: All chains on AggLayer share a unified liquidity pool, reducing fragmentation.
AggLayer Architecture
┌──────────────────────────────────────────────┐
│ Ethereum │
│ ┌─────────────────────────────────────────┐ │
│ │ Unified Bridge Contract │ │
│ │ (shared by all AggLayer chains) │ │
│ └─────────────────────────────────────────┘ │
│ ▲ ▲ ▲ │
│ Proofs│ Proofs│ Proofs│ │
│ │ │ │ │
│ ┌──────┴──────────────┴─────────────┴──────┐ │
│ │ AggLayer │ │
│ │ (pessimistic proof verification) │ │
│ └──────┬──────────────┬─────────────┬──────┘ │
└─────────┼──────────────┼─────────────┼────────┘
│ │ │
┌──────┴──┐ ┌──────┴──┐ ┌─────┴───┐
│ PoS │ │ zkEVM │ │ CDK │
│ Chain │ │ Chain │ │ Chain │
└─────────┘ └─────────┘ └──────────┘
Bridging
PoS Bridge (Polygon PoS <-> Ethereum)
The PoS bridge uses RootChainManager (Ethereum) and ChildChainManager (Polygon PoS).
Deposit (Ethereum -> Polygon PoS):
- Approve token to
RootChainManager'sERC20Predicate - Call
RootChainManager.depositFor(user, rootToken, depositData) - Wait ~7-8 minutes for state sync to Polygon PoS
Withdraw (Polygon PoS -> Ethereum):
- Burn tokens on Polygon PoS (transfer to
0x0or call burn function) - Wait for checkpoint inclusion (~30 minutes)
- Call
RootChainManager.exit(burnTxProof)on Ethereum
import { createWalletClient, http, parseAbi, encodePacked } from "viem";
import { mainnet, polygon } from "viem/chains";
const ROOT_CHAIN_MANAGER = "0xA0c68C638235ee32657e8f720a23ceC1bFc77C77" as const;
const ERC20_PREDICATE = "0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf" as const;
const rootChainManagerAbi = parseAbi([
"function depositFor(address user, address rootToken, bytes calldata depositData) external",
"function exit(bytes calldata inputData) external",
]);
// depositData is ABI-encoded amount
// encodePacked would be wrong here -- use encodeAbiParameters
import { encodeAbiParameters, parseAbiParameters } from "viem";
const depositData = encodeAbiParameters(
parseAbiParameters("uint256"),
[1000000n] // amount in token's smallest unit
);
zkEVM LxLy Bridge (zkEVM <-> Ethereum)
The zkEVM uses the LxLy bridge contract (also used by AggLayer chains).
Bridge Asset (L1 -> zkEVM):
const ZKEVM_BRIDGE = "0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe" as const;
const bridgeAbi = parseAbi([
"function bridgeAsset(uint32 destinationNetwork, address destinationAddress, uint256 amount, address token, bool forceUpdateGlobalExitRoot, bytes calldata permitData) external payable",
"function claimAsset(bytes32[32] calldata smtProofLocalExitRoot, bytes32[32] calldata smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes calldata metadata) external",
]);
// networkId 0 = Ethereum mainnet
// networkId 1 = Polygon zkEVM mainnet
Claiming on Destination:
After the bridge transaction is included and proof is generated, call claimAsset on the destination chain with the Merkle proof from the bridge API.
Bridge Monitoring
// Polygon PoS bridge API
const POS_BRIDGE_API = "https://proof-generator.polygon.technology/api/v1";
// Check if checkpoint included (for PoS withdrawals)
const checkpointStatus = await fetch(
`${POS_BRIDGE_API}/matic/block-included/${blockNumber}?networkType=mainnet`
);
// zkEVM bridge API
const ZKEVM_BRIDGE_API = "https://bridge-api.zkevm-rpc.com";
// Get bridge deposit status
const depositStatus = await fetch(
`${ZKEVM_BRIDGE_API}/bridges/${depositAddress}?offset=0&limit=25`
);
// Get Merkle proof for claiming
const merkleProof = await fetch(
`${ZKEVM_BRIDGE_API}/merkle-proof?deposit_cnt=${depositCount}&net_id=${networkId}`
);
Gas Model
Polygon PoS
- Gas is paid in POL (native token, formerly MATIC)
- Gas prices typically 30-100 gwei, significantly lower than Ethereum
- EIP-1559 is supported (base fee + priority fee)
- During congestion, gas can spike to 500+ gwei
import { createPublicClient, http } from "viem";
import { polygon } from "viem/chains";
const posClient = createPublicClient({
chain: polygon,
transport: http("https://polygon-rpc.com"),
});
const gasPrice = await posClient.getGasPrice();
const block = await posClient.getBlock();
// block.baseFeePerGas gives current base fee
Polygon zkEVM
- Gas is paid in ETH
- Pricing reflects L2 execution + L1 data posting cost
- Generally cheaper than Ethereum mainnet but more expensive than PoS
- Gas varies with L1 gas prices (data availability cost)
Ecosystem
Major Protocols on Polygon PoS
| Protocol | Category | Notes |
|---|---|---|
| QuickSwap | DEX | Largest Polygon-native DEX, UniV3-style |
| Aave V3 | Lending | Major lending market on Polygon |
| Uniswap V3 | DEX | Deployed on PoS |
| Balancer | DEX | Multi-token pools |
| Curve | DEX | Stablecoin DEX |
| 0x / Matcha | Aggregator | DEX aggregation |
| Polymarket | Prediction | Largest prediction market (on PoS) |
Infrastructure
| Service | Purpose |
|---|---|
| Polygonscan | Block explorer and verification |
| The Graph | Subgraph indexing (PoS + zkEVM) |
| Chainlink | Oracle feeds on PoS and zkEVM |
| Gelato | Automation and relaying |
| Polygon CDK | Chain Development Kit for custom chains |
Key Differences: PoS vs zkEVM vs Ethereum
| Feature | Polygon PoS | Polygon zkEVM | Ethereum |
|---|---|---|---|
| Chain ID | 137 | 1101 | 1 |
| Gas Token | POL | ETH | ETH |
| Consensus | Tendermint BFT | ZK rollup | PoS (Casper) |
| Block Time | ~2s | ~5-10s | ~12s |
| Finality | ~30 min (checkpoint) | ~30 min (proof) | ~13 min |
| Security Model | Own validators | Ethereum (ZK proof) | Native |
| EVM Compat | Full | Type-2 ZK-EVM | Native |
| Gas Cost | Very low | Low-medium | High |
| Decentralization | ~100 validators | Centralized sequencer | ~900k validators |
Viem Chain Definitions
import { defineChain } from "viem";
// Polygon PoS (built into viem)
import { polygon } from "viem/chains";
// Polygon zkEVM (built into viem)
import { polygonZkEvm } from "viem/chains";
// Amoy testnet (built into viem)
import { polygonAmoy } from "viem/chains";
// Cardona testnet (may need manual definition)
const polygonZkEvmCardona = defineChain({
id: 2442,
name: "Polygon zkEVM Cardona",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpcUrls: {
default: { http: ["https://rpc.cardona.zkevm-rpc.com"] },
},
blockExplorers: {
default: { name: "Blockscout", url: "https://cardona-zkevm.polygonscan.com" },
},
testnet: true,
});
Resources
- Polygon Documentation
- Polygon zkEVM Docs
- AggLayer Docs
- Polygonscan
- zkEVM Explorer
- Polygon Faucet
- Polygon CDK
- POL Token Migration
- Bridge UI
Skill Structure
polygon/
├── SKILL.md # This file
├── examples/
│ ├── deploy-contract/ # Deployment to PoS and zkEVM
│ ├── bridge-tokens/ # PoS bridge and LxLy bridge
│ ├── zkevm-patterns/ # zkEVM-specific patterns
│ └── pol-staking/ # POL staking and delegation
├── resources/
│ ├── contract-addresses.md # All key addresses
│ └── error-codes.md # Common errors
├── docs/
│ └── troubleshooting.md # Common issues and fixes
└── templates/
└── polygon-client.ts # Starter template