Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
0cc7c75
refactor getParentInterpretedName and ENS_ROOT_NAME
shrugs Apr 9, 2026
9559c91
refactor: no UnixTimestamp re-export
shrugs Apr 9, 2026
f5ac2dc
refactor: remove NormalizedName type in favor of InterpretedName acro…
shrugs Apr 9, 2026
fe4c7db
fix: ensure resolution lib works with interpreted name
shrugs Apr 9, 2026
4b5fa3d
refactor Address to NormalizedAddress where reasonable
shrugs Apr 9, 2026
b49bcdf
refactor validateAddress
shrugs Apr 9, 2026
5d4e6c9
fix: documentation for InterpretedNames in schema
shrugs Apr 9, 2026
6fb27e3
refactor: clean up expects in ensrainbow tests
shrugs Apr 9, 2026
ec5cac1
fix: use lazy for UR1 as well
shrugs Apr 10, 2026
ad94a8c
fix: use ENS_ROOT_NODE in comments
shrugs Apr 10, 2026
6b7fc4f
fix: use semantic types in ensapi integration tests
shrugs Apr 10, 2026
aae29f4
refactor: more semantic scalars, and move Duration to enssdk
shrugs Apr 10, 2026
597fa4c
refactor: local resolvers, add bigint deserialization resolvers
shrugs Apr 10, 2026
a2442dd
fix: add constraint that name be normalized in forward resolution
shrugs Apr 13, 2026
87de64f
fix: circular import, fix nameToInterpretedName helper, add tests, up…
shrugs Apr 13, 2026
cf6216f
fix: decodeEncodedReferrer returns NormalizedAddress, fix normalized …
shrugs Apr 13, 2026
e438eb2
tidy up isAddress usage, fix normalized address schema
shrugs Apr 13, 2026
e491549
fix: more specific error messages in address test
shrugs Apr 13, 2026
2960281
fix: pr notes, asLiteralName
shrugs Apr 13, 2026
101cc78
fix: streamline name-tokens-api
shrugs Apr 13, 2026
1bf8535
refactor: move EnsureInterpretedName to enskit/react
shrugs Apr 13, 2026
f97481e
feat: expact literalNameToInterpretedName logic
shrugs Apr 13, 2026
ae3859d
fix: correctly validate encodedlabelhashes in interpretation
shrugs Apr 13, 2026
75d1792
fix: remove ambiguous readFragment re-export in enskit/react/omnigraph
shrugs Apr 13, 2026
21ee782
fix: typos
shrugs Apr 13, 2026
76c9ac5
fix: use normalized address in namewrapper.ts
shrugs Apr 13, 2026
de4bc5b
fix: copilot notes
shrugs Apr 13, 2026
b45f191
fix: ensure referrer logic is using NormalizedAddress all the way down
shrugs Apr 13, 2026
be147ec
fix: correctly passthrough for by id lookups
shrugs Apr 13, 2026
5ced5ca
fix: find-domains use NormalizedAddress
shrugs Apr 13, 2026
3b694d3
fix: guard against partial data in cache-exchange accoutnid string
shrugs Apr 13, 2026
559756d
fix: support bigint[] in omnigraph
shrugs Apr 13, 2026
1fbbd33
fix: comments
shrugs Apr 13, 2026
365fae4
fix: relax toNormalizedAddress input type and clean up callsites
shrugs Apr 14, 2026
2637ec4
docs(changeset): Introduce the enskit/react submodule export for Reac…
shrugs Apr 14, 2026
ea8aa6e
fix: handle root name
shrugs Apr 14, 2026
47c8592
fix: keep cause for normalization errors
shrugs Apr 14, 2026
bb5e3ad
fix: further NormalizedAddress in ens-referrals
shrugs Apr 14, 2026
b3b10d6
fix: DRY up encoded labelhash parsing
shrugs Apr 14, 2026
0b9cb68
fix: don't catch the react children throwing
shrugs Apr 14, 2026
08a15c3
Merge branch 'main' into refactor/enssdk-refactor-continued
shrugs Apr 14, 2026
cf73bcd
docs and typos
shrugs Apr 14, 2026
b44c2e8
fix: referrer size check
shrugs Apr 14, 2026
dfcd4f9
fix: streamline ensure-interpreted-name
shrugs Apr 14, 2026
ffb27bb
fix: names test
shrugs Apr 14, 2026
50a4fa0
fix: decodeEncodedReferrer return type
shrugs Apr 14, 2026
2b5239d
fix: remove unnecessary introspection.ts
shrugs Apr 14, 2026
458c75a
fix: lockfile
shrugs Apr 14, 2026
43d4afc
pr notes
shrugs Apr 14, 2026
f1ad3da
relax isNormalizedAddress input type
shrugs Apr 14, 2026
4eff61f
fix: omnigaph barrel
shrugs Apr 14, 2026
13b1349
add basic normalized address schema test
shrugs Apr 14, 2026
98dbf3d
fix: name test again
shrugs Apr 14, 2026
14be264
Merge remote-tracking branch 'origin/main' into refactor/enssdk-refac…
shrugs Apr 14, 2026
25d62b2
fix: pr notes and docstrings and typins
shrugs Apr 14, 2026
54a03b9
fix: parseReverseName accepts InterpretedName, better error message i…
shrugs Apr 14, 2026
cefad95
docs updates
shrugs Apr 14, 2026
cedd134
docstrings
shrugs Apr 14, 2026
41bffaa
fix: parse reverse name test
shrugs Apr 14, 2026
604803b
fix: typo
shrugs Apr 14, 2026
921731c
fix: minor nits
shrugs Apr 14, 2026
ce8af05
pr notes
shrugs Apr 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/humble-mice-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"enskit": minor
---

