RollupNC

The Zero Knowledge Rollup (P.S. its not even zero knowledge you're just using some ZK proofs inside of a proof carrying rollup or validium)

This section is not a full-fledged definition of the use of Circom for proof-carrying rollups. It is meant to be an exploration of and introduction to the concept. We are by no means experts, so we are doing our best to provide this information as we have aggregated it and currently understand its application. Please reach out to us or the EF PSE Discord (see ECOSYSTEM > Communities to Join > Discord) for questions, comments, or concerns on this content.

RollupNC

Original Code base - Original Codelabs Demo - BattleZips 2022 Updated Code base

The Codelabs demo is highly recommended as a primer to the underlying mechanics of RollupNC. However, the Circom code used is somewhat out of date and will not work if compiled in Circom 2.0. You can use the BattleZips updated code base to reconcile these issues, or to simply deploy and run the RollupNC project for yourself quickly.

What is RollupNC?

From the RollupNC Readme:

SNARKs can generate succinct proofs for large computations, which are much faster and computationally easier to verify than they are to compute. This provides a way to "compress" expensive operations by computing them off-chain in a SNARK, and then only verifying the proof on-chain.

RollupNC is an implementation of rollup in which the relayer does not publish transaction data to the main chain, but only publishes the new Merkle root at every update. This provides gas savings but not data availability guarantees: we assume the operator will always provide data to users so they can update their leaf.

RollupNC is a very simplistic proof-carrying rollup demonstrating the use of Zero Knowledge proofs to perform batched, compressed, verifiable computations off-chain whose validity can be proven quickly on-chain.

RollupNC is a very simple rollup- there are three actions a user can perform:

  • Deposit an arbitrary ERC20 or Gas token in the ZK L2 contract

  • Transfer tokens from one account to another account on Layer 2

  • Withdraw tokens from L2, out of the ZK L2 contract, to an Ethereum account

There is a single sequencer responsible for committing state updates to the layer 2 network in this code base. This means that the sequencer could censor new state updates from occurring.

Moving Beyond RollupNC with Circom: Hermez

The RollupNC functionality is highly limited - after all, the simple act of transferring tokens between accounts is not very useful. Polygon Hermez is a spiritual successor to RollupNC, containing all of the functionality in RollupNC and much more:

  • Network validation rights tied to proof of stake

  • Network fees for users' actions

  • Users can swap tokens like an AMM

BattleZips' RollupNC Update

In the summer of 2022, BattleZips did an exploratory upgrade of the RollupNC codebase for the current version of Circom. Some changes, like naming or use of Poseidon over MiMC, are inconsequential to this compendium.

The primary improvement BattleZips makes on RollupNC is the creation of a modern unit test showing a heavily simplified experience for working with the RollupNC circuits. Chiefly, our use of @zk-kit/incremental-merkle-tree shows a standardized, efficient way to work with the many merkle trees needed to use the RollupNC circuits and contracts.

it('Process Batch #1 (4 new balance leaves)', async () => {
    // construct expected values
    const emptyLeaf = L2Account.emptyRoot(poseidon)
    const coordinatorPubkey = accounts.coordinator.L2.pubkey.map(point => F.toObject(point));
    const coordinatorLeaf = poseidon([...coordinatorPubkey, 0, 0, 0]);
    tree = new IncrementalMerkleTree(_poseidon, 4, 0);
    tree.insert(emptyLeaf);
    tree.insert(F.toObject(coordinatorLeaf));
    tree.insert(accounts.alice.L2.root);
    tree.insert(accounts.bob.L2.root);
    const expected = {
        oldRoot: zeroCache[zeroCache.length - 1],
        newRoot: tree.root
    }
    // construct transaction
    const position = [0, 0];
    const proof = [zeroCache[2], zeroCache[3]];
    const tx = rollup.connect(accounts.coordinator.L1).processDeposits(2, position, proof);
    // verify execution integrity
    await expect(tx).to.emit(rollup, "ConfirmDeposit").withArgs(
        expected.oldRoot,
        expected.newRoot,
        4
    );
})

Before, there were many supporting utility functions. While we still need many for transaction and account management, we can offload the work done on merkle trees/ merkle proofs to the imported zk-kit incremental merkle tree.

Last updated