Skip to content
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
167 changes: 167 additions & 0 deletions ERCS/erc-8049.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
eip: 8049
title: Contract-Level Onchain Metadata
description: A standard for storing contract-level metadata onchain with optional Diamond Storage pattern for predictable storage locations.

Check failure on line 4 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

preamble header `description` should not contain `standard` (or similar words.)

error[preamble-re-description]: preamble header `description` should not contain `standard` (or similar words.) --> ERCS/erc-8049.md:4:13 | 4 | ...on: A standard for storing contract-level metadata onchain with optional Diamond Storage pattern for predictable storage locations. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prohibited pattern was matched | = info: the pattern in question: `(?i)standar\w*\b` = help: see https://ethereum.github.io/eipw/preamble-re-description/

Check failure on line 4 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

preamble header `description` should not contain `standard` (or similar words.)

error[preamble-re-description]: preamble header `description` should not contain `standard` (or similar words.) --> ERCS/erc-8049.md:4:13 | 4 | ...on: A standard for storing contract-level metadata onchain with optional Diamond Storage pattern for predictable storage locations. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prohibited pattern was matched | = info: the pattern in question: `(?i)standar\w*\b` = help: see https://ethereum.github.io/eipw/preamble-re-description/
author: Prem Makeig (@nxt3d)
discussions-to: https://ethereum-magicians.org/t/erc-8049-contract-level-metadata-with-diamond-storage/25819
status: Draft
type: Standards Track
category: ERC
created: 2025-10-10
---

## Abstract

This ERC defines a standard for storing contract-level metadata onchain. It extends ERC-7572's contract-level metadata concept by providing onchain storage. Contracts MAY optionally use ERC-8042's Diamond Storage pattern for predictable storage locations, enabling cross-chain compatibility and supporting upgradable contracts.

Check failure on line 15 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 15 | This ERC defines a standard for storing contract-level metadata onchain. It extends ERC-7572's contract-level metadata concept by pr... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

Check failure on line 15 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 15 | This ERC defines a standard for storing contract-level metadata onchain. It extends ERC-7572's contract-level metadata concept by pr... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+` = help: see https://ethereum.github.io/eipw/markdown-link-first/

Check failure on line 15 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 15 | This ERC defines a standard for storing contract-level metadata onchain. It extends ERC-7572's contract-level metadata concept by pr... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

Check failure on line 15 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 15 | This ERC defines a standard for storing contract-level metadata onchain. It extends ERC-7572's contract-level metadata concept by pr... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+` = help: see https://ethereum.github.io/eipw/markdown-link-first/

## Motivation

ERC-7572 provides a standard for contract-level metadata via contractURI(), but it primarily focuses on offchain metadata storage. This ERC extends that concept by providing onchain storage. Contracts that need predictable storage locations for cross-chain compatibility or upgradable contracts can optionally use the Diamond Storage pattern from ERC-8042.

Check failure on line 19 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 19 | ERC-7572 provides a standard for contract-level metadata via contractURI(), but it primarily focuses on offchain metadata storage. T... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

Check failure on line 19 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 19 | ERC-7572 provides a standard for contract-level metadata via contractURI(), but it primarily focuses on offchain metadata storage. T... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

Check failure on line 19 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 19 | ERC-7572 provides a standard for contract-level metadata via contractURI(), but it primarily focuses on offchain metadata storage. T... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

Check failure on line 19 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 19 | ERC-7572 provides a standard for contract-level metadata via contractURI(), but it primarily focuses on offchain metadata storage. T... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

## 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.

### Scope

This ERC is an optional extension that MAY be implemented by any smart contract that wishes to store contract-level metadata onchain.

### Required Metadata Function and Event

Contracts implementing this ERC MUST implement the following interface:

```solidity
interface IERCXXXX {
/// @notice Get contract metadata value for a key.
function getContractMetadata(string calldata key) external view returns (bytes memory);

/// @notice Emitted when contract metadata is updated.
event ContractMetadataUpdated(string indexed indexedKey, string key, bytes value);
}
```

- `getContractMetadata(key)`: Returns the contract metadata value for the given key as bytes

Contracts implementing this ERC MAY also expose a `setContractMetadata(string calldata key, bytes calldata value)` function to allow metadata updates, with write policy determined by the contract.

Contracts implementing this ERC MUST emit the following event when metadata is set:

```solidity
event ContractMetadataUpdated(string indexed indexedKey, string key, bytes value);
```

### Optional Diamond Storage

Contracts implementing this ERC MAY use Diamond Storage pattern for predictable storage locations. If implemented, contracts MUST use the namespace ID `"erc8049.contract.metadata.storage"`.

The Diamond Storage pattern provides predictable storage locations for data, which is useful for cross-chain applications using inclusion proofs and for upgradable contracts. For more details on Diamond Storage, see ERC-8042.

