Skip to content

Database Schemas

This page explains the different database schemas in ENSDb, including the ENSNode Schema, and the modular ENSIndexer Schema.

ENSDb instance can have two distinct kinds of database schemas: a single shared ENSNode Schema for operational metadata, and one ENSIndexer Schema per running ENSIndexer instance for all indexed ENS data. View Interactive Diagram of ENSDb Schemas.

The ensnode database schema contains shared operational metadata, called ENSNode Metadata, for the entire ENSDb database.

Possible key-value pairs are defined by the EnsNodeMetadata union type. As of now, it includes: EnsNodeMetadataIndexingMetadataContext.

ColumnTypeNullableDescription
ens_indexer_schema_nametextnoReferences the name of the ENSIndexer Schema that the metadata record belongs to. This allows multi-tenancy where multiple ENSIndexer instances can write to the same ENSNode Metadata table.
keytextnoAllowed keys: indexing_metadata_context.
valuejsonbnoGuaranteed to be a serialized representation of a JSON object.

Primary key: (ens_indexer_schema_name, key) — ensures that there is only one record for each key per ENSIndexer instance.

KeyTypeScript typeDescription
indexing_metadata_contextIndexingMetadataContextInitializedStores indexing status and stack info for the ENSIndexer instance.

Each ENSIndexer instance owns a dedicated database schema in ENSDb. All indexed ENS data for that instance lives within it, fully isolated from other instances. On startup, an ENSIndexer instance registers itself in ensnode.metadata using its database schema name as ens_indexer_schema_name.

The ENSIndexer Schema is modular, composed of multiple logical database sub-schemas, each implemented for specific requirements by a separate Ponder plugin.


Defined in ensv2.schema.ts.

RegistryType

Value
ENSv1Registry
ENSv1VirtualRegistry
ENSv2Registry

DomainType

Value
ENSv1Domain
ENSv2Domain

RegistrationType

Value
NameWrapper
BaseRegistrar
ThreeDNS
ENSv2RegistryRegistration
ENSv2RegistryReservation
ColumnTypeNullableDescription
idtextnoPonder’s event ID. Primary key.
chain_idbigintnoChain the event was emitted on.
block_numbernumeric(78)noBlock number.
block_hashtextnoBlock hash.
timestampnumeric(78)noBlock timestamp.
transaction_hashtextnoTransaction hash.
transaction_indexintegernoIndex of the transaction within the block.
fromtextnoTransaction sender address (tx.from). Never HCA-aware — always the EOA/relayer that submitted the transaction. Use sender for the HCA-aware actor.
sendertextnoThe HCA account address if used, otherwise Transaction.from. For ENSv2 events that emit an explicit sender / owner / account argument, this is set from that argument. For all other events (and all ENSv1 events), this falls back to from (i.e. tx.from).
totextyesTransaction recipient address. A null value means this was a contract-deployment transaction.
addresstextnoAddress of the contract that emitted the log.
log_indexintegernoIndex of the log within the transaction.
selectortextnoEvent topic[0] (the event signature hash).
topicstext[]noAll log topics.
datatextnoLog data.

Indexes: selector, from, sender, timestamp.

Join table linking a domains record to its associated events.

ColumnTypeNullable
domain_idtextno
event_idtextno

Primary key: (domain_id, event_id).

Join table linking a resolvers record to its associated events.

ColumnTypeNullable
resolver_idtextno
event_idtextno

Primary key: (resolver_id, event_id).

Join table linking a permissions record to its associated events.

ColumnTypeNullable
permissions_idtextno
event_idtextno

Primary key: (permissions_id, event_id).

Join table linking a permissions_users record to its associated events — i.e. the per-(contract, resource, user) history of role grants, revokes, and bitmap mutations.

ColumnTypeNullable
permissions_user_idtextno
event_idtextno

Primary key: (permissions_user_id, event_id).

ColumnTypeNullableDescription
idtextnoEthereum address. Primary key.

Relations: has many registrations (as registrant), has many domains, has many permissions_users.

For ENSv1, each domain that has children implicitly owns a “virtual” Registry (ENSv1VirtualRegistry) whose sole parent is that domain. Children of the parent then point their registry_id at the virtual registry. Concrete ENSv1Registry rows (e.g. the mainnet ENS Registry, the Basenames Registry, the Lineanames Registry) sit at the top. ENSv2 namegraphs are rooted in a single ENSv2Registry RootRegistry.

