You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Aug 5, 2026. It is now read-only.
This repository was archived by the owner on Aug 5, 2026. It is now read-only.
ENSIndexer: Resolver.extended (is_extended) goes stale for proxy resolvers that activate IExtendedResolver after assignment — breaks wildcard resolution (.box) #2275
The resolvers.is_extended flag (whether a Resolver implements ENSIP-10 IExtendedResolver, surfaced as Resolver.extended) is classified once, at the block the resolver is first seen, via an eip-165 supportsInterface probe through Ponder's context.client. For proxy resolvers that activate IExtendedResolver after they're assigned (deploy-then-upgrade / lazy-init — extremely common), the flag is computed against the pre-upgrade implementation and gets stuck false forever.
Because extended must stay indexed (we deliberately avoid an RPC probe at omnigraph-query / accelerated-resolution time), a stale falsesilently breaks wildcard resolution: affected names don't virtualize into UnindexedDomain and Domain.resolve returns null. This hits whole TLDs (e.g. .box / 3DNS) and any wildcard whose resolver was a proxy at assignment time.
proxy deployed and set as box's resolver (same block); impl slot = 0xb4cd…959b
reverts
19128940 (~1.3h later)
EIP-1967 Upgraded → impl slot = 0xee65…4546
true (from here on)
ENSIndexer probed supportsInterface at the assignment block (19128555, old impl → revert) → cached is_extended=false. Never re-checked. Result: mystery.box returns domain: null instead of resolving (0x130EF17d1E1616470B3c51AfDf31625B7F767562).
Requirements
Keep extendedindexed — no supportsInterface RPC at query / acceleration time.
Agreed direction: classify on first visibility + re-check on known upgrade patterns.
Constraints / why the obvious approaches don't work
"Just probe at latest/finalized instead of the event block." We don't trivially have access to "the most recent block" inside the indexing context, so we can't simply move the probe to head.
Ponder factory() to watch each resolver's Upgraded events won't work.NewResolverregisters/references a pre-existing contract, it doesn't create it — so Ponder only sees the resolver from its "connection" point forward and misses upgrade events prior to first visibility. Not a general solution.
Proposed approach (scope: support the .box case for now)
Initial classification at first visibility (current behavior) — keep.
Re-check is_extended when the resolver undergoes a known proxy upgrade pattern, re-running the eip-165 probe and updating the row:
EIP-1967 Upgraded(address) (transparent / UUPS) — the .box case
BeaconUpgraded(address) + the beacon'sUpgraded (beacon proxies — one beacon ⇒ many resolvers)
(later) EIP-2535 DiamondCut if any resolver uses facets
Open design question: how to observe these upgrade events given constraint NameWrapper + Checkpointing #2 (factory won't catch pre-visibility upgrades). Options to evaluate: a topic-scoped Upgraded log source filtered to known resolver addresses; statically watching the known 3DNS resolver/beacon contracts; or a bounded re-probe of resolvers on a finalized cadence. Pick the narrowest thing that fixes .box.
Stopgap already applied (current 1.15.2 green index)
Manually set is_extended=true for 1-0xf97aac6c8dbaebcb54ff166d79706e3af7a813c8 in alphaSchema1.15.2 (session-local session_replication_role=replica to bypass the live_query/reorg triggers). Verified: mystery.box → 0x130EF…7562. The real fix lands in the next release.
Related
Sibling resolution-robustness fix (separate, already patched in working tree): multicoin addr(node, 60) decode crashes when a resolver returns address-encoding instead of bytes (e.g. world.id) — apps/ensapi/src/lib/resolution/execute-operations.ts.
Summary
The
resolvers.is_extendedflag (whether a Resolver implements ENSIP-10IExtendedResolver, surfaced asResolver.extended) is classified once, at the block the resolver is first seen, via an eip-165supportsInterfaceprobe through Ponder'scontext.client. For proxy resolvers that activateIExtendedResolverafter they're assigned (deploy-then-upgrade / lazy-init — extremely common), the flag is computed against the pre-upgrade implementation and gets stuckfalseforever.Because
extendedmust stay indexed (we deliberately avoid an RPC probe at omnigraph-query / accelerated-resolution time), a stalefalsesilently breaks wildcard resolution: affected names don't virtualize intoUnindexedDomainandDomain.resolvereturns null. This hits whole TLDs (e.g..box/ 3DNS) and any wildcard whose resolver was a proxy at assignment time.Evidence (cast, mainnet)
boxTLD resolver0xf97aac6c8dbaebcb54ff166d79706e3af7a813c8(EIP-1967 proxy):box's resolver (same block); impl slot =0xb4cd…959bUpgraded→ impl slot =0xee65…4546ENSIndexer probed
supportsInterfaceat the assignment block (19128555, old impl → revert) → cachedis_extended=false. Never re-checked. Result:mystery.boxreturnsdomain: nullinstead of resolving (0x130EF17d1E1616470B3c51AfDf31625B7F767562).Requirements
extendedindexed — nosupportsInterfaceRPC at query / acceleration time.Constraints / why the obvious approaches don't work
latest/finalized instead of the event block." We don't trivially have access to "the most recent block" inside the indexing context, so we can't simply move the probe to head.factory()to watch each resolver'sUpgradedevents won't work.NewResolverregisters/references a pre-existing contract, it doesn't create it — so Ponder only sees the resolver from its "connection" point forward and misses upgrade events prior to first visibility. Not a general solution.Proposed approach (scope: support the
.boxcase for now)is_extendedwhen the resolver undergoes a known proxy upgrade pattern, re-running the eip-165 probe and updating the row:Upgraded(address)(transparent / UUPS) — the.boxcaseBeaconUpgraded(address)+ the beacon'sUpgraded(beacon proxies — one beacon ⇒ many resolvers)DiamondCutif any resolver uses facetsUpgradedlog source filtered to known resolver addresses; statically watching the known 3DNS resolver/beacon contracts; or a bounded re-probe of resolvers on a finalized cadence. Pick the narrowest thing that fixes.box.Stopgap already applied (current
1.15.2green index)Manually set
is_extended=truefor1-0xf97aac6c8dbaebcb54ff166d79706e3af7a813c8inalphaSchema1.15.2(session-localsession_replication_role=replicato bypass thelive_query/reorgtriggers). Verified:mystery.box→0x130EF…7562. The real fix lands in the next release.Related
Sibling resolution-robustness fix (separate, already patched in working tree): multicoin
addr(node, 60)decode crashes when a resolver returns address-encoding instead ofbytes(e.g.world.id) —apps/ensapi/src/lib/resolution/execute-operations.ts.Part of #1360.