Skip to content

This repository implements a generic CCIP-Read gateway for fetching state proofs of data on other EVM chains. The intended use is for contracts on L1 to be able to fetch and verify data from contracts on L2 in a read context.

License

Notifications You must be signed in to change notification settings

ensdomains/evmgateway

Repository files navigation

EVM CCIP-Read Gateway

This repository implements a generic CCIP-Read gateway framework for fetching state proofs of data on other EVM chains. This allows L1 smart contracts to fetch and verify state from L2s. The library is built to be as modular and interchangeable as possible. This means:

  • Anyone can operate their own gateway, but...
  • Only one gateway needs to be operated for each chain, regardless of the applications requesting data from it.
  • Gateways do not need to be trusted; their responses are fully verified on L1.
  • Contracts can fetch L2 state using a simple builder interface and callbacks.
  • Contracts can change targets (eg, a different L2) just by swapping out the address of a verifier contract for another.

While this functionality is written primarily with read calls in mind, it also functions for transactions; using a compliant library like Ethers, a transaction that includes relevant L2 proofs can be generated and signed.

Usage

  1. Have your contract extend EVMFetcher.
  2. In a view/pure context, use EVMFetcher to fetch the value of slots from another contract (potentially on another chain). Calling EVMFetcher.fetch() terminates execution and generates a callback to the same contract on a function you specify.
  3. In the callback function, use the information from the relevant slots as you see fit.

Example

The example below fetches another contract's storage value testUint.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import { EVMFetcher } from '@ensdomains/evm-verifier/contracts/EVMFetcher.sol';
import { EVMFetchTarget } from '@ensdomains/evm-verifier/contracts/EVMFetchTarget.sol';
import { IEVMVerifier } from '@ensdomains/evm-verifier/contracts/IEVMVerifier.sol';

contract TestL2 {
    uint256 testUint; // Slot 0
    
    constructor() {
        testUint = 42;
    }
}

contract TestL1 is EVMFetchTarget {
    using EVMFetcher for EVMFetcher.EVMFetchRequest;

    IEVMVerifier verifier;
    address target;

    constructor(IEVMVerifier _verifier, address _target) {
        verifier = _verifier;
        target = _target;
    }

    function getTestUint() public view returns(uint256) {
        EVMFetcher.newFetchRequest(verifier, target)
            .getStatic(0)
            .fetch(this.getSingleStorageSlotCallback.selector, "");
    }

    function getSingleStorageSlotCallback(bytes[] memory values, bytes memory) public pure returns(uint256) {
        return uint256(bytes32(values[0]));
    }
}

Packages

This is a monorepo divided up into several packages:

A framework for constructing generic CCIP-Read gateways targeting different EVM-compatible chains. This repository implements all the functionality required to fetch and verify multiple storage slots from an EVM-compatible chain, omitting only the L2-specific logic of determining a block to target, and verifying the root of the generated proof.

An instantiation of evm-gateway that targets Ethereum L1 - that is, it implements a CCIP-Read gateway that generates proofs of contract state on L1.

This may at first seem useless, but as the simplest possible practical EVM gateway implementation, it acts as an excellent target for testing the entire framework end-to-end.

It may also prove useful for contracts that wish to trustlessly establish the content of storage variables of other contracts, or historic values for storage variables of any contract.

A Solidity library that verifies state proofs generated by an evm-gateway instance. This library implements all the functionality required make CCIP-Read calls to an EVM gateway and verify the responses, except for verifying the root of the proof. This library is intended to be used by libraries for specific EVM-compatible chains that implement the missing functionality.

A complete Solidity library that facilitates sending CCIP-Read requests for L1 state, and verifying the responses.

This repository also contains the end-to-end tests for the entire stack.

An instantiation of evm-gateway that targets Optimism. Combined with op-verifier, makes it possible for L1 contracts to fetch contract state data from Optimism.

A complete Solidity library that facilitates sending CCIP-Read requests for Optimism state, and verifying the responses.

An instantiation of evm-gateway that targets Arbitrum. Combined with arb-verifier, makes it possible for L1 contracts to fetch contract state data from Arbitrum.

A complete Solidity library that facilitates sending CCIP-Read requests for Arbitrum state, and verifying the responses.

An instantiation of evm-gateway that targets Scroll. Combined with scroll-verifier, makes it possible for L1 contracts to fetch contract state data from Scroll.

A complete Solidity library that facilitates sending CCIP-Read requests for Scroll state, and verifying the responses.

How to setup locally

gh repo clone ensdomains/evmgateway
bun install # `@ensdomains/@ensdomains` not found error will be thrown
bun run workspace evm-gateway build
bun install
bun run test

Troubleshooting

Error HH12: Trying to use a non-local installation of Hardhat, which is not supported.

yarn test spawns hardhat test in the forked process. When hardhat command is installed under the node_modules of under each workspace, it complains that it's using locally installed hardhat. Remove hardhat from local node_modules and make sure it's only installed under the root node_modules

rm -rf *-*/node_modules/hardhat
rm bun.lockb
bun install

A guide on adding new chains

In a L2 rollup system, state hashes are stored on-chain, along with the transaction calls and arguments logged as calldata. a rollup has a mechanism to verify the state of their chain on L1, either instantly or optimistically.

ENS integration utilizes this mechanism in the gateway. The gateway retrieves the data from L2 along side with the proof (often via eth_getProof) and returns back to the caller. The caller passes the data to L1 resolver contract to verify its state and data(more detail). As long as L1 contract can verify the state and storage of the L2 data, users no longer need to trust the gateway itself. If a gateway service is compromised, the worst can happen is that the gateway stops responding data ( when that happens, the owner of the resolver can simply startup new gateway and update the L1 contract to return the new gateway address). The parent owner does not even have to host the gateway services by themselves but can use third party gateway services.

To assess whether a L2 rollup system can integrate with ENS, please see the following steps.

  1. Does the new chain use same address format as the ones used in Ethereum? = Some ZKRollup chains use different address format. If that's the case, you need to add the wallet address format into ENS multicoin type. Please refer to Starknet support PR as a reference.
  2. Does RPC of the chain return eth_getProof? If not, it requies a way to retrieve a storage proof to verify on Ethereum L1
  3. Does the rollup contract have a function to return information of the latest L2 block committed to Ethereum L1? For Optimistic Rollup, it needs both the committed and finalised (after challenge period) block information. The blockhash is required to call eth_getProof equivalent function on L2
  4. Is there a way to verify on L1 contract that the state root returned from L2 is valid?
  5. Is there a way to verify that the storageProof is included in the state root? For Optimistic rollups, we can use Lib_SecureMerkleTrie library developed by the optimism team. If the chain doesn't support Patricia Merkle Trie, it needs own library

Integration examples

Here are some of the PoC examples provided by other chains and the actual integration pull requests describing the basic flow.

About

This repository implements a generic CCIP-Read gateway for fetching state proofs of data on other EVM chains. The intended use is for contracts on L1 to be able to fetch and verify data from contracts on L2 in a read context.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published