Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
317 changes: 317 additions & 0 deletions ensips/24.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
---
description: Defines a standard set of text records and a compiled-metadata resolver profile for smart contract metadata in ENS
contributors:
- nischal.eth
- csvensson.eth
ensip:
created: '2025-09-05'
status: draft
---

# ENSIP-24: Contract Metadata Standard and Text Records

## Abstract

This ENSIP extends [ENSIP-5: Text Records](https://docs.ens.domains/ensip/5) and is inspired by [ENSIP-18: Profile Text Records](https://docs.ens.domains/ensip/18) but for smart contracts. It defines a set of text records and a new compiled-metadata resolver profile that should be used for smart contract metadata information, along with the format that each should have.

## Motivation

While ENS is predominantly used for naming Externally Owned Accounts (EOAs) and storing user profile data, it has seen limited adoption for contract-related purposes. Although ENS names can resolve to contract addresses and [contracts can claim primary names](https://docs.ens.domains/web/naming-contracts/), the potential for storing rich metadata within ENS records remains largely unexplored.

[ENSIP-4](https://docs.ens.domains/ensip/4) provides a precedent by allowing contract ABIs to be stored and retrieved on-chain. However, a contract is defined by much more than just its ABI and smart contracts lack a standardized on-chain way to store metadata that describes themselves. ENSIP-4 also predates source code verification services such as Sourcify that have flourished in recent years.

Storing critical metadata including source code and potentially audit details directly in ENS text records would be invaluable for users, as it enables retrieval without reliance on centralized third-party servers.

### The Key Benefits: Trust, Consistency, and Usability

- **Consistency Across Platforms**: A single, on-chain source of truth ensures that all applications display the same verified information, creating a consistent experience across wallets, chain explorers, dApps, etc.
- **Trust and Verification**: By storing links to source code through compiled-metadata and audits on-chain, users can verify a contract's integrity independently.
- **Discoverability and Connection**: The standard makes it easy to find official documentation, project websites, and social links, directly connecting the on-chain contract to its off-chain community and developers.
- **Usability**: A rich, machine-readable, and human-friendly digital identity for any contract, anchored to its ENS name.

## Specification

This specification defines a standard set of text records for storing smart contract metadata and a new resolver profile for compiled-metadata field in ENS Resolvers. It details the format for each record and new `CompiledMetadata` Interface, covering all essential information such as source code verification and security audits.

The following JSON object is a sample contract metadata structure:

```json
{
"name": "My Awesome App",
"description": "A token that demonstrates best practices for metadata.",
"avatar": "ipfs://QmRRPWG96cmgTn2qSzjwr2...",
"url": "https://myproject.com",
"category": "defi",
"license": "MIT",
"docs": "https://docs.myproject.com",
"compiled-metadata": "ipfs://QmbRQF3HA9eZ8ZLwyU...",
"audits": [
{
"auditor": "OpenZeppelin",
"report": "ipfs://QmAuditReportCID..."
}
],
"proxy": {
"type": "erc1967",
"target": "0x1234...cdef"
}
}
```

General-purpose fields like `alias` (name), `description`, `avatar` and `url` are already established through community standards (ENSIP-5, ENSIP-12 and ENSIP-18).

This specification introduces the following new keys:
- `category`: The category under which the contract lies (e.g., defi, gaming, social, utility)
- `license`: The software license of the contract
- `docs`: A link to the contract's documentation
- `compiled-metadata`: URI to [contract metadata file](https://docs.soliditylang.org/en/latest/metadata.html#contract-metadata) generated by Solidity or Vyper compiler
- `audits`: An array of security audit reports
- `proxy` (optional): If the contract is a proxy, this defines its type and target address

And a new resolver profile:
- `compiled-metadata`: A multichain supported resolver interface that points to or stores the compiled metadata of smart contracts for various types of chain. Example - Ethereum (compiled with Solidity or Vyper) or other L1 chains like Solana, Avalanche, Sui, etc.

### Contract Keys

#### Alias
- **Description**: [ENSIP-18 Alias](https://docs.ens.domains/ensip/18#alias)
- **Format**: [ENSIP-18 Alias Format](https://docs.ens.domains/ensip/18#alias)
- **Example**: `ENSRegistry`

#### Description
- **Description**: [ENSIP-18 Description](https://docs.ens.domains/ensip/18#description)
- **Format**: [ENSIP-18 Description Format](https://docs.ens.domains/ensip/18#description)
- **Example**: `ENS registry contract, main contract from where the ENS resolution starts`

#### Avatar
- **Description**: [ENSIP-12 Avatar](https://docs.ens.domains/ensip/12)
- **Format**: [ENSIP-12 Avatar Format](https://docs.ens.domains/ensip/12)
- **Example**: `ipfs://QmRRPWG96cmgTn2qSzjwr2qvfNEuhunv6FNeMFGa9bx6mQ`

#### URL
- **Description**: [ENSIP-18 URL](https://docs.ens.domains/ensip/18#url)
- **Format**: [ENSIP-18 URL Format](https://docs.ens.domains/ensip/18#url)
- **Example**: `https://app.ens.domains/`

#### Category
- **Description**: Category under which the contract lies. Major categories include: Tokens, DeFi, Gaming, DAO, Infrastructure, tools, utility, proxy, factory, etc.
- **Format**: Lowercase single word text
- **Example**: `utility`

#### License
- **Description**: The official software license under which the contract's source code is released
- **Format**: The official [SPDX license identifier](https://spdx.org/licenses/)
- **Example**: `MIT`

#### Docs
- **Description**: A link to the primary documentation for the smart contract, intended for developers and users
- **Format**: A valid HTTP, HTTPS, or IPFS URL
- **Example**: `https://docs.ens.domains/`

#### Audits
- **Description**: A record of security audits performed on the contract by third-party firms
- **Format**: A JSON array of objects, where each object contains the auditor's name and a report URI linking to the full audit document
- **Example**: `[{"auditor":"OpenZeppelin","report":"ipfs://Qm..."},{"auditor":"Consensys","report":"https://diligence.consensys.net/audits/..."}]`

#### Proxy
- **Description**: If the contract is a proxy, this defines its type and the address of the underlying implementation contract it delegates calls to
- **Format**: A JSON object with a type (e.g., "EIP-1967", "UUPS") and a target address
- **Example**: `{"type":"EIP-1967","target":"0x1234...cdef"}`

### Resolver Profile: Compiled Metadata

#### Description
Smart contract metadata generated by compilers (Solidity, Vyper, Rust, Move, etc.) for various blockchain platforms. Contains the contract's ABI/interface definition, documentation, compiler version, settings, and source code hashes necessary for independent verification and interaction. Supports multiple encoding formats and cross-chain metadata storage.

#### Multichain Support
The compiled metadata field supports contracts from different blockchain ecosystems through the use of coin types as defined in [SLIP-0044](https://github.com/satoshilabs/slips/blob/master/slip-0044.md). This enables storing and retrieving metadata for contracts deployed on:

- Ethereum & EVM chains (coin type 60): Solidity/Vyper compiled contracts
- Solana (coin type 501): Rust-based programs
- Avalanche C-Chain (coin type 9005): EVM-compatible contracts
- Sui (coin type 784): Move-based smart contracts
- Aptos (coin type 637): Move-based smart contracts
- Near (coin type 397): Rust/AssemblyScript contracts
- Polkadot/Substrate (coin type 354): Rust-based pallets and smart contracts
- Flow (coin type 539): Cadence smart contracts
- And other blockchain platforms following SLIP-0044 registry

#### Supported Encodings
To accommodate different use cases and storage constraints, several encoding formats are supported:

| ID | Format | Description |
|----|---------|-------------|
| 1 | JSON | Uncompressed JSON (standard compiler output) |
| 2 | zlib-compressed JSON | Compressed JSON for reduced storage size |
| 4 | CBOR | Binary encoding, more compact and onchain-parseable |
| 8 | URI | External storage via URI (IPFS, HTTPS, Swarm, Arweave) |
| 16 | brotli-compressed JSON | Superior compression for storage optimization |

#### Examples
- **URI**: `"ipfs://QmbRQF3HA9eZ8ZLwyU..."`
- **Compressed JSON**: Binary data representing zlib-compressed metadata
- **Uncompressed JSON**: Direct compiler output

The following is a sample of the [contract metadata file generated by the Solidity compiler](https://docs.soliditylang.org/en/latest/metadata.html#contract-metadata), with some fields omitted for brevity:

```json
{
"compiler": {
"keccak256": "0x123...",
"version": "0.8.2+commit.661d1103"
},
"language": "Solidity",
"output": {
// Required: ABI definition of the contract
"abi": [/* ... */],
"devdoc": { /* ... */ }
},
"settings": {
"compilationTarget": {
"myDirectory/myFile.sol": "MyContract"
},
"libraries": {
"MyLib.sol:MyLib": "0x123123..."
}
// ... other compilation settings
},
// Required: Compilation source files/source units, keys are file paths
"sources": {
"settable": {
"content": "contract settable is owned { uint256 private x = 0; function set(uint256 _x) public { if (msg.sender == owner) x = _x; } }",
"keccak256": "0x234..."
},
"myDirectory/myFile.sol": {
"keccak256": "0x123...",
"license": "MIT",
// Required (unless "content" is used): Sorted URL(s)
// to the source file, IPFS URL recommended
"urls": [ "bzz-raw://7d7a...", "dweb:/ipfs/QmN..." ]
}
},
"version": 1
}
```

The key fields in this compiler-generated metadata file are `compiler.version`, `output.abi`, `settings`, and `sources`. This information is critical as it allows anyone to interact with the contract and independently verify its source code locally.

Similar compiled contract metadata file examples can be found for other chains apart from solidity.

- For Solana - [Contract PDA](https://solana.com/docs/programs/verified-builds#how-does-it-work) and [anchor data](https://explorer.solana.com/address/63XDCHrwZu3mXsw2RUFb4tbNpChuUHx4eA5aJMnHkpQQ/anchor-account).
- For Avalanche - Similar to Ethereum as contracts are written in Solidity, so they have compiled metadata.json file
- For Aptos and Sui - A combination of [Move.toml](https://move-book.com/concepts/manifest), bytecode module and source maps.

### CompiledMetadata Interface Spec

A new resolver interface is defined, consisting of the following method:

```solidity
/**
* @notice Returns compiled metadata for a contract in the requested encoding format
* @param node The ENS node to query
* @param coinType The SLIP-0044 coin type identifying the blockchain
* @param contentType Bitwise OR of acceptable encoding types
* @return contentType The encoding type used in the returned data
* @return data The compiled metadata in the specified encoding
*/
function compiledMetadata(
bytes32 node,
uint256 coinType,
uint256 contentType
) external view returns (uint256, bytes memory);
```

#### Interface Specifications

- **Interface ID**: `0xa0892b9d` for the `compiledMetadata(bytes32, uint256, uint256)` function, used for ERC-165 discovery
- **Parameters**:
- `node`: The ENS node to query
- `coinType`: SLIP-0044 coin type identifier for the target blockchain
- `contentType`: Bitfield representing the bitwise OR of all encoding types the caller will accept
- **Returns**:
- `contentType`: The encoding type used in the returned data (single bit set)
- `data`: The compiled metadata in the specified encoding format

#### Behavior Requirements

- Resolvers supporting this field MUST return `true` when `supportsInterface(0xa0892b9d)` is called
- The function must return metadata encoded using one of the requested formats
- Returns `(0, "")` if no metadata exists for the node or none of the requested formats are supported
- The compiledMetadata resolver profile is valid on both forward and reverse records

#### Recommended Format Priority

1. URI (type 8) - Most practical for large metadata files
2. Compressed formats (types 2, 16) - For moderate-sized onchain storage
3. CBOR (type 4) - For onchain parsing requirements
4. Uncompressed JSON (type 1) - Last resort due to size constraints

Implementers should support as many encoding formats as practical, with URI support recommended as the minimum implementation.

#### CompiledMetadata Lookup Process

When attempting to fetch compiled metadata based on an ENS name, implementers should follow this lookup sequence:

1. Query with specific coin type: First attempt a compiledMetadata lookup on the name itself with the requested coin type
2. Fallback to Ethereum: If that lookup returns no results, attempt lookup with the default coin type (60 - Ethereum mainnet)
3. Reverse lookup: If still no results, attempt a reverse lookup on the Ethereum address that the name resolves to, following similar to the ENSIP-4 process

Example usage:
```
// Query Ethereum contract metadata
const ethMetadata = await resolver.compiledMetadata(
node,
60, // Ethereum coin type (ENSIP-9)
8 // Request URI format
);

// Query Solana program metadata
const solMetadata = await resolver.compiledMetadata(
node,
501, // Solana coin type (ENSIP-9)
8 // Request URI format
);

// Query Sui module metadata
const suiMetadata = await resolver.compiledMetadata(
node,
784, // Sui coin type (ENSIP-9)
8 // Request URI format
);

// Query Aptos module metadata
const aptosMetadata = await resolver.compiledMetadata(
node,
637, // Aptos coin type (ENSIP-9)
8 // Request URI format
);
```

### Verifying a Contract

To verify a contract without relying on any third party or centralized server is possible via URLs or the IPFS hashes of the source files, as well as the compilation settings. Everything needed to reproduce a compilation can be obtained and then compared with the bytecode of the deployed contract. You can obtain the sources and compiler settings via the compiled-metadata file generated by Solidity or Vyper compiler.

Additional technical details can be found in the [Sourcify documentation](https://docs.sourcify.dev/) and [EIP-7834](https://ethereum-magicians.org/t/eip-7834-separate-metadata-section-for-eof/22138).

## Rationale

This proposal establishes a comprehensive metadata standard for smart contracts that goes beyond the ABI-only approach of ENSIP-4. The rationale includes:

1. **Comprehensive Metadata**: Modern contracts require more than just ABIs - documentation, audits, licensing, and verification data are equally important
2. **Multi-encoding Support**: Following ENSIP-4's proven approach while accommodating larger metadata files through URI storage
3. **Standardization**: Creating consistency across wallets, explorers, and dApps in how contract metadata is displayed
4. **Decentralization**: Reducing reliance on centralized services by storing critical metadata on-chain or in decentralized storage

## Backwards Compatibility

This specification is fully backwards-compatible as it does not alter any existing ENS functionality. Although we recommend deprecating [ENSIP-4: Support for contract ABIs](https://docs.ens.domains/ensip/4/) due to lack of significant adoption and high cost associated with on-chain storage of ABIs. Given the existence of the compiled-metadata field, which already stores the ABI, we anticipate limited future utility for ENSIP-4.

While there is a possibility that some of the proposed keys (e.g., docs, category, license) may already be in use for other purposes, existing records will not be affected. To ensure interoperability, it is strongly recommended that ENS names associated with smart contracts adopt this standard for their metadata.

## Security Considerations

None

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).