Skip to content

List Records

A List Record is a fundamental EFP data structure representing a record in an EFP List.

Each List Record consists of the following three components:

  • version: A uint8 representing the version of the List Record. This is used to ensure compatibility and facilitate future upgrades.
  • record_type: A uint8 indicating the type of record. This serves as an identifier for the kind of data the record holds.
  • data: A bytes array containing the actual data of the record. The structure of this data depends on the record type.

The version is always 1.

Record Types

There is only one record type defined at this time:

TypeDescriptionDataData Length
0ReservedN/AN/A
1Address20-byte address20
2 - 255ReservedN/AN/A

Record types 0 and 2-255 are reserved for future use.

To illustrate the design, however, consider hypothetical list record types:

  • a subscription to another EFP List, where the data field would contain the 32-byte token ID of the corresponding EFP NFT.
  • an encrypted list record, where the data field would contain a list record encrypted with the public key of the list owner/manager/user (for privacy).
  • an ERC-721 NFT token, where the data field would contain the 20-byte address of the ERC-721 contract, and the 32-byte token ID.
  • an ERC-1155 token, where the data field would contain the 20-byte address of the ERC-1155 contract, the 32-byte token ID (exclude token amount).
  • an ENS name, where the data field would contain the normalized string of the ENS name.
  • a DNS name, where the data field would contain the normalized string of the DNS name.
  • an IP address, where the data field would contain the IP address string.
  • an email address, where the data field would contain the email address string.
  • a torrent magnet link, where the data field would contain the magnet link string.
  • a git repository URL, where the data field would contain the git remote URL string.
  • an RSS feed, where the data field would contain the string URL of the RSS feed.
  • an Atom feed, where the data field would contain the string URL of the Atom feed.
  • a DID record, where the data field would contain the DID string.
  • a custom record, where the data field would contain arbitrary or custom data.

Clients may support some or all of these record types depending on use case (once more than one record type is defined).

Address Record (Type 1)

The following is an example of an encoded ListRecord of type 1 (address record):

Byte(s)DescriptionValue
0ListRecord version (1 byte)0x01
1ListRecord record_type (1 byte)0x01
2 - 21ListRecord data (20 bytes)0x00000000000000000000000000000000DeaDBeef

Validation

version should always be 1.

record_type should always be 1 until other record types are defined.

data should always be exactly 20 bytes for record type 1.

If any of the above conditions are not met, the ListRecord is considered invalid and should not be processed.

Encoding

Onchain, list records are packed into byte arrays with the version and record type prepended to data to form an array with 2 + data.length bytes.

+------------------+---------------------+------------------------+
| version (1 byte) | recordType (1 byte) | data (variable length) |
+------------------+---------------------+------------------------+

This byte array will itself be a subarray of the list op data.

Decoding

Managers have permissions to upload arbitrary list record data, so clients should be prepared to handle unexpected data.

When decoding a ListRecord, the version and recordType fields should be checked to ensure compatibility.

The length of the data field should be checked to ensure it is the expected length for the given recordType.

If the length of the data field is unexpected, the ListRecord should generally be ignored and not processed.

Tags

A Tag is a string associated with a ListRecord in a list. A ListRecord can have multiple tags associated with it. A Tag is represented as a string.

Normalization

Tags are normalized by converting them to lowercase and removing leading and trailing whitespace.

Tags should be normalized before they are encoded into a ListOp.

Code

List Record can be represented as a type in any programming language. Here are some examples:

Go

type ListRecord struct {
Version uint8
RecordType uint8
Data []byte
}

Python

class ListRecord:
version: int # 0-255
record_type: int # 0-255
data: bytes

Rust

struct ListRecord {
version: u8,
record_type: u8,
data: Vec<u8>,
}

Solidity

/**
* The EFP contracts don't use this struct; they only store list ops
* as `bytes` and do not store list records directly. However, this
* struct can be useful for offchain processing with foundry or other
* Solidity tooling
*/
struct ListRecord {
uint8 version;
uint8 recordType;
bytes data;
}

TypeScript

type ListRecord = {
version: number // 0-255
recordType: number // 0-255
data: Uint8Array
}