@ensnode/ensnode-schema
Version:
The ponder schema for ENSNode
1,512 lines (1,505 loc) • 61.4 kB
JavaScript
// src/schemas/ensnode-metadata.schema.ts
import { onchainTable } from "ponder";
var ensNodeMetadata = onchainTable("ensnode_metadata", (t) => ({
/**
* Key
*
* Allowed keys:
* - `EnsNodeMetadataEnsDbVersion['key']`
* - `EnsNodeMetadataEnsIndexerPublicConfig['key']`
* - `EnsNodeMetadataEnsIndexerIndexingStatus['key']`
*/
key: t.text().primaryKey(),
/**
* Value
*
* Allowed values:
* - `EnsNodeMetadataEnsDbVersion['value']`
* - `EnsNodeMetadataEnsIndexerPublicConfig['value']`
* - `EnsNodeMetadataEnsIndexerIndexingStatus['value']`
*
* Guaranteed to be a serialized representation of JSON object.
*/
value: t.jsonb().notNull()
}));
// src/schemas/ensv2.schema.ts
import { index, onchainEnum, onchainTable as onchainTable2, primaryKey, relations, sql, uniqueIndex } from "ponder";
var event = onchainTable2("events", (t) => ({
// Ponder's event.id
id: t.text().primaryKey(),
// Event Log Metadata
// chain
chainId: t.integer().notNull().$type(),
// block
blockHash: t.hex().notNull().$type(),
timestamp: t.bigint().notNull(),
// transaction
transactionHash: t.hex().notNull().$type(),
from: t.hex().notNull().$type(),
// log
address: t.hex().notNull().$type(),
logIndex: t.integer().notNull().$type()
}));
var account = onchainTable2("accounts", (t) => ({
id: t.hex().primaryKey().$type()
}));
var account_relations = relations(account, ({ many }) => ({
registrations: many(registration, { relationName: "registrant" }),
domains: many(v2Domain),
permissions: many(permissionsUser)
}));
var registry = onchainTable2(
"registries",
(t) => ({
// see RegistryId for guarantees
id: t.text().primaryKey().$type(),
chainId: t.integer().notNull().$type(),
address: t.hex().notNull().$type()
}),
(t) => ({
byId: uniqueIndex().on(t.chainId, t.address)
})
);
var relations_registry = relations(registry, ({ one, many }) => ({
domain: one(v2Domain, {
relationName: "subregistry",
fields: [registry.id],
references: [v2Domain.registryId]
}),
domains: many(v2Domain, { relationName: "registry" }),
permissions: one(permissions, {
relationName: "permissions",
fields: [registry.chainId, registry.address],
references: [permissions.chainId, permissions.address]
})
}));
var v1Domain = onchainTable2(
"v1_domains",
(t) => ({
// keyed by node, see ENSv1DomainId for guarantees.
id: t.text().primaryKey().$type(),
// must have a parent v1Domain (note: root node does not exist in index)
parentId: t.text().notNull().$type(),
// may have an owner
ownerId: t.hex().$type(),
// represents a labelHash
labelHash: t.hex().notNull().$type()
// NOTE: Domain-Resolver Relations tracked via Protocol Acceleration plugin
}),
(t) => ({
byParent: index().on(t.parentId),
byOwner: index().on(t.ownerId),
byLabelHash: index().on(t.labelHash)
})
);
var relations_v1Domain = relations(v1Domain, ({ one, many }) => ({
// v1Domain
parent: one(v1Domain, {
fields: [v1Domain.parentId],
references: [v1Domain.id]
}),
children: many(v1Domain, { relationName: "parent" }),
// shared
owner: one(account, {
relationName: "owner",
fields: [v1Domain.ownerId],
references: [account.id]
}),
label: one(label, {
relationName: "label",
fields: [v1Domain.labelHash],
references: [label.labelHash]
}),
registrations: many(registration)
}));
var v2Domain = onchainTable2(
"v2_domains",
(t) => ({
// see ENSv2DomainId for guarantees
id: t.text().primaryKey().$type(),
// has a tokenId
tokenId: t.bigint().notNull(),
// belongs to registry
registryId: t.text().notNull().$type(),
// may have one subregistry
subregistryId: t.text().$type(),
// may have an owner
ownerId: t.hex().$type(),
// represents a labelHash
labelHash: t.hex().notNull().$type()
// NOTE: Domain-Resolver Relations tracked via Protocol Acceleration plugin
}),
(t) => ({
byRegistry: index().on(t.registryId),
bySubregistry: index().on(t.subregistryId).where(sql`${t.subregistryId} IS NOT NULL`),
byOwner: index().on(t.ownerId),
byLabelHash: index().on(t.labelHash)
})
);
var relations_v2Domain = relations(v2Domain, ({ one, many }) => ({
// v2Domain
registry: one(registry, {
relationName: "registry",
fields: [v2Domain.registryId],
references: [registry.id]
}),
subregistry: one(registry, {
relationName: "subregistry",
fields: [v2Domain.subregistryId],
references: [registry.id]
}),
// shared
owner: one(account, {
relationName: "owner",
fields: [v2Domain.ownerId],
references: [account.id]
}),
label: one(label, {
relationName: "label",
fields: [v2Domain.labelHash],
references: [label.labelHash]
}),
registrations: many(registration)
}));
var registrationType = onchainEnum("RegistrationType", [
// TODO: prefix these with ENSv1, maybe excluding ThreeDNS
"NameWrapper",
"BaseRegistrar",
"ThreeDNS",
"ENSv2Registry"
]);
var registration = onchainTable2(
"registrations",
(t) => ({
// keyed by (domainId, index)
id: t.text().primaryKey().$type(),
domainId: t.text().notNull().$type(),
index: t.integer().notNull(),
// has a type
type: registrationType().notNull(),
// may have an expiry
expiry: t.bigint(),
// maybe have a grace period (BaseRegistrar)
gracePeriod: t.bigint(),
// registrar AccountId
registrarChainId: t.integer().notNull().$type(),
registrarAddress: t.hex().notNull().$type(),
// references registrant
registrantId: t.hex().$type(),
// may have a referrer
referrer: t.hex().$type(),
// may have fuses (NameWrapper, Wrapped BaseRegistrar)
fuses: t.integer(),
// TODO(paymentToken): add payment token tracking here
// may have base cost (BaseRegistrar, ENSv2Registrar)
base: t.bigint(),
// may have a premium (BaseRegistrar)
premium: t.bigint(),
// may be Wrapped (BaseRegistrar)
wrapped: t.boolean().default(false),
// has an event
eventId: t.text().notNull()
}),
(t) => ({
byId: uniqueIndex().on(t.domainId, t.index)
})
);
var latestRegistrationIndex = onchainTable2("latest_registration_indexes", (t) => ({
domainId: t.text().primaryKey().$type(),
index: t.integer().notNull()
}));
var registration_relations = relations(registration, ({ one, many }) => ({
// belongs to either v1Domain or v2Domain
v1Domain: one(v1Domain, {
fields: [registration.domainId],
references: [v1Domain.id]
}),
v2Domain: one(v2Domain, {
fields: [registration.domainId],
references: [v2Domain.id]
}),
// has one registrant
registrant: one(account, {
fields: [registration.registrantId],
references: [account.id],
relationName: "registrant"
}),
// has many renewals
renewals: many(renewal),
// has an event
event: one(event, {
fields: [registration.eventId],
references: [event.id]
})
}));
var renewal = onchainTable2(
"renewals",
(t) => ({
// keyed by (registrationId, index)
id: t.text().primaryKey().$type(),
domainId: t.text().notNull().$type(),
registrationIndex: t.integer().notNull(),
index: t.integer().notNull(),
// all renewals have a duration
duration: t.bigint().notNull(),
// may have a referrer
referrer: t.hex().$type(),
// TODO(paymentToken): add payment token tracking here
// may have base cost
base: t.bigint(),
// may have a premium (ENSv1 RegistrarControllers)
premium: t.bigint(),
// has an event
eventId: t.text().notNull()
}),
(t) => ({
byId: uniqueIndex().on(t.domainId, t.registrationIndex, t.index)
})
);
var renewal_relations = relations(renewal, ({ one }) => ({
// belongs to registration
registration: one(registration, {
fields: [renewal.domainId, renewal.registrationIndex],
references: [registration.domainId, registration.index]
}),
// has an event
event: one(event, {
fields: [renewal.eventId],
references: [event.id]
})
}));
var latestRenewalIndex = onchainTable2(
"latest_renewal_indexes",
(t) => ({
domainId: t.text().notNull().$type(),
registrationIndex: t.integer().notNull(),
index: t.integer().notNull()
}),
(t) => ({ pk: primaryKey({ columns: [t.domainId, t.registrationIndex] }) })
);
var permissions = onchainTable2(
"permissions",
(t) => ({
id: t.text().primaryKey().$type(),
chainId: t.integer().notNull().$type(),
address: t.hex().notNull().$type()
}),
(t) => ({
byId: uniqueIndex().on(t.chainId, t.address)
})
);
var relations_permissions = relations(permissions, ({ many }) => ({
resources: many(permissionsResource),
users: many(permissionsUser)
}));
var permissionsResource = onchainTable2(
"permissions_resources",
(t) => ({
id: t.text().primaryKey().$type(),
chainId: t.integer().notNull().$type(),
address: t.hex().notNull().$type(),
resource: t.bigint().notNull()
}),
(t) => ({
byId: uniqueIndex().on(t.chainId, t.address, t.resource)
})
);
var relations_permissionsResource = relations(permissionsResource, ({ one }) => ({
permissions: one(permissions, {
fields: [permissionsResource.chainId, permissionsResource.address],
references: [permissions.chainId, permissions.address]
})
}));
var permissionsUser = onchainTable2(
"permissions_users",
(t) => ({
id: t.text().primaryKey().$type(),
chainId: t.integer().notNull().$type(),
address: t.hex().notNull().$type(),
resource: t.bigint().notNull(),
user: t.hex().notNull().$type(),
// has one roles bitmap
roles: t.bigint().notNull()
}),
(t) => ({
byId: uniqueIndex().on(t.chainId, t.address, t.resource, t.user)
})
);
var relations_permissionsUser = relations(permissionsUser, ({ one }) => ({
account: one(account, {
fields: [permissionsUser.user],
references: [account.id]
}),
permissions: one(permissions, {
fields: [permissionsUser.chainId, permissionsUser.address],
references: [permissions.chainId, permissions.address]
}),
resource: one(permissionsResource, {
fields: [permissionsUser.chainId, permissionsUser.address, permissionsUser.resource],
references: [
permissionsResource.chainId,
permissionsResource.address,
permissionsResource.resource
]
})
}));
var label = onchainTable2(
"labels",
(t) => ({
labelHash: t.hex().primaryKey().$type(),
interpreted: t.text().notNull().$type()
}),
(t) => ({
byInterpreted: index().on(t.interpreted)
})
);
var label_relations = relations(label, ({ many }) => ({
domains: many(v2Domain)
}));
var registryCanonicalDomain = onchainTable2("registry_canonical_domains", (t) => ({
registryId: t.text().primaryKey().$type(),
domainId: t.text().notNull().$type()
}));
// src/schemas/protocol-acceleration.schema.ts
import { onchainTable as onchainTable3, primaryKey as primaryKey2, relations as relations2, uniqueIndex as uniqueIndex2 } from "ponder";
var reverseNameRecord = onchainTable3(
"reverse_name_records",
(t) => ({
// keyed by (address, coinType)
address: t.hex().notNull().$type(),
coinType: t.bigint().notNull(),
/**
* Represents the ENSIP-19 Reverse Name Record for a given (address, coinType).
*
* The value of this field is guaranteed to be a non-empty-string normalized ENS name (see
* `interpretNameRecordValue` for additional context and specific guarantees). Unnormalized
* names and empty string values are interpreted as a deletion of the associated Reverse Name
* Record entity (represented in the schema as the _absence_ of a relevant Reverse Name Record
* entity).
*/
value: t.text().notNull()
}),
(t) => ({
pk: primaryKey2({ columns: [t.address, t.coinType] })
})
);
var domainResolverRelation = onchainTable3(
"domain_resolver_relations",
(t) => ({
// keyed by (chainId, registry, node)
chainId: t.integer().notNull().$type(),
// The Registry (ENSv1Registry or ENSv2Registry)'s AccountId.
address: t.hex().notNull().$type(),
domainId: t.hex().notNull().$type(),
// The Domain's assigned Resolver's address (NOTE: always scoped to chainId)
resolver: t.hex().notNull().$type()
}),
(t) => ({
pk: primaryKey2({ columns: [t.chainId, t.address, t.domainId] })
})
);
var domainResolverRelation_relations = relations2(domainResolverRelation, ({ one }) => ({
resolver: one(resolver, {
fields: [domainResolverRelation.chainId, domainResolverRelation.resolver],
references: [resolver.chainId, resolver.address]
})
}));
var resolver = onchainTable3(
"resolvers",
(t) => ({
// keyed by (chainId, address)
id: t.text().primaryKey().$type(),
chainId: t.integer().notNull().$type(),
address: t.hex().notNull().$type()
}),
(t) => ({
byId: uniqueIndex2().on(t.chainId, t.address)
})
);
var resolver_relations = relations2(resolver, ({ many }) => ({
records: many(resolverRecords)
}));
var resolverRecords = onchainTable3(
"resolver_records",
(t) => ({
// keyed by (chainId, resolver, node)
id: t.text().primaryKey().$type(),
chainId: t.integer().notNull().$type(),
address: t.hex().notNull().$type(),
node: t.hex().notNull().$type(),
/**
* Represents the value of the reverse-resolution (ENSIP-3) name() record, used for Reverse Resolution.
*
* The emitted record values are interpreted according to `interpretNameRecordValue` — unnormalized
* names and empty string values are interpreted as a deletion of the associated record (represented
* here as `null`).
*
* If set, the value of this field is guaranteed to be a non-empty-string normalized ENS name
* (see `interpretNameRecordValue` for additional context and specific guarantees).
*/
name: t.text()
}),
(t) => ({
byId: uniqueIndex2().on(t.chainId, t.address, t.node)
})
);
var resolverRecords_relations = relations2(resolverRecords, ({ one, many }) => ({
// belongs to resolver
resolver: one(resolver, {
fields: [resolverRecords.chainId, resolverRecords.address],
references: [resolver.chainId, resolver.address]
}),
// resolverRecord has many address records
addressRecords: many(resolverAddressRecord),
// resolverRecord has many text records
textRecords: many(resolverTextRecord)
}));
var resolverAddressRecord = onchainTable3(
"resolver_address_records",
(t) => ({
// keyed by ((chainId, resolver, node), coinType)
chainId: t.integer().notNull().$type(),
address: t.hex().notNull().$type(),
node: t.hex().notNull().$type(),
// NOTE: all well-known CoinTypes fit into javascript number but NOT postgres .integer, must be
// stored as BigInt
coinType: t.bigint().notNull(),
/**
* Represents the value of the Addresss Record specified by ((chainId, resolver, node), coinType).
*
* The value of this field is interpreted by `interpretAddressRecordValue` — see its implementation
* for additional context and specific guarantees.
*/
value: t.text().notNull()
}),
(t) => ({
pk: primaryKey2({ columns: [t.chainId, t.address, t.node, t.coinType] })
})
);
var resolverAddressRecordRelations = relations2(resolverAddressRecord, ({ one }) => ({
// belongs to resolverRecord
resolver: one(resolverRecords, {
fields: [
resolverAddressRecord.chainId,
resolverAddressRecord.address,
resolverAddressRecord.node
],
references: [resolverRecords.chainId, resolverRecords.address, resolverRecords.node]
})
}));
var resolverTextRecord = onchainTable3(
"resolver_text_records",
(t) => ({
// keyed by ((chainId, resolver, node), key)
chainId: t.integer().notNull().$type(),
address: t.hex().notNull().$type(),
node: t.hex().notNull().$type(),
key: t.text().notNull(),
/**
* Represents the value of the Text Record specified by ((chainId, resolver, node), key).
*
* The value of this field is interpreted by `interpretTextRecordValue` — see its implementation
* for additional context and specific guarantees.
*/
value: t.text().notNull()
}),
(t) => ({
pk: primaryKey2({ columns: [t.chainId, t.address, t.node, t.key] })
})
);
var resolverTextRecordRelations = relations2(resolverTextRecord, ({ one }) => ({
// belongs to resolverRecord
resolver: one(resolverRecords, {
fields: [resolverTextRecord.chainId, resolverTextRecord.address, resolverTextRecord.node],
references: [resolverRecords.chainId, resolverRecords.address, resolverRecords.node]
})
}));
var migratedNode = onchainTable3("migrated_nodes", (t) => ({
node: t.hex().primaryKey()
}));
// src/schemas/registrars.schema.ts
import { index as index2, onchainEnum as onchainEnum2, onchainTable as onchainTable4, relations as relations3, uniqueIndex as uniqueIndex3 } from "ponder";
var subregistries = onchainTable4(
"subregistries",
(t) => ({
/**
* Subregistry ID
*
* Identifies 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.
*
* @see https://chainagnostic.org/CAIPs/caip-10
*/
subregistryId: t.text().primaryKey(),
/**
* The node (namehash) of the name the subregistry manages subnames of.
* Example subregistry managed names:
* - `eth`
* - `base.eth`
* - `linea.eth`
*
* Guaranteed to be a fully lowercase hex string representation of 32-bytes.
*/
node: t.hex().notNull()
}),
(t) => ({
uniqueNode: uniqueIndex3().on(t.node)
})
);
var registrationLifecycles = onchainTable4(
"registration_lifecycles",
(t) => ({
/**
* The node (namehash) of the FQDN of the domain the registration lifecycle
* is associated with.
*
* Guaranteed to be a subname of the node (namehash) of the subregistry
* identified by `subregistryId`.
*
* Guaranteed to be a fully lowercase hex string representation of 32-bytes.
*/
node: t.hex().primaryKey(),
/**
* Subregistry ID
*
* Identifies the chainId and address of the subregistry smart contract
* that manages the registration lifecycle.
*
* Guaranteed to be a fully lowercase string formatted according to
* the CAIP-10 standard.
*
* @see https://chainagnostic.org/CAIPs/caip-10
*/
subregistryId: t.text().notNull(),
/**
* Expires at
*
* Unix timestamp when the Registration Lifecycle is scheduled to expire.
*/
expiresAt: t.bigint().notNull()
}),
(t) => ({
bySubregistry: index2().on(t.subregistryId)
})
);
var registrarActionType = onchainEnum2("registrar_action_type", [
"registration",
"renewal"
]);
var registrarActions = onchainTable4(
"registrar_actions",
(t) => ({
/**
* "Logical registrar action" ID
*
* The `id` value is a deterministic and globally unique identifier for
* the "logical registrar action".
*
* The `id` value represents the *initial* onchain event associated with
* the "logical registrar action", but the full state of
* the "logical registrar action" is an aggregate across each of
* the onchain events referenced in the `eventIds` field.
*
* Guaranteed to be the very first element in `eventIds` array.
*/
id: t.text().primaryKey(),
/**
* The type of the "logical registrar action".
*/
type: registrarActionType().notNull(),
/**
* Subregistry ID
*
* The ID of the subregistry the "logical registrar action" was taken on.
*
* Identifies the chainId and address of the associated subregistry smart
* contract.
*
* Guaranteed to be a fully lowercase string formatted according to
* the CAIP-10 standard.
*
* @see https://chainagnostic.org/CAIPs/caip-10
*/
subregistryId: t.text().notNull(),
/**
* The node (namehash) of the FQDN of the domain associated with
* the "logical registrar action".
*
* Guaranteed to be a fully lowercase hex string representation of 32-bytes.
*/
node: t.hex().notNull(),
/**
* Incremental Duration
*
* If `type` is "registration":
* - Represents the duration between `blockTimestamp` and
* the initial `expiresAt` value that the associated
* "registration lifecycle" will be initialized with.
* If `type` is "renewal":
* - Represents the incremental increase in duration made to
* the `expiresAt` value in the associated "registration lifecycle".
*
* A "registration lifecycle" may be extended via renewal even after it
* expires if it is still within its grace period.
*
* Consider the following scenario:
*
* The "registration lifecycle" of a direct subname of .eth is scheduled to
* expire on Jan 1, midnight UTC. It is currently 30 days after this
* expiration time. Therefore, there are currently another 60 days of grace
* period remaining for this name. Anyone can still make a renewal to
* extend the "registration lifecycle" of this name.
*
* Given this scenario, consider the following examples:
*
* 1. If a renewal is made with 10 days incremental duration,
* the "registration lifecycle" for this name will remain in
* an "expired" state, but it will now have another 70 days of
* grace period remaining.
*
* 2. If a renewal is made with 50 days incremental duration,
* the "registration lifecycle" for this name will no longer be
* "expired" and will become "active", but the "registration lifecycle"
* will now be scheduled to expire again in 20 days.
*
* After the "registration lifecycle" for a name becomes expired by more
* than its grace period, it can no longer be renewed by anyone and is
* considered "released". The name must first be registered again, starting
* a new "registration lifecycle" of
* active / expired / grace period / released.
*
* May be 0.
*
* Guaranteed to be a non-negative bigint value.
*/
incrementalDuration: t.bigint().notNull(),
/**
* Base cost
*
* Base cost (before any `premium`) of Ether measured in units of Wei
* paid to execute the "logical registrar action".
*
* May be 0.
*
* Guaranteed to be:
* 1) null if and only if `total` is null.
* 2) Otherwise, a non-negative bigint value.
*/
baseCost: t.bigint(),
/**
* Premium
*
* "premium" cost (in excesses of the `baseCost`) of Ether measured in
* units of Wei paid to execute the "logical registrar action".
*
* May be 0.
*
* Guaranteed to be:
* 1) null if and only if `total` is null.
* 2) Otherwise, zero when `type` is `renewal`.
* 3) Otherwise, a non-negative bigint value.
*/
premium: t.bigint(),
/**
* Total
*
* Total cost of Ether measured in units of Wei paid to execute
* the "logical registrar action".
*
* May be 0.
*
* Guaranteed to be:
* 1) null if and only if both `baseCost` and `premium` are null.
* 2) Otherwise, a non-negative bigint value, equal to the sum of
* `baseCost` and `premium`.
*/
total: t.bigint(),
/**
* Registrant
*
* Identifies the address that initiated the "logical registrar action" and
* is paying the `total` cost (if applicable).
*
* It may not be the owner of the name:
* 1. When a name is registered, the initial owner of the name may be
* distinct from the registrant.
* 2. There are no restrictions on who may renew a name.
* Therefore the owner of the name may be distinct from the registrant.
*
*
* The "chainId" of this address is the same as is referenced in `subregistryId`.
*
* Guaranteed to be a fully lowercase address
*/
registrant: t.hex().notNull(),
/**
* Encoded Referrer
*
* Represents the "raw" 32-byte "referrer" value emitted onchain in
* association with the registrar action.
*
* Guaranteed to be:
* 1) null if the emitted `eventIds` contain no information about a referrer.
* 2) Otherwise, a fully lowercase hex string representation of 32-bytes.
*/
encodedReferrer: t.hex(),
/**
* Decoded referrer
*
* The referrer address decoded from `encodedReferrer` using strict
* left-zero-padding validation.
*
* Identifies the interpreted address of the referrer.
* The "chainId" of this address is the same as is referenced in
* `subregistryId`.
*
* Guaranteed to be:
* 1) null if `encodedReferrer` is null.
* 2) Otherwise, a fully lowercase address.
* 3) May be the "zero address" to represent that an `encodedReferrer` is
* defined but that it is interpreted as no referrer.
*/
decodedReferrer: t.hex(),
/**
* Number of the block that includes the "logical registrar action".
*
* The "chainId" of this block is the same as is referenced in
* `subregistryId`.
*
* Guaranteed to be a non-negative bigint value.
*/
blockNumber: t.bigint().notNull(),
/**
* Unix timestamp of the block referenced by `blockNumber` that includes
* the "logical registrar action".
*/
timestamp: t.bigint().notNull(),
/**
* Transaction hash of the transaction associated with
* the "logical registrar action".
*
* The "chainId" of this transaction is the same as is referenced in
* `subregistryId`.
*
* Note that a single transaction may be associated with any number of
* "logical registrar actions".
*
* Guaranteed to be a fully lowercase hex string representation of 32-bytes.
*/
transactionHash: t.hex().notNull(),
/**
* Event IDs
*
* Array of the eventIds that have contributed to the state of
* the "logical registrar action" record.
*
* Each eventId is a deterministic and globally unique onchain event
* identifier.
*
* Guarantees:
* - Each eventId is of events that occurred within the block
* referenced by `blockNumber`.
* - At least 1 eventId.
* - Ordered chronologically (ascending) by logIndex within `blockNumber`.
* - The first element in the array is equal to the `id` of
* the overall "logical registrar action" record.
*
* The following ideas are not generalized for ENS overall but happen to
* be a characteristic of the scope of our current indexing logic:
* 1. These id's always reference events emitted by
* a related "BaseRegistrar" contract.
* 2. These id's optionally reference events emitted by
* a related "Registrar Controller" contract. This is because our
* current indexing logic doesn't guarantee to index
* all "Registrar Controller" contracts.
*/
eventIds: t.text().array().notNull()
}),
(t) => ({
byDecodedReferrer: index2().on(t.decodedReferrer),
byTimestamp: index2().on(t.timestamp)
})
);
var internal_registrarActionMetadataType = onchainEnum2(
"_ensindexer_registrar_action_metadata_type",
["CURRENT_LOGICAL_REGISTRAR_ACTION"]
);
var internal_registrarActionMetadata = onchainTable4(
"_ensindexer_registrar_action_metadata",
(t) => ({
/**
* Registrar Action Metadata Type
*
* The type of internal registrar action metadata being stored.
*/
metadataType: internal_registrarActionMetadataType().primaryKey(),
/**
* Logical Event Key
*
* A fully lowercase string formatted as:
* `{domainId}:{transactionHash}`
*/
logicalEventKey: t.text().notNull(),
/**
* Logical Event ID
*
* A string holding the `id` value of the existing "logical registrar action"
* record that is currently being built as an aggregation of onchain events.
*
* May be used by subsequent event handlers to identify which
* "logical registrar action" to aggregate additional indexed state into.
*/
logicalEventId: t.text().notNull()
})
);
var subregistryRelations = relations3(subregistries, ({ many }) => ({
registrationLifecycle: many(registrationLifecycles)
}));
var registrationLifecycleRelations = relations3(
registrationLifecycles,
({ one, many }) => ({
subregistry: one(subregistries, {
fields: [registrationLifecycles.subregistryId],
references: [subregistries.subregistryId]
}),
registrarAction: many(registrarActions)
})
);
var registrarActionRelations = relations3(registrarActions, ({ one }) => ({
registrationLifecycle: one(registrationLifecycles, {
fields: [registrarActions.node],
references: [registrationLifecycles.node]
})
}));
// src/schemas/subgraph.schema.ts
import { index as index3, onchainTable as onchainTable5, relations as relations4 } from "ponder";
// src/lib/collate.ts
function monkeypatchCollate(col, collation) {
col.getSQLType = function() {
return `${Object.getPrototypeOf(this).getSQLType.call(this)} COLLATE ${collation}`;
};
return col;
}
// src/schemas/subgraph.schema.ts
var subgraph_domain = onchainTable5(
"subgraph_domains",
(t) => ({
// The namehash of the name
id: t.hex().primaryKey(),
/**
* The ENS Name that this Domain represents.
*
* If {@link ENSIndexerConfig#isSubgraphCompatible}, this value is guaranteed to be either:
* a) null (in the case of the root node), or
* b) a Subgraph Interpreted Name.
*
* @see https://ensnode.io/docs/reference/terminology#subgraph-indexability--labelname-interpretation
*
* Otherwise, this value is guaranteed to be an Interpreted Name, which is either:
* a) a normalized Name, or
* b) a Name entirely consisting of Interpreted Labels.
*
* Note that the type of the column will remain string | null, for legacy subgraph compatibility,
* but in practice will never be null. The Root node's name will be '' (empty string).
*
* @see https://ensnode.io/docs/reference/terminology#interpreted-name
*/
name: t.text(),
/**
* The Label associated with the Domain.
*
* If {@link ENSIndexerConfig#isSubgraphCompatible}, this value is guaranteed to be either:
* a) null, in the case of the root Node or a name whose childmost label is subgraph-unindexable, or
* b) a subgraph-indexable Subgraph Interpreted Label (i.e. a Literal Label of undefined normalization).
*
* @see https://ensnode.io/docs/reference/terminology#subgraph-indexability--labelname-interpretation
*
* Otherwise, this value is guaranteed to be an Interpreted Label which is either:
* a) null, exclusively in the case of the root Node,
* b) a normalized Label, or
* c) an Encoded LabelHash, which encodes either
* i. in the case of an Unknown Label, the LabelHash emitted onchain, or
* ii. in the case of an Unnormalized Label, the LabelHash of the Literal Label value found onchain.
*
* @see https://ensnode.io/docs/reference/terminology#interpreted-label
*/
labelName: t.text(),
// keccak256(labelName)
labelhash: t.hex(),
// The namehash (id) of the parent name
parentId: t.hex(),
// The number of subdomains
subdomainCount: t.integer().notNull().default(0),
// Address logged from current resolver, if any
resolvedAddressId: t.hex(),
// The resolver that controls the domain's settings
resolverId: t.text(),
// The time-to-live (TTL) value of the domain's records
ttl: t.bigint(),
// Indicates whether the domain has been migrated to a new registrar
isMigrated: t.boolean().notNull().default(false),
// The time when the domain was created
createdAt: t.bigint().notNull(),
// The account that owns the domain
ownerId: t.hex().notNull(),
// The account that owns the ERC721 NFT for the domain
registrantId: t.hex(),
// The account that owns the wrapped domain
wrappedOwnerId: t.hex(),
// The expiry date for the domain, from either the registration, or the wrapped domain if PCC is burned
expiryDate: t.bigint()
}),
(t) => ({
byLabelhash: index3().on(t.labelhash),
byParentId: index3().on(t.parentId),
byOwnerId: index3().on(t.ownerId),
byRegistrantId: index3().on(t.registrantId),
byWrappedOwnerId: index3().on(t.wrappedOwnerId)
})
);
monkeypatchCollate(subgraph_domain.name, '"C"');
monkeypatchCollate(subgraph_domain.labelName, '"C"');
var subgraph_domainRelations = relations4(subgraph_domain, ({ one, many }) => ({
resolvedAddress: one(subgraph_account, {
fields: [subgraph_domain.resolvedAddressId],
references: [subgraph_account.id]
}),
owner: one(subgraph_account, {
fields: [subgraph_domain.ownerId],
references: [subgraph_account.id]
}),
parent: one(subgraph_domain, {
fields: [subgraph_domain.parentId],
references: [subgraph_domain.id]
}),
resolver: one(subgraph_resolver, {
fields: [subgraph_domain.resolverId],
references: [subgraph_resolver.id]
}),
subdomains: many(subgraph_domain, { relationName: "parent" }),
registrant: one(subgraph_account, {
fields: [subgraph_domain.registrantId],
references: [subgraph_account.id]
}),
wrappedOwner: one(subgraph_account, {
fields: [subgraph_domain.wrappedOwnerId],
references: [subgraph_account.id]
}),
wrappedDomain: one(subgraph_wrappedDomain, {
fields: [subgraph_domain.id],
references: [subgraph_wrappedDomain.domainId]
}),
registration: one(subgraph_registration, {
fields: [subgraph_domain.id],
references: [subgraph_registration.domainId]
}),
// event relations
transfers: many(subgraph_transfer),
newOwners: many(subgraph_newOwner),
newResolvers: many(subgraph_newResolver),
newTTLs: many(subgraph_newTTL),
wrappedTransfers: many(subgraph_wrappedTransfer),
nameWrappeds: many(subgraph_nameWrapped),
nameUnwrappeds: many(subgraph_nameUnwrapped),
fusesSets: many(subgraph_fusesSet),
expiryExtendeds: many(subgraph_expiryExtended)
}));
var subgraph_account = onchainTable5("subgraph_accounts", (t) => ({
id: t.hex().primaryKey()
}));
var subgraph_accountRelations = relations4(subgraph_account, ({ many }) => ({
domains: many(subgraph_domain),
wrappedDomains: many(subgraph_wrappedDomain),
registrations: many(subgraph_registration)
}));
var subgraph_resolver = onchainTable5(
"subgraph_resolvers",
(t) => ({
// The unique identifier for this resolver, which is a concatenation of the domain namehash and the resolver address
id: t.text().primaryKey(),
// The domain that this resolver is associated with
domainId: t.hex().notNull(),
// The address of the resolver contract
address: t.hex().notNull().$type(),
// The current value of the 'addr' record for this resolver, as determined by the associated events
addrId: t.hex(),
// The content hash for this resolver, in binary format
contentHash: t.text(),
// The set of observed text record keys for this resolver
// NOTE: we avoid .notNull.default([]) to match subgraph behavior
texts: t.text().array(),
// The set of observed SLIP-44 coin types for this resolver
// NOTE: we avoid .notNull.default([]) to match subgraph behavior
coinTypes: t.bigint().array()
}),
(t) => ({
byDomainId: index3().on(t.domainId)
})
);
var subgraph_resolverRelations = relations4(subgraph_resolver, ({ one, many }) => ({
addr: one(subgraph_account, {
fields: [subgraph_resolver.addrId],
references: [subgraph_account.id]
}),
domain: one(subgraph_domain, {
fields: [subgraph_resolver.domainId],
references: [subgraph_domain.id]
}),
// event relations
addrChangeds: many(subgraph_addrChanged),
multicoinAddrChangeds: many(subgraph_multicoinAddrChanged),
nameChangeds: many(subgraph_nameChanged),
abiChangeds: many(subgraph_abiChanged),
pubkeyChangeds: many(subgraph_pubkeyChanged),
textChangeds: many(subgraph_textChanged),
contenthashChangeds: many(subgraph_contenthashChanged),
interfaceChangeds: many(subgraph_interfaceChanged),
authorisationChangeds: many(subgraph_authorisationChanged),
versionChangeds: many(subgraph_versionChanged)
}));
var subgraph_registration = onchainTable5(
"subgraph_registrations",
(t) => ({
// The unique identifier of the registration
id: t.hex().primaryKey(),
// The domain name associated with the registration
domainId: t.hex().notNull(),
// The registration date of the domain
registrationDate: t.bigint().notNull(),
// The expiry date of the domain
expiryDate: t.bigint().notNull(),
// The cost associated with the domain registration
cost: t.bigint(),
// The account that registered the domain
registrantId: t.hex().notNull(),
/**
* The Label associated with the domain registration.
*
* If {@link ENSIndexerConfig#isSubgraphCompatible}, this value is guaranteed to be either:
* a) null, in the case of the root Node or a Domain whose label is subgraph-unindexable, or
* b) a subgraph-indexable Subgraph Interpreted Label (i.e. a Literal Label of undefined normalization).
*
* @see https://ensnode.io/docs/reference/terminology#subgraph-indexability--labelname-interpretation
*
* Otherwise, this value is guaranteed to be an Interpreted Label which is either:
* a) a normalized Label, or
* b) in the case of an Unnormalized Label, an Encoded LabelHash of the Literal Label value found onchain.
*
* Note that the type of the column will remain string | null, for legacy subgraph compatibility.
* In practice however, because there is no Registration entity for the root Node (the only Node
* with a null labelName) this field will never be null.
*
* @see https://ensnode.io/docs/reference/terminology#interpreted-label
*/
labelName: t.text()
}),
(t) => ({
byDomainId: index3().on(t.domainId),
byRegistrationDate: index3().on(t.registrationDate)
})
);
var subgraph_registrationRelations = relations4(subgraph_registration, ({ one, many }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_registration.domainId],
references: [subgraph_domain.id]
}),
registrant: one(subgraph_account, {
fields: [subgraph_registration.registrantId],
references: [subgraph_account.id]
}),
// event relations
nameRegistereds: many(subgraph_nameRegistered),
nameReneweds: many(subgraph_nameRenewed),
nameTransferreds: many(subgraph_nameTransferred)
}));
var subgraph_wrappedDomain = onchainTable5(
"subgraph_wrapped_domains",
(t) => ({
// The unique identifier for each instance of the WrappedDomain entity
id: t.hex().primaryKey(),
// The domain that is wrapped by this WrappedDomain
domainId: t.hex().notNull(),
// The expiry date of the wrapped domain
expiryDate: t.bigint().notNull(),
// The number of fuses remaining on the wrapped domain
fuses: t.integer().notNull(),
// The account that owns this WrappedDomain
ownerId: t.hex().notNull(),
/**
* The Name that this WrappedDomain represents. Names are emitted by the NameWrapper contract as
* DNS-Encoded Names which may be malformed, which will result in this field being `null`.
*
* If {@link ENSIndexerConfig#isSubgraphCompatible}, this value is guaranteed to be either:
* a) null (in the case of a DNS-Encoded Name that is malformed or contains subgraph-unindexable labels), or
* b) a subgraph-indexable Subgraph Interpreted Label (i.e. a Literal Label of undefined normalization).
*
* @see https://ensnode.io/docs/reference/terminology#subgraph-indexability--labelname-interpretation
*
* Otherwise, this value is guaranteed to be either:
* a) null (in the case of a malformed DNS-Encoded Name),
* b) an Interpreted Name.
*
* @see https://ensnode.io/docs/reference/terminology#interpreted-name
*/
name: t.text()
}),
(t) => ({
byDomainId: index3().on(t.domainId)
})
);
var subgraph_wrappedDomainRelations = relations4(subgraph_wrappedDomain, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_wrappedDomain.domainId],
references: [subgraph_domain.id]
}),
owner: one(subgraph_account, {
fields: [subgraph_wrappedDomain.ownerId],
references: [subgraph_account.id]
})
}));
var sharedEventColumns = (t) => ({
id: t.text().primaryKey(),
blockNumber: t.integer().notNull(),
transactionID: t.hex().notNull()
});
var domainEvent = (t) => ({
...sharedEventColumns(t),
domainId: t.hex().notNull()
});
var domainEventIndex = (t) => ({
// primary reverse lookup
idx: index3().on(t.domainId),
// sorting index
idx_compound: index3().on(t.domainId, t.id)
});
var subgraph_transfer = onchainTable5(
"subgraph_transfers",
(t) => ({
...domainEvent(t),
ownerId: t.hex().notNull()
}),
domainEventIndex
);
var subgraph_newOwner = onchainTable5(
"subgraph_new_owners",
(t) => ({
...domainEvent(t),
ownerId: t.hex().notNull(),
parentDomainId: t.hex().notNull()
}),
domainEventIndex
);
var subgraph_newResolver = onchainTable5(
"subgraph_new_resolvers",
(t) => ({
...domainEvent(t),
resolverId: t.text().notNull()
}),
domainEventIndex
);
var subgraph_newTTL = onchainTable5(
"subgraph_new_ttls",
(t) => ({
...domainEvent(t),
ttl: t.bigint().notNull()
}),
domainEventIndex
);
var subgraph_wrappedTransfer = onchainTable5(
"subgraph_wrapped_transfers",
(t) => ({
...domainEvent(t),
ownerId: t.hex().notNull()
}),
domainEventIndex
);
var subgraph_nameWrapped = onchainTable5(
"subgraph_name_wrapped",
(t) => ({
...domainEvent(t),
name: t.text(),
fuses: t.integer().notNull(),
ownerId: t.hex().notNull(),
expiryDate: t.bigint().notNull()
}),
domainEventIndex
);
var subgraph_nameUnwrapped = onchainTable5(
"subgraph_name_unwrapped",
(t) => ({
...domainEvent(t),
ownerId: t.hex().notNull()
}),
domainEventIndex
);
var subgraph_fusesSet = onchainTable5(
"subgraph_fuses_set",
(t) => ({
...domainEvent(t),
fuses: t.integer().notNull()
}),
domainEventIndex
);
var subgraph_expiryExtended = onchainTable5(
"subgraph_expiry_extended",
(t) => ({
...domainEvent(t),
expiryDate: t.bigint().notNull()
}),
domainEventIndex
);
var registrationEvent = (t) => ({
...sharedEventColumns(t),
registrationId: t.hex().notNull()
});
var registrationEventIndex = (t) => ({
// primary reverse lookup
idx: index3().on(t.registrationId),
// sorting index
idx_compound: index3().on(t.registrationId, t.id)
});
var subgraph_nameRegistered = onchainTable5(
"subgraph_name_registered",
(t) => ({
...registrationEvent(t),
registrantId: t.hex().notNull(),
expiryDate: t.bigint().notNull()
}),
registrationEventIndex
);
var subgraph_nameRenewed = onchainTable5(
"subgraph_name_renewed",
(t) => ({
...registrationEvent(t),
expiryDate: t.bigint().notNull()
}),
registrationEventIndex
);
var subgraph_nameTransferred = onchainTable5(
"subgraph_name_transferred",
(t) => ({
...registrationEvent(t),
newOwnerId: t.hex().notNull()
}),
registrationEventIndex
);
var resolverEvent = (t) => ({
...sharedEventColumns(t),
resolverId: t.text().notNull()
});
var resolverEventIndex = (t) => ({
// primary reverse lookup
idx: index3().on(t.resolverId),
// sorting index
idx_compound: index3().on(t.resolverId, t.id)
});
var subgraph_addrChanged = onchainTable5(
"subgraph_addr_changed",
(t) => ({
...resolverEvent(t),
addrId: t.hex().notNull()
}),
resolverEventIndex
);
var subgraph_multicoinAddrChanged = onchainTable5(
"subgraph_multicoin_addr_changed",
(t) => ({
...resolverEvent(t),
coinType: t.bigint().notNull(),
addr: t.hex().notNull()
}),
resolverEventIndex
);
var subgraph_nameChanged = onchainTable5(
"subgraph_name_changed",
(t) => ({
...resolverEvent(t),
name: t.text().notNull()
}),
resolverEventIndex
);
var subgraph_abiChanged = onchainTable5(
"subgraph_abi_changed",
(t) => ({
...resolverEvent(t),
contentType: t.bigint().notNull()
}),
resolverEventIndex
);
var subgraph_pubkeyChanged = onchainTable5(
"subgraph_pubkey_changed",
(t) => ({
...resolverEvent(t),
x: t.hex().notNull(),
y: t.hex().notNull()
}),
resolverEventIndex
);
var subgraph_textChanged = onchainTable5(
"subgraph_text_changed",
(t) => ({
...resolverEvent(t),
key: t.text().notNull(),
value: t.text()
}),
resolverEventIndex
);
var subgraph_contenthashChanged = onchainTable5(
"subgraph_contenthash_changed",
(t) => ({
...resolverEvent(t),
hash: t.hex().notNull()
}),
resolverEventIndex
);
var subgraph_interfaceChanged = onchainTable5(
"subgraph_interface_changed",
(t) => ({
...resolverEvent(t),
interfaceID: t.hex().notNull(),
implementer: t.hex().notNull()
}),
resolverEventIndex
);
var subgraph_authorisationChanged = onchainTable5(
"subgraph_authorisation_changed",
(t) => ({
...resolverEvent(t),
owner: t.hex().notNull(),
target: t.hex().notNull(),
isAuthorized: t.boolean().notNull()
}),
resolverEventIndex
);
var subgraph_versionChanged = onchainTable5(
"subgraph_version_changed",
(t) => ({
...resolverEvent(t),
version: t.bigint().notNull()
}),
resolverEventIndex
);
var subgraph_transferRelations = relations4(subgraph_transfer, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_transfer.domainId],
references: [subgraph_domain.id]
}),
owner: one(subgraph_account, {
fields: [subgraph_transfer.ownerId],
references: [subgraph_account.id]
})
}));
var subgraph_newOwnerRelations = relations4(subgraph_newOwner, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_newOwner.domainId],
references: [subgraph_domain.id]
}),
owner: one(subgraph_account, {
fields: [subgraph_newOwner.ownerId],
references: [subgraph_account.id]
}),
parentDomain: one(subgraph_domain, {
fields: [subgraph_newOwner.parentDomainId],
references: [subgraph_domain.id]
})
}));
var subgraph_newResolverRelations = relations4(subgraph_newResolver, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_newResolver.domainId],
references: [subgraph_domain.id]
}),
resolver: one(subgraph_resolver, {
fields: [subgraph_newResolver.resolverId],
references: [subgraph_resolver.id]
})
}));
var subgraph_newTTLRelations = relations4(subgraph_newTTL, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_newTTL.domainId],
references: [subgraph_domain.id]
})
}));
var subgraph_wrappedTransferRelations = relations4(subgraph_wrappedTransfer, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_wrappedTransfer.domainId],
references: [subgraph_domain.id]
}),
owner: one(subgraph_account, {
fields: [subgraph_wrappedTransfer.ownerId],
references: [subgraph_account.id]
})
}));
var subgraph_nameWrappedRelations = relations4(subgraph_nameWrapped, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_nameWrapped.domainId],
references: [subgraph_domain.id]
}),
owner: one(subgraph_account, {
fields: [subgraph_nameWrapped.ownerId],
references: [subgraph_account.id]
})
}));
var subgraph_nameUnwrappedRelations = relations4(subgraph_nameUnwrapped, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_nameUnwrapped.domainId],
references: [subgraph_domain.id]
}),
owner: one(subgraph_account, {
fields: [subgraph_nameUnwrapped.ownerId],
references: [subgraph_account.id]
})
}));
var subgraph_fusesSetRelations = relations4(subgraph_fusesSet, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_fusesSet.domainId],
references: [subgraph_domain.id]
})
}));
var subgraph_expiryExtendedRelations = relations4(subgraph_expiryExtended, ({ one }) => ({
domain: one(subgraph_domain, {
fields: [subgraph_expiryExtended.domainId],
references: [subgraph_domain.id]
})
}));
var subgraph_nameRegisteredRelations = relations4(subgraph_nameRegistered, ({ one }) => ({
registration: one(subgraph_registration, {
fields: [subgraph_nameRegistered.registrationId],
references: [subgraph_registration.id]
}),
registrant: one(subgraph_account, {
fields: [subgraph_nameRegistered.registrantId],
references: [subgraph_account.id]
})
}));
var subgraph_nameRenewedRelations = relations4(subgraph_nameRenewed, ({ one }) => ({
registration: one(subgraph_registration, {
fields: [subgraph_nameRenewed.registrationId],
references: [subgraph_registration.id]
})
}));
var subgraph_nameTransferredRelations = relations4(subgraph_nameTransferred, ({ one }) => ({
registration: one(subgraph_registration, {
fields: [subgraph_nameTransferred.registrationId],
references: [subgraph_registration.id]
}),
newOwner: one(subgraph_account, {
fields: [subgraph_nameTransferred.newOwnerId],
references: [subgraph_account.id]
})
}));
var subgraph_addrChangedRelations = relations4(subgraph_addrChanged, ({ one }) => ({
resolver: one(subgraph_resolver, {
fields: [subgraph_addrChanged.resolverId],
references: [subgraph_resolver.id]
}),
addr: one(subgraph_account, {
fields: [subgraph_addrChanged.addrId],
references: [subgraph_account.id]
})
}));
var subgraph_multicoinAddrChangedRelations = relations4(
subgraph_multicoinAddrChanged,
({ one }) => ({