Skip to content

feat: add contenthash interpretation - #2285

Merged
sevenzing merged 8 commits into
mainfrom
ll/domain-profile-contenthash-02
Jun 12, 2026
Merged

feat: add contenthash interpretation#2285
sevenzing merged 8 commits into
mainfrom
ll/domain-profile-contenthash-02

Conversation

@sevenzing

@sevenzing sevenzing commented Jun 11, 2026

Copy link
Copy Markdown
Member

Summary

  • Add Domain.resolve.profile.contenthash interpretation

decided to use simple structure for that:

type ProfileContenthash {
  decoded: String!
  httpUrl: String
  protocolType: String!
  uri: String!
}

Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

@sevenzing
sevenzing requested a review from a team as a code owner June 11, 2026 13:33
@changeset-bot

changeset-bot Bot commented Jun 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fdd3bda

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 24 packages
Name Type
ensapi Patch
ensindexer Patch
ensadmin Patch
ensrainbow Patch
fallback-ensapi Patch
enssdk Patch
enscli Patch
enskit Patch
ensskills Patch
@ensnode/datasources Patch
@ensnode/ensrainbow-sdk Patch
@ensnode/ensdb-sdk Patch
@ensnode/ensnode-sdk Patch
@ensnode/integration-test-env Patch
@ensnode/ponder-sdk Patch
@ensnode/ponder-subgraph Patch
@ensnode/shared-configs Patch
@docs/ensnode Patch
@docs/ensrainbow Patch
@namehash/ens-referrals Patch
@namehash/namehash-ui Patch
@ensnode/ensindexer-perf-testing Patch
@ensnode/enskit-react-example Patch
@ensnode/enssdk-example Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
enskit-react-example.ensnode.io Ready Ready Preview, Comment Jun 12, 2026 3:16pm
3 Skipped Deployments
Project Deployment Actions Updated (UTC)
admin.ensnode.io Skipped Skipped Jun 12, 2026 3:16pm
ensnode.io Skipped Skipped Jun 12, 2026 3:16pm
ensrainbow.io Skipped Skipped Jun 12, 2026 3:16pm

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@sevenzing, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 21 minutes and 44 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f5354dd7-ed2f-4458-a309-7d46e39191e3

📥 Commits

Reviewing files that changed from the base of the PR and between a97c908 and fdd3bda.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • apps/ensapi/src/handlers/api/resolution/resolve-records.integration.test.ts
  • apps/ensapi/src/omnigraph-api/lib/resolution/profile/interpreters/contenthash.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts
  • packages/integration-test-env/package.json
  • packages/integration-test-env/src/devnet/fixtures.ts
  • packages/integration-test-env/src/seed/registered-names.ts
  • packages/integration-test-env/src/seed/resolver-records.ts
📝 Walkthrough

Walkthrough

Adds end-to-end ENSIP-7 contenthash interpretation and exposes it as profile.contenthash with fields { protocolType, decoded, uri, httpUrl }; includes interpreter, schema, resolver selection wiring, integration tests/fixtures, docs, a changeset, and a new dependency.

Changes

ENS Domain Contenthash Profile Integration

Layer / File(s) Summary
Contenthash Interpreter Implementation
apps/ensapi/src/omnigraph-api/lib/resolution/profile/interpreters/contenthash.ts, apps/ensapi/src/omnigraph-api/lib/resolution/profile/interpreters/index.ts, apps/ensapi/src/omnigraph-api/lib/resolution/profile/profile-descriptions.ts
Adds ProfileContenthashModel, PROTOCOL_CONFIG, and ProfileContenthashInterpreter that normalize and decode hex contenthash records, detect codec, build canonical uri, and compute optional httpUrl.
GraphQL Schema & Wiring
apps/ensapi/src/omnigraph-api/schema/profile.ts
Introduces ContenthashProtocol enum and ProfileContenthashRef object with protocolType, decoded, uri, and nullable httpUrl. Adds nullable contenthash field to DomainProfileRef resolved by the interpreter.
Resolution Pipeline Selection Wiring
apps/ensapi/src/omnigraph-api/lib/resolution/profile/build-profile-selection.ts, apps/ensapi/src/omnigraph-api/lib/resolution/profile/interpreters/index.ts
Detects profile.contenthash selection and merges ProfileContenthashInterpreter.selection into the resolver records selection pipeline.
Integration Tests and Fixtures
apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts, packages/integration-test-env/src/devnet/fixtures.ts
Extends DomainProfile test types and query to request contenthash { protocolType decoded uri httpUrl }, updates assertions for test.eth, and replaces placeholder fixture with a fixed contenthash hex value.
Documentation, SKILL, Changeset, and Dependency
apps/ensapi/src/omnigraph-api/lib/resolution/profile/README.md, packages/ensskills/skills/omnigraph/SKILL.md, .changeset/clean-insects-accept.md, apps/ensapi/package.json
Documents contenthash.ts interpreter and marks roadmap entry complete, adds ProfileContenthash to SKILL, adds a Changeset entry, and adds @ensdomains/content-hash@^3.1.0-rc.1 dependency.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • namehash/ensnode#2286: Adds contenthash data to devnet fixtures/names that this PR decodes and exposes via profile.contenthash.

Suggested labels

javascript

Poem

A rabbit nibbles bytes so small,
Decodes the hash and hears the call,
IPFS, Arweave, gateways shine,
Profile URIs now aligned,
Hooray — contenthash, cached and fine 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is missing the 'Why' and 'Testing' sections required by the template, though it does include a summary and pre-review checklist. Add 'Why' section explaining the motivation/GitHub issues, and 'Testing' section describing how this was tested. Consider adding a 'Notes for Reviewer' section if there are non-obvious details.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'feat: add contenthash interpretation' clearly summarizes the main change: adding a new contenthash interpretation feature to the Domain.resolve.profile schema.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ll/domain-profile-contenthash-02

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds Domain.resolve.profile.contenthash interpretation using the @ensdomains/content-hash library. When a raw ENSIP-7 contenthash is present, it is decoded into a structured ProfileContenthash object carrying protocolType (a new ContenthashProtocol enum), decoded CID/hash, a protocol-native uri, and an optional public-gateway httpUrl; null is returned for unset, empty (0x), or unrecognisable bytes.

  • New interpreter (contenthash.ts): covers all seven codecs (IPFS, IPNS, Swarm, Arweave, Onion, Onion3, Skynet) with per-codec gateway URLs and a shared try/catch boundary so malformed bytes never surface as errors.
  • Schema additions (profile.ts): new ContenthashProtocol enum and ProfileContenthash object type wired into DomainProfile; generated schema.graphql and introspection updated accordingly.
  • Test fixtures refactored (fixtures.ts): raw hex strings replaced by encode/decode round-trips from the library's own test vectors; empty, invalid, and zero sentinel entries added (all expected to resolve to null).

Confidence Score: 5/5

Safe to merge — the interpreter is well-bounded by a try/catch, all null/empty cases are explicitly handled, and the schema change is purely additive.

The core decoder is straightforward: strip 0x, call getCodec/decode, assemble the output object, catch everything else and return null. Error paths are covered. The GraphQL additions are additive and non-breaking. The two comments are style observations about dead fallback code and sentinel fixtures in the devnet, neither of which affects correctness in production.

No files require special attention. fixtures.ts is worth a glance to confirm that seeding the empty/invalid/zero sentinel subnames on-chain is intentional.

Important Files Changed

Filename Overview
apps/ensapi/src/omnigraph-api/lib/resolution/profile/interpreters/contenthash.ts New interpreter for ENSIP-7 contenthash: decodes hex bytes using @ensdomains/content-hash, maps codec → protocolType enum, constructs protocol-native URI and public gateway HTTP URL; errors return null gracefully.
apps/ensapi/src/omnigraph-api/schema/profile.ts Adds ContenthashProtocol enum and ProfileContenthash object type to the Pothos schema, wires the interpreter into DomainProfile, and re-exports the model type.
packages/integration-test-env/src/devnet/fixtures.ts Replaces raw hex fixture strings with encode/decode round-trips; adds empty/invalid/zero sentinel fixtures and derives contenthashSubnames from ALL entries including the three sentinels, which creates blockchain subnames for them during seeding.
packages/integration-test-env/src/seed/registered-names.ts Changes contenthash guard from strict !== undefined to falsy check; null now correctly skips setContenthash while '0x' (truthy) still calls it, consistent with the empty-bytes test intent.
apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts Adds contenthash assertions to existing profile test, plus two new tests: one covering all fixture codecs via DomainProfiles query, another verifying null returned for empty contenthash on emptyrecords.eth.
apps/ensapi/src/omnigraph-api/lib/resolution/profile/build-profile-selection.ts Adds contenthash field gate to the profile selection builder, consistent with the pattern used for all other profile fields.
packages/enssdk/src/omnigraph/generated/schema.graphql Auto-generated: adds ContenthashProtocol enum and ProfileContenthash object type with decoded, httpUrl, protocolType, uri fields.

Sequence Diagram

