Skip to content

Instantly share code, notes, and snippets.

@oed
Created November 21, 2025 13:42
Show Gist options
  • Select an option

  • Save oed/6ddfc9ca5f753852a72bd264fc213701 to your computer and use it in GitHub Desktop.

Select an option

Save oed/6ddfc9ca5f753852a72bd264fc213701 to your computer and use it in GitHub Desktop.

Goal

Currently the way to use sourcify is through the repo.sourcify.dev domain. This app talks to the sourcify backend in order to resolve metadata about the contract. This is fragile because if the sourcify backend were to for some reason be censored or disappear access to smart contract metadata would not be possible. This document outlines an approach to publishing contract metadata directly on Ethereum using ENS+IPFS, without having to make any additional on-chain transactions. The core idea is to resolve <address>.<chain-id>.sourcify.eth to a website with full verification of smart contract at that address.

Spec

The overall approach relies on the on-chain contract metadata hash, a custom ENS resolver, as well as precomputing IPFS objects off-chain.

Custom ENS resolver

In order to enable domains such as https://0x99acdb2946b7240aac9aeb290cc0af145c48007e.1.sourcify.eth.limo to resolve we need to implement a custom ENS resolver. More specifically we need to implement a wildcard resolver (ENSIP-10), so that even names without a specific resolver can be handled by a parent resolver, e.g. all domains that match *.example.eth can be handled.

We want to support two levels of subdomain resolution:

  1. chain-id - since we want to support multiple networks
  2. address - the contract address itself

For (1) we can use a static resolver that just points to a wildcard resolver for addresses. On mainnet this is trivial, just use the address of that resolver. To support L2 networks we need to point to a resolver on that network. We will cover that in a later section. For now let's focus on how we would implement the wildcard resolver

Contract wildcard resolver

According to the ENSIP-10 spec the resolver will be called like this: result = resolver.resolve(dnsencode(name), calldata) We can parse the DNS encoded name and parse the contract address. Then we find the contract code (i.e. address(contractAddress).code) and parse the contract metadata hash. We can convert this hash to a CID in the following way:

function hashToCid(bytes32 metadataHash) internal pure returns (bytes memory) {
    // Create multihash: 0x1b (keccak-256) + 0x20 (32 bytes) + hash
    bytes memory multihash = abi.encodePacked(hex"1b20", metadataHash);

    // Create CIDv1: 0x01 (version) + multihash
    return abi.encodePacked(hex"01", multihash);
}

Now if we only returned this CID the resolver would simply result in the user loading the metadata.json, but we want to return a functioning webapp similar to the existing repo.sourcify.dev website. This can be achieved in the following way:

  1. The resolver contract should hold two variables:
    1. indexHtmlCid - the CID of the index.html of the webapp
    2. assets - the CID of a folder containing assets needed by the webapp, e.g. javascript, css, etc.
  2. The resolver takes these two variables along with the metadata.json CID and constructs an IPFS UnixFs folder with the following structure
    {
      "metadata.json": <metadata-cid>,
      "index.html": <index-html-cid>,
      "assets": <asset-folder-cid>
    }
    This can be easily achived using the UnixFs portion of the CIDv1.sol library.
  3. Next we hash the folder constructed in (2) and calculate it's CID
  4. Finally the resolver encodes the CID in the ENS contenthash format and returns it as the resolution result

L2 support

In order to support chainIds other than 1(mainnet) we need to deploy the wildcard resolver on each L2, then point to it using the CCIP-read standard. This is a system that enables off-chain and L2 support for name resolution in ENS. We won't cover how to do it here because it is already extensively documented by ENS.

Static webapp

The webapp mentioned above is a generalized webapp with a similar look and feel to the current contract page of repo.sourcify.dev. It has a few requirements:

  • Loads contract metadata from /metadata.json
  • All javascript, css, fonts, and other assets needs to be loaded from /assets/*
  • Should ideally verify the contract source code client side in the users browser

IPFS folder precomputation

In order for urls like https://0x99acdb2946b7240aac9aeb290cc0af145c48007e.1.sourcify.eth.limo to resolve to an actual website, the folder created by the wildcard resolver also needs to be available off-chain (in particular, it has to be retrievable over IPFS). We can achieve this by running an off-chain process that precomputes it and stores it in an IPFS node (ideally the node(s) sourcify already operate). It likely makes sense to do this for all contracts that have been verified on sourcify.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment