ZK-rollups have long been regarded as the endgame of Ethereum scaling. However, despite their importance to the Ethereum scaling roadmap, there is still widespread uncertainty about several key points:

  1. What exactly is a zk-rollup?
  2. What differs between application-specific and general purpose rollups?
  3. What is a zk-EVM rollup? What do terms like EVM-equivalent and EVM-compatible actually mean, and how do they apply to rollups?
  4. What is the current state of the zk-rollup ecosystem, and what does that mean for my project?

If you’re a developer looking to understand the next phase of Ethereum scaling, this article will (hopefully) help.

ZK-Rollups

ZK-rollups are made possible by a simple observation: proof systems like STARKs or SNARKs allow for a linear number of statements to be verified with sub-linear processing (e.g. 1000 statements → 10 verifier checks, 10,000 statements → 11 verifier checks). We can use this property to create massively scalable blockchain transaction processing as follows:

  1. Users lock their assets in a zk-rollup smart contract on L1
  2. Users submit transactions involving those assets to an L2 sequencer, which gathers them into ordered batches, and generates a validity proof (e.g. a STARK/SNARK) and aggregated state update for each batch
  3. This state update and proof are submitted to and verified by our L1 zk-rollup smart contract, and used to update our L1 state
  4. Users can use this L1 state (subject to different data availability mechanisms) to retrieve their assets, allowing for full self-custody and “Ethereum security”

Simplified ZK-Rollup Architecture

The gas cost of verifying the proof is sublinear to the number of transactions being proven, allowing for vastly more scale compared to direct usage of L1. To understand this process in more granular detail, I’d recommend Vitalik’s Incomplete Guide to Rollups or Delphi’s newly released Complete Guide to Rollups.

Application-Specific Rollups

So far, all production-grade zk-rollups have been what we call “application-specific rollups’’. In an application specific rollup, the rollup supports a fixed number of “state transitions” (e.g. trading) defined by the rollup operator. This is incredibly useful for hyper-optimizing common use cases e.g.:

Application-specific rollups are fantastic at scaling particular, well-understood problems. If your needs as a project can be met by an application-specific rollup, you will likely get better performance, better UX and better pricing for your use case, as their lack of generalisation is a huge advantage. At Immutable, for instance, we are able to eliminate gas fees by subsidising free NFT mints and transfers with a fee on NFT trades — a tradeoff which is only possible due to the predictable nature of the rollup’s state transitions.

However, many projects want to be able to create their own custom logic and smart contracts, independent of the rollup operator, which isn’t possible in an application-specific rollup. Additionally, many DeFi projects need “composability”, or the ability to atomically interact with other projects (e.g. many DeFi projects use Uniswap as a price oracle). Composability is only possible when your rollup supports not only custom code, but native smart contracts which can be deployed by any user. To achieve this, we’ll need to modify the architecture of our zk-rollup to generalize each of our components.