The Problem
names traditionally point to static content: a fixed address, an IPFS hash pinned at deploy time, a text record changed manually through a wallet transaction. Every update costs gas. Every change requires a transaction to settle. Content is frozen between updates.
This makes ENS impractical for anything dynamic — a live portfolio, a dapp that changes state, a profile that updates automatically, a subdomain-per-user system.
The Idea
What if an ENS name could point to a live backend?
EIP-3668 (CCIP Read)
makes this possible. Instead of storing data on-chain, the resolver contract tells the client: "go fetch this from a URL, then come back with the signed result." The contract verifies the signature and returns the data — trustlessly.
Combined with
ENSIP-10
wildcard resolution, a single resolver contract can handle any subdomain of your ENS name. One gateway serves thousands of names. Records update in real-time via API — no gas, no transactions, no redeploy.
What this enables
Dynamic ENS profiles — update your address, avatar, social links without paying gas
Subdomain-as-identity — mint subdomains to users, point each at their wallet/profile
Token-gated subdomains — issue holder.yourproject.eth to NFT holders automatically
Live dapp state in ENS — point latest.yourprotocol.eth contenthash at your current frontend
Multi-tenant ENS — one resolver, many tenants, each with their own subdomain namespace
CI/CD for ENS — update app.yourname.eth on every deploy, no wallet needed
Browser-native IPFS — store contenthash on-chain once so Brave/Opera resolve your .eth name directly without CCIP Read
How it works
The contract never stores records. It only stores the gateway URL and the signer address. All data lives in the gateway's SQLite database — fully under your control, instantly updatable.
CCIP Read flow (7 steps):
Client calls resolve(name) on the ENS Registry
Registry forwards to the OffchainResolver contract
Contract reverts with OffchainLookup — includes the gateway URL and calldata
Client calls GET /lookup/:sender/:data on the gateway
Gateway decodes the name, fetches the record from SQLite, signs the ABI-encoded response with its private key
Client calls resolveWithProof(response, extraData) back on the contract
Contract verifies the ECDSA signature matches the registered signer — returns the record
Total round-trips: 2 contract calls + 1 HTTP request. No gas. Instant updates.
IPFS browser resolution (Brave / Opera)
Browsers like Brave resolve .eth names by calling contenthash(bytes32) directly on the resolver — they do not follow CCIP Read. The v2 resolver supports this with an on-chain contenthashes mapping:
The admin UI's ENS → IPFS Browser Resolution → Set On-chain (Brave fix) button does both in one click: updates the gateway DB (for CCIP Read clients) and sends the setContenthash() transaction (for Brave direct resolution). Gas paid once; all clients stay in sync.
Standard ENS resolution (MetaMask, ENS app, viem) works via CCIP Read automatically. For browsers that resolve .eth names natively via the address bar, you need an on-chain contenthash.
Pipeline (all from the admin UI, ENS tab):
Build your frontend as a static export (OUTPUT_STATIC=1 bun run build in the client)
Pin the out/ folder to IPFS — use the Pin to Pinata button (requires a Pinata JWT in settings)
Copy the resulting CID into the CID field
Click Set On-chain (Brave fix) — this does both in one transaction:Updates the gateway DB (so CCIP Read clients get the new CID immediately) Sends setContenthash() on-chain (so Brave/direct eth_call clients resolve correctly)
After the transaction confirms, all clients resolve to the new IPFS content — CCIP Read and Brave alike.
The contenthash is encoded as EIP-1577 CIDv1 (dag-pb, sha2-256) so browsers decode it to a valid bafy... CID and IPFS gateways can serve it.
Text Record Extension Spec (ENS-KIT/1)
Status: Draft — A proposed convention for driving frontend UI from ENS text records. Compatible with any ENS name; no custom resolver required beyond standard text record support.
Text records are the config layer. Every key below maps directly to a UI behaviour on the profile page. Set any record via the admin panel or the push API and it takes effect instantly — no redeploy, no gas.
The full spec is served at .eth/spec (the client includes a /spec route).
Conventions
Keys follow existing ENSIP-5 conventions where they exist (com.twitter, com.github, avatar, url, email)
New keys use lowercase with underscores (pfp_button, pfp_button_2)
Multi-value fields use | as separator (label first, URL second)
All URL fields accept ipfs:// as well as https://
Unknown keys are ignored — forwards compatible
Push update endpoint
Update records from any backend — CI pipeline, webhook, cron job:
Contract
OffchainResolver.sol implements:
resolve(bytes name, bytes data) — ENSIP-10 wildcard entry point, reverts with OffchainLookup
resolveWithProof(bytes response, bytes extraData) — verifies gateway ECDSA signature, returns decoded result
contenthash(bytes32 node) — returns on-chain IPFS contenthash (for Brave / direct browser resolution)
setContenthash(bytes32 node, bytes contenthash) — owner-only, set contenthash on-chain (one gas tx)
supportsInterface — declares IExtendedResolver, IAddrResolver, ITextResolver, IContentHashResolver, IERC165
setSigner(address) — update the signing key without redeploying
setGatewayURLs(string[]) — update the gateway URL without redeploying
Mainnet deployment (v2):
0xa912dF7bb8b0a531800dF47dCD4cfE9bD533d33a
Brave / Opera / Freedom browsers: ens://dinamic.eth
Chrome:
Full Post: https://x.com/MerloOfficial/status/2046413347122262125?s=20
This is a early stage live demo
If you wish to contribute visit :
















Top comments (0)