ColumnTypeNullableDescription
idtextnoSee RegistryId for guarantees. Primary key.
typeRegistryTypenoRegistry type.
chain_idbigintnoChain the registry contract is deployed on.
addresstextnoAddress of the registry contract.
nodetextyesIf this is an ENSv1VirtualRegistry, the namehash of the parent ENSv1 domain that owns it, otherwise null.
canonical_domain_idtextyesThe Registry’s declared Canonical Domain (unidirectional).
canonicalbooleannoWhether this Registry is part of the canonical nametree. This encodes bi-directional agreement between domains.subregistry_id and registries.canonical_domain_id, so traversal of the canonical nametree filtered to domains/registries where canonical=true is safe and doesn’t require edge-authenticating oneself (i.e. don’t need to compare domains.subregistry_id and registries.canonical_domain_id in the query, can just WHERE canonical = true). Default false.
has_childrenbooleannoInternal bookkeeping field. Synthetic monotonic sentinel flipped to true the first time a child Domain is registered under this Registry. Used to optimize canonicality cascades. Default false.

Indexes: (chain_id, address) — non-unique, because multiple rows can share (chain_id, address) across virtual registries.

Relations: has many domains (as parent registry), has many domains (as subregistry), has one permissions via (chain_id, address).

The domains.owner_id for ENSv1 Domains is the materialized effective owner. ENSv1 includes a diverse number of ways to ‘own’ a domain, including the ENSv1 Registry, various Registrars, and the NameWrapper. The ENSv1 indexing logic materializes the effective owner to simplify this aspect of ENS and enable efficient queries against domains.owner_id.

ColumnTypeNullableDescription
idtextnoENSv1DomainId: {ENSv1RegistryId}/{node}. ENSv2DomainId: CAIP-19 asset identifier. Primary key.
typeDomainTypenoENSv1Domain or ENSv2Domain.
registry_idtextnoThe registry this domain belongs to.
subregistry_idtextyesThe registry that manages subdomains of this domain, if any.
token_idnumeric(78)yesENSv2 only: the TokenId within the ENSv2Registry. null for ENSv1 domains.
nodetextyesENSv1 only: the domain’s namehash. null for ENSv2 domains.
label_hashtextnoRepresents a labelHash. References labels.label_hash.
owner_idtextyesIf ENSv1Domain, the materialized effective owner address. If ENSv2Domain, the on-chain owner address (the HCA account address if used).
root_registry_owner_idtextyesENSv1 only: the owner recorded in the root ENSv1 registry. null for ENSv2 domains.
canonicalbooleannoWhether this Domain is part of the canonical nametree. This encodes bi-directional agreement between domains.subregistry_id and registries.canonical_domain_id, so traversal of the canonical nametree filtered to domains/registries where canonical=true is safe and doesn’t require edge-authenticating oneself (i.e. don’t need to compare domains.subregistry_id and registries.canonical_domain_id in the query, can just WHERE canonical = true). Mirrors the parent Registry’s flag. Default false.

Indexes: type, registry_id, subregistry_id (partial: non-null only), owner_id, label_hash.

Relations: belongs to one registries record, belongs to one registries record (as subregistry), has one accounts record (owner), has one accounts record (rootRegistryOwner), has one labels record, has many registrations records.

Internal rainbow table mapping a label_hash to its interpreted label string. Domains reference labels by hash; names are healed at resolution-time.

ColumnTypeNullableDescription
label_hashtextnokeccak256 of the label. Primary key.
interpretedtextnoThe interpreted label string.

Indexes: interpreted (hash index for exact match), interpreted (GIN trigram index for prefix/substring LIKE)

Relations: has many domains.

A registration is keyed by id.

ColumnTypeNullableDescription
idtextnoA key derived from (domain_id, registration_index). Primary key.
domain_idtextnoThe registered domain.
registration_indexintegernoMonotonically increasing index per domain.
typeRegistrationTypenoThe mechanism through which this registration was made.
startnumeric(78)noUnix timestamp of registration start.
expirynumeric(78)yesUnix timestamp of expiry, if applicable.
grace_periodnumeric(78)yesGrace period duration in seconds. BaseRegistrar only.
registrar_chain_idbigintnoChain of the registrar contract.
registrar_addresstextnoAddress of the registrar contract.
registrant_idtextyesAccount that initiated the registration. For ENSv2 Registrations, the protocol-emitted registrant address (the HCA account address if used).
unregistrant_idtextyesAccount that triggered an unregistration, if applicable. For ENSv2 Registrations, the protocol-emitted unregistrant address (the HCA account address if used).
referrertextyesEncoded referrer value emitted at registration time.
fusesintegeryesFuse bitmap. NameWrapper and wrapped BaseRegistrar only.
basenumeric(78)yesBase registration cost in wei. BaseRegistrar and ENSv2Registrar only.
premiumnumeric(78)yesPremium cost in wei above base. BaseRegistrar only.
wrappedbooleannoWhether the registration is currently wrapped by the NameWrapper. Default false.
event_idtextnoThe event that created this registration record.

