Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
10 changes: 6 additions & 4 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,8 @@ import config from "@/config";

import {
asInterpretedName,
ENS_ROOT,
getParentNameFQDN,
ENS_ROOT_NAME,
getParentInterpretedName,
type Node,
namehashInterpretedName,
} from "enssdk";
Expand Down Expand Up @@ -72,7 +72,7 @@ app.openapi(getNameTokensRoute, async (c) => {
const name = asInterpretedName(request.name);

// return 404 when the requested name was the ENS Root
if (name === ENS_ROOT) {
if (name === ENS_ROOT_NAME) {
return c.json(
serializeNameTokensResponse(
makeNameTokensNotIndexedResponse(
Expand All @@ -83,7 +83,9 @@ app.openapi(getNameTokensRoute, async (c) => {
);
}

const parentNode = namehashInterpretedName(getParentNameFQDN(name));
// biome-ignore lint/style/noNonNullAssertion: getParentInterpretedName only throws if name === ENS_ROOT_NAME but we handle that case above
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 remove this ignore and the ! and instead do the check here for parentName being null and if so move the code here that generates the 404 error for name param not being the ENS Root.

const parentName = getParentInterpretedName(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
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 must be an InterpretedName
const activeName = asInterpretedName(bytesToPacket(dnsEncodedNameBytes.slice(offset)));
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.

Shouldn't we say that bytesToPacket returns a LiteralName and that we therefore need to transform from the LiteralName to an InterpretedName?


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
31 changes: 10 additions & 21 deletions apps/ensapi/src/lib/resolution/forward-resolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import { replaceBigInts } from "@ponder/utils";
import {
type AccountId,
asInterpretedName,
isNormalizedName,
type InterpretedName,
type Node,
namehashInterpretedName,
normalizeName,
parseReverseName,
} from "enssdk";

Expand Down Expand Up @@ -57,10 +56,6 @@ import {
const logger = makeLogger("forward-resolution");
const tracer = trace.getTracer("forward-resolution");

// NOTE: normalize generic name to force the normalization lib to lazy-load itself (otherwise the
// first trace generated here would be unusually slow)
normalizeName("example.eth");

/**
* Implements Forward Resolution of record values for a specified ENS Name.
*
Expand Down Expand Up @@ -95,9 +90,12 @@ export async function resolveForward<SELECTION extends ResolverRecordsSelection>
selection: ForwardResolutionArgs<SELECTION>["selection"],
options: Omit<Parameters<typeof _resolveForward>[2], "registry">,
): Promise<ForwardResolutionResult<SELECTION>> {
// Invariant: Name must be an InterpretedName
const interpretedName = asInterpretedName(name);
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.

We have a related issue open: #1032

What do you suggest we do in relation to issue 1032 within the scope of this PR (PR 1908)? Should we work to confirm that issue 1032 can be successfully closed, or maybe keep issue 1032 open and make any new relevant comments on it that might help us with working on it later?

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 believe the name param (currently typed as ForwardResolutionArgs<SELECTION>["name"]) should be updated so that it is already a validated InterpretedName and that the validation that it is a valid interpreted name might be handled by Zod when we're parsing the query params?

We could then also remove the need for creating interpretedName here as a distinct field from the name param.


// NOTE: `resolveForward` is just `_resolveForward` with the enforcement that `registry` must
// initially be ENS Root Chain's Registry: see `_resolveForward` for additional context.
return _resolveForward(name, selection, {
// initially be ENS Root Registry: see `_resolveForward` for additional context.
return _resolveForward(interpretedName, selection, {
...options,
registry: getENSv1Registry(config.namespace),
});
Expand All @@ -108,7 +106,7 @@ export async function resolveForward<SELECTION extends ResolverRecordsSelection>
* `registry`.
*/
async function _resolveForward<SELECTION extends ResolverRecordsSelection>(
name: ForwardResolutionArgs<SELECTION>["name"],
name: InterpretedName,
selection: ForwardResolutionArgs<SELECTION>["selection"],
options: { registry: AccountId; accelerate: boolean; canAccelerate: boolean },
): Promise<ForwardResolutionResult<SELECTION>> {
Expand Down Expand Up @@ -141,18 +139,11 @@ async function _resolveForward<SELECTION extends ResolverRecordsSelection>(
// Validate Input
//////////////////////////////////////////////////

// Invariant: Name must be normalized
if (!isNormalizedName(name)) {
throw new Error(`Invariant: Name "${name}" must be normalized.`);
}

const node: Node = namehashInterpretedName(asInterpretedName(name));
const node: Node = namehashInterpretedName(name);
span.setAttribute("node", node);

// if selection is empty, give them what they asked for
if (isSelectionEmpty(selection)) {
return makeEmptyResolverRecordsResponse(selection);
}
if (isSelectionEmpty(selection)) return makeEmptyResolverRecordsResponse(selection);

// construct the set of resolve() calls indicated by selection
const calls = makeResolveCalls(node, selection);
Expand Down Expand Up @@ -224,9 +215,7 @@ async function _resolveForward<SELECTION extends ResolverRecordsSelection>(
!!activeResolver,
);
// we're unable to find an active resolver for this name, return empty response
if (!activeResolver) {
return makeEmptyResolverRecordsResponse(selection);
}
if (!activeResolver) return makeEmptyResolverRecordsResponse(selection);

// set some attributes on the span for easy reference
span.setAttribute("activeResolver", activeResolver);
Expand Down
Loading
Loading