sequenceDiagram
    participant Client as GraphQL Client
    participant Schema as profile.ts (Schema)
    participant Builder as build-profile-selection.ts
    participant Resolver as ENS Resolver (on-chain)
    participant Interpreter as ProfileContenthashInterpreter
    participant Lib as @ensdomains/content-hash

    Client->>Schema: "query { domain { resolve { profile { contenthash { ... } } } } }"
    Schema->>Builder: buildProfileSelectionFromResolveContainerInfo(info)
    Builder->>Builder: topLevelFields.has(contenthash) → merge selection
    Builder-->>Schema: "{ contenthash: true }"
    Schema->>Resolver: fetch records.contenthash (raw hex)
    Resolver-->>Schema: "0xe30101... | 0x | null"
    Schema->>Interpreter: interpret(result)
    Interpreter->>Interpreter: "raw == null || raw == 0x → return null"
    Interpreter->>Lib: "getCodec(hex) → ipfs | swarm | ..."
    Interpreter->>Lib: decode(hex) → CID / hash string
    Interpreter->>Interpreter: build uri, httpUrl from PROTOCOL_CONFIG
    Interpreter-->>Schema: "{ protocolType, decoded, uri, httpUrl } | null"
    Schema-->>Client: "ProfileContenthash | null"
Loading

Reviews (6): Last reviewed commit: "add UrlString" | Re-trigger Greptile

Comment thread apps/ensapi/package.json Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/integration-test-env/src/devnet/fixtures.ts`:
- Around line 97-99: The inline comment for the contenthash value (the property
named contenthash in the fixture object) is inconsistent with the actual decoded
CID — decode the hex string "0xe30101..." assigned to contenthash (or re-derive
the correct hex for the expected CID) and update either the comment to reflect
the true CID (e.g., bafybei... if that decodes correctly) or replace the hex
value so it encodes the commented CID (QmRAQ...). Locate the contenthash
property in fixtures.ts, validate the multicodec/multihash decoding result, and
make the comment and assigned hex consistent with each other. Ensure the chosen
fix preserves test expectations that rely on the decoded CID.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 94d69902-f372-4323-9abf-6fb60b9b98e8

📥 Commits

Reviewing files that changed from the base of the PR and between 6fa2f2f and efee14f.

⛔ Files ignored due to path filters (3)
  • packages/enssdk/src/omnigraph/generated/introspection.ts is excluded by !**/generated/**
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • .changeset/clean-insects-accept.md
  • apps/ensapi/package.json
  • apps/ensapi/src/omnigraph-api/lib/resolution/profile/README.md
  • apps/ensapi/src/omnigraph-api/lib/resolution/profile/build-profile-selection.ts
  • apps/ensapi/src/omnigraph-api/lib/resolution/profile/interpreters/contenthash.ts
  • apps/ensapi/src/omnigraph-api/lib/resolution/profile/interpreters/index.ts
  • apps/ensapi/src/omnigraph-api/lib/resolution/profile/profile-descriptions.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/profile.ts
  • packages/ensskills/skills/omnigraph/SKILL.md
  • packages/integration-test-env/src/devnet/fixtures.ts

Comment thread packages/integration-test-env/src/devnet/fixtures.ts Outdated

@shrugs shrugs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment thread apps/ensapi/src/omnigraph-api/lib/resolution/profile/interpreters/contenthash.ts Outdated
@shrugs

shrugs commented Jun 11, 2026

Copy link
Copy Markdown
Member

i could see a schema improvement with either:

a) protocolType should become enum, or
b) ProfileContenthash should become an interface with concrete types for the known contenthash protocols, then you can drop protocolType entirely in favor of __typename differentiation. the ProfileContenthash interface implements all fields and the concrete implementation provide no specific fields

@sevenzing sevenzing changed the title add contenthash interpretation feat: add contenthash interpretation Jun 12, 2026
@sevenzing

Copy link
Copy Markdown
Member Author

agree, I will do option A.

@sevenzing

Copy link
Copy Markdown
Member Author

@greptile review please ❤️

@vercel
vercel Bot temporarily deployed to Preview – ensnode.io June 12, 2026 15:16 Inactive
@vercel
vercel Bot temporarily deployed to Preview – admin.ensnode.io June 12, 2026 15:16 Inactive
@vercel
vercel Bot temporarily deployed to Preview – ensrainbow.io June 12, 2026 15:16 Inactive
@sevenzing
sevenzing merged commit ba68bbe into main Jun 12, 2026
20 checks passed
@sevenzing
sevenzing deleted the ll/domain-profile-contenthash-02 branch June 12, 2026 15:22
@github-actions github-actions Bot mentioned this pull request Jun 12, 2026
@tk-o tk-o mentioned this pull request Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants