On a recent ecosystem call I asked a query about the supersession of previous standards in the context of ENSIPs. I had written resolvers that I believed to be to spec but in certain Wallet clients and libraries they were not working as expected. Some of the issues were on my end, others were in the client implementations.
Having read through all of the ENSIPs again I think it would be extremely useful if ENSIPs (or sections of them) that have been superseded by another ENSIP could have notices added which forward users to the latest related specification. Thoughts?
As regards incorrect client implementations I have found some of the specs to be a little confusing. I do appreciate that many were written many many years ago. I was hoping that other ecosystem participants could provide clarity where my understanding is incorrect…
Some context
As it relates to forward name resolution we currently have the following ENSIPs that I have considered here.
ENSIP-1
Resolvers MUST specify a fallback function that throws.
I see a lot of resolvers that do not do this.
Resolvers wishing to support contract address resources must provide the following function.
This is clear but there is no similar clarity on what clients should do to correctly integrate the protocol. I appreciate that in the early days a client could reasonably assume that something labelled as a resolver by the Registry would implement addr(node)
but as the protocol has developed and extended there is a solid (in my opinion) argument for now requiring clients to call the ERC165 supportsInterface
method to discern the appropriate resolution path. I feel as though clarity on precedence should also be codified (discussed further down).
I use ethers.js as an example as it is the client library with which I have the most experience. Within the ethers.js ENS resolver functionality resolution checks if a resolver supports Wildcard Resolution and if it does not calls addr(node)
.
ENSIP 9
ENSIP-9 does not specify any requirement to implement supportsInterface
for its respective Interface ID. This is inconsistent with other ENSIPs.
With ethers.js if someone does not implement ENSIP-10 but does implement ENSIP-9 they necessarily have to support ENSIP-1 for support when resolving chain ID 60, Mainnet Ethereum.
What is the expectation? Is the idea that the entry point for mainnet resolution is always addr(node)
? That seems to be what is being assumed here. I have no issue with that assumption, I just think it needs clarifying.
The backwards compatibility section notes:
If the resolver supports the
addr(bytes32)
interface
The implication being that ENSIP-9 can be implemented without needing ENSIP-1 addr(node)
to be implemented and as such my resolver that does so should really work with common client libraries.
ENSIP 10
I have outlined my understanding of ENSIP-10 below. I have spent numerous hours re-reading this, and looking at/testing client implementations.
ENSIP-10 is named Wildcard Resolution yet it holds the specification for the IExtendedResolver
interface and notes explicitly:
“Resolvers wishing to implement the new
resolve
function for non-wildcard use-cases (eg, where the resolver is set directly on the name being resolved) should consider what to return to legacy clients that call the individual resolution functions for maximum compatibility.”
The implication is that its contents don’t specifically pertain to Wildcard Resolution and that resolve
can be called with a current name that is equal to the queried name.
In principle a to specification resolver could be set on a 2LD and implement resolve
standalone without any connection to subnames or wildcard resolution which makes the naming of the ENSIP a little confusing.
The latter part of that statement implies that you can implement both resolve
and the ENSIP-1 addr
method (for example), and that you probably should for backwards compatibility with clients that are not up to date with the latest specs.
My read is that the IExtendedResolver
interface is the generic resolution entry point and the wildcard aspect is simply ‘current name != queried name’.
The spec continues on to state:
- If
supportsENSIP10
is false andname == currentname
, setresult
to the result of callingresolver
withcalldata
.
So in the non-wildcard case we call the resolver directly with the calldata completely bypassing the (not implemented) resolve
method.
This then comes full circle to that outlined in the section on ENSIP-9. In this scenario ethers.js will call through to addr(node)
assuming its existence.
Thoughts
There are a few inline questions in the body above.
My only other question is as to what clients should do in terms of discoverability and precedence moving forward. Is there potential for improvements in this regard?
In my opinion an ideal client implementation should call supportsInterface
for the available resolution interfaces - IExtendedResolver
, the ENSIP-9 addr(node,cointype)
interface, and the ENSIP-1 addr(node)
interface. This should be done up front using a multicall. The results should be considered in that order of precedence.
If IExtendedResolver
returns true, find the appropriate resolver and call resolve
. If it returns false call the next implemented addr
. If none are implemented => 0x
I.E. Determine the available resolution paths, use the most ‘modern’.
What do others thing about this?