Writing an Ethereum smart contract today means more than writing Solidity. You choose between mainnet and layer 2s, design for gas and storage costs shaped by recent upgrades, decide whether the contract can ever be upgraded, and plan verification, monitoring and audits. This guide focuses on the Ethereum-specific decisions; the general principles live in the broader smart contract development guide.
Where to deploy: mainnet or layer 2
Ethereum mainnet offers the highest security and the deepest liquidity, at higher fees. Rollups such as Arbitrum, Optimism, Base and ZKsync Era run the same EVM (with small differences) at a fraction of the cost and settle to mainnet. Since the Dencun upgrade in 2024 introduced blob data (EIP-4844), rollup fees fell sharply, and most consumer applications now deploy on layer 2s first.
| Deploy on | Good for | Watch out for |
|---|---|---|
| Ethereum mainnet | High-value DeFi, protocol core contracts, assets that must be maximally neutral | Gas costs shape every design decision |
| Optimistic rollups | General dApps, DeFi, consumer apps | Withdrawal delays to L1; sequencer centralization |
| ZK rollups | Apps wanting faster L1 finality | Some EVM differences; verify opcode and precompile support |
Deploying the same contracts on several chains is common. Use deterministic deployment (CREATE2 through a standard factory) if you want identical addresses, and never assume a contract on one chain is the same as one at the same address on another. See scaling with layer 2s for the trade-offs.
Recent upgrades that change how you write contracts
- Transient storage (EIP-1153), added in Dencun, gives cheap storage that clears at the end of the transaction. It is ideal for reentrancy locks and intra-transaction accounting.
- SELFDESTRUCT restrictions (EIP-6780) mean a contract can only be destroyed in the transaction that created it. Do not design upgrade or cleanup patterns around it.
- EIP-7702, part of the Pectra upgrade in 2025, lets ordinary accounts delegate to contract code. Your contracts can no longer assume that a caller with no code is a human-controlled wallet, and checks such as
tx.origin == msg.senderare unreliable as "not a contract" tests.
Designing for gas
Storage dominates costs. Writing a new storage slot is far more expensive than updating one, and reading cold storage costs more than warm. Practical rules: pack related small values into one slot, use events rather than storage for data only needed off-chain, avoid unbounded loops over user-controlled arrays, and prefer pull-based payments over pushing to many recipients. Measure with Foundry's gas reports instead of guessing, and remember that on layer 2s, calldata and data-posting costs can matter more than execution.
Tooling
Foundry (forge, cast, anvil) is the default for many teams: tests in Solidity, fast fuzzing and invariant testing, and mainnet forking. Hardhat remains popular for TypeScript-heavy teams. OpenZeppelin Contracts provide audited implementations of ERC-20, ERC-721, ERC-1155, ERC-4626 vaults, access control and proxies. Static analyzers such as Slither catch common issues early. Verify source on block explorers (Etherscan-family and Sourcify) at deployment so users can read what they interact with.
Upgradeability: decide deliberately
Immutable contracts are simplest to trust. Upgradeable proxies (UUPS or transparent proxies) let you fix bugs but give an admin power over user funds. If you upgrade, use ERC-7201 namespaced storage to avoid layout collisions, put the upgrade role behind a multisig with a timelock, and document who holds it. Many protocols make core contracts immutable and keep only peripheral contracts upgradeable.
A development workflow that holds up
- Write a specification with invariants ("total shares always match total assets").
- Implement on top of standard libraries; avoid clever code.
- Test with unit, fuzz and invariant tests, plus fork tests against real protocols you integrate.
- Run static analysis and an internal review, then an external smart contract audit.
- Deploy with scripted, reproducible deployments; verify source; transfer admin roles to a multisig.
- Monitor events and invariants in production and run a bug bounty.
For language-level detail see Solidity development, and for token contracts specifically, Ethereum token development.
Frequently asked questions
How much does an Ethereum smart contract cost to build?
A standard token can take days; a DeFi protocol with novel logic can take a senior team months plus several audits. Effort scales with novelty and the value at risk more than with lines of code.
Solidity or Vyper?
Solidity has the larger ecosystem, tooling and auditor pool. Vyper is a solid choice for teams that value its simplicity, and several major protocols use it.
Do contracts on Ethereum work unchanged on layer 2s?
Usually, but check differences in block numbers and timestamps, precompiles, gas pricing and chain-specific system contracts. Always test on the target chain.
Can a deployed contract be changed?
Not its code, unless it was deployed behind a proxy. That is why testing and audits happen before deployment.