Skip to content

feat(ensapi): improve seedDevnet - add names with contenthash#2286

Open
sevenzing wants to merge 1 commit into
mainfrom
ll/better-tests
Open

feat(ensapi): improve seedDevnet - add names with contenthash#2286
sevenzing wants to merge 1 commit into
mainfrom
ll/better-tests

Conversation

@sevenzing

Copy link
Copy Markdown
Member

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • What changed (1-3 bullets, no essays).

Why

  • Why this change exists. Link to related GitHub issues where relevant.

Testing

  • How this was tested.
  • If you didn't test it, say why.

Notes for Reviewer (Optional)

  • Anything non-obvious or worth a heads-up.

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 16:24
@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)
admin.ensnode.io Ready Ready Preview, Comment Jun 11, 2026 4:25pm
enskit-react-example.ensnode.io Ready Ready Preview, Comment Jun 11, 2026 4:25pm
ensnode.io Ready Ready Preview, Comment Jun 11, 2026 4:25pm
ensrainbow.io Ready Ready Preview, Comment Jun 11, 2026 4:25pm

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces complete devnet seeding infrastructure for ENSv2 registered names and resolver records. It defines contract ABIs for registrar operations, adds test fixtures for contenthash values and name structures, implements registration and seeding primitives, and extends integration tests to validate domain resolution queries against seeded data.

Changes

ENSv2 Devnet Seeding Infrastructure and Integration Tests

Layer / File(s) Summary
ENSv2 Contract ABIs
packages/datasources/src/abis/ensv2/MockToken.ts, packages/datasources/src/abis/ensv2/UserRegistry.ts, packages/datasources/src/abis/ensv2/VerifiableFactory.ts, packages/datasources/src/abis/ensv2/ETHRegistrar.ts, packages/datasources/src/index.ts
Minimal viem ABIs added for MockToken (mint), UserRegistry (initialize), and VerifiableFactory (deployProxy, ProxyDeployed); ETHRegistrar updated with rentPrice function; all re-exported as public ABIs.
Test Fixtures and Data Types
packages/integration-test-env/src/devnet/fixtures.ts
ENSIP-7 contenthash fixtures for multiple codecs, TypeScript types (NameRecords, RegisteredName, RegisteredSubname) defining name/subname structure, and registeredNames fixture exporting a contenthash.eth entry with codec-specific subnames.
Registrar Primitives: Registry Deployment and Name Registration
packages/integration-test-env/src/seed/registrar.ts
Exports ROLES_ALL and MAX_EXPIRY constants; implements advanceTime for devnet clock progression, deterministic salt computation for UserRegistry proxies, deployUserRegistry via VerifiableFactory CREATE2, registerEthName commit–reveal flow with payment token handling, and registerSubname for per-registry subname registration.
Resolver Record Seeding Helpers
packages/integration-test-env/src/seed/resolver-records.ts
Exports previously internal resolver record functions (setTextRecord, setMulticoinAddress, setContenthash, setAbi, setInterfaceImplementer); setContenthash casts contenthash to Hex and logs the resolver node.
Devnet Seeding Orchestration
packages/integration-test-env/src/seed/registered-names.ts, packages/integration-test-env/src/seed/index.ts
seedNameRecords helper conditionally seeds contenthash; seedRegisteredNames walks registeredNames fixtures, deploys UserRegistry per entry, registers 2LDs and subnames via ETHRegistrar and subregistry; wallet client extended with testActions; waitForTransactionReceipt returns TransactionReceipt instead of void; seedDevnet invokes seedRegisteredNames.
Integration Tests: Domain Name and Records Resolution
apps/ensapi/src/test/integration/devnet-names.ts, apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts, apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts
DEVNET_NAMES splits into static + seeded entries from fixtures; new parametrized test validates DomainRecordsAll resolves seeded subnames with correct contenthash records; NAME pagination ordering fixed to use localeCompare with ignorePunctuation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • namehash/ensnode#2191: Both PRs touch the ENSv2 ETHRegistrar contract ABI, so this PR's devnet seeding depends on the same registrar interface definition.
  • namehash/ensnode#1994: Both PRs modify the devnet seeding and integration-test infrastructure in packages/integration-test-env, with this PR extending it to seed additional registered names.

