Universal Resolver Bug

I was doing final tests for our *.ipfs2.eth gateway resolver,
ethers.js(v6) works ok (code below) but ens app is showing No Content Hash, * we only support ipfs/ipns hash as <subdomain>.ipfs2.eth to ens contenthash decoding in this service resolver.

let wallet = new ethers.InfuraProvider("goerli");// goerli testnet
let resolver = await wallet.getResolver("bafybeiee2lzvemjxesych64jw75cypjvce7nzvcyznbl3ogrztrmz2vnii.ipfs2.eth");
let content = await resolver.getContentHash();
//> ipfs://QmXH96FRK4YgbZx5ozFWeFaZuUNsfkdV7tidAuGP8GNxz5 

App link : bafybeiee2lzvemjxesych64jw75cypjvce7nzvcyznbl3ogrztrmz2vnii.ipfs2.eth on ENS

IPFS2.eth resolver : https://goerli.etherscan.io/address/0x4774c87ec49589464b6a0e7b24097ac03a9779a9#code

Github link for full tests :


It shows 0x0000000000000000000000000000000000000020 for the ETH address.

Are you intentionally returning that? Because that looks like the length for an address in ABI-encoded data, not the address itself.

If not, my guess is that either your contract or your gateway service is not handling ABI-encoded data properly. That could cause data mismatches or other weird issues…

Nope, we’ve strict revert("Not Supported") for non-contenthash requests in resolve function for subdomains.

        if (name.length == 11 && bytes11(name) == nameCheck) { // == ipfs2.eth encoded check
            iCCIP(ccip2eth).resolve(name, data); //
        } else if (bytes4(data[:4]) != iResolver.contenthash.selector) {
            revert("Not Supported");

Return value is proper `abi.encode(contenthash). Ethers.js v5 was unable to handle direct return value from resolve function, but it’s all working in ethers.js v6 & I was jus looking how it’s displayed on ens app. :rofl:

Ah okay, I thought you were using CCIP-read, but your contract isn’t, it’s just returning the contenthash directly from the extended resolve method:

The UniversalResolver works fine there too though:

That’s my bad, I saw the word “gateway” and assumed it was using CCIP-read hah.

1 Like

I’ve no time to catch up with full universal resolver codes (23 files) tonight, but I GUESS it’s missing ( bytes4(error[:4]) == Resolver.OffchainLookup.selector) check somewhere in batched multicall from App, if resolve function reverts something else instead of revert OffchainLookup(…).

Yep, appears to be the case.

The UniversalResolver is returning incorrect garbled data for an addr call, when it should just be reverting I think.

That’s a good catch… cc: @taytems

Looks like if the target resolver reverts, the UniversalResolver does not revert, but it just returns the revertData as the actual return data for the call.

So there’s no way for a client to know whether the call reverted, and whether to treat the return data as the actual requested data, or to treat it as an error message.

1 Like

I think App/js side is taking shortcuts while decoding return values too… bytes(0x…02…) result should throw error on client side while decoding wrong output bytes as address or other invalid types.

It could be easy fix on app codes by checking/decoding all results properly.

Yep that’d be prudent to do specifically for the ETH address and many other addresses. Technically speaking, the addr methods return just an arbitrary amount of bytes, though I don’t know if any coin types actually have encoded addresses that are >32 bytes. Similar thing for the contenthash, technically it just returns bytes and it’s supposed to support any valid multicodec value.

And if it’s a string (like all the text records), then I don’t think there would be any way of knowing. It’d be indistinguishable from just setting a text record value to Not Supported.

Universal resolver is still reading revert(“Message”) data as result… pls fix this ASAP!

address ::