I’d like to share a new resolver setup for offchain resolution + some related tech.
First, TheOffchainResolver.sol is a trustless singleton resolver contract that can dispatch to an offchain server for both DNS or ENS. The current mainnet deployment only supports DNS, as I’m waiting for the bug in the OffchainDNSResolver to get fixed, but you can use the DNS part right now.
- This enables DNS to serve offchain names gas-free
- Using a single wildcard TXT record, you can serve an entire subtree.
- This enables on-chain ENS names to serve offchain names by setting 2 records (resolver + text record)
- No need to deploy a custom resolver contract
- Features: multicall(), PublicResolver fallback, etc.
It expects the CCIP-Read server confirms to a standard protocol and the queried name has valid context:
- Create a context
CONTEXT
=${SIGNER} ${SERVER_ENDPOINT}
SIGNER
=0x
-prefixed public address of your signing keySERVER_ENDPOINT
= URL of your CCIP-Read server
- Example:
0xd00d726b2aD6C81E894DC6B87BE6Ce9c5572D2cd https://raffy.xyz/ezccip/
- Set the context
- “I have a DNS name” →
TXT
=ENS1 0xa4407E257Aa158C737292ac95317a29b4C90729D ${CONTEXT}
- “I have an ENS name” → PublicResolver
.setText("ccip.context", CONTEXT)
- “I have a DNS name” →
Example: ezccip.raffy.xyz
DNS TXT → Resolver or ENS
Second, ezccip.js is “turnkey CCIP-Read Handler for ENS”. It’s a single function that you feed {sender, data}
from POST/GET, a signing key, and a callback for name
→ Record?
and it follows the TheOffchainResolver protocol and produces a response {data}
or throws.
The github readme or example server.js explain this better.
Supports resolve(multicall())
and multicall(resolve())
Tracks call history and handles partial errors:
- Call:
resolve("raffy.eth", multicall([text("avatar), poop()])
History.toString()
:resolve("raffy.eth").multicall(2)[text(name) "Error: unsupported ccip method poop()"]
- Imagine
multicall()
with 100 records, of which half fail, you don’t want to see 50 stack traces.
Third, TheOffchainGateway.js uses ezccip.js and provides a single server that hosts multiple endpoints with various routers. Here are some examples:
- router/simple.js — serves a static JSON file
- Example:
bob.raffy.xyz
- Example:
- router/airtable.js — serves an AirTable
- Example:
air1.raffy.xyz
/air2.raffy.xyz
- Example:
- router/mirror.js — transforms
a.b.c
toa.eth
and mirrors mainnet.- Example:
raffy.raffy.xyz
== raffy.eth
- Example:
- router/tree.js — serves a subtree
- Example:
alice.raffy.xyz
- Example:
It’s extremely easy to configure:
npm i
- edit
config.js
and pick your routers npm run start
- setup context (see above)