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
106 changes: 106 additions & 0 deletions ERCS/erc-8074.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
eip: 8074
title: Self-Describing Bytes via EIP-712 Selectors
description: Defines a convention for self-describing structured data in `bytes` parameters using 4-byte selectors derived from EIP-712 type strings.
author: Andrew Richardson (@awrichar)
discussions-to: https://ethereum-magicians.org/t/erc-8074-self-describing-bytes-via-eip-712-selectors/25649
status: Draft
type: Standards Track
category: ERC
created: 2025-10-30
requires: 712
---

## Abstract

This ERC standardizes a convention for tagging ABI-encoded structures placed inside `bytes` parameters with a compact type selector derived from the [EIP-712](./eip-712.md) type string.
It also defines a canonical multi-payload wrapper, allowing multiple typed payloads to be carried in a single `bytes` parameter.

## Motivation

Many smart contract methods use a `bytes` parameter to support future extensibility—including common standards such as [ERC-721](./eip-721.md) and [ERC-1155](./eip-1155.md).
The convention of carrying extra data in a `bytes` parameter was also codified further in [ERC-5750](./eip-5750.md).

In many practical cases, the `bytes` payload may encode a structured type that must be ABI-decoded before it can be processed. However:

- Different contracts use different, ad-hoc conventions for distinguishing among possible payloads.
- A single contract may need to support multiple encodings.
- In more complex workflows, a payload may be propagated across multiple contracts, each of which may need to parse it differently.

Currently, there is no standardized convention for identifying the "type" of an encoded payload, nor for supporting multiple data items in a single bytes parameter.
This ERC defines a minimal, interoperable convention for self-describing payloads that remain compatible with existing ABI tooling.

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

### Terms

- **Type string** — the canonical EIP-712 type string, e.g.
`TransferNote(bytes32 reference,string comment,uint256 deadline)`
- **Type selector (`bytes4`)** — `keccak256(typeString)[0:4]`
- **Single-payload** — a selector followed by `abi.encode` of that struct’s fields
- **Multi-payload wrapper** — `DataList(bytes[] items)`; each `items[i]` is a valid single-payload

### Single-payload encoding

- An ABI-encoded struct is prefixed with a 4-byte selector.
- The selector is defined as the first 4 bytes of the keccak256 hash of its EIP-712 type string.

```
typeSelector(T) = bytes4(keccak256(bytes(T)))
encoding = typeSelector(T) ++ abi.encode(<fields of T>)
```

Example:

```
T = "TransferNote(bytes32 reference,string comment,uint256 deadline)"
keccak256(T) = 0xf91f3a243a886588394dfd70af07dce0ca18c55e402d76152d4cb300349c9e9d
selector = 0xf91f3a24
encoding = 0xf91f3a24 ++ abi.encode(reference, comment, deadline)
```

A consumer may look for a known selector before attempting to decode the data, and can easily distinguish between multiple different payloads that it knows how to accept.

### Multi-payload wrapper

- Uses a canonical wrapper type `DataList(bytes[] items)` with selector `0xae74f986`.
- Each element in the items array is itself a single-struct payload (with its own selector).

```
DataList(bytes[] items)
selector(DataList) = bytes4(keccak256("DataList(bytes[] items)")) = 0xae74f986
encoding = 0xae74f986 ++ abi.encode(items)
```

Each `items[i]` MUST be a valid single-payload as above.
Consumers can look for this well-known selector, and can then decode the list to be scanned recursively for recognized items.

### Decoding

- Read the first 4 bytes as the **selector**.
- If the selector is `0xae74f986`, decode the remainder as `(bytes[] items)` and parse each item recursively.
- If the selector is another recognized selector, the remainder should be parsed accordingly.
- Unknown selectors MUST be ignored.
- Order is not significant; producers SHOULD avoid duplicates.

## Rationale

- **EIP-712 reuse:** avoids new schema syntax and aligns with the signing ecosystem.
- **4-byte selectors:** mirror Solidity’s function selector convention for compactness.
- **Simple wrapper:** `DataList` provides multiplexing without special parsing or new ABI rules.

## Backwards Compatibility

Existing contracts that already accept arbitrary `bytes` remain compatible. Contracts unaware of this ERC can continue to treat the payload as opaque.

## Security Considerations

- **Payload bounds:** When parsing `DataList`, consumers SHOULD limit `items.length` and total payload size (for example ≤ 8 items and ≤ 8 KB).
- **Early exit:** Consumers SHOULD stop scanning once all expected selectors are found.
- **Unknown data:** Unrecognized items MUST be ignored safely.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
Loading