Indexes: unique on (domain_id, registration_index).

Relations: belongs to one domains record, has one accounts record (registrant), has one accounts record (unregistrant), has many renewals, has one events record.

Tracks the highest registration_index seen for each domain. Used to sequence registrations.

ColumnTypeNullable
domain_idtextno
registration_indexintegerno

Primary key: domain_id.

A renewal is keyed by id and belongs to a specific registration.

ColumnTypeNullableDescription
idtextnoA key derived from (domain_id, registration_index, renewal_index). Primary key.
domain_idtextnoThe renewed domain.
registration_indexintegernoIndex of the parent registration.
renewal_indexintegernoMonotonically increasing index per registration.
durationnumeric(78)noDuration added by this renewal, in seconds.
referrertextyesEncoded referrer value emitted at renewal time.
basenumeric(78)yesBase renewal cost in wei.
premiumnumeric(78)yesPremium cost in wei above base. ENSv1 RegistrarControllers only.
event_idtextnoThe event that created this renewal record.

Indexes: unique on (domain_id, registration_index, renewal_index).

Relations: belongs to one registrations record via (domain_id, registration_index), has one events record via (event_id).

Tracks the highest renewal_index seen for each registration. Used to sequence renewals.

ColumnTypeNullable
domain_idtextno
registration_indexintegerno
renewal_indexintegerno

Primary key: (domain_id, registration_index).

An ENSv2 permissions contract instance.

ColumnTypeNullableDescription
idtextnoPrimary key.
chain_idbigintnoChain the permissions contract is deployed on.
addresstextnoAddress of the permissions contract.

Indexes: unique on (chain_id, address).

Relations: has many permissions_resources, has many permissions_users.

A resource managed by a permissions contract.

ColumnTypeNullableDescription
idtextnoPrimary key.
chain_idbigintnoChain of the parent permissions contract.
addresstextnoAddress of the parent permissions contract.
resourcenumeric(78)noResource identifier (a uint256 token ID or similar).

Indexes: unique on (chain_id, address, resource).

Relations: belongs to one permissions via (chain_id, address).

A user’s role bitmap for a specific resource within a permissions contract.

ColumnTypeNullableDescription
idtextnoPrimary key.
chain_idbigintnoChain of the parent permissions contract.
addresstextnoAddress of the parent permissions contract.
resourcenumeric(78)noResource identifier.
usertextnoThe user/grantee address this Permission is granted to (the HCA account address if used).
rolesnumeric(78)noRoles bitmap for this user on this resource.

Indexes: unique on (chain_id, address, resource, user).

Relations: has one accounts record (user), belongs to one permissions record via (chain_id, address), belongs to one permissions_resource record via (chain_id, address, resource).


Defined in protocol-acceleration.schema.ts.

Provides accelerated lookups for the Resolution API. Rather than traversing the full namegraph at query time for common operations, this database sub-schema materializes the minimal state needed to answer resolution queries efficiently.

Tracks an Account’s ENSIP-19 Reverse Name Records by CoinType.

ColumnTypeNullableDescription
addresstextnoThe account address. Part of primary key.
coin_typenumeric(78)noENSIP-19 coin type. Part of primary key.
valuetextnoRepresents the ENSIP-19 Reverse Name Record for a given (address, coin_type). Guaranteed to be a non-empty InterpretedName.

Primary key: (address, coin_type).

Tracks Domain-Resolver relationships. This powers: (1) Domain-Resolver relationships within the GraphQL API, and (2) accelerated lookups of a Domain’s Resolver within the Resolution API.

It is keyed by (chain_id, address, domain_id) to match the on-chain data model of Registry / (shadow)Registry Domain-Resolver relationships.