Check failure on line 57 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 57 | The Diamond Storage pattern provides predictable storage locations for data, which is useful for cross-chain applications using incl... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

Check failure on line 57 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 57 | The Diamond Storage pattern provides predictable storage locations for data, which is useful for cross-chain applications using incl... | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

### Key/Value Pairs

This ERC specifies that the key is a string type and the value is bytes type. This provides flexibility for storing any type of data while maintaining an intuitive string-based key interface.

### Value Interpretation

If no standard is specified for a metadata value, clients MAY assume the value is a UTF-8 encoded string (bytes(string)) unless otherwise specified by the implementing contract or protocol.

### Examples

#### Example: Basic Contract Information

A contract can store basic information about itself:

- Key: `"name"` → Value: `bytes("MyToken")`
- Key: `"description"` → Value: `bytes("A decentralized exchange for trading ERC-20 tokens")`

Check failure on line 74 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

EIP references should not be in backticks

error[markdown-no-backticks]: EIP references should not be in backticks --> ERCS/erc-8049.md | 74 | - Key: `"description"` → Value: `bytes("A decentralized exchange for trading ERC-20 tokens")` | = info: the pattern in question: `(?i)(eip|erc)-[0-9]+` = help: see https://ethereum.github.io/eipw/markdown-no-backticks/

Check failure on line 74 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

EIP references should not be in backticks

error[markdown-no-backticks]: EIP references should not be in backticks --> ERCS/erc-8049.md | 74 | - Key: `"description"` → Value: `bytes("A decentralized exchange for trading ERC-20 tokens")` | = info: the pattern in question: `(?i)(eip|erc)-[0-9]+` = help: see https://ethereum.github.io/eipw/markdown-no-backticks/
- Key: `"collaborators"` → Value: `bytes(abi.encodePacked(address1, address2, address3))`

#### Example: ENS Name for Contract

A contract can specify its ENS name using this standard:

- Key: `"ens_name"` → Value: `bytes("mycontract.eth")`

This allows clients to discover the contract's ENS name and resolve it to get additional information about the contract.


## Rationale

This design prioritizes simplicity and flexibility by using a string-key, bytes-value store that provides an intuitive interface for any type of contract metadata. The minimal interface with a single `getContractMetadata` function provides all necessary functionality. The optional `setContractMetadata` function enables flexible access control for metadata updates. The required `ContractMetadataUpdated` event provides transparent audit trails with indexed key for efficient filtering. Contracts that need predictable storage locations can optionally use Diamond Storage pattern. This makes the standard suitable for diverse use cases including contract identification, collaboration tracking, and custom metadata storage.

## Backwards Compatibility

- Fully compatible with existing smart contracts.
- Non-supporting clients can ignore the scheme.

## Reference Implementation

The interface is defined in the Required Metadata Function and Event section above. Here are reference implementations:

### Basic Implementation

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import "./IERCXXXX.sol";

contract BasicContractMetadata is IERCXXXX {
// Simple mapping for contract-level metadata
mapping(string key => bytes value) private _metadata;

function getContractMetadata(string calldata key) external view override returns (bytes memory) {
return _metadata[key];
}

function setContractMetadata(string calldata key, bytes calldata value) external {
_metadata[key] = value;
emit ContractMetadataUpdated(key, key, value);
}
}
```

### Diamond Storage Implementation

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import "./IERCXXXX.sol";

contract DiamondContractMetadata is IERCXXXX {
struct ContractMetadataStorage {
mapping(string key => bytes value) metadata;
}

// keccak256("erc8049.contract.metadata.storage")
bytes32 private constant CONTRACT_METADATA_STORAGE_LOCATION =
keccak256("erc8049.contract.metadata.storage");

function _getContractMetadataStorage() private pure returns (ContractMetadataStorage storage $) {
bytes32 location = CONTRACT_METADATA_STORAGE_LOCATION;
assembly {
$.slot := location
}
}

function getContractMetadata(string calldata key) external view override returns (bytes memory) {
ContractMetadataStorage storage $ = _getContractMetadataStorage();
return $.metadata[key];
}

function setContractMetadata(string calldata key, bytes calldata value) external {
ContractMetadataStorage storage $ = _getContractMetadataStorage();
$.metadata[key] = value;
emit ContractMetadataUpdated(key, key, value);
}
}
```

## Security Considerations

This ERC is designed to put metadata onchain, providing security benefits through onchain storage.

Implementations that choose to use the optional Diamond Storage pattern should consider the security considerations of ERC-8042.

Check failure on line 163 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 163 | Implementations that choose to use the optional Diamond Storage pattern should consider the security considerations of ERC-8042. | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

Check failure on line 163 in ERCS/erc-8049.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-8049.md | 163 | Implementations that choose to use the optional Diamond Storage pattern should consider the security considerations of ERC-8042. | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+`

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
1 change: 1 addition & 0 deletions lib/forge-std
Submodule forge-std added at 0051db
Loading