Poem

🐰 Hop along the ENSv2 trail,
Where registries and subnames sail,
Fixtures bloom with contenthash bright,
Seeding names both day and night,
Tests confirm the records right! 🌟

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is entirely a template with no actual content filled in—all sections (Summary, Why, Testing, Notes for Reviewer) and the Pre-Review Checklist are empty or incomplete. Fill in all required template sections: provide a 1-3 bullet summary of changes, explain the motivation and link relevant issues, describe how the changes were tested, note any non-obvious aspects, and complete the blocking pre-review checklist.
Docstring Coverage ⚠️ Warning Docstring coverage is 36.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(ensapi): improve seedDevnet - add names with contenthash' accurately describes the main changes: adding registered names with contenthash support to the seedDevnet function.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ll/better-tests

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.

const [log] = parseEventLogs({
abi: VerifiableFactoryABI,
eventName: "ProxyDeployed",
logs: receipt.logs,

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.

Missing null check on destructured event log causes crash when ProxyDeployed event is not found in transaction receipt

Fix on Vercel

});
});

it.each(registeredNames.flatMap((entry) => [...entry.subnames]))(

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.

Suggested change
it.each(registeredNames.flatMap((entry) => [...entry.subnames]))(
it.each(registeredNames.flatMap((entry) => [...(entry.subnames ?? [])]))(

Spreading undefined value when entry.subnames is optional causes TypeError

Fix on Vercel

// Derived from `registeredNames` fixture — expands automatically when new names are added there.
const seededDevnetNames = registeredNames.flatMap((entry) => [
{ name: entry.name, canonical: entry.name },
...entry.subnames.map((sub) => ({ name: sub.name, canonical: sub.name })),

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.

Suggested change
...entry.subnames.map((sub) => ({ name: sub.name, canonical: sub.name })),
...(entry.subnames ?? []).map((sub) => ({ name: sub.name, canonical: sub.name })),

Missing null check causes crash when entry.subnames is undefined - calling .map() on undefined throws TypeError

Fix on Vercel

@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: 3

🤖 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 `@apps/ensapi/src/test/integration/devnet-names.ts`:
- Around line 30-33: The code maps over registeredNames and uses entry.subnames
without handling the optional field, which can crash if subnames is undefined;
update the mapping expressions (e.g., where seededDevnetNames is created using
registeredNames.flatMap and any other similar mapping in the domain integration
test) to use a fallback like (entry.subnames ?? []) before calling .map, i.e.
replace ...entry.subnames.map(...) with ...(entry.subnames ?? []).map(...),
ensuring RegisteredName.subnames is safely handled.

In `@apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts`:
- Around line 97-112: The test uses String.prototype.localeCompare with an
implicit locale; update both calls in the ascending/descending checks in
test-domain-pagination.ts to pass an explicit locale (e.g., "en-US") as the
first argument while keeping the { ignorePunctuation: true } option so ordering
matches Postgres ICU collation consistently across environments; ensure you
change both occurrences inside the if (dir === "ASC") and else blocks where
av.localeCompare(bv, undefined, { ignorePunctuation: true }) is used.

In `@packages/integration-test-env/src/seed/registrar.ts`:
- Around line 174-196: The balance check, mint and approve must use the same
payer identity: determine a single payer (e.g., const payer =
client.account?.address ?? owner) and use that payer for the balanceOf and mint
calls (replace owner with payer) and ensure the approve is executed from the
same payer (either call writeContract with the client's signer set to payer or
use a client instance tied to payer) so balance/mint/approve are consistent for
registerEthName (references: owner, client.account.address, paymentToken,
erc20Abi, MockTokenABI, writeContract, readContract, waitForTransactionReceipt,
contracts.ETHRegistrar).
🪄 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: 202653ab-6581-4827-8161-ead196f4e94c

📥 Commits

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

📒 Files selected for processing (13)
  • apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts
  • apps/ensapi/src/test/integration/devnet-names.ts
  • apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts
  • packages/datasources/src/abis/ensv2/ETHRegistrar.ts
  • packages/datasources/src/abis/ensv2/MockToken.ts
  • packages/datasources/src/abis/ensv2/UserRegistry.ts
  • packages/datasources/src/abis/ensv2/VerifiableFactory.ts
  • packages/datasources/src/index.ts
  • packages/integration-test-env/src/devnet/fixtures.ts
  • packages/integration-test-env/src/seed/index.ts
  • packages/integration-test-env/src/seed/registered-names.ts
  • packages/integration-test-env/src/seed/registrar.ts
  • packages/integration-test-env/src/seed/resolver-records.ts

Comment on lines +30 to +33
const seededDevnetNames = registeredNames.flatMap((entry) => [
{ name: entry.name, canonical: entry.name },
...entry.subnames.map((sub) => ({ name: sub.name, canonical: sub.name })),
]);

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing optional chaining on entry.subnames in both files.

Both devnet-names.ts and domain.integration.test.ts access entry.subnames without checking for undefined. Since RegisteredName.subnames is optional, any future fixture entry that omits subnames will cause a runtime crash. Add ?? [] fallback in both locations.

🤖 Prompt for 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.

In `@apps/ensapi/src/test/integration/devnet-names.ts` around lines 30 - 33, The
code maps over registeredNames and uses entry.subnames without handling the
optional field, which can crash if subnames is undefined; update the mapping
expressions (e.g., where seededDevnetNames is created using
registeredNames.flatMap and any other similar mapping in the domain integration
test) to use a fallback like (entry.subnames ?? []) before calling .map, i.e.
replace ...entry.subnames.map(...) with ...(entry.subnames ?? []).map(...),
ensuring RegisteredName.subnames is safely handled.

Comment on lines +97 to 112
// Use localeCompare with ignorePunctuation to match Postgres ICU collation, which treats
// punctuation (including ".") as variable/ignorable at the primary level. Without this,
// JS bytewise ordering disagrees with the DB for names like "onion3.x" vs "onion.x":
// Postgres sorts "onion3" before "onion." (digits < letters after stripping dots), while
// JS places "." (code 46) before "3" (code 51).
if (dir === "ASC") {
expect(av <= bv, `expected "${av}" <= "${bv}" at indices ${i},${i + 1} (NAME ASC)`).toBe(
true,
);
expect(
av.localeCompare(bv, undefined, { ignorePunctuation: true }) <= 0,
`expected "${av}" <= "${bv}" at indices ${i},${i + 1} (NAME ASC)`,
).toBe(true);
} else {
expect(av >= bv, `expected "${av}" >= "${bv}" at indices ${i},${i + 1} (NAME DESC)`).toBe(
true,
);
expect(
av.localeCompare(bv, undefined, { ignorePunctuation: true }) >= 0,
`expected "${av}" >= "${bv}" at indices ${i},${i + 1} (NAME DESC)`,
).toBe(true);
}

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.

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider explicit locale for localeCompare to match Postgres configuration.

The code uses localeCompare(bv, undefined, { ignorePunctuation: true }) with an implicit locale (line 104, 109). While this works in the current devnet environment, the default locale may vary across systems. If the Postgres ICU collation uses a specific locale (e.g., en-US), explicitly passing that locale would ensure consistent ordering across environments.

♻️ Optional improvement
-        av.localeCompare(bv, undefined, { ignorePunctuation: true }) <= 0,
+        av.localeCompare(bv, "en-US", { ignorePunctuation: true }) <= 0,
🤖 Prompt for 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.

In `@apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts`
around lines 97 - 112, The test uses String.prototype.localeCompare with an
implicit locale; update both calls in the ascending/descending checks in
test-domain-pagination.ts to pass an explicit locale (e.g., "en-US") as the
first argument while keeping the { ignorePunctuation: true } option so ordering
matches Postgres ICU collation consistently across environments; ensure you
change both occurrences inside the if (dir === "ASC") and else blocks where
av.localeCompare(bv, undefined, { ignorePunctuation: true }) is used.

Comment on lines +174 to +196
const balance = await client.readContract({
address: paymentToken,
abi: erc20Abi,
functionName: "balanceOf",
args: [owner],
});

if (balance < price) {
const mintHash = await client.writeContract({
address: paymentToken,
abi: MockTokenABI,
functionName: "mint",
args: [owner, price - balance],
});
await waitForTransactionReceipt(client, mintHash);
}

const approveHash = await client.writeContract({
address: paymentToken,
abi: erc20Abi,
functionName: "approve",
args: [contracts.ETHRegistrar, price],
});

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Align payer identity across balance/mint/approve in registerEthName.

Line 174 checks ERC20 balance for owner and Line 186 mints to owner, but Line 191 approves from the signer (client.account). If owner !== client.account.address, this creates inconsistent funding/allowance setup and can fail registration.

Suggested fix
 export async function registerEthName(
   client: DevnetWalletClient,
   {
     label,
     owner,
@@
 ): Promise<void> {
+  const signer = client.account.address;
+  if (owner !== signer) {
+    throw new Error("registerEthName requires owner to match signer");
+  }
+
   const duration = BigInt(durationDays * ONE_DAY_SECONDS);
@@
   const balance = await client.readContract({
     address: paymentToken,
     abi: erc20Abi,
     functionName: "balanceOf",
-    args: [owner],
+    args: [signer],
   });
@@
   if (balance < price) {
     const mintHash = await client.writeContract({
       address: paymentToken,
       abi: MockTokenABI,
       functionName: "mint",
-      args: [owner, price - balance],
+      args: [signer, price - balance],
     });
     await waitForTransactionReceipt(client, mintHash);
   }
🤖 Prompt for 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.

In `@packages/integration-test-env/src/seed/registrar.ts` around lines 174 - 196,
The balance check, mint and approve must use the same payer identity: determine
a single payer (e.g., const payer = client.account?.address ?? owner) and use
that payer for the balanceOf and mint calls (replace owner with payer) and
ensure the approve is executed from the same payer (either call writeContract
with the client's signer set to payer or use a client instance tied to payer) so
balance/mint/approve are consistent for registerEthName (references: owner,
client.account.address, paymentToken, erc20Abi, MockTokenABI, writeContract,
readContract, waitForTransactionReceipt, contracts.ETHRegistrar).

@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, great stuff

): Promise<void> {
const duration = BigInt(durationDays * ONE_DAY_SECONDS);
const paymentToken = contracts.MockUSDC;
const referrer = "0x0000000000000000000000000000000000000000000000000000000000000000" as Hex;

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.

zeroHash

*
* @see https://github.com/ensdomains/content-hash/blob/master/src/index.test.ts
*/
export const contenthashFixtures = {

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.

looks like no need to export, and perhaps could even hardcode these values into the registeredNames const?

* To add more names: append entries here. Seeding, DEVNET_NAMES, and tests pick them up
* automatically — no other files need changing.
*/
export const registeredNames = [

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.

i would name this REGISTERED_NAMES const case

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.

perhaps even ADDITIONALLY_REGISTERED_NAMES

export const DEVNET_NAMES = [
import { registeredNames } from "@ensnode/integration-test-env/devnet";

const staticDevnetNames = [

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.

this too, const-case STATIC_DEVNET_NAMES

] as const;

// Derived from `registeredNames` fixture — expands automatically when new names are added there.
const seededDevnetNames = registeredNames.flatMap((entry) => [

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.

and const anming here

@changeset-bot

changeset-bot Bot commented Jun 11, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: c2c7642

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extends the devnet seeding infrastructure to register a set of ENS names with real contenthash values (ipfs, swarm, ipns, onion, onion3, skynet, arweave) via the ENSv2 ETHRegistrar commit-reveal flow, and adds integration tests that verify the seeded records are returned correctly by the GraphQL API.

  • Adds MockToken, UserRegistry, and VerifiableFactory ABIs, plus a new rentPrice overload to ETHRegistrar, to support the full ENSv2 registration flow in the devnet seed.
  • Introduces registeredNames fixture and seedRegisteredNames seeding function that deploys a UserRegistry per 2LD, registers names, wires the canonical parent, and sets resolver records on subnames — with DEVNET_NAMES and integration tests picking up new entries automatically.
  • Fixes a test-ordering assertion to use localeCompare({ ignorePunctuation: true }) to match Postgres ICU collation, which became necessary because the new onion/onion3 names expose a byte-order vs. ICU-order discrepancy on ..

Confidence Score: 4/5

Safe to merge; all changes are devnet seeding and test infrastructure with no production code paths affected.

The registration flow, ABI definitions, and test assertions all look correct. The only findings are a pair of inconsistent null-guard patterns (direct entry.subnames access vs. ?? []) and a system-locale-dependent localeCompare call that is safe for ASCII names but could theoretically vary across environments.

apps/ensapi/src/test/integration/devnet-names.ts and domain.integration.test.ts for the subnames null-guard inconsistency; apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts for the undefined locale.

Important Files Changed

Filename Overview
packages/integration-test-env/src/seed/registrar.ts New file implementing the full ENSv2 commit-reveal registration flow; ABI arg order, referrer/secret types, and token approval logic all look correct.
packages/integration-test-env/src/seed/registered-names.ts Orchestrates deploy-register-setParent-seedRecords for each entry in the fixture; step-comment numbering skips 4. (minor cosmetic issue).
packages/integration-test-env/src/devnet/fixtures.ts Adds contenthash test vectors and the RegisteredName/RegisteredSubname types; values match ENSIP-7 test vectors from the reference library.
apps/ensapi/src/test/integration/devnet-names.ts Derives seeded names from the fixture automatically; accesses entry.subnames without null-safety unlike registered-names.ts — safe today via const narrowing but inconsistent.
apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts Adds parameterized test over all subnames verifying contenthash records; spreads entry.subnames without null guard — safe now but diverges from the ?? [] pattern elsewhere.
apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts Replaces byte-order string comparison with localeCompare({ignorePunctuation:true}) to match Postgres ICU; the undefined locale is environment-dependent but safe for ASCII-only ENS names.
packages/datasources/src/abis/ensv2/ETHRegistrar.ts Adds the owner-aware rentPrice overload alongside the existing getRegisterPrice; both coexist correctly in the ABI array.
packages/integration-test-env/src/seed/index.ts Wires seedRegisteredNames into seedDevnet; DevnetWalletClient type simplified to ReturnType and waitForTransactionReceipt now returns the receipt.
packages/integration-test-env/src/seed/resolver-records.ts Exports previously-private setTextRecord/setMulticoinAddress/setContenthash/setAbi/setInterfaceImplementer for reuse; adds Hex cast fix on fixtures.contenthash.

Sequence Diagram

sequenceDiagram
    participant Seed as seedRegisteredNames
    participant VF as VerifiableFactory
    participant ETHReg as ETHRegistrar
    participant UR as UserRegistry
    participant ETHRegistry as ETHRegistry
    participant Resolver as PermissionedResolver

    loop for each entry in registeredNames
        Seed->>VF: deployProxy(UserRegistryImpl, salt, initData)
        VF-->>Seed: ProxyDeployed → userRegistry address

        Seed->>ETHReg: makeCommitment(label, owner, secret, subregistry, resolver, duration, referrer)
        ETHReg-->>Seed: commitment hash
        Seed->>ETHReg: commit(commitment)
        Seed->>Seed: advanceTime(minAge + 1s)
        Seed->>ETHReg: rentPrice(label, owner, duration, token)
        ETHReg-->>Seed: base + premium
        Seed->>MockUSDC: mint(owner, shortfall) if needed
        Seed->>MockUSDC: approve(ETHRegistrar, price)
        Seed->>ETHReg: register(label, owner, secret, subregistry, resolver, duration, token, referrer)

        Seed->>UR: setParent(ETHRegistry, label)

        opt entry.records.contenthash
            Seed->>Resolver: setContenthash(node, contenthash)
        end

        loop for each subname
            Seed->>UR: register(label, owner, 0x0, resolver, ROLES_ALL, MAX_EXPIRY)
            opt sub.records.contenthash
                Seed->>Resolver: setContenthash(subnode, contenthash)
            end
        end
    end
Loading

Reviews (1): Last reviewed commit: "add registration of names with contentha..." | Re-trigger Greptile

Comment on lines +30 to +33
const seededDevnetNames = registeredNames.flatMap((entry) => [
{ name: entry.name, canonical: entry.name },
...entry.subnames.map((sub) => ({ name: sub.name, canonical: sub.name })),
]);

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.

P2 The registered-names.ts seeding code uses entry.subnames ?? [] as a defensive fallback, but here entry.subnames.map(...) is accessed directly. Both are TypeScript-safe today because as const infers subnames as always-present, but the inconsistency means that if a future fixture entry omits subnames, this file will fail to compile while registered-names.ts would silently skip subnames via ?? []. Aligning on (entry.subnames ?? []).map(...) keeps the behaviour consistent across both call-sites.

Suggested change
const seededDevnetNames = registeredNames.flatMap((entry) => [
{ name: entry.name, canonical: entry.name },
...entry.subnames.map((sub) => ({ name: sub.name, canonical: sub.name })),
]);
const seededDevnetNames = registeredNames.flatMap((entry) => [
{ name: entry.name, canonical: entry.name },
...(entry.subnames ?? []).map((sub) => ({ name: sub.name, canonical: sub.name })),
]);

});
});

it.each(registeredNames.flatMap((entry) => [...entry.subnames]))(

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.

P2 Same inconsistency as in devnet-names.ts: [...entry.subnames] accesses subnames without a null guard, unlike registered-names.ts which uses ?? []. Spreading (entry.subnames ?? []) makes the intent explicit and matches the defensive pattern used in the seeding code.

Suggested change
it.each(registeredNames.flatMap((entry) => [...entry.subnames]))(
it.each(registeredNames.flatMap((entry) => [...(entry.subnames ?? [])]))(

Comment on lines +103 to +111
expect(
av.localeCompare(bv, undefined, { ignorePunctuation: true }) <= 0,
`expected "${av}" <= "${bv}" at indices ${i},${i + 1} (NAME ASC)`,
).toBe(true);
} else {
expect(av >= bv, `expected "${av}" >= "${bv}" at indices ${i},${i + 1} (NAME DESC)`).toBe(
true,
);
expect(
av.localeCompare(bv, undefined, { ignorePunctuation: true }) >= 0,
`expected "${av}" >= "${bv}" at indices ${i},${i + 1} (NAME DESC)`,
).toBe(true);

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.

P2 Passing undefined as the locale falls back to the runtime's system locale, which can differ between developer machines and CI environments. For pure ASCII ENS names the difference is almost certainly benign, but pinning an explicit neutral locale like "en-US" makes the comparison deterministic regardless of the environment's LANG setting.

Suggested change
expect(
av.localeCompare(bv, undefined, { ignorePunctuation: true }) <= 0,
`expected "${av}" <= "${bv}" at indices ${i},${i + 1} (NAME ASC)`,
).toBe(true);
} else {
expect(av >= bv, `expected "${av}" >= "${bv}" at indices ${i},${i + 1} (NAME DESC)`).toBe(
true,
);
expect(
av.localeCompare(bv, undefined, { ignorePunctuation: true }) >= 0,
`expected "${av}" >= "${bv}" at indices ${i},${i + 1} (NAME DESC)`,
).toBe(true);
expect(
av.localeCompare(bv, "en-US", { ignorePunctuation: true }) <= 0,
`expected "${av}" <= "${bv}" at indices ${i},${i + 1} (NAME ASC)`,
).toBe(true);
} else {
expect(
av.localeCompare(bv, "en-US", { ignorePunctuation: true }) >= 0,
`expected "${av}" >= "${bv}" at indices ${i},${i + 1} (NAME DESC)`,
).toBe(true);

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +68 to +72
if (entry.records) {
await seedNameRecords(client, resolver, namehash(entry.name) as Hex, entry.records);
}

// 5. Register subnames and seed their records.

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.

P2 The JSDoc above this function lists steps 1–5, but the inline comment after step 3 jumps straight to // 5. — step 4 ("Seed resolver records on the 2LD") has no matching inline comment. Adding it keeps the numbering consistent with the doc.

Suggested change
if (entry.records) {
await seedNameRecords(client, resolver, namehash(entry.name) as Hex, entry.records);
}
// 5. Register subnames and seed their records.
// 4. Seed resolver records on the 2LD.
if (entry.records) {
await seedNameRecords(client, resolver, namehash(entry.name) as Hex, entry.records);
}
// 5. Register subnames and seed their records.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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