ColumnTypeNullableDescription
chain_idbigintnoKeyed by (chain_id, address, domain_id). Part of primary key.
addresstextnoThe Registry (ENSv1Registry or ENSv2Registry)‘s AccountId. Part of primary key.
domain_idtextnoPart of primary key.
resolvertextnoThe Domain’s assigned Resolver’s address. Always scoped to chain_id.

Primary key: (chain_id, address, domain_id).

Relations: has one resolver via (chain_id, resolver).

Represents an individual IResolver contract that has emitted at least one event. Note that Resolver contracts can exist on-chain but not emit any events and still function properly, so checks against a Resolver’s existence and metadata must be done at runtime.

ColumnTypeNullableDescription
idtextnoKeyed by (chain_id, address). Primary key.
chain_idbigintnoChain the resolver contract is deployed on.
addresstextnoAddress of the resolver contract.

Indexes: unique on (chain_id, address).

Relations: has many resolver_records.

Tracks a set of records for a specified node within a resolver contract on chain_id.

Represents one name resolution record (see ENSIP-3), has many resolver_address_records (unique by coin_type, see ENSIP-9), and has many resolver_text_records (unique by key, see ENSIP-5).

ColumnTypeNullableDescription
idtextnoKeyed by (chain_id, resolver, node). Primary key.
chain_idbigintnoPart of the composite key.
addresstextnoResolver contract address. Part of the composite key.
nodetextnoThe name’s namehash. Part of the composite key.
nametextyesThe reverse-resolution (ENSIP-3) name() record, used for Reverse Resolution. If present, guaranteed to be a non-empty InterpretedName.
contenthashtextyesENSIP-7 contenthash raw bytes, or null if not set.
pubkeyXtextyesPubkeyResolver X coordinate. Invariant: both pubkeyX and pubkeyY are either both null or both set.
pubkeyYtextyesPubkeyResolver Y coordinate. Invariant: both pubkeyX and pubkeyY are either both null or both set.
dnszonehashtextyesIDNSZoneResolver zone hash, or null if not set.
versionnumeric(78)yesIVersionableResolver version. null when no VersionChanged event has been seen for this (chain_id, address, node) — the resolver may not implement IVersionableResolver, or simply may never have been version-bumped. Consumers should treat null as “unknown” rather than 0.

Indexes: unique on (chain_id, address, node).

Relations: belongs to one resolvers record via (chain_id, address), has many resolver_address_records, has many resolver_text_records.

Tracks address records for a node by coin_type within a resolver on chain_id.

Keyed by (chain_id, resolver, node, coin_type), where the composite key segment (chain_id, resolver, node) describes a resolver_records entity. A resolver_address_record is then additionally keyed by coin_type.

ColumnTypeNullableDescription
chain_idbigintnoPart of primary key.
addresstextnoResolver contract address. Part of primary key.
nodetextnoName namehash. Part of primary key.
coin_typenumeric(78)noAll well-known CoinTypes fit into a JavaScript number but NOT a Postgres integer, and must be stored as bigint. Part of primary key.
valuetextnoThe value of the Address Record specified by ((chain_id, resolver, node), coin_type). Interpreted by interpretAddressRecordValue — see its implementation for additional context and specific guarantees.

Primary key: (chain_id, address, node, coin_type).

Relations: belongs to one resolver_records record via (chain_id, address, node).

Tracks text records for a node by key within a resolver on chain_id.

Keyed by (chain_id, resolver, node, key), where the composite key segment (chain_id, resolver, node) describes a resolver_records entity. A resolver_text_record is then additionally keyed by key.

ColumnTypeNullableDescription
chain_idbigintnoPart of primary key.
addresstextnoResolver contract address. Part of primary key.
nodetextnoName namehash. Part of primary key.
keytextnoText record key. Part of primary key.
valuetextnoThe value of the Text Record specified by ((chain_id, resolver, node), key). Interpreted by interpretTextRecordValue — see its implementation for additional context and specific guarantees.

Primary key: (chain_id, address, node, key).

Relations: belongs to one resolver_records record via (chain_id, address, node).

Tracks the migration status of a node, keyed by (parent_node, label_hash). Due to a security issue, ENS migrated from the RegistryOld contract to a new Registry contract. When indexing events, the indexer must ignore any events on RegistryOld for domains that have since been migrated to the new Registry.

The set of nodes registered in the (new) Registry contract on the ENS Root Chain is stored here. When a RegistryOld#NewOwner event is encountered (which emits both parent_node and label_hash directly), the relevant row is looked up here; if it exists, the event is ignored.

