Code Index
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.28;
interface IERC7744 {
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 ERC7744 is IERC7744 {
mapping(bytes32 => address) private index;
function isValidContainer(address container) private view returns (bool) {
bytes memory code = container.code;
bytes32 codeHash = container.codehash;
bytes32 eip7702Hash = bytes32(0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329);
// Contract should have non-empty code and valid codehash
return (code.length > 0 && codeHash != bytes32(0) && codeHash != eip7702Hash);
}
/**
* @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 or if returns EIP7702 hash
*/
function register(address container) external {
address etalon = index[container.codehash];
require(isValidContainer(container), "Invalid container");
if (etalon != address(0)) {
if (isValidContainer(etalon)) revert alreadyExists(container.codehash, container);
}
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: 0xC0dE1D2F7662c63796E544B2647b2A94EE658E07
using CREATE2
via the deterministic deployer at 0x4e59b44847b379578588920ca78fbf26c0b4956c
with a salt of 0x70b27c94ed692bfb60748cee464ef910d4bf768ac1f3a63eeb4c05258f629256
is obtained by seeking a vanity address with meaningful name “Code ID (0xC0dE1D
).
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.
EIP-7702: The index does not index the EIP-7702 delegated accounts, as it is a special case and its bytecode is not deterministic. During attempt to register, it checks EXTCODEHASH
for new address and if value is 0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329
(keccak256(0xef01)
) it will revert.
Self-Destruct Contracts: In case of indexed contract storage becomes empty, contracts may be re-indexed, During register function call, iF contract is already indexed, we run isValidContainer
check on the indexed address. It it fails, re-indexing is allowed with a newly specified address.
Copyright
Copyright and related rights waived via CC0.