Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions .changeset/strong-baboons-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ensapi": minor
---

ENSNode GraphQL API: `ENSv1Domain.rootRegistryOwner` is now available, indicating the owner of the Domain's node within the ENSv1 Registry contract.
11 changes: 11 additions & 0 deletions apps/ensapi/src/graphql-api/schema/domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,17 @@ ENSv1DomainRef.implement({
nullable: true,
resolve: (parent) => parent.parentId,
}),

/////////////////////////////////
// ENSv1Domain.rootRegistryOwner
/////////////////////////////////
rootRegistryOwner: t.field({
description:
"The rootRegistryOwner of this Domain, i.e. the owner() of this Domain within the ENSv1 Registry.",
type: AccountRef,
nullable: true,
resolve: (parent) => parent.rootRegistryOwnerId,
}),
}),
});

Expand Down
37 changes: 19 additions & 18 deletions apps/ensindexer/src/plugins/ensv2/handlers/ensv1/ENSv1Registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,14 @@ export default function () {
// upsert domain
await context.db
.insert(schema.v1Domain)
.values({
id: domainId,
parentId,
labelHash,
})
.values({ id: domainId, parentId, labelHash })
.onConflictDoNothing();

// update rootRegistryOwner
await context.db
.update(schema.v1Domain, { id: domainId })
.set({ rootRegistryOwnerId: interpretAddress(owner) });

// materialize domain owner
// NOTE: despite Domain.ownerId being materialized from other sources of truth (i.e. Registrars
// like BaseRegistrars & NameWrapper) it's ok to always set it here because the Registrar-emitted
Expand All @@ -99,25 +100,25 @@ export default function () {
context: Context;
event: EventWithArgs<{ node: Node; owner: Address }>;
}) {
const { node, owner: _owner } = event.args;
const owner = interpretAddress(_owner);
const { node, owner } = event.args;

// ENSv2 model does not include root node, no-op
if (node === ROOT_NODE) return;

const domainId = makeENSv1DomainId(node);

if (owner === null) {
await context.db.delete(schema.v1Domain, { id: domainId });
} else {
// materialize domain owner
// NOTE: despite Domain.ownerId being materialized from other sources of truth (i.e. Registrars
// like BaseRegistrars & NameWrapper) it's ok to always set it here because the Registrar-emitted
// events occur _after_ the Registry events. So when a name is wrapped, for example, the Registry's
// owner changes to that of the NameWrapper but then the NameWrapper emits NameWrapped, and this
// indexing code re-materializes the Domain.ownerId to the NameWraper-emitted value.
await materializeENSv1DomainEffectiveOwner(context, domainId, owner);
}
// set the domain's rootRegistryOwner to `owner`
await context.db
.update(schema.v1Domain, { id: domainId })
.set({ rootRegistryOwnerId: interpretAddress(owner) });

// materialize domain owner
// NOTE: despite Domain.ownerId being materialized from other sources of truth (i.e. Registrars
// like BaseRegistrars & NameWrapper) it's ok to always set it here because the Registrar-emitted
// events occur _after_ the Registry events. So when a name is wrapped, for example, the Registry's
// owner changes to that of the NameWrapper but then the NameWrapper emits NameWrapped, and this
// indexing code re-materializes the Domain.ownerId to the NameWraper-emitted value.
await materializeENSv1DomainEffectiveOwner(context, domainId, owner);
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/ensnode-schema/src/schemas/ensv2.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ export const v1Domain = onchainTable(
// represents a labelHash
labelHash: t.hex().notNull().$type<LabelHash>(),

// may have a `rootRegistryOwner` (ENSv1Registry's owner()), zeroAddress interpreted as null
rootRegistryOwnerId: t.hex().$type<Address>(),

// NOTE: Domain-Resolver Relations tracked via Protocol Acceleration plugin
}),
(t) => ({
Expand All @@ -190,6 +193,11 @@ export const relations_v1Domain = relations(v1Domain, ({ one, many }) => ({
references: [v1Domain.id],
}),
children: many(v1Domain, { relationName: "parent" }),
rootRegistryOwner: one(account, {
relationName: "rootRegistryOwner",
fields: [v1Domain.rootRegistryOwnerId],
references: [account.id],
}),

// shared
owner: one(account, {
Expand Down
4 changes: 4 additions & 0 deletions packages/ensnode-sdk/src/graphql-api/example-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ query DomainByName($name: Name!) {
label { interpreted }
name

... on ENSv1Domain {
rootRegistryOwner { address }
}

... on ENSv2Domain {
subregistry {
contract { chainId address }
Expand Down