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/reclassify-extended-on-proxy-upgrade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ensindexer": patch
---

ENSIndexer now re-derives a Resolver's ENSIP-10 `IExtendedResolver` support when a known proxy Resolver emits an EIP-1967 `Upgraded` event, instead of fixing the value once at first visibility. Proxy Resolvers that activate `IExtendedResolver` via a post-assignment upgrade (e.g. the 3DNS Resolver behind `.box`) were stuck `extended = false` forever, silently breaking wildcard resolution for affected names.
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,54 @@ type ResolverRecordsCompositeKey = Pick<
>;

/**
* Ensures a Resolver entity exists for `resolver`, capturing additional metadata.
*
* @dev performs a single `supportsInterface` RPC (via Ponder's cached `context.client`) to determine
* `isExtended` support.
* Ensures a Resolver entity exists for `resolver`, deriving its Supported Interfaces on first insert.
*/
Comment thread
shrugs marked this conversation as resolved.
export async function upsertResolver(
context: IndexingEngineContext,
resolver: AccountId,
): Promise<typeof ensIndexerSchema.resolver.$inferSelect> {
export async function upsertResolver(context: IndexingEngineContext, resolver: AccountId) {
const id = makeResolverId(resolver);

const existing = await context.ensDb.find(ensIndexerSchema.resolver, { id });
if (existing) return existing;

// if already exists, no-op
if (existing) return;

// insert the new Resolver record
await context.ensDb.insert(ensIndexerSchema.resolver).values({ id, ...resolver });
Comment thread
shrugs marked this conversation as resolved.

// update its Supported Interfaces
await updateResolverInterfaces(context, resolver);
Comment thread
shrugs marked this conversation as resolved.
}

/**
* Updates a Resolver's Supported Interfaces.
*/
async function updateResolverInterfaces(context: IndexingEngineContext, resolver: AccountId) {
const id = makeResolverId(resolver);

const isExtended = await isExtendedResolver({
publicClient: context.client,
address: resolver.address,
publicClient: context.client,
});

const row = { id, ...resolver, isExtended };
await context.ensDb.insert(ensIndexerSchema.resolver).values(row).onConflictDoNothing();
return row;
await context.ensDb.update(ensIndexerSchema.resolver, { id }).set({ isExtended });
}

/**
* Handles a Resolver's implementation changing by updating its Supported Interfaces, if the Resolver
* is already indexed.
*
* @dev intentionally avoids upserting a Resolver entity for contracts not already an indexed Resolver.
* If a contract were to emit Upgraded and then emit a Resolver event, `upsertResolver` above would
* ensure that the Supported Interfaces are correctly indexed.
*/
export async function handleResolverImplementationChange(
context: IndexingEngineContext,
resolver: AccountId,
) {
const id = makeResolverId(resolver);
const existing = await context.ensDb.find(ensIndexerSchema.resolver, { id });
if (!existing) return;

await updateResolverInterfaces(context, resolver);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import attach_ENSv2RegistryHandlers from "./handlers/ENSv2Registry";
import attach_ResolverHandlers from "./handlers/Resolver";
import attach_StandaloneReverseRegistrarHandlers from "./handlers/StandaloneReverseRegistrar";
import attach_ThreeDNSTokenHandlers from "./handlers/ThreeDNSToken";
import attach_UpgradeableProxyResolverHandlers from "./handlers/UpgradeableProxyResolver";

export default function () {
attach_ENSv1RegistryHandlers();
attach_ENSv2RegistryHandlers();
attach_ResolverHandlers();
attach_StandaloneReverseRegistrarHandlers();
attach_UpgradeableProxyResolverHandlers();
attach_ThreeDNSTokenHandlers();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { PluginName } from "@ensnode/ensnode-sdk";

import { getThisAccountId } from "@/lib/get-this-account-id";
import { addOnchainEventListener } from "@/lib/indexing-engines/ponder";
import { namespaceContract } from "@/lib/plugin-helpers";
import { handleResolverImplementationChange } from "@/lib/protocol-acceleration/resolver-db-helpers";

const pluginName = PluginName.ProtocolAcceleration;

/**
* Handlers for any Resolvers that are UpgradeableProxies, necessary for tracking implementation updates.
*/
export default function () {
addOnchainEventListener(
namespaceContract(pluginName, "UpgradeableProxyResolver:Upgraded"),
async ({ context, event }) => {
const resolver = getThisAccountId(context, event);
await handleResolverImplementationChange(context, resolver);
},
);
}
17 changes: 17 additions & 0 deletions apps/ensindexer/src/plugins/protocol-acceleration/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ResolverABI,
StandaloneReverseRegistrarABI,
ThreeDNSTokenABI,
UpgradeableProxyABI,
} from "@ensnode/datasources";
import { buildBlockNumberRange, PluginName } from "@ensnode/ensnode-sdk";
import {
Expand Down Expand Up @@ -101,6 +102,22 @@ export default createPlugin({
),
},

////////////////////////////
// UpgradeableProxyResolver
////////////////////////////
[namespaceContract(pluginName, "UpgradeableProxyResolver")]: {
abi: UpgradeableProxyABI,
chain: {
// the DotBoxL1Resolver is an UpgradeableProxy
...("DotBoxL1Resolver" in ensroot.contracts &&
chainConfigForContract(
config.globalBlockrange,
ensroot.chain.id,
ensroot.contracts.DotBoxL1Resolver,
)),
},
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/////////////////////
// ENSv1 RegistryOld
/////////////////////
Expand Down
18 changes: 18 additions & 0 deletions packages/datasources/src/abis/shared/UpgradeableProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Abi } from "viem";

/**
* Minimal ABI for EIP-1967 upgradeable proxies.
*
* Captures only the `Upgraded(address indexed implementation)` event, emitted by transparent/UUPS
* proxies whenever their implementation slot changes.
*
* @see https://eips.ethereum.org/EIPS/eip-1967
*/
export const UpgradeableProxy = [
{
type: "event",
name: "Upgraded",
inputs: [{ name: "implementation", type: "address", indexed: true, internalType: "address" }],
anonymous: false,
},
] as const satisfies Abi;
1 change: 1 addition & 0 deletions packages/datasources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { Registry as RegistryABI } from "./abis/ensv2/Registry";
export { L2ReverseRegistrar as L2ReverseRegistrarABI } from "./abis/root/L2ReverseRegistrar";
export { StandaloneReverseRegistrar as StandaloneReverseRegistrarABI } from "./abis/shared/StandaloneReverseRegistrar";
export { UniversalResolverABI } from "./abis/shared/UniversalResolver";
export { UpgradeableProxy as UpgradeableProxyABI } from "./abis/shared/UpgradeableProxy";
export { ThreeDNSToken as ThreeDNSTokenABI } from "./abis/threedns/ThreeDNSToken";
export * from "./identify-contracts";
export { AnyRegistrarABI } from "./lib/AnyRegistrarABI";
Expand Down
5 changes: 5 additions & 0 deletions packages/datasources/src/mainnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ export default {
address: "0x1507ce9421232fdbd302f5ebe4590f8d77febbff",
startBlock: 24640923,
},
DotBoxL1Resolver: {
abi: ResolverABI,
address: "0xf97aac6c8dbaebcb54ff166d79706e3af7a813c8",
startBlock: 19128555,
},

// the Resolver for *.argent.xyz names
ArgentResolver: {
Expand Down
Loading