Introduce the enskit/react submodule export for React components and (in the future) hooks.
11 changes: 6 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ Runnable commands for validating changes; lint and format with Biome.

- Install dependencies: `pnpm install`
- Run all tests: `pnpm test`
- Run tests for a single package/app: `pnpm --filter <package-name> test` (e.g. `pnpm --filter ensapi test`)
- Run tests for a single project: `pnpm test --project <project>` (e.g. `pnpm test --project ensapi`)
- Run tests for a single file: `pnpm test <path>`
- Lint and format: `pnpm lint` (fixes where applicable); CI lint: `pnpm lint:ci`
- Type checking: `pnpm typecheck` (runs typecheck in all workspaces)
- Always prefer `pnpm -F <package-name> typecheck` over `tsc`
- Always use `pnpm -F <package-name> typecheck`, never call `tsc` or `tsgo` directly

## Testing

Expand Down Expand Up @@ -76,7 +77,7 @@ Fail fast and loudly on invalid inputs.
## Workflow

- Add a changeset when your PR includes a logical change that should bump versions or be communicated in release notes: https://ensnode.io/docs/contributing/prs#changesets
- Before declaring work complete, run validation in the affected packages:
1. `pnpm -F <affected-packages> typecheck`
- Before declaring work complete, run validation in the affected project(s):
1. `pnpm -F <affected-project> typecheck`
2. `pnpm lint`
3. `pnpm -F <affected-packages> test`
3. `pnpm test --project <affected-project> [--project <other-affected-project>]`
4 changes: 2 additions & 2 deletions apps/ensadmin/src/app/mock/display-identity/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
getEnsManagerAddressDetailsUrl,
} from "@namehash/namehash-ui";
import type { Address, ChainId, DefaultableChainId, Name } from "enssdk";
import { asLowerCaseAddress, DEFAULT_EVM_CHAIN_ID } from "enssdk";
import { DEFAULT_EVM_CHAIN_ID, toNormalizedAddress } from "enssdk";
import { useState } from "react";
import { isAddress } from "viem";

Expand Down Expand Up @@ -76,7 +76,7 @@ export default function MockDisplayIdentityPage() {
}

// at a data-model level, we always represent addresses fully in lowercase.
selectedAddress = asLowerCaseAddress(selectedAddress);
selectedAddress = toNormalizedAddress(selectedAddress);

// fallback to selecting the default name if
// selectedRawName is an empty string
Expand Down
3 changes: 2 additions & 1 deletion apps/ensadmin/src/app/mock/registrar-actions/mocks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Duration } from "enssdk";
import { asInterpretedName } from "enssdk";

import { type Duration, type NamedRegistrarAction } from "@ensnode/ensnode-sdk";
import { type NamedRegistrarAction } from "@ensnode/ensnode-sdk";

