Abstract

This EIP defines a standard interface for indexing smart contracts on Ethereum by their bytecode hash. This enables trustless discovery and verification of contract code, facilitating use cases like bytecode signing, whitelisting, and decentralized distribution mechanisms.

Motivation

Existing contract discovery relies on addresses, which are non-deterministic and can be obfuscated through proxies. Indexing by bytecode hash provides a deterministic and tamper-proof way to identify and verify contract code, enhancing security and trust in the Ethereum ecosystem.

Consider a security auditor who wants to attest to the integrity of a contract’s code. By referencing bytecode hashes, auditors can focus their audit on the bytecode itself, without needing to assess deployment parameters or storage contents. This method verifies the integrity of a contract’s codebase without auditing the entire contract state.

Additionally, bytecode referencing allows whitelist contracts before deployment, allowing developers to get pre-approval for their codebase without disclosing the code itself, or even pre-setup infrastructure that will change it behavior upon adding some determined functionality on chain.

For developers relying on extensive code reuse, bytecode referencing protects against malicious changes that can occur with address-based referencing through proxies. This builds long-term trust chains extending to end-user applications.

For decentralized application (dApp) developers, a code index can save gas costs by allowing them to reference existing codebases instead of redeploying them, optimizing resource usage. This can be useful for dApps that rely on extensive re-use of same codebase as own dependencies.

Why this registry needs to be an ERC

The Code Index is essential for trustless and secure smart contract development. By standardizing the interface for indexing contracts by their bytecode, developers can easily integrate this feature into their smart contracts, enhancing the security and trustworthiness of the Ethereum ecosystem.

Its simplicity and generic nature make it suitable for a wide range of applications. The ability to globally reference the same codebase makes it an ideal candidate for standardization.

Ultimately, this feature should be incorporated into EIP standards, as it is a fundamental building block for trustless and secure smart contract development. This standard is a step towards this goal.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

// SPDX-License-Identifier: CC0-1.0
pragma solidity =0.8.20;

interface ICodeIndex {
    event Indexed(address indexed container, bytes32 indexed codeHash);
    error alreadyExists(bytes32 id, address source);

    function register(address container) external;

    function get(bytes32 id) external view returns (address);
}

/**
 * @title Byte Code Indexer Contract
 * @notice You can use this contract to index contracts by their bytecode.
 * @dev This allows to query contracts by their bytecode instead of addresses.
 * @author Tim Pechersky (@Peersky)
 */
contract CodeIndex is ICodeIndex {
    mapping(bytes32 => address) private index;

    /**
     * @notice Registers a contract in the index by its bytecode hash
     * @param container The contract to register
     * @dev `msg.codeHash` will be used
     * @dev It will revert if the contract is already indexed
     */
    function register(address container) external {
        address etalon = index[container.codehash];
        if (etalon != address(0)) {
            revert alreadyExists(container.codehash, etalon);
        }
        index[container.codehash] = container;
        emit Indexed(container, container.codehash);
    }

    /**
     * @notice Returns the contract address by its bytecode hash
     * @dev returns zero if the contract is not indexed
     * @param id The bytecode hash
     * @return The contract address
     */
    function get(bytes32 id) external view returns (address) {
        return index[id];
    }
}

Deployment method

The CodeIndex contract is deployed at: 0xc0D31d398c5ee86C5f8a23FA253ee8a586dA03Ce using CREATE2 via the deterministic deployer at 0x4e59b44847b379578588920ca78fbf26c0b4956c with a salt of 0x220a70730c743a005cfd55180805d2c0d5b8c7695c5496100dcffa91c02befce is obtained by seeking a vanity address with meaningful name “Code ID (c0D31d).

Rationale

Bytecode over Addresses: Bytecode is deterministic and can be verified on-chain, while addresses are opaque and mutable.

Reverting on re-indexing: There is small, yet non-zero probability of hash collision attack. Disallowing updates to indexed location of bytecode coupes with this.

Simple Interface: The interface is minimal and focused to maximize composability and ease of implementation.

Library Implementation: Implementing this as a library would limit its impact, making code reuse more difficult and lacking a single, official source of truth. By establishing this as an ERC, we ensure standardization and widespread adoption, driving the ecosystem forward.

Reference Implementation

Reference implementation of the Code Index can be found in the assets folder. There you can find the interface and the implementation of the Code Index.

Security Considerations

Malicious Code: The index does NOT guarantee the safety or functionality of indexed contracts. Users MUST exercise caution and perform their own due diligence before interacting with indexed contracts.

Storage contents of registered contracts: The index only refers to the bytecode of the contract, not the storage contents. This means that the contract state is not indexed and may change over time.

Copyright and related rights waived via CC0.