The composite key is chosen so that Ponder’s profile-pattern matcher can decompose it from event args directly, keeping the read on the indexing-cache prefetch hot-path.

ColumnTypeNullable
parent_nodetextno
label_hashtextno

Primary key: (parent_node, label_hash).

Sibling lookup-by-namehash table for migrated_nodes_by_parent, keyed by node. The three RegistryOld handlers (Transfer / NewTTL / NewResolver) emit only the post-namehash node and cannot reconstruct the (parent_node, label_hash) pair without an unprofileable reverse lookup. Existence in this table is equivalent to existence in migrated_nodes_by_parent; both rows are written together by the migration helper. See protocol-acceleration/migrated-node-db-helpers.ts for the full rationale.

ColumnTypeNullable
nodetextno

Primary key: node.


Defined in registrars.schema.ts.

Models the lifecycle of ENS name registrations and renewals as logical actions, aggregating data from multiple on-chain events (e.g. a BaseRegistrar event and a RegistrarController event) into a single record per logical action.

registrar_action_type — Types of “logical registrar action”.

Value
registration
renewal

A “subregistry” represents a smart contract that manages the subnames of a given parent name.

The following simplifying assumptions are currently in place:

  1. No two subregistries hold state for the same node.
  2. The subregistry associated with name X in the ENS root registry exclusively holds state for subnames of X.

These assumptions hold for the current scope of indexing logic but may not hold as indexing expands to handle more complex scenarios.

ColumnTypeNullableDescription
subregistry_idtextnoIdentifies the chainId and address of the smart contract associated with the subregistry. Guaranteed to be a fully lowercase string formatted according to the CAIP-10 standard. Primary key.
nodetextnoThe node (namehash) of the name the subregistry manages subnames of. Examples: eth, base.eth, linea.eth. Guaranteed to be a fully lowercase hex string representation of 32 bytes.

Indexes: unique on node.

Relations: has many registration_lifecycles.

A “registration lifecycle” represents a single cycle of a name being registered once, followed by renewals (expiry date extensions) any number of times.

ColumnTypeNullableDescription
nodetextnoThe node (namehash) of the FQDN of the domain the registration lifecycle is associated with. Guaranteed to be a subname of the node of the subregistry identified by subregistry_id. Guaranteed to be a fully lowercase hex string representation of 32 bytes. Primary key.
subregistry_idtextnoIdentifies the chainId and address of the subregistry smart contract that manages the registration lifecycle. Guaranteed to be a fully lowercase CAIP-10 string.
expires_atnumeric(78)noUnix timestamp when the Registration Lifecycle is scheduled to expire.

Indexes: subregistry_id.

Relations: belongs to one subregistries record, has many registrar_actions records.

Models “logical actions” rather than “events” because a single logical action, such as a single registration or renewal, may emit multiple on-chain events from multiple contracts where each individual event may only provide a subset of the data about the full logical action. Each logical action in this table is associated with a single transaction. A single transaction may perform any number of logical actions.

For example, consider the logical registrar action of registering a direct subname of .eth. This logical action spans interactions across multiple contracts:

  1. The EthBaseRegistrar contract emits a NameRegistered event, enabling tracking of node, incrementalDuration, and registrant.
  2. A RegistrarController contract emits its own NameRegistered event, enabling tracking of baseCost, premium, total, and encodedReferrer.

The state from both events is aggregated into a single logical registrar action.