export const registrationWithReferral = {
action: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { AbsoluteTime } from "@namehash/namehash-ui";
import type { UnixTimestamp } from "enssdk";
import { Clock } from "lucide-react";

import {
Expand All @@ -12,7 +13,6 @@ import {
getTimestampForLowestOmnichainStartBlock,
type RealtimeIndexingStatusProjection,
sortChainStatusesByStartBlockAsc,
type UnixTimestamp,
} from "@ensnode/ensnode-sdk";

import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
"use client";

import { formatRelativeTime, RelativeTime, useNow } from "@namehash/namehash-ui";
import type { UnixTimestamp } from "enssdk";
import type { Duration, UnixTimestamp } from "enssdk";
import { InfoIcon } from "lucide-react";

import type { Duration } from "@ensnode/ensnode-sdk";

import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useNow } from "@namehash/namehash-ui";
import { secondsToMilliseconds } from "date-fns";
import type { Duration } from "enssdk";
import { useCallback, useMemo } from "react";

import {
Expand All @@ -15,7 +16,6 @@ import {
import {
CrossChainIndexingStatusSnapshotOmnichain,
createRealtimeIndexingStatusProjection,
Duration,
type IndexingStatusRequest,
IndexingStatusResponseCodes,
IndexingStatusResponseOk,
Expand Down
1 change: 0 additions & 1 deletion apps/ensapi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@
"@ensnode/shared-configs": "workspace:*",
"@types/node": "catalog:",
"@types/prismjs": "^1.26.6",
"@urql/introspection": "^1.2.1",
"chalk": "^5.6.2",
"graphql-request": "^7.4.0",
"pino-pretty": "^13.1.2",
Expand Down
10 changes: 5 additions & 5 deletions apps/ensapi/src/handlers/api/explore/name-tokens-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import config from "@/config";

import {
asInterpretedName,
ENS_ROOT,
getParentNameFQDN,
getParentInterpretedName,
type Node,
namehashInterpretedName,
} from "enssdk";
Expand Down Expand Up @@ -70,9 +69,10 @@ app.openapi(getNameTokensRoute, async (c) => {

if (request.name !== undefined) {
const name = asInterpretedName(request.name);
const parentName = getParentInterpretedName(name);

// return 404 when the requested name was the ENS Root
if (name === ENS_ROOT) {
// return 404 when the requested name was the ENS Root (which does not have a parent)
if (parentName === null) {
return c.json(
serializeNameTokensResponse(
makeNameTokensNotIndexedResponse(
Expand All @@ -83,7 +83,7 @@ app.openapi(getNameTokensRoute, async (c) => {
);
}

const parentNode = namehashInterpretedName(getParentNameFQDN(name));
const parentNode = namehashInterpretedName(parentName);
const subregistry = indexedSubregistries.find((s) => s.node === parentNode);

// Return 404 response with error code for Name Tokens Not Indexed when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
RegistrarActionsOrders,
} from "@ensnode/ensnode-sdk";
import {
makeLowercaseAddressSchema,
makeNodeSchema,
makeNormalizedAddressSchema,
makePositiveIntegerSchema,
makeUnixTimestampSchema,
} from "@ensnode/ensnode-sdk/internal";
Expand Down Expand Up @@ -51,7 +51,7 @@ export const registrarActionsQuerySchema = z
.describe("Filter to only include actions with referrals")
.openapi({ default: false }),

decodedReferrer: makeLowercaseAddressSchema("decodedReferrer")
decodedReferrer: makeNormalizedAddressSchema("decodedReferrer")
.optional()
.describe("Filter by decoded referrer address"),

Expand Down
2 changes: 1 addition & 1 deletion apps/ensapi/src/handlers/api/meta/realtime-api.routes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createRoute, z } from "@hono/zod-openapi";
import { minutesToSeconds } from "date-fns";
import type { Duration } from "enssdk";

import type { Duration } from "@ensnode/ensnode-sdk";
import { makeDurationSchema } from "@ensnode/ensnode-sdk/internal";

import { params } from "@/lib/handlers/params.schema";
Expand Down
2 changes: 1 addition & 1 deletion apps/ensapi/src/handlers/api/meta/realtime-api.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { UnixTimestamp } from "enssdk";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

import {
type CrossChainIndexingStatusSnapshot,
createRealtimeIndexingStatusProjection,
type UnixTimestamp,
} from "@ensnode/ensnode-sdk";

import { createApp } from "@/lib/hono-factory";
Expand Down
3 changes: 2 additions & 1 deletion apps/ensapi/src/handlers/api/resolution/resolution-api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Duration } from "enssdk";

import type {
Duration,
ResolvePrimaryNameResponse,
ResolvePrimaryNamesResponse,
ResolveRecordsResponse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
makeReferrerMetricsEditionsArraySchema,
} from "@namehash/ens-referrals/v1/internal";

import { makeLowercaseAddressSchema } from "@ensnode/ensnode-sdk/internal";
import { makeNormalizedAddressSchema } from "@ensnode/ensnode-sdk/internal";

export const basePath = "/v1/ensanalytics";

Expand Down Expand Up @@ -39,7 +39,7 @@ const referrerLeaderboardPageQuerySchema = z.object({

// Referrer address parameter schema
const referrerAddressSchema = z.object({
referrer: makeLowercaseAddressSchema("Referrer address").describe("Referrer Ethereum address"),
referrer: makeNormalizedAddressSchema("Referrer address").describe("Referrer Ethereum address"),
});

// Editions query parameter schema
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createRoute, z } from "@hono/zod-openapi";
import { REFERRERS_PER_LEADERBOARD_PAGE_MAX } from "@namehash/ens-referrals";

import { makeLowercaseAddressSchema } from "@ensnode/ensnode-sdk/internal";
import { makeNormalizedAddressSchema } from "@ensnode/ensnode-sdk/internal";

export const basePath = "/ensanalytics";

Expand All @@ -28,7 +28,7 @@ const paginationQuerySchema = z.object({

// Referrer address parameter schema
const referrerAddressSchema = z.object({
referrer: makeLowercaseAddressSchema("Referrer address").describe("Referrer Ethereum address"),
referrer: makeNormalizedAddressSchema("Referrer address").describe("Referrer Ethereum address"),
});

export const getReferrerLeaderboardRoute = createRoute({
Expand Down
3 changes: 2 additions & 1 deletion apps/ensapi/src/handlers/subgraph/subgraph-api.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import config from "@/config";

import type { Duration } from "enssdk";
import { createDocumentationMiddleware } from "ponder-enrich-gql-docs-middleware";

// FIXME: use the import from:
// import { ensIndexerSchema } from "@/lib/ensdb/singleton";
// Once the lazy proxy implemented for `ensIndexerSchema` export is improved
// to support Drizzle ORM in `ponder-subgraph` package.
import * as ensIndexerSchema from "@ensnode/ensdb-sdk/ensindexer-abstract";
import { type Duration, hasSubgraphApiConfigSupport } from "@ensnode/ensnode-sdk";
import { hasSubgraphApiConfigSupport } from "@ensnode/ensnode-sdk";
import { subgraphGraphQLMiddleware } from "@ensnode/ponder-subgraph";

import { createApp } from "@/lib/hono-factory";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { ReferralProgramRules } from "@namehash/ens-referrals/v1";
import { minutesToSeconds } from "date-fns";
import type { UnixTimestamp } from "enssdk";
import type { Duration, UnixTimestamp } from "enssdk";

import { addDuration, type Duration } from "@ensnode/ensnode-sdk";
import { addDuration } from "@ensnode/ensnode-sdk";

/**
* Duration after which we assume a closed edition is safe from chain reorganizations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
type ReferrerMetrics,
} from "@namehash/ens-referrals/v1";
import { and, asc, count, desc, eq, gte, isNotNull, lte, ne, sql, sum } from "drizzle-orm";
import { type Address, stringifyAccountId } from "enssdk";
import { type NormalizedAddress, stringifyAccountId } from "enssdk";
import { zeroAddress } from "viem";

import { deserializeDuration, priceEth } from "@ensnode/ensnode-sdk";
Expand Down Expand Up @@ -77,7 +77,7 @@ export const getReferrerMetrics = async (
// 2. `totalIncrementalDuration` is guaranteed to be non-null as it is the sum of non-null bigint values
// 3. `totalRevenueContribution` is guaranteed to be non-null due to COALESCE with 0
interface NonNullRecord {
referrer: Address;
referrer: NormalizedAddress;
totalReferrals: number;
totalIncrementalDuration: string;
totalRevenueContribution: string;
Expand Down Expand Up @@ -144,7 +144,7 @@ export const getReferralEvents = async (rules: ReferralProgramRules): Promise<Re
// 3. `total` is guaranteed non-null by COALESCE with 0
interface NonNullRecord {
id: string;
referrer: Address;
referrer: NormalizedAddress;
timestamp: bigint;
incrementalDuration: bigint;
total: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
type ReferrerMetrics,
} from "@namehash/ens-referrals";
import { and, count, desc, eq, gte, isNotNull, lte, ne, sql, sum } from "drizzle-orm";
import { type Address, stringifyAccountId } from "enssdk";
import { type NormalizedAddress, stringifyAccountId } from "enssdk";
import { zeroAddress } from "viem";

import { deserializeDuration } from "@ensnode/ensnode-sdk";
Expand Down Expand Up @@ -76,7 +76,7 @@ export const getReferrerMetrics = async (
// 2. `totalIncrementalDuration` is guaranteed to be non-null as it is the sum of non-null bigint values
// 3. `totalRevenueContribution` is guaranteed to be non-null due to COALESCE with 0
interface NonNullRecord {
referrer: Address;
referrer: NormalizedAddress;
totalReferrals: number;
totalIncrementalDuration: string;
totalRevenueContribution: string;
Expand Down
4 changes: 2 additions & 2 deletions apps/ensapi/src/lib/handlers/params.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { isSelectionEmpty, type ResolverRecordsSelection } from "@ensnode/ensnod
import {
makeCoinTypeStringSchema,
makeDefaultableChainIdStringSchema,
makeLowercaseAddressSchema,
makeNormalizedAddressSchema,
} from "@ensnode/ensnode-sdk/internal";

const excludingDefaultChainId = z
Expand Down Expand Up @@ -36,7 +36,7 @@ const name = z

const trace = z.optional(boolstring).default(false).openapi({ default: false });
const accelerate = z.optional(boolstring).default(false).openapi({ default: false });
const address = makeLowercaseAddressSchema();
const address = makeNormalizedAddressSchema();
const defaultableChainId = makeDefaultableChainIdStringSchema();
const coinType = makeCoinTypeStringSchema();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import config from "@/config";

import { eq } from "drizzle-orm/sql";
import { type AccountId, asInterpretedName, type Node } from "enssdk";
import { type AccountId, asInterpretedName, type Node, type UnixTimestamp } from "enssdk";

import {
bigIntToNumber,
Expand All @@ -11,7 +11,6 @@ import {
type NFTMintStatus,
parseAssetId,
type RegisteredNameTokens,
type UnixTimestamp,
} from "@ensnode/ensnode-sdk";

import { ensDb, ensIndexerSchema } from "@/lib/ensdb/singleton";
Expand Down
17 changes: 8 additions & 9 deletions apps/ensapi/src/lib/protocol-acceleration/find-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import {
asInterpretedName,
type DomainId,
getNameHierarchy,
type Name,
type Node,
type NormalizedName,
type InterpretedName,
namehashInterpretedName,
} from "enssdk";
import { isAddressEqual, type PublicClient, toHex, zeroAddress } from "viem";
Expand All @@ -29,7 +27,7 @@ type FindResolverResult =
activeResolver: null;
requiresWildcardSupport: undefined;
}
| { activeName: Name; requiresWildcardSupport: boolean; activeResolver: Address };
| { activeName: InterpretedName; requiresWildcardSupport: boolean; activeResolver: Address };

const NULL_RESULT: FindResolverResult = {
activeName: null,
Expand Down Expand Up @@ -62,7 +60,7 @@ export async function findResolver({
publicClient,
}: {
registry: AccountId;
name: NormalizedName;
name: InterpretedName;
accelerate: boolean;
canAccelerate: boolean;
publicClient: PublicClient;
Expand Down Expand Up @@ -94,7 +92,7 @@ export async function findResolver({
*/
async function findResolverWithUniversalResolver(
publicClient: PublicClient,
name: Name,
name: InterpretedName,
): Promise<FindResolverResult> {
return withActiveSpanAsync(
tracer,
Expand Down Expand Up @@ -147,7 +145,8 @@ async function findResolverWithUniversalResolver(
}

// UniversalResolver returns the offset in bytes within the DNS Encoded Name where the activeName begins
const activeName: Name = bytesToPacket(dnsEncodedNameBytes.slice(offset));
// Invariant: the decoded name is a LiteralName that must conform to InterpretedName
const activeName = asInterpretedName(bytesToPacket(dnsEncodedNameBytes.slice(offset)));

return {
activeName,
Expand Down Expand Up @@ -175,7 +174,7 @@ async function findResolverWithUniversalResolver(
*/
async function findResolverWithIndex(
registry: AccountId,
name: NormalizedName,
name: InterpretedName,
): Promise<FindResolverResult> {
return withActiveSpanAsync(
tracer,
Expand All @@ -194,7 +193,7 @@ async function findResolverWithIndex(

// 2. compute domainId of each node
// NOTE: this is currently ENSv1-specific
const nodes = names.map((name) => namehashInterpretedName(asInterpretedName(name)) as Node);
const nodes = names.map((name) => namehashInterpretedName(name));
const domainIds = nodes as DomainId[];

// 3. for each domain, find its associated resolver in the selected registry
Expand Down
Loading
Loading