Layer 2 Solution Development
"We need our own L2" — a phrase I hear increasingly often. Sometimes it's justified: a project with thousands of transactions per second that doesn't want to pay Ethereum gas and doesn't want to depend on someone else's infrastructure. Often — it's excessive, and existing L2 is enough. Before building your own L2, honestly answer: do you need an application-specific rollup or do you just want cheap transactions? In the latter case — deploying on Arbitrum or OP Stack will take days, not months.
L2 Typology: What Exactly We're Building
Optimistic Rollup
Transactions execute off-chain, result (state root) is published to L1. It's assumed everything is honest — if someone found fraud, they submit a fraud proof within challenge window (7 days for Arbitrum, 7 days for OP Stack).
Pros: EVM-equivalence or close to it, mature frameworks (OP Stack, Arbitrum Orbit). Cons: 7-day withdrawal period to exit to L1. Natively solved via liquidity providers (bridges like Hop, Across).
Ready frameworks:
- OP Stack — used by Base, Mode, Zora, dozens of others. Open source, Superchain concept from Optimism.
- Arbitrum Orbit — for creating L3 on top of Arbitrum One/Nova.
ZK Rollup
Each batch of transactions is accompanied by zero-knowledge proof — mathematical proof of correctness. L1 verifies proof, not re-executing transactions.
Pros: Instant withdrawal finality (no challenge window), cryptographic guarantees instead of economic. Cons: Complexity — ZK proof generation requires specialized schemes. Not all EVM opcodes are efficiently provable.
Ready frameworks:
- Polygon CDK (Chain Development Kit) — for zkEVM-compatible chains
- zkSync ZK Stack — based on zkSync Era infrastructure
- Scroll SDK — for maximum EVM-equivalence
Validium
Like ZK Rollup, but data stored off-chain (Data Availability Committee or IPFS), not on L1. Cheaper, but weaker data availability guarantees.
Application-specific chain (not rollup)
Sometimes you don't need an L2 as a rollup, but a separate chain with its own consensus. Cosmos SDK is standard for this: Inter-Blockchain Communication (IBC) for cross-chain transfers, full control over governance and gas token.
Development on OP Stack: Detailed Breakdown
OP Stack — the most mature choice for EVM-compatible Optimistic Rollup. Let's review key components.
System Components
L1 (Ethereum)
├── OptimismPortal.sol — L1→L2 deposits, L2→L1 withdrawals
├── L2OutputOracle.sol — stores L2 state roots
├── DisputeGameFactory.sol — fault proof games (Cannon)
└── SystemConfig.sol — chain parameters
L2 (OP Stack chain)
├── op-node — consensus (reads L1, manages sequencer)
├── op-geth — execution (Geth fork)
├── op-batcher — publishes L2 transactions to L1 calldata/blobs
└── op-proposer — publishes L2 output roots to L1
Deploying OP Stack Chain
# Clone Optimism monorepo
git clone https://github.com/ethereum-optimism/optimism.git
cd optimism
git checkout op-contracts/v1.6.0
# Install dependencies
pnpm install
make op-node op-batcher op-proposer
Chain configuration via deploy-config.json:
{
"l1ChainID": 1,
"l2ChainID": 42069,
"l2BlockTime": 2,
"l1BlockTime": 12,
"maxSequencerDrift": 600,
"sequencerWindowSize": 3600,
"channelTimeout": 300,
"p2pSequencerAddress": "0x...",
"batchInboxAddress": "0xff00000000000000000000000000000000042069",
"batchSenderAddress": "0x...",
"l2OutputOracleSubmissionInterval": 120,
"l2OutputOracleStartingBlockNumber": 0,
"l2OutputOracleStartingTimestamp": ...,
"l2OutputOracleProposer": "0x...",
"l2OutputOracleChallenger": "0x...",
"finalizationPeriodSeconds": 604800,
"proxyAdminOwner": "0x...",
"baseFeeVaultRecipient": "0x...",
"l1FeeVaultRecipient": "0x...",
"sequencerFeeVaultRecipient": "0x...",
"enableGovernance": false,
"governanceTokenSymbol": "OP",
"governanceTokenName": "Optimism",
"eip1559Denominator": 50,
"eip1559Elasticity": 6,
"l2GenesisBlockGasLimit": "0x2faf080",
"l2GenesisBlockBaseFeePerGas": "0x3B9ACA00"
}
Deploy L1 contracts:
cd packages/contracts-bedrock
forge script scripts/deploy/Deploy.s.sol:Deploy \
--rpc-url $L1_RPC_URL \
--broadcast \
--private-key $DEPLOYER_PRIVATE_KEY \
--slow
Data Availability: Calldata vs EIP-4844 Blobs
Before EIP-4844 (Dencun upgrade, March 2024), L2 published data to L1 calldata — expensive (~$1–5 per batch). After Dencun — via blobs (EIP-4844): special data type in block with separate gas market. Blobs cheapen data publication by ~10–100x.
// op-batcher uses blobs automatically if L1 supports them
// Config in op-batcher:
--data-availability-type blobs // or 'calldata' for forced fallback
--max-channel-duration 1800 // max 1800 L2 blocks in one channel
For high-load L2: if blob space is insufficient (blob gas market congested) — configure fallback to EigenDA or Celestia as external DA layer. This is validium approach, but with better guarantees than pure off-chain.
Sequencer: Centralization and Consequences
Classical OP Stack has single sequencer — trusted, centralized. This is an acknowledged tradeoff: convenience for centralization.
For production projects — consider shared sequencer options:
- Espresso Systems — decentralized sequencer for OP Stack chains
- Based rollup — sequencer-free, blocks proposed by L1 validators directly
Or minimally: sequencer behind multisig with monitoring and automatic force-include for users ignored by sequencer.
Bridge: Standard and Security
L1StandardBridge and L2StandardBridge — built-in OP Stack bridges. For custom tokens:
// Custom ERC-20 with standard bridge support
contract MyL2Token is OptimismMintableERC20 {
constructor(
address _bridge,
address _remoteToken
) OptimismMintableERC20(_bridge, _remoteToken, "MyToken", "MTK") {}
}
Never deploy custom bridge without careful audit. Most notable Web3 hacks are bridges: Ronin ($625M), Wormhole ($320M), Nomad ($190M). Use standard bridge, add custom logic only when absolutely necessary.
Sequencer Economics
L2 network earns:
- L2 gas fees — users pay for execution on L2
- L1 data cost — sequencer spends on publishing data to L1
Margin = L2 fees − L1 publishing cost. EIP-4844 blobs drastically reduced L1 cost, allowing low gas price on L2 while staying profitable.
L2 Transaction Fee = L2 Base Fee × Gas Used + L1 Data Fee
L1 Data Fee = (tx data size × 16) × L1 Base Fee × overhead_scalar
Calculator for your chain: l2fees.info — useful reference point.
ZK Path: zkSync ZK Stack
If chose ZK Rollup — ZK Stack from Matter Labs:
# ZK Stack CLI
curl -L https://raw.githubusercontent.com/matter-labs/zksync-era/main/zkstack_cli/zkstackup/install | bash
zkstackup
# Create new chain
zkstack ecosystem create
zkstack chain create --chain-name mychain --chain-id 12345
ZK Stack uses Boojum — PLONK-based proof system with custom gates. Proof generation takes minutes and requires GPU for production speeds (~RTX 4090 or A100).
Real proof generation times:
- CPU (32 cores): ~15–30 minutes per batch
- RTX 4090: ~2–5 minutes
- A100: ~1–2 minutes
For project with frequent transactions — GPU prover is mandatory.
Timeline and Financial Estimates
| Phase | OP Stack | ZK Stack | Cosmos SDK |
|---|---|---|---|
| Deploy and setup | 1–2 weeks | 2–4 weeks | 4–8 weeks |
| Bridge + explorer | 1–2 weeks | 2–3 weeks | 2–4 weeks |
| Infrastructure audit | 2–4 weeks | 4–8 weeks | 4–8 weeks |
| Production-ready | 1–2 months | 2–4 months | 3–6 months |
Infrastructure budget (monthly):
- L1 gas for sequencer: $500–$5000/month (depends on activity)
- RPC providers (L1 and L2): $500–$2000/month
- Servers (sequencer, nodes): $500–$3000/month
- Block explorer (Blockscout self-hosted): $200–$500/month
Your own L2 is not one-time work, it's operational responsibility. Someone must watch nodes, update clients, monitor bridge, react to incidents 24/7.