ColumnTypeNullableDescription
idtextnoDeterministic and globally unique identifier for the logical registrar action. Represents the initial on-chain event associated with the action. Guaranteed to be the first element in eventIds. Primary key. See note below about the ID format.
typeregistrar_action_typenoregistration or renewal.
subregistry_idtextnoThe ID of the subregistry the action was taken on. Identifies the chainId and address of the associated subregistry smart contract. Guaranteed to be a fully lowercase CAIP-10 string.
nodetextnoThe node (namehash) of the FQDN of the domain associated with the action. Guaranteed to be a fully lowercase hex string representation of 32 bytes.
incremental_durationnumeric(78)noDuration added to the registration by this action, in seconds. May be 0. See detailed description below.
base_costnumeric(78)yesBase cost in wei. Guaranteed to be null if and only if total is null. Otherwise a non-negative value.
premiumnumeric(78)yesPremium cost in wei above base_cost. Guaranteed to be null if and only if total is null. Guaranteed to be zero when type is renewal.
totalnumeric(78)yesTotal cost in wei, equal to the sum of base_cost and premium. Guaranteed to be null if and only if both base_cost and premium are null.
registranttextnoIdentifies the address that initiated the action and is paying total (if applicable). May not be the owner of the name — there are no restrictions on who may renew a name, and the initial owner may be distinct from the registrant. Guaranteed to be a fully lowercase address.
encoded_referrertextyesThe raw 32-byte referrer value emitted on-chain. null if no referrer information was present in the indexed events.
decoded_referrertextyesThe referrer address decoded from encoded_referrer using strict left-zero-padding validation. null if encoded_referrer is null. May be the zero address to represent that an encoded_referrer is defined but interpreted as no referrer. Guaranteed to be a fully lowercase address.
block_numbernumeric(78)noBlock number that includes the action. The chainId of this block is the same as is referenced in subregistry_id.
timestampnumeric(78)noUnix timestamp of the block referenced by block_number.
transaction_hashtextnoTransaction hash of the action. The chainId of this transaction is the same as referenced in subregistry_id. Note that a single transaction may be associated with any number of logical registrar actions.
event_idstext[]noArray of Ponder event IDs that contributed to this record. Guarantees: at least 1 element; ordered chronologically by log_index within block_number; the first element equals the id of this record.

Indexes: decoded_referrer, timestamp.

Relations: belongs to one registration_lifecycles record via node.

The id value is a Ponder checkpoint string — a fixed-length decimal string encoding the following fields (left to right, most to least significant):

FieldWidth (digits)Description
block_timestamp10Unix seconds timestamp of the block
chain_id16EIP-155 chain ID
block_number16Block number
transaction_index16Index of the transaction within the block
event_type1Internal Ponder event type (always 5)
event_index16Index of the event within the transaction

All fields are zero-padded to their fixed widths, so the string has constant length and lexicographic order equals chronological order. Because all registrar actions originate from Ponder log (smart-contract event) handlers, every id shares the same event_type digit (5), making direct lexicographic or bigint comparison safe for establishing total chronological order.

If type is registration: represents the duration between block_timestamp and the initial expires_at value that the associated registration lifecycle will be initialized with.

If type is renewal: represents the incremental increase in duration made to the expires_at value in the associated registration lifecycle. A registration lifecycle may be extended via renewal even after it expires, as long as it is still within its grace period.

Example: A registration lifecycle is scheduled to expire on Jan 1 midnight UTC. It is currently 30 days past expiration, with 60 days of grace period remaining.

  1. A renewal with 10 days incremental duration: the lifecycle remains “expired” but now has 70 days of grace period remaining.
  2. A renewal with 50 days incremental duration: the lifecycle becomes “active” again but will expire again in 20 days.

After the grace period expires entirely, the name is considered “released” and can no longer be renewed — it must be registered again, starting a new lifecycle.

_ensindexer_registrar_action_metadata_type enum:

Value
CURRENT_LOGICAL_REGISTRAR_ACTION
ColumnTypeNullableDescription
metadata_type_ensindexer_registrar_action_metadata_typenoThe type of internal registrar action metadata being stored. Primary key.
logical_event_keytextnoA fully lowercase string formatted as {domain_id}:{transaction_hash}.
logical_event_idtextnoHolds the id value of the existing registrar_actions record currently being built as an aggregation of on-chain events. Used by subsequent event handlers to identify which logical registrar action to aggregate additional indexed state into.

Defined in subgraph.schema.ts.

A complete re-implementation of the legacy ENS Subgraph data model. When the subgraph_ prefix is stripped and the resulting database schema is paired with @ensnode/ponder-subgraph, the resulting GraphQL API is fully compatible with the legacy ENS Subgraph.

ColumnTypeNullableDescription
idtextnoThe namehash of the name. Primary key.
nametextyesThe ENS name that this Domain represents. In subgraph-compatible mode: null for the root node, or a Subgraph Interpreted Name. Otherwise: an Interpreted Name (normalized, or consisting entirely of Interpreted Labels). The root node’s name is '' (empty string) rather than null in practice.
label_nametextyesThe label associated with the Domain. In subgraph-compatible mode: null for the root node or a subgraph-unindexable label; otherwise a Subgraph Interpreted Label. In non-compatible mode: null exclusively for the root node; otherwise a normalized label, or an Encoded LabelHash for unknown or unnormalized labels.
labelhashtextyeskeccak256(label_name).
parent_idtextyesThe namehash (id) of the parent name.
subdomain_countintegernoThe number of subdomains. Default 0.
resolved_address_idtextyesAddress logged from the current resolver, if any.
resolver_idtextyesThe resolver that controls the domain’s settings.
ttlnumeric(78)yesThe time-to-live (TTL) value of the domain’s records.
is_migratedbooleannoIndicates whether the domain has been migrated to a new registrar. Default false.
created_atnumeric(78)noThe time when the domain was created.
owner_idtextnoThe account that owns the domain.
registrant_idtextyesThe account that owns the ERC721 NFT for the domain.
wrapped_owner_idtextyesThe account that owns the wrapped domain.
expiry_datenumeric(78)yesThe expiry date for the domain, from either the registration or the wrapped domain if PCC is burned.

