New ENSIP draft: Gasless DNS resolution

By popular demand, I’ve written up the protocol used by our new gasless DNSSEC implementation. This draft ENSIP specifies how gasless DNSSEC TXT records are formatted, how the resolver’s resolution process functions, and provides a public API for the CCIP-Read DNSSEC gateway used for the implementation.

Feedback greatly appreciated.

8 Likes

So let me ask this–

You can essentially set your your address that is registered to an ENS in the text record once ( ENS 1 ).

Write a custom contract that inherits the public resolver…

( and add text record in a subsequent TXT record entry. By logic the TXT record after ENS1 ( if doesn’t contain ’ . ‘) and ’ is address’ will be read as the resolver, and in this case would be the addr of the custom resolver)

…and implement a proxy-redirect that you can control by setAddr or remove Addr, allowing you to change your receiving address without having to change your addr your name is registered with. This provides more privacy as to where your tx actually ends up?

registered name / addr : name.eth 0x010
public resolver : 0x020
custom resolver 0x030
redirect addr : 0x040

gateway reads 0x030 (set at ens 3) ->reads 0x020 ->relays back to 0x030which tells the gateway 0x040 ( where tx is actually sent )

txt ens 1 0x010
txt ens 2 0x020
txt ens 3 0x030

does that make sense?

That extra context in IExtendedDNSResolver is really useful to pass signer address/approval signatures for our new gasless DNS resolver using https://domain.tld/.well-known/.. format as ccip-read/write gateway. We already have similar features in current Namesys resolver that can use https://domain.eth.limo as CCIP-Read gateway for domain.eth.

I’ve few question/suggestions…
a) if it’s possible to add wildcard support in DNS *similar to ENS wildcard…
eg. I’ve TXT record set for domain.tld with my resolver & context data, when I try to getAddr(…) for sub.domain.tld, IF there’s no TXT record set for that subdomain it should auto fallback and resolve that sub.domain.tld address using resolver set in TXT record for domain.tld. Most DNS service providers have limit on max number of records and total data size in TXT records/zone limiting max numbers of sub domains using TXT records only.

b) Duplicate ENS1 TXT records…
what happens when there are two or more TXT records set with ENS1 format for asme domain.tld?

I’m using the following format for a new resolver idea:

ENS1 <resolver> <signer> <ccip endpoint>
ENS1 0x09D2233D3d109683ea95Da4546e7E9Fc17a6dfAF 0x33333A1416A4c2D1a982948C0Bbd8f01aAAb080F https://api.gmcafe.io/ccip-sepolia

My resolver sepolia:0x09D2233D3d109683ea95Da4546e7E9Fc17a6dfAF is Offchain, unlike the current Wildcard DNS resolver that interprets context as addr(60).

I’m able to parse context and my resolver and ccip server get hit, but after I respond, something breaks.

I think there’s a bug in OffchainDNSResolver when OffchainLookup gets wrapped:

handleOffchainLookupError() doesn’t pass the target/sender, I think:

  • L333 should be abi.encode(name, abi.encode(extraData, target) innerCallbackFunction).
  • L89 resolveCallback() when selector != 0 should just pass targetData

Although, I think it would be cleaner to not overuse that callback handler and have the wrapped call go through a different callback.

You’re right, this needs fixing. Discussing our best options for this now. It’ll need another DAO vote, so likely best combined with other tweaks such as concatenating multiple TXT record fields.

A workaround in the meantime - though it will break when we fix this - would be to decode the ABI encoded address, targetData tuple in your contract.

1 Like

Ah yeah, good point.

I was able to get it working with the following:

When I revert OffchainLookup, I wrap my extraData as abi.encode(extraData, address(this)) and use buggedCallback.selector.

On callback, I remove the extra wrapper, and call the normal callback:

function buggedCallback(bytes calldata response, bytes calldata buggedExtraData) external view returns (bytes memory) {
	return resolveCallback(response, abi.decode(buggedExtraData, (bytes)));
}

Relatedly, I’ve written a new version of the ExtendedDNSResolver that uses this functionality to resolve records with no onchain transactions; this version supports addresses for all chain IDs, as well as text records: Rewrite ExtendedDNSResolver to support more record types by Arachnid · Pull Request #331 · ensdomains/ens-contracts · GitHub

1 Like

Is the assumption here labelCount = rrset.labels correct?

I cannot verify raffy.home.raffy.xyz through the OffchainDNSResolver due to labelCount = 4, rrset.labels = 3.

raffy.xyz is mine and *.home is wildcard. DNS provider is Namecheap.

I’ve seen this work for other wildcard setups, so I’m curious if Namecheap is wrong or there’s a missing RRSIG because one of those label is virtual.

We don’t currently support wildcards. Previously, support for NSEC records made wildcard support very involved; now that’s gone it would be much simpler but still needs to be explicitly added.

We’re planning on working on it for the next release, but a PR is always welcome if you want to tackle it yourself!

? It’s working on etherscan & I tested with ethers v5 too…
Using txt at *.ipns.dev > wildcard.ipns.dev

Using txt at *.home.ipns.dev > wildcard.home.ipns.dev

@raffy pls check this, we’re using cloudflare DNS…
DNSSEC Debugger - wildcard.home.ipns.dev
vs
DNSSEC Debugger - raffy.home.raffy.xyz

1 Like

As tate explained to me, some DNS providers provide positive proofs (dynamic signing) which make wildcard names appear like fully qualified records, whereas Namecheap Advanced DNS is lazy and provides negative proofs (static) which are not supported.