Introducing JSONAPI.ETH

:pray:

JSONAPI.ETH is an ENS wildcard resolver implementing dynamic onchain IPLD/dag-json contenthash generator.

Features:

  • Resolves
    <reg'd token symbol/contract>.jsonapi.eth,
    <address/ens>.jsonapi.eth,
    <address/ens>.<token/contract>.jsonapi.eth,
    <id>.<nft/contract>.jsonapi.eth
  • Returns JSON with user’s ETH and ENS info, token info (ERC20/721 metadata, price, supply), balances, NFT details

Live Demo App: https://jsonapi.eth.limo

Github: https://github.com/namesys-eth/jsonapi.eth

Resolver Address: 0xF31352EDE0b4673e101D4E77dE119ab7Dd5A7251

Example dag-json contenthas:

Time/Block/Balance/Price values are dynamic.


Current Limitations:

  • Direct browser access via .eth.limo may fail for longer responses due to IPFS/Kubo client-side handling of concatenated DNS/DoH _dnslink TXT records. Direct DoH lookups & decoding payload without gateway method below still works. https://x.com/eth_limo/status/1908639259780612465

Decoding raw/dag-json Contenthash Directly (without any Gateway):

  1. Request Contenthash:
    Using standard ENS client procedures, request contenthash for <*>.jsonapi.eth or <*>.<*>.jsonapi.eth. This returns base32 cidv1/dag-json hash.

  2. Decode Result:

    • Decode base32 cidv1 to bytes, skip 0x01800400 cidv1/dag-json prefix OR use multicodec/multiformats library for this.
    • Read the next varint length byte (2 hex chars). If next hex value is >= 128 (0x80), skip two bytes (total 4 hex chars skipped for the 2-byte varint). Otherwise, just skip one byte (total 2 hex chars)
    • The remaining hex data is raw JSON payload
    • Convert remaining raw/DAG-JSON hex payload to a UTF-8 string

This is a demo project to test ipld/dag-json contenthash, not recommended for production use. It’s best suited for other projects to batch read their own contract data by deploying their own wildcard ENS data resolvers. jsonapi.eth resolver is internally using Check the Chain contracts for Uniswap/v3 pool prices, so some price data may differ from other live market price feeds.

What’s next?

  • Optimize & publish our standalone library for IPLD contenthash generator. (raw/html, dag-json & dag-cbor).
  • May be new ENSIP for IPLD namespace? …with proper gateway less decoding for raw data? For now we’re hijacking IPFS namespace, as technically IPFS is IPLD with FS & everything is IPLD.
  • Fully onchain dynamic partial HTMX/HTML generator with offchain dag-cbor linked JS/CSS, eg, all in one dag-cbor linked hash

In short, we can use ENS+Ethereum World computer as a permanent d/web server. :vulcan_salute:

10 Likes

This is cool. :pinched_fingers:

2 Likes

Eureka—resolved w/o a gateway!

Successfully resolved and decoded the contenthash for estmcmxci.jsonapi.eth directly from the ENS wildcard resolver, without relying on a gateway.

The process involved:

  • Encoding the ENS name (estmcmxci.jsonapi.eth) in DNS wire format.
  • Calling the resolve() function on the wildcard resolver at 0xF31352EDE0b4673e101D4E77dE119ab7Dd5A7251.
  • Decoding the returned contenthash using the standard ABI for contenthash(bytes32).
  • Interpreting the raw bytes as DAG-JSON encoded CBOR content.
  • Parsing the content locally using the IPLD dag-json and multiformats libraries.

The result was a valid IPFS CID string, matching what’s displayed in the ENS app, but retrieved and decoded completely client-side.

This confirms that records like estmcmxci.jsonapi.eth can be accessed programmatically and decoded without a gateway dependency.

Here’s the link to the repo in case anyone wants to fork it and try it out themselves.

2 Likes

:pray:
directly access json string…

    const raw = await contract.resolve(encodedDnsName, data);
    const [contenthashBytes] = contenthashInterface.decodeFunctionResult("contenthash", raw);

    console.log("✅ Raw contenthash (hex):", contenthashBytes);

    // shorthand for varint length skipper
    const start = contenthashBytes.length - 14 > 128 ? 18 : 16;
    const payload = "0x" + contenthashBytes.substring(start)
    console.log("🌐 Decoded raw/dag-json:", ethers.toUtf8String(payload));


So why’s this CIDv1 not resolving directly?
it’s valid cidv1+ipld/dag-json with raw payload :white_check_mark:

a) dweb.link or localhost:8080 gateways are auto redirected to sub domain, so it fails to load longer cidv1.
b) ipfs.io/ipfs/… works, but at certain length it’ll top resolving.
c) eth.limo’s DOH can’t handle this coz looks like _dnslink’s txt length is hardcoded in IPFS/Kubo clients.

only way to resolve this is by using 127.0.0.1:8080 IPFS API (not in gateway mode) so it’s not auto redirected to localhost subdomain. OR go raw mode decoding payload without any gateways.

on js clients side,
viem got no direct contenthash support yet…
ethers.js is still using cidv0 (base58).

error @ v6 & v5 / cc @ricmoo

ethers.min.js:1 Uncaught (in promise) Error: invalid or unsupported content hash data (operation="getContentHash()", 
info={ "data": "0xe30101800400bc017b226f6b223a747275652c2274696d65223a2231373434333230333539222c22626c6f636b223a223232323431323033222c22657263223a302c2275736572223a7b2261646472657373223a22307864386441364246323639363461463944376545643965303345353334313544333761413936303435222c226e616d65223a22766974616c696b2e657468222c2262616c616e6365223a223233372e353436313039222c227072696365223a22313531392e353032333835227d7d" }, code=UNSUPPORTED_OPERATION, version=6.13.1)
1 Like

I think this is great work and shows a lot of potential for what a decentralized API layer could look like — one that uses ENS as a programmable namespace rather than just a naming system.

One application I’ve been thinking about is how this approach could be especially useful for something like Oscillator, an open music metadata protocol. Using a forked jsonapi.eth-style resolver, oscillator.eth could expose structured metadata for artists, releases, and tracks — all mapped to ENS subnames like:

  • bjork.oscillator.eth → artist metadata
  • bjork.vespertine.oscillator.eth → release metadata
  • bjork.vespertine.aurora.oscillator.eth → track metadata

Because the data is encoded as DAG-JSON and returned via contenthash, it could be resolved and parsed without relying on any gateway or API — just a single ENS call using a standard Ethereum provider.

Would love to explore what it might look like to formalize this pattern. Could an ENSIP help define standards for dynamic, structured resolution (e.g. DAG-JSON over contenthash) as a canonical resolver type?

Open to thoughts and potential next steps — I think it could lay the groundwork for a new class of ENS-native, data-rich applications.

5 Likes