Indexes:

  • name — hash index, because some name values exceed the btree max row size (8191 bytes).
  • name — GIN trigram index for partial-match filters (_contains, _starts_with, _ends_with).
  • labelhash, parent_id, owner_id, registrant_id, wrapped_owner_id, resolved_address_id.

Relations: has one subgraph_accounts record (resolved_address), has one subgraph_accounts record (owner), has one subgraph_accounts record (registrant), has one subgraph_accounts record (wrapped_owner), has one subgraph_resolvers record, has one subgraph_domains record (parent), has many subgraph_domains records (subdomains), has one subgraph_wrapped_domains record, has one subgraph_registrations record, has many domain event tables.

ColumnTypeNullable
idtextno

Relations: has many subgraph_domains records, has many subgraph_wrapped_domains records, has many subgraph_registrations records.

ColumnTypeNullableDescription
idtextnoUnique identifier: concatenation of the domain namehash and the resolver address. Primary key.
domain_idtextnoThe domain that this resolver is associated with.
addresstextnoThe address of the resolver contract.
addr_idtextyesThe current value of the addr record for this resolver, as determined by the associated events.
content_hashtextyesThe content hash for this resolver, in binary format.
textstext[]yesThe set of observed text record keys for this resolver. Nullable (not defaulting to []) to match subgraph behavior.
coin_typesnumeric(78)[]yesThe set of observed SLIP-44 coin types for this resolver. Nullable (not defaulting to []) to match subgraph behavior.

Indexes: domain_id.

Relations: has one subgraph_accounts record (addr), has one subgraph_domains record, has many resolver event tables.

ColumnTypeNullableDescription
idtextnoThe unique identifier of the registration (namehash). Primary key.
domain_idtextnoThe domain name associated with the registration.
registration_datenumeric(78)noThe registration date of the domain.
expiry_datenumeric(78)noThe expiry date of the domain.
costnumeric(78)yesThe cost associated with the domain registration.
registrant_idtextnoThe account that registered the domain.
label_nametextyesThe label associated with the domain registration. In subgraph-compatible mode: null for a subgraph-unindexable label; otherwise a Subgraph Interpreted Label. In non-compatible mode: a normalized label, or an Encoded LabelHash for unnormalized labels. null is not expected in practice because there is no Registration entity for the root node (the only node with a null label_name).

Indexes: domain_id, registration_date, expiry_date.

Relations: has one subgraph_domains record, has one subgraph_accounts record (registrant), has many registration event tables.

ColumnTypeNullableDescription
idtextnoThe unique identifier for each instance of the WrappedDomain entity. Primary key.
domain_idtextnoThe domain that is wrapped by this WrappedDomain.
expiry_datenumeric(78)noThe expiry date of the wrapped domain.
fusesintegernoThe number of fuses remaining on the wrapped domain.
owner_idtextnoThe account that owns this WrappedDomain.
nametextyesThe name that this WrappedDomain represents. Names are emitted by the NameWrapper contract as DNS-Encoded Names which may be malformed, resulting in null. In subgraph-compatible mode: null for malformed or subgraph-unindexable labels; otherwise a Subgraph Interpreted Label. In non-compatible mode: null for a malformed DNS-Encoded Name; otherwise an Interpreted Name.

Indexes: domain_id.

Relations: has one subgraph_domains record, has one subgraph_accounts record (owner).

All event tables share the base columns id (primary key), block_number, and transaction_id. Domain event tables additionally carry domain_id; registration event tables carry registration_id; resolver event tables carry resolver_id. The indexes on each event table are (domain_id/resolver_id/registration_id) for reverse lookups and (domain_id/resolver_id/registration_id, id) for sorted pagination.

Domain event tables

TableAdditional columns
subgraph_transfersowner_id
subgraph_new_ownersowner_id, parent_domain_id
subgraph_new_resolversresolver_id
subgraph_new_ttlsttl
subgraph_wrapped_transfersowner_id
subgraph_name_wrappedname, fuses, owner_id, expiry_date
subgraph_name_unwrappedowner_id
subgraph_fuses_setfuses
subgraph_expiry_extendedexpiry_date

Registration event tables

TableAdditional columns
subgraph_name_registeredregistrant_id, expiry_date
subgraph_name_renewedexpiry_date
subgraph_name_transferrednew_owner_id

Resolver event tables

TableAdditional columns
subgraph_addr_changedaddr_id
subgraph_multicoin_addr_changedcoin_type, addr
subgraph_name_changedname
subgraph_abi_changedcontent_type
subgraph_pubkey_changedx, y
subgraph_text_changedkey, value
subgraph_contenthash_changedhash
subgraph_interface_changedinterface_id, implementer
subgraph_authorisation_changedowner, target, is_authorized
subgraph_version_changedversion

Defined in tokenscope.schema.ts.

Tracks ENS-related NFT token ownership and secondary market sales via the Seaport protocol.

ColumnTypeNullableDescription
idtextnoUnique and deterministic identifier of the on-chain event associated with the sale. Composite key format: {chain_id}-{block_number}-{log_index} (e.g. 1-1234567-5). Primary key.
chain_idbigintnoThe chain where the sale occurred.
block_numbernumeric(78)noThe block number on chain_id where the sale occurred.
log_indexintegernoThe log index position of the sale event within block_number.
transaction_hashtextnoThe EVM transaction hash on chain_id associated with the sale.
order_hashtextnoThe Seaport order hash.
contract_addresstextnoThe address of the contract on chain_id that manages token_id.
token_idnumeric(78)noThe tokenId managed by contract_address that was sold.
asset_namespacetextnoThe CAIP-19 Asset Namespace of the token that was sold. Either erc721 or erc1155.
asset_idtextnoThe CAIP-19 Asset ID of the token that was sold. A globally unique reference to the specific asset.
domain_idtextnoThe namehash (Node) of the ENS domain that was sold.
buyertextnoThe account that bought the token controlling ownership of domain_id from the seller, for the amount of currency associated with the sale.
sellertextnoThe account that sold the token controlling ownership of domain_id to the buyer, for the amount of currency associated with the sale.
currencytextnoCurrency of the payment. One of: ETH, USDC, or DAI.
amountnumeric(78)noThe amount of currency paid, denominated in the smallest unit. ETH/WETH: wei (1 ETH = 10^18). USDC: micro-units (1 USDC = 10^6). DAI: wei-equivalent (1 DAI = 10^18).
timestampnumeric(78)noUnix timestamp of the block when the sale occurred.

Indexes: domain_id, asset_id, buyer, seller, timestamp.

After an NFT is indexed, it is never deleted from the index. When an indexed NFT is burned on-chain, its record is retained and its mint_status is updated to burned. If the NFT is minted again after being burned, mint_status is updated back to minted.

ColumnTypeNullableDescription
idtextnoThe CAIP-19 Asset ID of the token. A globally unique reference to this token. Primary key.
domain_idtextnoThe namehash (Node) of the ENS name associated with the token. An ENS name may have more than one distinct token across time. It is also possible for multiple distinct tokens for an ENS name to have a mint_status of minted at the same time — for example, when a direct subname of .eth is wrapped by the NameWrapper (one minted token managed by the BaseRegistrar, owned by the NameWrapper; one minted token managed by the NameWrapper, owned by the effective owner).
chain_idbigintnoThe chain that manages the token.
contract_addresstextnoThe address of the contract on chain_id that manages the token.
token_idnumeric(78)noThe tokenId of the token managed by contract_address.
asset_namespacetextnoThe CAIP-19 Asset Namespace of the token. Either erc721 or erc1155.
ownertextnoThe account that owns the token. Value is the zero address if and only if mint_status is burned. Note: the owner of the token for a given domain_id may differ from the owner of the associated node in the registry. For example, if address X owns foo.eth in both the BaseRegistrar and the Registry, and X transfers registry ownership directly to Y, the BaseRegistrar token owner remains X. The BaseRegistrar implements a reclaim function allowing the token owner to reclaim registry ownership.
mint_statustextnoEither minted or burned.

Indexes: domain_id, owner.