diff --git a/apps/examples.nameguard.io/src/app/components/SecurePrimaryName.tsx b/apps/examples.nameguard.io/src/app/components/SecurePrimaryName.tsx
index 688fc4de5..9fcc6f601 100644
--- a/apps/examples.nameguard.io/src/app/components/SecurePrimaryName.tsx
+++ b/apps/examples.nameguard.io/src/app/components/SecurePrimaryName.tsx
@@ -25,36 +25,31 @@ export async function SecurePrimaryName({ address }: Props) {
headers();
// This function does not use the NameGuard API server
- const data = await nameguard.getSecurePrimaryName(address,
- { returnNameGuardReport: true });
+ const data = await nameguard.getSecurePrimaryName(address, {
+ returnNameGuardReport: true,
+ });
const pillColor =
- data.impersonation_estimate === "potential" ?
- "bg-red-300" :
- data.impersonation_estimate === "unlikely" ?
- "bg-green-300" :
- "bg-yellow-300";
+ data.impersonation_estimate === "potential"
+ ? "bg-red-300"
+ : data.impersonation_estimate === "unlikely"
+ ? "bg-green-300"
+ : "bg-yellow-300";
const pillText =
- data.impersonation_estimate === "potential" ?
- "Potential impersonation!" :
- data.impersonation_estimate === "unlikely" ?
- "Name is secure" :
- "No primary name!";
+ data.impersonation_estimate === "potential"
+ ? "Potential impersonation!"
+ : data.impersonation_estimate === "unlikely"
+ ? "Name is secure"
+ : "No primary name!";
return (
);
}
diff --git a/apps/examples.nameguard.io/src/app/components/SecurePrimaryNameLoading.tsx b/apps/examples.nameguard.io/src/app/components/SecurePrimaryNameLoading.tsx
index bcd83515b..da32ef9b7 100644
--- a/apps/examples.nameguard.io/src/app/components/SecurePrimaryNameLoading.tsx
+++ b/apps/examples.nameguard.io/src/app/components/SecurePrimaryNameLoading.tsx
@@ -7,9 +7,7 @@ export function SecurePrimaryNameLoading({ address }: Props) {
diff --git a/apps/nameai.io/app/page.tsx b/apps/nameai.io/app/page.tsx
index 622301a18..17cf1ae1e 100644
--- a/apps/nameai.io/app/page.tsx
+++ b/apps/nameai.io/app/page.tsx
@@ -11,37 +11,6 @@ export default function Page() {
<>
diff --git a/apps/namehashlabs.org/lib/client/avatar.ts b/apps/namehashlabs.org/lib/client/avatar.ts
index 11c2ed087..3c40c595c 100644
--- a/apps/namehashlabs.org/lib/client/avatar.ts
+++ b/apps/namehashlabs.org/lib/client/avatar.ts
@@ -45,7 +45,7 @@ export const queryMultipleEndpointsToGetAvatar = async ({
console.error(
"Failed to query ",
avatarQueries[queryCallbackIndex],
- ", trying next one"
+ ", trying next one",
);
}
}
@@ -59,7 +59,7 @@ export const queryMultipleEndpointsToGetAvatar = async ({
"Successfully queried ",
avatarQueries[queryCallbackIndex],
", response: ",
- successfulQueryRes
+ successfulQueryRes,
);
}
} else {
diff --git a/apps/namehashlabs.org/lib/client/nh-labs-avatar.ts b/apps/namehashlabs.org/lib/client/nh-labs-avatar.ts
index a798283ba..9b9cab63f 100644
--- a/apps/namehashlabs.org/lib/client/nh-labs-avatar.ts
+++ b/apps/namehashlabs.org/lib/client/nh-labs-avatar.ts
@@ -36,7 +36,7 @@ const getFallbackAvatarCallback = async (ensName: string) => {
};
export const getNameHashLabsAvatarCallbacks = (
- profile: Profile
+ profile: Profile,
): AvatarQueryModel[] => {
return [
async () => await getCachedAvatarCallback(profile.ensName),
diff --git a/apps/namehashlabs.org/lib/utils/careers.test.tsx b/apps/namehashlabs.org/lib/utils/careers.test.tsx
index 42d2501d0..c4bd93f2a 100644
--- a/apps/namehashlabs.org/lib/utils/careers.test.tsx
+++ b/apps/namehashlabs.org/lib/utils/careers.test.tsx
@@ -5,65 +5,89 @@ import { describe, it, expect } from "vitest";
import CategoriesData from "@/data/roleCategoryData";
describe("getRelatedRoles", () => {
+ const buildTestRole = (title: string, category: RoleCategory): Role => {
+ return {
+ slug: title.toLowerCase().replace(/\s/g, "_"),
+ title,
+ category: category,
+ team: "team",
+ location: "location",
+ description:
description
,
+ };
+ };
- const buildTestRole = (title: string, category: RoleCategory): Role => {
- return {
- slug: title.toLowerCase().replace(/\s/g, "_"),
- title,
- category: category,
- team: "team",
- location: "location",
- description: (
description
),
- };
- };
+ const frontendA = buildTestRole("Frontend A", CategoriesData.frontend);
+ const frontendB = buildTestRole("Frontend B", CategoriesData.frontend);
+ const backendA = buildTestRole("Backend A", CategoriesData.backend);
+ const backendB = buildTestRole("Backend B", CategoriesData.backend);
- const frontendA = buildTestRole("Frontend A", CategoriesData.frontend);
- const frontendB = buildTestRole("Frontend B", CategoriesData.frontend);
- const backendA = buildTestRole("Backend A", CategoriesData.backend);
- const backendB = buildTestRole("Backend B", CategoriesData.backend);
+ const allOpenRoles: Role[] = [frontendA, backendA, frontendB, backendB];
- const allOpenRoles: Role[] = [frontendA, backendA, frontendB, backendB];
+ it("should return an empty array when allOpenRoles is empty", () => {
+ const relatedRoles = getRelatedRoles(frontendA, [], true, 3);
+ expect(relatedRoles).toEqual([]);
+ });
- it("should return an empty array when allOpenRoles is empty", () => {
- const relatedRoles = getRelatedRoles(frontendA, [], true, 3);
- expect(relatedRoles).toEqual([]);
- });
+ it("should return an empty array when maxRelatedRoles is 0", () => {
+ const relatedRoles = getRelatedRoles(frontendA, allOpenRoles, true, 0);
+ expect(relatedRoles).toEqual([]);
+ });
- it("should return an empty array when maxRelatedRoles is 0", () => {
- const relatedRoles = getRelatedRoles(frontendA, allOpenRoles, true, 0);
- expect(relatedRoles).toEqual([]);
- });
+ it("should not return the same role being viewed", () => {
+ const relatedRoles = getRelatedRoles(
+ frontendA,
+ allOpenRoles,
+ true,
+ allOpenRoles.length,
+ );
+ expect(relatedRoles.length).toBe(allOpenRoles.length - 1);
+ expect(relatedRoles).not.toContain(frontendA);
+ });
- it("should not return the same role being viewed", () => {
- const relatedRoles = getRelatedRoles(frontendA, allOpenRoles, true, allOpenRoles.length);
- expect(relatedRoles.length).toBe(allOpenRoles.length - 1);
- expect(relatedRoles).not.toContain(frontendA);
- });
+ it("should return a subset of related roles when maxRelatedRoles is less than the length of allOpenRoles", () => {
+ const relatedRoles = getRelatedRoles(
+ frontendA,
+ allOpenRoles,
+ true,
+ allOpenRoles.length - 2,
+ );
+ expect(relatedRoles.length).toBe(allOpenRoles.length - 2);
+ expect(relatedRoles).not.toContain(frontendA);
+ });
- it("should return a subset of related roles when maxRelatedRoles is less than the length of allOpenRoles", () => {
- const relatedRoles = getRelatedRoles(frontendA, allOpenRoles, true, allOpenRoles.length - 2);
- expect(relatedRoles.length).toBe(allOpenRoles.length - 2);
- expect(relatedRoles).not.toContain(frontendA);
- });
+ it("should return allOpenRoles (less duplicates) when maxRelatedRoles is greater than or equal to the length of allOpenRoles", () => {
+ const relatedRoles = getRelatedRoles(
+ frontendA,
+ allOpenRoles,
+ true,
+ allOpenRoles.length,
+ );
+ expect(relatedRoles.length).toBe(allOpenRoles.length - 1);
- it("should return allOpenRoles (less duplicates) when maxRelatedRoles is greater than or equal to the length of allOpenRoles", () => {
- const relatedRoles = getRelatedRoles(frontendA, allOpenRoles, true, allOpenRoles.length);
- expect(relatedRoles.length).toBe(allOpenRoles.length - 1);
+ const relatedRoles2 = getRelatedRoles(
+ backendA,
+ allOpenRoles,
+ true,
+ allOpenRoles.length + 1,
+ );
+ expect(relatedRoles2.length).toBe(allOpenRoles.length - 1);
+ });
- const relatedRoles2 = getRelatedRoles(backendA, allOpenRoles, true, allOpenRoles.length + 1);
- expect(relatedRoles2.length).toBe(allOpenRoles.length - 1);
- });
+ it("should return roles from the same category first", () => {
+ const relatedRoles = getRelatedRoles(frontendA, allOpenRoles, false, 4);
+ expect(relatedRoles.length).toBe(3);
+ expect(relatedRoles[0].category).toBe(CategoriesData.frontend);
+ expect(relatedRoles[1].category).toBe(CategoriesData.backend);
+ expect(relatedRoles[2].category).toBe(CategoriesData.backend);
+ });
- it("should return roles from the same category first", () => {
- const relatedRoles = getRelatedRoles(frontendA, allOpenRoles, false, 4);
- expect(relatedRoles.length).toBe(3);
- expect(relatedRoles[0].category).toBe(CategoriesData.frontend);
- expect(relatedRoles[1].category).toBe(CategoriesData.backend);
- expect(relatedRoles[2].category).toBe(CategoriesData.backend);
- });
-
- it("should never return duplicates", () => {
- const relatedRoles = getRelatedRoles(frontendA, [frontendA, frontendB, frontendB], false, 4);
- expect(relatedRoles.length).toBe(1);
- });
-});
\ No newline at end of file
+ it("should never return duplicates", () => {
+ const relatedRoles = getRelatedRoles(
+ frontendA,
+ [frontendA, frontendB, frontendB],
+ false,
+ 4,
+ );
+ expect(relatedRoles.length).toBe(1);
+ });
+});
diff --git a/apps/namehashlabs.org/lib/utils/careers.ts b/apps/namehashlabs.org/lib/utils/careers.ts
index bf0b0465c..14564e292 100644
--- a/apps/namehashlabs.org/lib/utils/careers.ts
+++ b/apps/namehashlabs.org/lib/utils/careers.ts
@@ -3,14 +3,14 @@ import { Role } from "@/types";
/**
* Gets the distinct set of roles from a list of roles.
* Uses each role's slug to determine uniqueness.
- *
+ *
* @param roles The list of roles to filter.
* @param slugs An optional list of slugs to also exclude from the results.
* @returns The distinct set of roles.
*/
export const getDistinctRoles = (roles: Role[], slugs?: string[]): Role[] => {
const seenSlugs = new Set
(slugs ? slugs : []);
- return roles.filter(role => {
+ return roles.filter((role) => {
if (seenSlugs.has(role.slug)) {
return false;
} else {
@@ -18,14 +18,14 @@ export const getDistinctRoles = (roles: Role[], slugs?: string[]): Role[] => {
return true;
}
});
-}
+};
/**
* Gets distinct roles in `allOpenRoles` that are distinct from `role` but most related to `role`.
- *
+ *
* Related roles are defined as roles in the same category as `role`, followed by roles
* in different categories.
- *
+ *
* Distinct roles are defined as roles with distinct `slug` values.
*
* @param role The `Role` to get related roles for.
@@ -42,9 +42,8 @@ export const getRelatedRoles = (
role: Role,
allOpenRoles: Role[],
shuffle: boolean,
- maxRelatedRoles: number
+ maxRelatedRoles: number,
): Role[] => {
-
// filter out the specified role and any duplicates in allOpenRoles
const distinctRoles = getDistinctRoles(allOpenRoles, [role.slug]);
@@ -53,12 +52,12 @@ export const getRelatedRoles = (
// get all roles in the same category as the specified role
const sameCategoryRoles = shuffledRoles.filter(
- (item) => item.category.name === role.category.name
+ (item) => item.category.name === role.category.name,
);
// get all roles in a different category as the specified role
const differentCategoryRoles = shuffledRoles.filter(
- (item) => item.category.name !== role.category.name
+ (item) => item.category.name !== role.category.name,
);
// combine the two sets of roles, ensuring that the same category roles come first
diff --git a/apps/namehashlabs.org/middleware.ts b/apps/namehashlabs.org/middleware.ts
index 32c793b5b..e772bcc57 100644
--- a/apps/namehashlabs.org/middleware.ts
+++ b/apps/namehashlabs.org/middleware.ts
@@ -4,7 +4,7 @@ const allowedOrigins = [
"https://namehashlabs.org",
"https://www.nameguard.io",
"https://www.namekit.io",
- "https://ensawards.org"
+ "https://ensawards.org",
];
const corsOptions = {
diff --git a/apps/namehashlabs.org/vitest.config.ts b/apps/namehashlabs.org/vitest.config.ts
index c7a151ef0..4114d2535 100644
--- a/apps/namehashlabs.org/vitest.config.ts
+++ b/apps/namehashlabs.org/vitest.config.ts
@@ -1,9 +1,9 @@
-import { UserConfig, defineConfig } from 'vitest/config';
+import { UserConfig, defineConfig } from "vitest/config";
export default defineConfig({
- resolve: {
- alias: {
- '@': '/.'
- },
+ resolve: {
+ alias: {
+ "@": "/.",
},
-} as UserConfig);
\ No newline at end of file
+ },
+} as UserConfig);
diff --git a/apps/namekit.io/src/components/atoms/icons/ens-vision-icon.tsx b/apps/namekit.io/src/components/atoms/icons/ens-vision-icon.tsx
deleted file mode 100644
index ddc90b49a..000000000
--- a/apps/namekit.io/src/components/atoms/icons/ens-vision-icon.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import { type SVGProps } from "react";
-
-export function EnsVisionIcon(props: SVGProps) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-export default EnsVisionIcon;
diff --git a/apps/namekit.io/src/components/atoms/icons/ensvision-icon.tsx b/apps/namekit.io/src/components/atoms/icons/ensvision-icon.tsx
deleted file mode 100644
index ddc90b49a..000000000
--- a/apps/namekit.io/src/components/atoms/icons/ensvision-icon.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import { type SVGProps } from "react";
-
-export function EnsVisionIcon(props: SVGProps) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-export default EnsVisionIcon;
diff --git a/apps/namekit.io/src/components/atoms/icons/explore-web3-lp/ens-vision-logo.tsx b/apps/namekit.io/src/components/atoms/icons/explore-web3-lp/ens-vision-logo.tsx
deleted file mode 100644
index 2fa773f44..000000000
--- a/apps/namekit.io/src/components/atoms/icons/explore-web3-lp/ens-vision-logo.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import { type SVGProps } from "react";
-
-export const EnsVisionLogo = (props: SVGProps) => {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-};
diff --git a/apps/namekit.io/src/components/molecules/buy-sell-section.tsx b/apps/namekit.io/src/components/molecules/buy-sell-section.tsx
index 6fdb0407c..d482fcc34 100644
--- a/apps/namekit.io/src/components/molecules/buy-sell-section.tsx
+++ b/apps/namekit.io/src/components/molecules/buy-sell-section.tsx
@@ -1,4 +1,3 @@
-import { EnsVisionLogo } from "@/components/atoms/icons/explore-web3-lp/ens-vision-logo";
import { OpenseaLogo } from "@/components/atoms/icons/explore-web3-lp/opensea-logo";
import { ExploreWeb3CardsSection } from "@/components/organisms/explore-web3-cards-section";
import Image from "next/image";
@@ -29,21 +28,6 @@ export const BuySellSection = () => {
title: "Buy & sell",
}}
apps={[
- {
- title: ,
- description:
- "Discover and trade ENS names across marketplaces. Bulk search, bulk register, and explore a marketplace exclusively dedicated to ENS names.",
- illustration: (
-
- ),
- gradient: "#FFF6E7",
- url: "https://ens.vision/",
- },
{
title: ,
description:
diff --git a/apps/namekit.io/src/components/organisms/services-section.tsx b/apps/namekit.io/src/components/organisms/services-section.tsx
index 8d00b6980..b63ccbd15 100644
--- a/apps/namekit.io/src/components/organisms/services-section.tsx
+++ b/apps/namekit.io/src/components/organisms/services-section.tsx
@@ -18,7 +18,6 @@ import {
ShoppingCartIcon,
} from "@heroicons/react/24/solid";
import { ExternalLinkIcon } from "../atoms/icons/external-link-icon";
-import { EnsVisionIcon } from "../atoms/icons/ensvision-icon";
import OpenSeaIcon from "../atoms/icons/opensea-icon";
import { LooksRareIcon } from "../atoms/icons/looksrare-icon";
// import LensProtocolLogo from "../atoms/icons/lens-protocol-logo";
@@ -279,7 +278,6 @@ const services: ServiceProps[] = [
Automatic integrations with:
-
diff --git a/apps/storybook.namekit.io/stories/Namekit/TruncatedText.stories.tsx b/apps/storybook.namekit.io/stories/Namekit/TruncatedText.stories.tsx
index 2cd90d2ae..27e472136 100644
--- a/apps/storybook.namekit.io/stories/Namekit/TruncatedText.stories.tsx
+++ b/apps/storybook.namekit.io/stories/Namekit/TruncatedText.stories.tsx
@@ -2,7 +2,8 @@ import { TruncatedText } from "@namehash/namekit-react/client";
import type { Meta, StoryObj } from "@storybook/react";
const SHORT_TEXT = "heyiamsmall";
-const LONG_TEXT = "heyiamaverylongtextthatkeepsgrowingunstopablyomgiamstillgoingonokdone";
+const LONG_TEXT =
+ "heyiamaverylongtextthatkeepsgrowingunstopablyomgiamstillgoingonokdone";
const meta: Meta
= {
component: TruncatedText,
diff --git a/internal/internal/src/icons/service-provider-badge.tsx b/internal/internal/src/icons/service-provider-badge.tsx
index 073f6a2c8..976fc5ee5 100644
--- a/internal/internal/src/icons/service-provider-badge.tsx
+++ b/internal/internal/src/icons/service-provider-badge.tsx
@@ -1,5 +1,5 @@
export const ServiceProviderBadge = (
- props: React.HTMLAttributes
+ props: React.HTMLAttributes,
) => {
return (
{
-
- it("doesn't begin with 0x", () => {
- const address = "0000000000000000000000000000000000000000";
+ it("doesn't begin with 0x", () => {
+ const address = "0000000000000000000000000000000000000000";
- expect(() => buildAddress(address)).toThrow();
- });
+ expect(() => buildAddress(address)).toThrow();
+ });
- it("too few digits", () => {
- const address = "0x000000000000000000000000000000000000000";
+ it("too few digits", () => {
+ const address = "0x000000000000000000000000000000000000000";
- expect(() => buildAddress(address)).toThrow();
- });
+ expect(() => buildAddress(address)).toThrow();
+ });
- it("too many digits", () => {
- const address = "0x00000000000000000000000000000000000000000";
+ it("too many digits", () => {
+ const address = "0x00000000000000000000000000000000000000000";
- expect(() => buildAddress(address)).toThrow();
- });
+ expect(() => buildAddress(address)).toThrow();
+ });
- it("valid address, checksum wrong but not strict", () => {
- const address = "0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF";
- const expectedAddress = checksumAddress(address, MAINNET.chainId);
+ it("valid address, checksum wrong but not strict", () => {
+ const address = "0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF";
+ const expectedAddress = checksumAddress(address, MAINNET.chainId);
- const result = buildAddress(address);
- expect(result.address).toBe(expectedAddress);
- });
+ const result = buildAddress(address);
+ expect(result.address).toBe(expectedAddress);
+ });
- it("valid address, checksum wrong and strict", () => {
- const address = "0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF";
+ it("valid address, checksum wrong and strict", () => {
+ const address = "0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF";
- expect(() => buildAddress(address, true, MAINNET)).toThrow();
- });
+ expect(() => buildAddress(address, true, MAINNET)).toThrow();
+ });
- it("valid address, checksum right and strict", () => {
- const address = "0x80C9a4104F594029F3F7f9e4Fde5bc25E9E64cdf";
+ it("valid address, checksum right and strict", () => {
+ const address = "0x80C9a4104F594029F3F7f9e4Fde5bc25E9E64cdf";
- const result = buildAddress(address, true, MAINNET);
- expect(result.address).toBe(address);
- });
+ const result = buildAddress(address, true, MAINNET);
+ expect(result.address).toBe(address);
+ });
});
describe("truncateAddress() function", () => {
-
- it("truncate address", () => {
- const address = buildAddress("0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF");
+ it("truncate address", () => {
+ const address = buildAddress("0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF");
- const result = truncateAddress(address);
- expect(result).toBe("0x80C9...4cdf");
- });
+ const result = truncateAddress(address);
+ expect(result).toBe("0x80C9...4cdf");
+ });
});
describe("isAddressEqual() function", () => {
-
- it("equal addresses", () => {
- const a = buildAddress("0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF");
- const b = buildAddress("0x80c9a4104f594029f3f7f9e4fde5bc25e9e64cdf");
-
- const result = isAddressEqual(a, b);
- expect(result).toBe(true);
- });
-
- it("non-equal addresses", () => {
- const a = buildAddress("0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF");
- const b = buildAddress("0x80c9a4104f594029f3f7f9e4fde5bc25e9e64cd0");
-
- const result = isAddressEqual(a, b);
- expect(result).toBe(false);
- });
-});
\ No newline at end of file
+ it("equal addresses", () => {
+ const a = buildAddress("0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF");
+ const b = buildAddress("0x80c9a4104f594029f3f7f9e4fde5bc25e9e64cdf");
+
+ const result = isAddressEqual(a, b);
+ expect(result).toBe(true);
+ });
+
+ it("non-equal addresses", () => {
+ const a = buildAddress("0x80C9A4104F594029F3F7F9E4FDE5BC25E9E64CDF");
+ const b = buildAddress("0x80c9a4104f594029f3f7f9e4fde5bc25e9e64cd0");
+
+ const result = isAddressEqual(a, b);
+ expect(result).toBe(false);
+ });
+});
diff --git a/packages/ens-utils/src/address.ts b/packages/ens-utils/src/address.ts
index 85744df08..250ce46f0 100644
--- a/packages/ens-utils/src/address.ts
+++ b/packages/ens-utils/src/address.ts
@@ -2,28 +2,33 @@ import { checksumAddress, isAddress } from "viem";
import { ChainId, MAINNET } from "./chain";
export interface Address {
- address: `0x${string}`;
+ address: `0x${string}`;
}
-export const buildAddress = (maybeAddress: string, strict: boolean = false, chain: ChainId = MAINNET): Address => {
+export const buildAddress = (
+ maybeAddress: string,
+ strict: boolean = false,
+ chain: ChainId = MAINNET,
+): Address => {
+ if (!isAddress(maybeAddress, { strict: false }))
+ throw new Error(`Invalid address: ${maybeAddress}`);
- if (!isAddress(maybeAddress, { strict: false }))
- throw new Error(`Invalid address: ${maybeAddress}`);
+ const address = checksumAddress(maybeAddress, chain.chainId);
- const address = checksumAddress(maybeAddress, chain.chainId);
+ if (strict && address !== maybeAddress)
+ throw new Error(
+ `Invalid address checksum: ${maybeAddress} expected ${address} on chainId ${chain.chainId}`,
+ );
- if (strict && address !== maybeAddress)
- throw new Error(`Invalid address checksum: ${maybeAddress} expected ${address} on chainId ${chain.chainId}`);
-
- return {
- address: address
- };
-}
+ return {
+ address: address,
+ };
+};
export const truncateAddress = (address: Address): string => {
- return address.address.slice(0, 6) + "..." + address.address.slice(-4);
+ return address.address.slice(0, 6) + "..." + address.address.slice(-4);
};
export const isAddressEqual = (a: Address, b: Address): boolean => {
- return a.address.toLowerCase() === b.address.toLowerCase()
-}
\ No newline at end of file
+ return a.address.toLowerCase() === b.address.toLowerCase();
+};
diff --git a/packages/ens-utils/src/chain.test.ts b/packages/ens-utils/src/chain.test.ts
index 32b85e3bd..e1fc4f9f6 100644
--- a/packages/ens-utils/src/chain.test.ts
+++ b/packages/ens-utils/src/chain.test.ts
@@ -1,102 +1,103 @@
import { describe, it, expect } from "vitest";
-import { MAINNET, buildChainId, getChainByName, getChainMetadata } from "./chain";
+import {
+ MAINNET,
+ buildChainId,
+ getChainByName,
+ getChainMetadata,
+} from "./chain";
describe("buildChainId() function", () => {
+ it("Build from string", () => {
+ const chainId = "1";
- it("Build from string", () => {
- const chainId = "1";
+ const result = buildChainId(chainId);
- const result = buildChainId(chainId);
-
- expect(result).toStrictEqual(MAINNET);
- });
+ expect(result).toStrictEqual(MAINNET);
+ });
- it("Build from number", () => {
- const chainId = 1;
+ it("Build from number", () => {
+ const chainId = 1;
- const result = buildChainId(chainId);
-
- expect(result).toStrictEqual(MAINNET);
- });
+ const result = buildChainId(chainId);
- it("Invalid chainId: non-number", () => {
- const chainId = "q";
-
- expect(() => buildChainId(chainId)).toThrow();
- });
+ expect(result).toStrictEqual(MAINNET);
+ });
- it("Invalid chainId: chainId non-positive", () => {
- const chainId = 0;
+ it("Invalid chainId: non-number", () => {
+ const chainId = "q";
- expect(() => buildChainId(chainId)).toThrow();
- });
+ expect(() => buildChainId(chainId)).toThrow();
+ });
- it("Invalid chainId: chainId negative", () => {
- const chainId = -1;
+ it("Invalid chainId: chainId non-positive", () => {
+ const chainId = 0;
- expect(() => buildChainId(chainId)).toThrow();
- });
+ expect(() => buildChainId(chainId)).toThrow();
+ });
- it("Invalid chainId: chainId non-integer", () => {
- const chainId = 1.5;
+ it("Invalid chainId: chainId negative", () => {
+ const chainId = -1;
- expect(() => buildChainId(chainId)).toThrow();
- });
+ expect(() => buildChainId(chainId)).toThrow();
+ });
- it("Invalid chainId: chainId non-integer string", () => {
- const chainId = "1.5";
-
- expect(() => buildChainId(chainId)).toThrow();
- });
+ it("Invalid chainId: chainId non-integer", () => {
+ const chainId = 1.5;
- it("Invalid chainId: chainId NaN", () => {
- const chainId = NaN;
+ expect(() => buildChainId(chainId)).toThrow();
+ });
- expect(() => buildChainId(chainId)).toThrow();
- });
+ it("Invalid chainId: chainId non-integer string", () => {
+ const chainId = "1.5";
- it("Invalid chainId: chainId Infinity", () => {
- const chainId = Infinity;
+ expect(() => buildChainId(chainId)).toThrow();
+ });
- expect(() => buildChainId(chainId)).toThrow();
- });
+ it("Invalid chainId: chainId NaN", () => {
+ const chainId = NaN;
+ expect(() => buildChainId(chainId)).toThrow();
+ });
+
+ it("Invalid chainId: chainId Infinity", () => {
+ const chainId = Infinity;
+
+ expect(() => buildChainId(chainId)).toThrow();
+ });
});
describe("getChainByName() function", () => {
-
it("known chain", () => {
- const name = "mainnet";
+ const name = "mainnet";
- const result = getChainByName(name);
-
- expect(result).toStrictEqual(MAINNET);
- });
+ const result = getChainByName(name);
- it("case-insensitive unknown chain", () => {
- const name = "Mainnet";
+ expect(result).toStrictEqual(MAINNET);
+ });
- expect(() => getChainByName(name)).toThrow();
- });
+ it("case-insensitive unknown chain", () => {
+ const name = "Mainnet";
- it("general unknown chain", () => {
- const name = "unknown";
+ expect(() => getChainByName(name)).toThrow();
+ });
- expect(() => getChainByName(name)).toThrow();
- });
+ it("general unknown chain", () => {
+ const name = "unknown";
+
+ expect(() => getChainByName(name)).toThrow();
+ });
});
describe("getChainMetadata() function", () => {
-
it("known chain", () => {
- const result = getChainMetadata(MAINNET);
-
- expect(result).toBeDefined();
- });
-
- it("unknown chain", () => {
- const chainId = buildChainId(1234567890);
-
- expect(() => getChainMetadata(chainId)).toThrow();
- });
-});
\ No newline at end of file
+ const result = getChainMetadata(MAINNET);
+
+ expect(result).toBeDefined();
+ });
+
+ it("unknown chain", () => {
+ const chainId = buildChainId(1234567890);
+
+ expect(() => getChainMetadata(chainId)).toThrow();
+ });
+});
diff --git a/packages/ens-utils/src/chain.ts b/packages/ens-utils/src/chain.ts
index 6183590dd..4e1cc217b 100644
--- a/packages/ens-utils/src/chain.ts
+++ b/packages/ens-utils/src/chain.ts
@@ -1,123 +1,127 @@
export interface ChainId {
-
- /**
- * Chain Id. See https://chainlist.org/
- * Always a positive integer.
- */
- chainId: number;
-};
+ /**
+ * Chain Id. See https://chainlist.org/
+ * Always a positive integer.
+ */
+ chainId: number;
+}
export interface ChainMetadata {
-
- /**
- * Chain Id.
- */
- chain: ChainId;
-
- /**
- * Distinct chain name.
- */
- name: string;
-
- /**
- * Chain name for display to end users.
- */
- displayName: string;
-};
+ /**
+ * Chain Id.
+ */
+ chain: ChainId;
+
+ /**
+ * Distinct chain name.
+ */
+ name: string;
+
+ /**
+ * Chain name for display to end users.
+ */
+ displayName: string;
+}
/**
* Builds a ChainId object.
* @param maybeChainId the chain ID to reference. See https://chainid.network/
* @returns a ChainRef object.
*/
-export const buildChainId = (
- maybeChainId: number | string,
-): ChainId => {
-
- let chainId : number;
-
- if (typeof maybeChainId === "string") {
-
- chainId = Number(maybeChainId);
- } else {
- chainId = maybeChainId;
- }
-
- if (Number.isNaN(chainId)) {
- throw new Error(`Invalid chain ID: ${maybeChainId}. All chain IDs must be numbers.`);
- }
-
- if (!Number.isFinite(chainId)) {
- throw new Error(`Invalid chain ID: ${maybeChainId}. All chain IDs must be finite numbers.`);
- }
-
- if (!Number.isInteger(chainId)) {
- throw new Error(`Invalid chain ID: ${maybeChainId}. All chain IDs must be integers.`);
- }
-
- if (!Number.isSafeInteger(chainId)) {
- throw new Error(`Invalid chain ID: ${maybeChainId}. All chain IDs must be safe integers.`);
- }
-
- if (chainId <= 0) {
- throw new Error(`Invalid chain ID: ${maybeChainId}. All chain IDs must be positive integers.`);
- }
-
- return {
- chainId,
- };
-}
+export const buildChainId = (maybeChainId: number | string): ChainId => {
+ let chainId: number;
+
+ if (typeof maybeChainId === "string") {
+ chainId = Number(maybeChainId);
+ } else {
+ chainId = maybeChainId;
+ }
+
+ if (Number.isNaN(chainId)) {
+ throw new Error(
+ `Invalid chain ID: ${maybeChainId}. All chain IDs must be numbers.`,
+ );
+ }
+
+ if (!Number.isFinite(chainId)) {
+ throw new Error(
+ `Invalid chain ID: ${maybeChainId}. All chain IDs must be finite numbers.`,
+ );
+ }
+
+ if (!Number.isInteger(chainId)) {
+ throw new Error(
+ `Invalid chain ID: ${maybeChainId}. All chain IDs must be integers.`,
+ );
+ }
+
+ if (!Number.isSafeInteger(chainId)) {
+ throw new Error(
+ `Invalid chain ID: ${maybeChainId}. All chain IDs must be safe integers.`,
+ );
+ }
+
+ if (chainId <= 0) {
+ throw new Error(
+ `Invalid chain ID: ${maybeChainId}. All chain IDs must be positive integers.`,
+ );
+ }
+
+ return {
+ chainId,
+ };
+};
let knownChains: ChainMetadata[] = [];
/**
* Add a chain to the list of known chains.
* Throws an error if a chain with the same ID or name is already registered.
- */
-export const addKnownChain = (
- metadata: ChainMetadata
-): void => {
- knownChains.every(c => {
- if (c.chain.chainId === metadata.chain.chainId) {
- throw new Error(`Chain with ID ${metadata.chain.chainId} already registered.`);
- }
- if (c.name === metadata.name) {
- throw new Error(`Chain with name ${metadata.name} already registered.`);
- }
- return true;
- });
- knownChains.push(metadata);
-}
+ */
+export const addKnownChain = (metadata: ChainMetadata): void => {
+ knownChains.every((c) => {
+ if (c.chain.chainId === metadata.chain.chainId) {
+ throw new Error(
+ `Chain with ID ${metadata.chain.chainId} already registered.`,
+ );
+ }
+ if (c.name === metadata.name) {
+ throw new Error(`Chain with name ${metadata.name} already registered.`);
+ }
+ return true;
+ });
+ knownChains.push(metadata);
+};
// starting simple here
export const MAINNET = buildChainId(1);
export const SEPOLIA = buildChainId(11155111);
-addKnownChain({chain: MAINNET, name: "mainnet", displayName: "Ethereum Mainnet" });
-addKnownChain({chain: SEPOLIA, name: "sepolia", displayName: "Sepolia" });
+addKnownChain({
+ chain: MAINNET,
+ name: "mainnet",
+ displayName: "Ethereum Mainnet",
+});
+addKnownChain({ chain: SEPOLIA, name: "sepolia", displayName: "Sepolia" });
/**
* Get a chain by name (case-sensitive).
* @param name name of the chain to get.
* @returns A `ChainId` object if the chain is known, otherwise throws an error.
*/
-export const getChainByName = (
- name: string
-): ChainId => {
- const chain = knownChains.find(c => c.name === name);
- if (!chain) throw new Error(`Unknown chain: ${name}`);
- return chain.chain;
-}
+export const getChainByName = (name: string): ChainId => {
+ const chain = knownChains.find((c) => c.name === name);
+ if (!chain) throw new Error(`Unknown chain: ${name}`);
+ return chain.chain;
+};
/**
* Get the chain metadata for a given chain.
* @param chainId chain to get metadata for.
* @returns A `ChainMetadata` object if the chain is known, otherwise throws an error.
*/
-export const getChainMetadata = (
- chainId: ChainId
-): ChainMetadata => {
- const chain = knownChains.find(c => c.chain.chainId === chainId.chainId);
- if (!chain) throw new Error(`Unknown chainId: ${chainId.chainId}`);
- return chain;
-}
\ No newline at end of file
+export const getChainMetadata = (chainId: ChainId): ChainMetadata => {
+ const chain = knownChains.find((c) => c.chain.chainId === chainId.chainId);
+ if (!chain) throw new Error(`Unknown chainId: ${chainId.chainId}`);
+ return chain;
+};
diff --git a/packages/ens-utils/src/contract.test.ts b/packages/ens-utils/src/contract.test.ts
index 493899597..96807d00e 100644
--- a/packages/ens-utils/src/contract.test.ts
+++ b/packages/ens-utils/src/contract.test.ts
@@ -4,16 +4,14 @@ import { MAINNET } from "./chain";
import { buildAddress } from "./address";
describe("buildContractRef() function", () => {
+ it("buildContractRef", () => {
+ const address = buildAddress("0x1234567890123456789012345678901234567890");
- it("buildContractRef", () => {
- const address = buildAddress("0x1234567890123456789012345678901234567890");
+ const result = buildContractRef(MAINNET, address);
- const result = buildContractRef(MAINNET, address);
-
- expect(result).to.toStrictEqual({
- chain: MAINNET,
- address: address,
- });
+ expect(result).to.toStrictEqual({
+ chain: MAINNET,
+ address: address,
});
-
-});
\ No newline at end of file
+ });
+});
diff --git a/packages/ens-utils/src/contract.ts b/packages/ens-utils/src/contract.ts
index 32ee85c9b..90c7d5590 100644
--- a/packages/ens-utils/src/contract.ts
+++ b/packages/ens-utils/src/contract.ts
@@ -2,17 +2,16 @@ import { ChainId } from "./chain";
import { Address } from "./address";
export interface ContractRef {
+ /**
+ * Chain Id of the contract.
+ */
+ chain: ChainId;
- /**
- * Chain Id of the contract.
- */
- chain: ChainId;
-
- /**
- * Contract address
- */
- address: Address;
-};
+ /**
+ * Contract address
+ */
+ address: Address;
+}
/**
* Builds a ContractRef object.
@@ -21,12 +20,11 @@ export interface ContractRef {
* @returns a ContractRef object.
*/
export const buildContractRef = (
- chain: ChainId,
- address: Address,
+ chain: ChainId,
+ address: Address,
): ContractRef => {
-
- return {
- chain,
- address
- };
-}
\ No newline at end of file
+ return {
+ chain,
+ address,
+ };
+};
diff --git a/packages/ens-utils/src/currency.test.ts b/packages/ens-utils/src/currency.test.ts
index f7e78ad50..d305d2952 100644
--- a/packages/ens-utils/src/currency.test.ts
+++ b/packages/ens-utils/src/currency.test.ts
@@ -22,8 +22,8 @@ describe("getPrimaryDisplayCurrency() function", () => {
getPrimaryDisplayCurrency(
CurrencyDisplayRule.PreferredCurrency,
preferredCurrency,
- Currency.Usd
- )
+ Currency.Usd,
+ ),
).toBe(preferredCurrency);
});
@@ -34,8 +34,8 @@ describe("getPrimaryDisplayCurrency() function", () => {
getPrimaryDisplayCurrency(
CurrencyDisplayRule.NativeCurrency,
Currency.Eth,
- nativeCurrency
- )
+ nativeCurrency,
+ ),
).toBe(nativeCurrency);
});
});
@@ -46,8 +46,8 @@ describe("getAlternateDisplayCurrency() function", () => {
getAlternateDisplayCurrency(
CurrencyDisplayRule.PreferredCurrency,
Currency.Usd,
- Currency.Usd
- )
+ Currency.Usd,
+ ),
).toBe(Currency.Eth);
});
@@ -56,8 +56,8 @@ describe("getAlternateDisplayCurrency() function", () => {
getAlternateDisplayCurrency(
CurrencyDisplayRule.PreferredCurrency,
Currency.Eth,
- Currency.Eth
- )
+ Currency.Eth,
+ ),
).toBe(Currency.Usd);
});
@@ -66,8 +66,8 @@ describe("getAlternateDisplayCurrency() function", () => {
getAlternateDisplayCurrency(
CurrencyDisplayRule.PreferredCurrency,
Currency.Eth,
- Currency.Usd
- )
+ Currency.Usd,
+ ),
).toBe(Currency.Usd);
});
@@ -76,8 +76,8 @@ describe("getAlternateDisplayCurrency() function", () => {
getAlternateDisplayCurrency(
CurrencyDisplayRule.NativeCurrency,
Currency.Eth,
- Currency.Usd
- )
+ Currency.Usd,
+ ),
).toBe(Currency.Eth);
});
@@ -86,8 +86,8 @@ describe("getAlternateDisplayCurrency() function", () => {
getAlternateDisplayCurrency(
CurrencyDisplayRule.NativeCurrency,
Currency.Eth,
- Currency.Eth
- )
+ Currency.Eth,
+ ),
).toBe(Currency.Usd);
});
@@ -96,8 +96,8 @@ describe("getAlternateDisplayCurrency() function", () => {
getAlternateDisplayCurrency(
CurrencyDisplayRule.NativeCurrency,
Currency.Usd,
- Currency.Usd
- )
+ Currency.Usd,
+ ),
).toBe(Currency.Eth);
});
});
@@ -137,13 +137,13 @@ describe("parseStringToCurrency() function", () => {
it("should throw an error for invalid currency string", () => {
expect(() => parseStringToCurrency("invalid")).toThrow(
- "Cannot convert: \"invalid\" to a recognized Currency"
+ 'Cannot convert: "invalid" to a recognized Currency',
);
});
it("should throw an error for empty string", () => {
expect(() => parseStringToCurrency("")).toThrow(
- "Cannot convert: \"\" to a recognized Currency"
+ 'Cannot convert: "" to a recognized Currency',
);
});
});
diff --git a/packages/ens-utils/src/currency.ts b/packages/ens-utils/src/currency.ts
index 6a1b1692c..3e713e7fb 100644
--- a/packages/ens-utils/src/currency.ts
+++ b/packages/ens-utils/src/currency.ts
@@ -137,7 +137,7 @@ export const PriceCurrencyFormat: Record = {
export const getPrimaryDisplayCurrency = (
rule: CurrencyDisplayRule,
preferredCurrency: Currency,
- nativeCurrency: Currency
+ nativeCurrency: Currency,
): Currency => {
if (rule === CurrencyDisplayRule.PreferredCurrency) {
return preferredCurrency;
@@ -149,7 +149,7 @@ export const getPrimaryDisplayCurrency = (
export const getAlternateDisplayCurrency = (
rule: CurrencyDisplayRule,
preferredCurrency: Currency,
- nativeCurrency: Currency
+ nativeCurrency: Currency,
): Currency => {
if (rule === CurrencyDisplayRule.PreferredCurrency) {
if (nativeCurrency === preferredCurrency) {
@@ -170,7 +170,8 @@ export const parseStringToCurrency = (str: string): Currency => {
const curatedStr = str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
const currency = Currency[curatedStr as keyof typeof Currency];
- if (!currency) throw new Error(`Cannot convert: "${str}" to a recognized Currency`);
+ if (!currency)
+ throw new Error(`Cannot convert: "${str}" to a recognized Currency`);
return currency;
};
diff --git a/packages/ens-utils/src/ensname.test.ts b/packages/ens-utils/src/ensname.test.ts
index cffb4f375..fd481123e 100644
--- a/packages/ens-utils/src/ensname.test.ts
+++ b/packages/ens-utils/src/ensname.test.ts
@@ -418,7 +418,7 @@ describe("charCount", () => {
const text = "🧟♂";
const result = charCount(text);
- expect(result).toBe(3); // 3 Unicode characters
+ expect(result).toBe(3); // 3 Unicode characters
expect(text.length).toBe(4); // 4 UTF-16 code units
});
@@ -443,7 +443,7 @@ describe("charCount", () => {
const result = charCount(text);
expect(result).toBe(4); // 4 Unicode characters
- expect(text.length).toBe(6); // 6 UTF-16 code units
+ expect(text.length).toBe(6); // 6 UTF-16 code units
});
});
@@ -459,7 +459,7 @@ describe("charSplit", () => {
const text = "🧟♂";
const result = charSplit(text);
- expect(result).toEqual(["🧟", "", "♂"]); // 3 Unicode characters
+ expect(result).toEqual(["🧟", "", "♂"]); // 3 Unicode characters
});
it("splits another multi codepoint emoji", () => {
diff --git a/packages/ens-utils/src/ethregistrar.test.ts b/packages/ens-utils/src/ethregistrar.test.ts
index cf5ce4640..455a8a2eb 100644
--- a/packages/ens-utils/src/ethregistrar.test.ts
+++ b/packages/ens-utils/src/ethregistrar.test.ts
@@ -1,57 +1,75 @@
import { describe, it, expect } from "vitest";
-import { Registrar, UNWRAPPED_MAINNET_ETH_REGISTRAR, WRAPPED_MAINNET_ETH_REGISTRAR, buildNFTRefFromENSName } from "./ethregistrar";
+import {
+ Registrar,
+ UNWRAPPED_MAINNET_ETH_REGISTRAR,
+ WRAPPED_MAINNET_ETH_REGISTRAR,
+ buildNFTRefFromENSName,
+} from "./ethregistrar";
import { ENSName, buildENSName } from "./ensname";
import { MAINNET, SEPOLIA } from "./chain";
import { buildNFTRef } from "./nft";
// TODO: add a lot more unit tests here
-function testNFTRefFromRegistrar(name: ENSName, registrar: Registrar, isWrapped: boolean): void {
- const expectedToken = registrar.getTokenId(name, isWrapped);
- const expectedNFT = buildNFTRef(registrar.contract, expectedToken);
- const result = buildNFTRefFromENSName(name, registrar.contract.chain, isWrapped);
- expect(result).toStrictEqual(expectedNFT);
+function testNFTRefFromRegistrar(
+ name: ENSName,
+ registrar: Registrar,
+ isWrapped: boolean,
+): void {
+ const expectedToken = registrar.getTokenId(name, isWrapped);
+ const expectedNFT = buildNFTRef(registrar.contract, expectedToken);
+ const result = buildNFTRefFromENSName(
+ name,
+ registrar.contract.chain,
+ isWrapped,
+ );
+ expect(result).toStrictEqual(expectedNFT);
}
describe("buildNFTRefFromENSName", () => {
+ it("unrecognized registrar", () => {
+ expect(() =>
+ buildNFTRefFromENSName(buildENSName("foo.eth"), SEPOLIA, false),
+ ).toThrow();
+ });
- it("unrecognized registrar", () => {
- expect(() => buildNFTRefFromENSName(buildENSName("foo.eth"), SEPOLIA, false)).toThrow();
- });
-
- it("unwrapped non-.eth TLD", () => {
- expect(() => buildNFTRefFromENSName(buildENSName("foo.com"), MAINNET, false)).toThrow();
- });
-
- it("wrapped non-.eth TLD", () => {
- const name = buildENSName("foo.com");
- const registrar = WRAPPED_MAINNET_ETH_REGISTRAR;
- const isWrapped = true;
- testNFTRefFromRegistrar(name, registrar, isWrapped);
- });
-
- it("unwrapped subname of a .eth subname", () => {
- expect(() => buildNFTRefFromENSName(buildENSName("x.foo.eth"), MAINNET, false)).toThrow();
- });
-
- it("wrapped subname of a .eth subname", () => {
- const name = buildENSName("x.foo.eth");
- const registrar = WRAPPED_MAINNET_ETH_REGISTRAR;
- const isWrapped = true;
- testNFTRefFromRegistrar(name, registrar, isWrapped);
- });
-
- it("unwrapped direct subname of .eth", () => {
- const name = buildENSName("foo.eth");
- const registrar = UNWRAPPED_MAINNET_ETH_REGISTRAR;
- const isWrapped = false;
- testNFTRefFromRegistrar(name, registrar, isWrapped);
- });
-
- it("wrapped direct subname of .eth", () => {
- const name = buildENSName("foo.eth");
- const registrar = WRAPPED_MAINNET_ETH_REGISTRAR;
- const isWrapped = true;
- testNFTRefFromRegistrar(name, registrar, isWrapped);
- });
-});
\ No newline at end of file
+ it("unwrapped non-.eth TLD", () => {
+ expect(() =>
+ buildNFTRefFromENSName(buildENSName("foo.com"), MAINNET, false),
+ ).toThrow();
+ });
+
+ it("wrapped non-.eth TLD", () => {
+ const name = buildENSName("foo.com");
+ const registrar = WRAPPED_MAINNET_ETH_REGISTRAR;
+ const isWrapped = true;
+ testNFTRefFromRegistrar(name, registrar, isWrapped);
+ });
+
+ it("unwrapped subname of a .eth subname", () => {
+ expect(() =>
+ buildNFTRefFromENSName(buildENSName("x.foo.eth"), MAINNET, false),
+ ).toThrow();
+ });
+
+ it("wrapped subname of a .eth subname", () => {
+ const name = buildENSName("x.foo.eth");
+ const registrar = WRAPPED_MAINNET_ETH_REGISTRAR;
+ const isWrapped = true;
+ testNFTRefFromRegistrar(name, registrar, isWrapped);
+ });
+
+ it("unwrapped direct subname of .eth", () => {
+ const name = buildENSName("foo.eth");
+ const registrar = UNWRAPPED_MAINNET_ETH_REGISTRAR;
+ const isWrapped = false;
+ testNFTRefFromRegistrar(name, registrar, isWrapped);
+ });
+
+ it("wrapped direct subname of .eth", () => {
+ const name = buildENSName("foo.eth");
+ const registrar = WRAPPED_MAINNET_ETH_REGISTRAR;
+ const isWrapped = true;
+ testNFTRefFromRegistrar(name, registrar, isWrapped);
+ });
+});
diff --git a/packages/ens-utils/src/hashutils.test.ts b/packages/ens-utils/src/hashutils.test.ts
index 02b7da21b..b0960ee49 100644
--- a/packages/ens-utils/src/hashutils.test.ts
+++ b/packages/ens-utils/src/hashutils.test.ts
@@ -10,12 +10,16 @@ import {
describe("labelhash", () => {
it("correctly hashes an empty label", () => {
const result = labelhash("");
- expect(result).toBe("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
+ expect(result).toBe(
+ "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
+ );
});
it("correctly hashes a non-empty label", () => {
const result = labelhash("example");
- expect(result).toBe("0x6fd43e7cffc31bb581d7421c8698e29aa2bd8e7186a394b85299908b4eb9b175");
+ expect(result).toBe(
+ "0x6fd43e7cffc31bb581d7421c8698e29aa2bd8e7186a394b85299908b4eb9b175",
+ );
});
});
diff --git a/packages/ens-utils/src/hashutils.ts b/packages/ens-utils/src/hashutils.ts
index 328490ca6..8ccad0723 100644
--- a/packages/ens-utils/src/hashutils.ts
+++ b/packages/ens-utils/src/hashutils.ts
@@ -1,4 +1,4 @@
-import { keccak256, toHex } from 'viem'
+import { keccak256, toHex } from "viem";
/**
* Simple wrapper around the viem implementation of `labelhash` that returns a generic string instead.
diff --git a/packages/ens-utils/src/index.ts b/packages/ens-utils/src/index.ts
index 87a8895d0..22b682f58 100644
--- a/packages/ens-utils/src/index.ts
+++ b/packages/ens-utils/src/index.ts
@@ -10,4 +10,4 @@ export * from "./nft";
export * from "./number";
export * from "./price";
export * from "./time";
-export * from "./transaction";
\ No newline at end of file
+export * from "./transaction";
diff --git a/packages/ens-utils/src/nameparser.ts b/packages/ens-utils/src/nameparser.ts
index 4f966915f..7dd311161 100644
--- a/packages/ens-utils/src/nameparser.ts
+++ b/packages/ens-utils/src/nameparser.ts
@@ -127,7 +127,7 @@ export function assumeTld(labels: string[], assumedTld: string): string[] {
export function parseName(
inputName: string,
- options?: NameParserOptions
+ options?: NameParserOptions,
): ParsedName {
const trimWhitespace =
options?.trimWhitespace !== undefined
diff --git a/packages/ens-utils/src/nft.test.ts b/packages/ens-utils/src/nft.test.ts
index 0f6d1ce2c..c9329f0cb 100644
--- a/packages/ens-utils/src/nft.test.ts
+++ b/packages/ens-utils/src/nft.test.ts
@@ -1,17 +1,16 @@
import { describe, it, expect } from "vitest";
import {
- buildNFTRef,
- convertNFTRefToString,
- buildNFTReferenceFromString,
- buildTokenId,
+ buildNFTRef,
+ convertNFTRefToString,
+ buildNFTReferenceFromString,
+ buildTokenId,
} from "./nft";
import { MAINNET } from "./chain";
import { buildContractRef } from "./contract";
import { buildAddress } from "./address";
describe("buildTokenId() function", () => {
-
it("Non-integer tokenId", () => {
const tokenId = "x";
@@ -30,17 +29,17 @@ describe("buildTokenId() function", () => {
const result = buildTokenId(tokenId);
expect(result).toStrictEqual({
- tokenId: tokenId,
+ tokenId: tokenId,
});
});
it("Max allowed tokenId value", () => {
- const tokenId = (2n ** 256n) - 1n;
+ const tokenId = 2n ** 256n - 1n;
const result = buildTokenId(tokenId);
expect(result).toStrictEqual({
- tokenId: tokenId,
+ tokenId: tokenId,
});
});
@@ -49,64 +48,67 @@ describe("buildTokenId() function", () => {
expect(() => buildTokenId(tokenId)).toThrow();
});
-
});
describe("buildNFTRef() function", () => {
+ it("buildNFTRef", () => {
+ const chain = MAINNET;
+ const contractAddress = buildAddress(
+ "0x1234567890123456789012345678901234567890",
+ );
+ const token = buildTokenId(1234567890123456789012345678901234567890n);
- it("buildNFTRef", () => {
- const chain = MAINNET;
- const contractAddress = buildAddress("0x1234567890123456789012345678901234567890");
- const token = buildTokenId(1234567890123456789012345678901234567890n);
-
- const contract = buildContractRef(chain, contractAddress);
- const result = buildNFTRef(contract, token);
-
- expect(result).toStrictEqual({
- contract: contract,
- token: token,
- });
- });
+ const contract = buildContractRef(chain, contractAddress);
+ const result = buildNFTRef(contract, token);
+ expect(result).toStrictEqual({
+ contract: contract,
+ token: token,
+ });
+ });
});
describe("convertNFTRefToString() function", () => {
+ it("convertNFTRefToString", () => {
+ const chain = MAINNET;
+ const contractAddress = buildAddress(
+ "0x1234567890123456789012345678901234567890",
+ );
+ const token = buildTokenId(1234567890123456789012345678901234567890n);
- it("convertNFTRefToString", () => {
- const chain = MAINNET;
- const contractAddress = buildAddress("0x1234567890123456789012345678901234567890");
- const token = buildTokenId(1234567890123456789012345678901234567890n);
+ const contract = buildContractRef(chain, contractAddress);
+ const nft = buildNFTRef(contract, token);
- const contract = buildContractRef(chain, contractAddress);
- const nft = buildNFTRef(contract, token);
-
- const result = convertNFTRefToString(nft);
-
- expect(result).toEqual("1:0x1234567890123456789012345678901234567890:1234567890123456789012345678901234567890");
- });
+ const result = convertNFTRefToString(nft);
+ expect(result).toEqual(
+ "1:0x1234567890123456789012345678901234567890:1234567890123456789012345678901234567890",
+ );
+ });
});
describe("buildNFTReferenceFromString() function", () => {
+ it("too few params", () => {
+ expect(() => buildNFTReferenceFromString(":")).toThrow();
+ });
- it("too few params", () => {
- expect(() => buildNFTReferenceFromString(":")).toThrow();
- });
-
- it("too many params", () => {
- expect(() => buildNFTReferenceFromString(":::")).toThrow();
- });
+ it("too many params", () => {
+ expect(() => buildNFTReferenceFromString(":::")).toThrow();
+ });
- it("valid params", () => {
- const result = buildNFTReferenceFromString("1:0x1234567890123456789012345678901234567890:1234567890123456789012345678901234567890");
+ it("valid params", () => {
+ const result = buildNFTReferenceFromString(
+ "1:0x1234567890123456789012345678901234567890:1234567890123456789012345678901234567890",
+ );
- const chain = MAINNET;
- const contractAddress = buildAddress("0x1234567890123456789012345678901234567890");
- const contract = buildContractRef(chain, contractAddress);
- const token = buildTokenId(1234567890123456789012345678901234567890n);
- const nft = buildNFTRef(contract, token);
+ const chain = MAINNET;
+ const contractAddress = buildAddress(
+ "0x1234567890123456789012345678901234567890",
+ );
+ const contract = buildContractRef(chain, contractAddress);
+ const token = buildTokenId(1234567890123456789012345678901234567890n);
+ const nft = buildNFTRef(contract, token);
- expect(result).toStrictEqual(nft);
- });
-
-});
\ No newline at end of file
+ expect(result).toStrictEqual(nft);
+ });
+});
diff --git a/packages/ens-utils/src/nft.ts b/packages/ens-utils/src/nft.ts
index cd14d47f6..1b2237bdb 100644
--- a/packages/ens-utils/src/nft.ts
+++ b/packages/ens-utils/src/nft.ts
@@ -3,60 +3,64 @@ import { buildChainId } from "./chain";
import { ContractRef, buildContractRef } from "./contract";
export interface TokenId {
- /**
- * Token ID of an NFT.
- * Always a non-negative integer.
- */
- tokenId: bigint;
-};
+ /**
+ * Token ID of an NFT.
+ * Always a non-negative integer.
+ */
+ tokenId: bigint;
+}
-const MAX_UINT256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935n;
+const MAX_UINT256 =
+ 115792089237316195423570985008687907853269984665640564039457584007913129639935n;
/**
* Builds a TokenId object.
* @param maybeTokenId the token ID of an NFT.
* @returns a TokenId object.
*/
-export const buildTokenId = (
- maybeTokenId: bigint | string
-): TokenId => {
-
- let tokenId: bigint;
-
- if (typeof maybeTokenId === "string") {
- try {
- tokenId = BigInt(maybeTokenId);
- } catch (e) {
- throw new Error(`Invalid token ID: ${maybeTokenId}. All token ID values must be integers.`);
- }
- } else {
- tokenId = maybeTokenId;
- }
-
- if (tokenId < 0) {
- throw new Error(`Invalid token ID: ${maybeTokenId}. All token ID values must be non-negative.`);
- }
-
- if (tokenId > MAX_UINT256) {
- throw new Error(`Invalid token ID: ${maybeTokenId}. All token ID values must be representable as a uint256 value.`);
+export const buildTokenId = (maybeTokenId: bigint | string): TokenId => {
+ let tokenId: bigint;
+
+ if (typeof maybeTokenId === "string") {
+ try {
+ tokenId = BigInt(maybeTokenId);
+ } catch (e) {
+ throw new Error(
+ `Invalid token ID: ${maybeTokenId}. All token ID values must be integers.`,
+ );
}
-
- return {
- tokenId
- };
-}
+ } else {
+ tokenId = maybeTokenId;
+ }
+
+ if (tokenId < 0) {
+ throw new Error(
+ `Invalid token ID: ${maybeTokenId}. All token ID values must be non-negative.`,
+ );
+ }
+
+ if (tokenId > MAX_UINT256) {
+ throw new Error(
+ `Invalid token ID: ${maybeTokenId}. All token ID values must be representable as a uint256 value.`,
+ );
+ }
+
+ return {
+ tokenId,
+ };
+};
export interface NFTRef {
- /**
- * Contract of the NFT.
- */
- contract: ContractRef;
-
- /**
- * Reference to the token of the NFT within the related contract.
- */
- token: TokenId;
-};
+ /**
+ * Contract of the NFT.
+ */
+ contract: ContractRef;
+
+ /**
+ * Reference to the token of the NFT within the related contract.
+ */
+ token: TokenId;
+}
/**
* Builds a NFTRef object.
@@ -64,26 +68,20 @@ export interface NFTRef {
* @param token the token ID of the NFT within the specified contract.
* @returns a NFTRef object.
*/
-export const buildNFTRef = (
- contract: ContractRef,
- token: TokenId
-): NFTRef => {
-
- return {
- contract,
- token
- };
-}
+export const buildNFTRef = (contract: ContractRef, token: TokenId): NFTRef => {
+ return {
+ contract,
+ token,
+ };
+};
/**
* Convert a NFTRef to a string.
* @param nft: NFTRef - The NFTRef to convert.
* @returns string - The converted string.
*/
-export const convertNFTRefToString = (
- nft: NFTRef
- ): string => {
- return `${nft.contract.chain.chainId}:${nft.contract.address.address}:${nft.token.tokenId}`;
+export const convertNFTRefToString = (nft: NFTRef): string => {
+ return `${nft.contract.chain.chainId}:${nft.contract.address.address}:${nft.token.tokenId}`;
};
/**
@@ -91,19 +89,17 @@ export const convertNFTRefToString = (
* @param maybeNFT: string - The string to parse.
* @returns NFTRef - The NFTRef object for the parsed string.
*/
-export const buildNFTReferenceFromString = (
- maybeNFT: string
- ): NFTRef => {
- const parts = maybeNFT.split(":");
+export const buildNFTReferenceFromString = (maybeNFT: string): NFTRef => {
+ const parts = maybeNFT.split(":");
- if (parts.length !== 3) {
- throw new Error(`Cannot convert: "${maybeNFT}" to NFTRef`);
- }
+ if (parts.length !== 3) {
+ throw new Error(`Cannot convert: "${maybeNFT}" to NFTRef`);
+ }
- const chainId = buildChainId(parts[0]);
- const contractAddress = buildAddress(parts[1]);
- const contract = buildContractRef(chainId, contractAddress);
- const tokenId = buildTokenId(parts[2]);
+ const chainId = buildChainId(parts[0]);
+ const contractAddress = buildAddress(parts[1]);
+ const contract = buildContractRef(chainId, contractAddress);
+ const tokenId = buildTokenId(parts[2]);
- return buildNFTRef(contract, tokenId);
-}
\ No newline at end of file
+ return buildNFTRef(contract, tokenId);
+};
diff --git a/packages/ens-utils/src/number.test.ts b/packages/ens-utils/src/number.test.ts
index 5fb312400..cb1cec91d 100644
--- a/packages/ens-utils/src/number.test.ts
+++ b/packages/ens-utils/src/number.test.ts
@@ -41,14 +41,14 @@ describe("decimalToBigInt() function", () => {
it("Correctly converts positive decimals to BigInt", () => {
expect(decimalToBigInt(new Decimal("123.456"))).toBe(123n);
expect(decimalToBigInt(new Decimal("9007199254740991.999"))).toBe(
- 9007199254740992n
+ 9007199254740992n,
);
});
it("Correctly converts negative decimals to BigInt", () => {
expect(decimalToBigInt(new Decimal("-456.789"))).toBe(-457n); // Rounded down
expect(decimalToBigInt(new Decimal("-9007199254740991.999"))).toBe(
- -9007199254740992n
+ -9007199254740992n,
); // Rounded down
});
@@ -66,7 +66,7 @@ describe("decimalToBigInt() function", () => {
it("Correctly handles decimals with a large number of decimal places", () => {
expect(
- decimalToBigInt(new Decimal("123.456789012345678901234567890"))
+ decimalToBigInt(new Decimal("123.456789012345678901234567890")),
).toBe(123n);
});
@@ -81,7 +81,7 @@ describe("decimalToBigInt() function", () => {
it("Correctly throws an error for invalid Decimal input", () => {
// Assuming your Decimal library throws an error for invalid input
expect(() => decimalToBigInt(new Decimal("abc"))).toThrowError(
- "[DecimalError] Invalid argument: abc"
+ "[DecimalError] Invalid argument: abc",
);
});
});
@@ -93,13 +93,13 @@ describe("stringToBigInt() function", () => {
it("Correctly converts a large positive integer string", () => {
expect(stringToBigInt("123456789012345678901234567890")).toBe(
- 123456789012345678901234567890n
+ 123456789012345678901234567890n,
);
});
it("Correctly converts a large negative integer string", () => {
expect(stringToBigInt("-123456789012345678901234567890")).toBe(
- -123456789012345678901234567890n
+ -123456789012345678901234567890n,
);
});
@@ -113,25 +113,25 @@ describe("stringToBigInt() function", () => {
it("Correctly throws an error for non-numeric strings", () => {
expect(() => stringToBigInt("abc")).toThrowError(
- "Cannot convert string: abc to BigInt"
+ "Cannot convert string: abc to BigInt",
);
});
it("Correctly throws an error for strings with non-numeric characters and numeric part", () => {
expect(() => stringToBigInt("123abc")).toThrowError(
- "Cannot convert string: 123abc to BigInt"
+ "Cannot convert string: 123abc to BigInt",
);
});
it("Correctly throws an error for a string with special characters", () => {
expect(() => stringToBigInt("@#$%^")).toThrowError(
- "Cannot convert string: @#$%^ to BigInt"
+ "Cannot convert string: @#$%^ to BigInt",
);
});
it("Correctly throws an error for a string representing a floating-point number", () => {
expect(() => stringToBigInt("123.45")).toThrowError(
- "Cannot convert string: 123.45 to BigInt"
+ "Cannot convert string: 123.45 to BigInt",
);
});
@@ -141,7 +141,7 @@ describe("stringToBigInt() function", () => {
it('Correctly throws an error for a string starting with "0x" but not a valid hexadecimal number', () => {
expect(() => stringToBigInt("0xinvalid")).toThrowError(
- "Cannot convert string: 0xinvalid to BigInt"
+ "Cannot convert string: 0xinvalid to BigInt",
);
});
});
@@ -177,25 +177,25 @@ describe("numberToBigInt() function", () => {
it("Correctly handles positive infinity by throwing an error", () => {
expect(() => numberToBigInt(Number.POSITIVE_INFINITY)).toThrowError(
- "Cannot convert number: Infinity to BigInt"
+ "Cannot convert number: Infinity to BigInt",
);
});
it("Correctly handles negative infinity by throwing an error", () => {
expect(() => numberToBigInt(Number.NEGATIVE_INFINITY)).toThrowError(
- "Cannot convert number: -Infinity to BigInt"
+ "Cannot convert number: -Infinity to BigInt",
);
});
it("Correctly handles NaN by throwing an error", () => {
expect(() => numberToBigInt(NaN)).toThrowError(
- "Cannot convert number: NaN to BigInt"
+ "Cannot convert number: NaN to BigInt",
);
});
it("Correctly throws an error for non-numeric input", () => {
expect(() => numberToBigInt("abc" as any)).toThrowError(
- "Cannot convert number: abc to BigInt"
+ "Cannot convert number: abc to BigInt",
);
});
});
diff --git a/packages/ens-utils/src/number.ts b/packages/ens-utils/src/number.ts
index a3ea47f8e..e6efab4f7 100644
--- a/packages/ens-utils/src/number.ts
+++ b/packages/ens-utils/src/number.ts
@@ -10,7 +10,7 @@ export const stringToBigInt = (stringValue: string): bigint => {
export const decimalToBigInt = (decimalValue: Decimal): bigint => {
return numberToBigInt(
- Number(decimalValue.toFixed(0, Decimal.ROUND_HALF_DOWN))
+ Number(decimalValue.toFixed(0, Decimal.ROUND_HALF_DOWN)),
);
};
@@ -49,7 +49,7 @@ export const bigIntToNumber = (bigIntValue: bigint): number => {
export const approxScaleBigInt = (
bigIntValue: bigint,
scaleFactor: number,
- digitsOfPrecision: bigint
+ digitsOfPrecision: bigint,
): bigint => {
if (digitsOfPrecision < 0n)
throw Error("digitsOfPrecision must be non-negative");
@@ -72,7 +72,7 @@ export const approxScaleBigInt = (
// the conversion to BigInt here will implicitly cause inflatedScaleFactor to
// lose any digits of precision beyond digitsOfPrecision
const inflatedScaleFactorBigInt = BigInt(
- Math.round(inflatedScaleFactorNumber)
+ Math.round(inflatedScaleFactorNumber),
);
const inflatedResult = bigIntValue * inflatedScaleFactorBigInt;
diff --git a/packages/ens-utils/src/price.test.ts b/packages/ens-utils/src/price.test.ts
index 1f3e3ad15..9e0f992fb 100644
--- a/packages/ens-utils/src/price.test.ts
+++ b/packages/ens-utils/src/price.test.ts
@@ -1,48 +1,55 @@
import { describe, it, expect } from "vitest";
-import { Price, buildPrice, convertCurrencyWithRates, formattedPrice } from "./price";
+import {
+ Price,
+ buildPrice,
+ convertCurrencyWithRates,
+ formattedPrice,
+} from "./price";
import { Currency, PriceCurrencyFormat } from "./currency";
describe("buildPrice() function", () => {
-
it("Build from string values", () => {
- const value = "100";
- const currency = "USD";
-
- const result = buildPrice(value, currency);
-
- expect(result).toStrictEqual({
- value: 100n,
- currency: Currency.Usd,
- });
- });
+ const value = "100";
+ const currency = "USD";
- it("Build from non-string values", () => {
- const value = 100n;
- const currency = Currency.Usd;
+ const result = buildPrice(value, currency);
- const result = buildPrice(value, currency);
-
- expect(result).toStrictEqual({
- value: 100n,
- currency: Currency.Usd,
- });
+ expect(result).toStrictEqual({
+ value: 100n,
+ currency: Currency.Usd,
});
+ });
- it("Invalid value", () => {
- const value = "abc";
- const currency = "USD";
-
- expect(() => buildPrice(value, currency)).toThrow(`Cannot convert string: ${value} to BigInt`);
- });
+ it("Build from non-string values", () => {
+ const value = 100n;
+ const currency = Currency.Usd;
- it("Invalid currency", () => {
- const value = "100";
- const currency = "invalid";
-
- expect(() => buildPrice(value, currency)).toThrow(`Cannot convert: "${currency}" to a recognized Currency`);
+ const result = buildPrice(value, currency);
+
+ expect(result).toStrictEqual({
+ value: 100n,
+ currency: Currency.Usd,
});
+ });
+
+ it("Invalid value", () => {
+ const value = "abc";
+ const currency = "USD";
+ expect(() => buildPrice(value, currency)).toThrow(
+ `Cannot convert string: ${value} to BigInt`,
+ );
+ });
+
+ it("Invalid currency", () => {
+ const value = "100";
+ const currency = "invalid";
+
+ expect(() => buildPrice(value, currency)).toThrow(
+ `Cannot convert: "${currency}" to a recognized Currency`,
+ );
+ });
});
enum CurrencyTestScenario {
@@ -272,14 +279,14 @@ const exchangeRatesMock = {
const runCurrencyTestsForScenario = (
scenario: CurrencyTestScenario,
- currency: Currency
+ currency: Currency,
) => {
const test = currencyTestInputs[scenario][currency];
const exchangedPrice = convertCurrencyWithRates(
test.fromPrice,
test.toCurrency,
- exchangeRatesMock
+ exchangeRatesMock,
);
const resFormatted = formattedPrice({
@@ -296,7 +303,7 @@ describe("Currencies underflow displaying", () => {
it("GAS - Underflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.UNDERFLOW,
- Currency.Gas
+ Currency.Gas,
);
// console.log("GAS Underflow is ", result);
@@ -306,7 +313,7 @@ describe("Currencies underflow displaying", () => {
it("USD - Underflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.UNDERFLOW,
- Currency.Usd
+ Currency.Usd,
);
// console.log("USD Underflow is ", result);
@@ -316,7 +323,7 @@ describe("Currencies underflow displaying", () => {
it("ETH - Underflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.UNDERFLOW,
- Currency.Eth
+ Currency.Eth,
);
// console.log("ETH Underflow is ", result);
@@ -326,7 +333,7 @@ describe("Currencies underflow displaying", () => {
it("WETH - Underflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.UNDERFLOW,
- Currency.Weth
+ Currency.Weth,
);
// console.log("WETH Underflow is ", result);
@@ -336,7 +343,7 @@ describe("Currencies underflow displaying", () => {
it("DAI - Underflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.UNDERFLOW,
- Currency.Dai
+ Currency.Dai,
);
// console.log("DAI Underflow is ", result);
@@ -346,7 +353,7 @@ describe("Currencies underflow displaying", () => {
it("USDC - Underflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.UNDERFLOW,
- Currency.Usdc
+ Currency.Usdc,
);
// console.log("USDC Underflow is ", result);
@@ -359,7 +366,7 @@ describe("Currencies min value displaying", () => {
it("USD - Min", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.MIN,
- Currency.Usd
+ Currency.Usd,
);
// console.log("USD Min is ", result);
@@ -369,7 +376,7 @@ describe("Currencies min value displaying", () => {
it("ETH - Min", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.MIN,
- Currency.Eth
+ Currency.Eth,
);
// console.log("ETH Min is ", result);
@@ -379,7 +386,7 @@ describe("Currencies min value displaying", () => {
it("WETH - Min", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.MIN,
- Currency.Weth
+ Currency.Weth,
);
// console.log("WETH Min is ", result);
@@ -389,7 +396,7 @@ describe("Currencies min value displaying", () => {
it("DAI - Min", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.MIN,
- Currency.Dai
+ Currency.Dai,
);
// console.log("DAI Min is ", result);
@@ -399,7 +406,7 @@ describe("Currencies min value displaying", () => {
it("USDC - Min", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.MIN,
- Currency.Usdc
+ Currency.Usdc,
);
// console.log("USDC Min is ", result);
@@ -412,7 +419,7 @@ describe("Currencies regular values displaying", () => {
it("USD - Regular", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.REGULAR,
- Currency.Usd
+ Currency.Usd,
);
// console.log("USD Regular is ", result);
@@ -422,7 +429,7 @@ describe("Currencies regular values displaying", () => {
it("ETH - Regular", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.REGULAR,
- Currency.Eth
+ Currency.Eth,
);
// console.log("ETH Regular is ", result);
@@ -432,7 +439,7 @@ describe("Currencies regular values displaying", () => {
it("WETH - Regular", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.REGULAR,
- Currency.Weth
+ Currency.Weth,
);
// console.log("WETH Regular is ", result);
@@ -442,7 +449,7 @@ describe("Currencies regular values displaying", () => {
it("DAI - Regular", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.REGULAR,
- Currency.Dai
+ Currency.Dai,
);
// console.log("DAI Regular is ", result);
@@ -452,7 +459,7 @@ describe("Currencies regular values displaying", () => {
it("USDC - Regular", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.REGULAR,
- Currency.Usdc
+ Currency.Usdc,
);
// console.log("USDC Regular is ", result);
@@ -465,7 +472,7 @@ describe("Currencies max values displaying", () => {
it("GAS - Max", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.MAX,
- Currency.Gas
+ Currency.Gas,
);
// console.log("GAS Max is ", result);
@@ -475,7 +482,7 @@ describe("Currencies max values displaying", () => {
it("USD - Max", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.MAX,
- Currency.Usd
+ Currency.Usd,
);
// console.log("USD Max is ", result);
@@ -492,7 +499,7 @@ describe("Currencies max values displaying", () => {
it("USDC - Max", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.MAX,
- Currency.Usdc
+ Currency.Usdc,
);
// console.log("USDC Max is ", result);
@@ -505,7 +512,7 @@ describe("Currencies overflow values displaying", () => {
it("GAS - Overflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.OVERFLOW,
- Currency.Gas
+ Currency.Gas,
);
// console.log("GAS Overflow is ", result);
@@ -515,7 +522,7 @@ describe("Currencies overflow values displaying", () => {
it("USD - Overflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.OVERFLOW,
- Currency.Usd
+ Currency.Usd,
);
// console.log("USD Overflow is ", result);
@@ -525,7 +532,7 @@ describe("Currencies overflow values displaying", () => {
it("ETH - Overflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.OVERFLOW,
- Currency.Eth
+ Currency.Eth,
);
// console.log("ETH Overflow is ", result);
@@ -535,7 +542,7 @@ describe("Currencies overflow values displaying", () => {
it("WETH - Overflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.OVERFLOW,
- Currency.Weth
+ Currency.Weth,
);
// console.log("WETH Overflow is ", result);
@@ -545,7 +552,7 @@ describe("Currencies overflow values displaying", () => {
it("DAI - Overflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.OVERFLOW,
- Currency.Dai
+ Currency.Dai,
);
// console.log("DAI Overflow is ", result);
@@ -555,7 +562,7 @@ describe("Currencies overflow values displaying", () => {
it("USDC - Overflow", () => {
const result = runCurrencyTestsForScenario(
CurrencyTestScenario.OVERFLOW,
- Currency.Usdc
+ Currency.Usdc,
);
// console.log("USDC Overflow is ", result);
diff --git a/packages/ens-utils/src/price.ts b/packages/ens-utils/src/price.ts
index 75ac307d2..62642e4e5 100644
--- a/packages/ens-utils/src/price.ts
+++ b/packages/ens-utils/src/price.ts
@@ -1,8 +1,11 @@
-import { Currency, PriceCurrencyFormat, parseStringToCurrency } from "./currency";
+import {
+ Currency,
+ PriceCurrencyFormat,
+ parseStringToCurrency,
+} from "./currency";
import { approxScaleBigInt, stringToBigInt } from "./number";
export interface Price {
-
// TODO: consider adding a constraint where value is never negative
/**
* The value of the price. This is a BigInt to avoid floating point math issues when working with prices.
@@ -23,19 +26,21 @@ export interface ExchangeRates extends Partial> {}
/**
* Builds a Price object.
* @param value the value of the price. This is a BigInt to avoid floating point math issues when working with prices.
- * For example, a price of 1.23 USD would be represented as 123n with a currency of USD.
- * Note that the value is always in the smallest unit of the currency (e.g. cents for USD, wei for ETH).
- * See the CurrencyConfig for the related currency for the number of decimals to use when converting the value to a human-readable format.
- * @param currency
- * @returns
+ * For example, a price of 1.23 USD would be represented as 123n with a currency of USD.
+ * Note that the value is always in the smallest unit of the currency (e.g. cents for USD, wei for ETH).
+ * See the CurrencyConfig for the related currency for the number of decimals to use when converting the value to a human-readable format.
+ * @param currency
+ * @returns
*/
-export const buildPrice = (value: bigint | string, currency: Currency | string): Price => {
-
- let priceValue : bigint;
- let priceCurrency : Currency;
+export const buildPrice = (
+ value: bigint | string,
+ currency: Currency | string,
+): Price => {
+ let priceValue: bigint;
+ let priceCurrency: Currency;
if (typeof value === "string") {
- priceValue = stringToBigInt(value)
+ priceValue = stringToBigInt(value);
} else {
priceValue = value;
}
@@ -47,7 +52,7 @@ export const buildPrice = (value: bigint | string, currency: Currency | string):
}
return { value: priceValue, currency: priceCurrency };
-}
+};
export const priceAsNumber = (price: Price): number => {
return (
@@ -61,12 +66,12 @@ export const numberAsPrice = (number: number, currency: Currency): Price => {
// Fix the number's displayed decimals (e.g. from 0.00001 to 0.00001)
const numberWithCorrectCurrencyDecimals = Number(
- number.toFixed(currencyDecimals)
+ number.toFixed(currencyDecimals),
);
// Remove the decimals from the number (e.g. from 0.00001 to 1)
const numberWithoutDecimals = Number(
- numberWithCorrectCurrencyDecimals * 10 ** currencyDecimals
+ numberWithCorrectCurrencyDecimals * 10 ** currencyDecimals,
).toFixed(0);
/*
@@ -102,7 +107,7 @@ export const addPrices = (prices: Array): Price => {
export const subtractPrices = (price1: Price, price2: Price): Price => {
if (price1.currency !== price2.currency) {
throw new Error(
- `Cannot subtract price of currency ${price1.currency} to price of currency ${price2.currency}`
+ `Cannot subtract price of currency ${price1.currency} to price of currency ${price2.currency}`,
);
} else {
return {
@@ -150,7 +155,7 @@ export const formattedPrice = ({
) {
// If formatted number is 0.0 but real 'value' is not 0, then we show the Underflow price
formattedAmount = String(
- PriceCurrencyFormat[price.currency].MinDisplayValue
+ PriceCurrencyFormat[price.currency].MinDisplayValue,
);
} else if (wouldDisplayAsZero && price.value == 0n) {
// But if the real 'value' is really 0, then we show 0.00 (in the correct number of Display Decimals)
@@ -158,7 +163,7 @@ export const formattedPrice = ({
formattedAmount = prefix.padEnd(
Number(PriceCurrencyFormat[price.currency].DisplayDecimals) +
prefix.length,
- "0"
+ "0",
);
}
@@ -168,10 +173,10 @@ export const formattedPrice = ({
formattedAmount = displayNumber.toLocaleString("en-US", {
minimumFractionDigits: Number(
- PriceCurrencyFormat[price.currency].DisplayDecimals
+ PriceCurrencyFormat[price.currency].DisplayDecimals,
),
maximumFractionDigits: Number(
- PriceCurrencyFormat[price.currency].DisplayDecimals
+ PriceCurrencyFormat[price.currency].DisplayDecimals,
),
});
@@ -197,7 +202,7 @@ export const formattedPrice = ({
export const approxScalePrice = (
price: Price,
scaleFactor: number,
- digitsOfPrecision = 20n
+ digitsOfPrecision = 20n,
): Price => {
return {
value: approxScaleBigInt(price.value, scaleFactor, digitsOfPrecision),
@@ -208,13 +213,13 @@ export const approxScalePrice = (
export const convertCurrencyWithRates = (
fromPrice: Price,
toCurrency: Currency,
- exchangeRates: ExchangeRates
+ exchangeRates: ExchangeRates,
): Price => {
if (typeof exchangeRates[toCurrency] === "undefined") {
throw new Error(`Exchange rate for currency ${toCurrency} not found`);
} else if (typeof exchangeRates[fromPrice.currency] === "undefined") {
throw new Error(
- `Exchange rate for currency ${fromPrice.currency} not found`
+ `Exchange rate for currency ${fromPrice.currency} not found`,
);
}
diff --git a/packages/ens-utils/src/time.ts b/packages/ens-utils/src/time.ts
index 064a51b0f..f53e786cf 100644
--- a/packages/ens-utils/src/time.ts
+++ b/packages/ens-utils/src/time.ts
@@ -321,7 +321,7 @@ const DEFAULT_LOCALE = "en-US";
/**
* Formats a `Timestamp` as `string`.
- *
+ *
* @param {Timestamp} timestamp - The `Timestamp` to format.
* @param {FormatTimestampOptions} [options] - Optional. The options for how to
* format the `Timestamp`.
diff --git a/packages/ens-utils/src/transaction.test.ts b/packages/ens-utils/src/transaction.test.ts
index 30bf7e9cb..4ca82f289 100644
--- a/packages/ens-utils/src/transaction.test.ts
+++ b/packages/ens-utils/src/transaction.test.ts
@@ -2,29 +2,32 @@ import { describe, it, expect } from "vitest";
import { buildTxnHash } from "./transaction";
describe("buildTxnHash() function", () => {
-
- it("doesn't begin with 0x", () => {
- const hash = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
+ it("doesn't begin with 0x", () => {
+ const hash =
+ "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
- expect(() => buildTxnHash(hash)).toThrow();
- });
+ expect(() => buildTxnHash(hash)).toThrow();
+ });
- it("too few digits", () => {
- const hash = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcde";
+ it("too few digits", () => {
+ const hash =
+ "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcde";
- expect(() => buildTxnHash(hash)).toThrow();
- });
+ expect(() => buildTxnHash(hash)).toThrow();
+ });
- it("too many digits", () => {
- const hash = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1";
+ it("too many digits", () => {
+ const hash =
+ "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1";
- expect(() => buildTxnHash(hash)).toThrow();
- });
+ expect(() => buildTxnHash(hash)).toThrow();
+ });
- it("valid hash", () => {
- const hash = "0x1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF";
+ it("valid hash", () => {
+ const hash =
+ "0x1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF";
- const result = buildTxnHash(hash);
- expect(result.hash).toStrictEqual(hash.toLowerCase());
- });
-});
\ No newline at end of file
+ const result = buildTxnHash(hash);
+ expect(result.hash).toStrictEqual(hash.toLowerCase());
+ });
+});
diff --git a/packages/ens-utils/src/transaction.ts b/packages/ens-utils/src/transaction.ts
index 8400bde53..168d718e2 100644
--- a/packages/ens-utils/src/transaction.ts
+++ b/packages/ens-utils/src/transaction.ts
@@ -1,21 +1,20 @@
export interface TxnHash {
- hash: `0x${string}`;
+ hash: `0x${string}`;
}
const regex = /^0x[0-9a-fA-F]{64}$/;
const isTxnHash = (maybeTxnHash: string): boolean => {
- return regex.test(maybeTxnHash);
-}
+ return regex.test(maybeTxnHash);
+};
export const buildTxnHash = (maybeTxnHash: string): TxnHash => {
+ if (!isTxnHash(maybeTxnHash))
+ throw new Error(`Invalid transaction hash: ${maybeTxnHash}`);
- if (!isTxnHash(maybeTxnHash))
- throw new Error(`Invalid transaction hash: ${maybeTxnHash}`);
-
- const normalizedHash = maybeTxnHash.toLowerCase() as `0x${string}`;
+ const normalizedHash = maybeTxnHash.toLowerCase() as `0x${string}`;
- return {
- hash: normalizedHash
- };
-}
\ No newline at end of file
+ return {
+ hash: normalizedHash,
+ };
+};
diff --git a/packages/ens-utils/vitest.config.ts b/packages/ens-utils/vitest.config.ts
index 7d29ae9fe..616297205 100644
--- a/packages/ens-utils/vitest.config.ts
+++ b/packages/ens-utils/vitest.config.ts
@@ -5,4 +5,4 @@ export default defineConfig({
globals: true,
environment: "node",
},
-} as UserConfig);
\ No newline at end of file
+} as UserConfig);
diff --git a/packages/nameai-sdk/README.md b/packages/nameai-sdk/README.md
index 0fd4b6435..60ecf604b 100644
--- a/packages/nameai-sdk/README.md
+++ b/packages/nameai-sdk/README.md
@@ -15,6 +15,7 @@ This SDK provides a TypeScript interface to the NameAI API. Developers intereste
## Features
Additional features provided by NameAI on top of NameGuard:
+
- **Natural Language Processing**: Evaluate how well ENS names represent meaningful words or phrases
- **Tokenization**: Break down names into meaningful word components with probability scoring
- **Purity Scoring**: Assess the cleanliness and quality of ENS names
@@ -50,32 +51,32 @@ const report = await nameai.inspectName("vitalik.eth");
nameai: {
// Quality score (0.0 to 1.0) for the first label
purity_score: 0.29,
-
+
// Ranking score (0.0 to 1.0) for the first label
sort_score: 0.35,
-
+
analysis: { // undefined for uninspected names
// The normalization status of the name (normalized, unnormalized, or unknown)
status: "normalized",
-
+
// Details about the inspected name component
inspection: {
label: "vitalik",
// ... other inspection details
},
-
+
// Text meaningfulness (0.0 to 1.0)
probability: 0.95,
-
+
// Natural log of probability (≤ 0.0)
log_probability: -0.05,
-
+
// Minimum words in valid tokenizations
word_count: 1,
-
+
// Recommended word breakdown (may be undefined)
top_tokenization: ["vitalik"],
-
+
// All possible tokenizations (up to 1000)
tokenizations: [
{
@@ -95,7 +96,9 @@ const report = await nameai.inspectName("vitalik.eth");
The SDK provides detailed tokenization inspection:
```ts
-const { nameai: { analysis } } = await nameai.inspectName("cryptowallet.eth");
+const {
+ nameai: { analysis },
+} = await nameai.inspectName("cryptowallet.eth");
console.log(analysis.top_tokenization); // ["crypto", "wallet"]
console.log(analysis.tokenizations); // Array of possible tokenizations with probabilities
@@ -110,7 +113,7 @@ import { createClient } from "@namehash/nameai";
const nameai = createClient({
nameaiEndpoint: "...",
- network: "sepolia"
+ network: "sepolia",
});
```
diff --git a/packages/nameai-sdk/src/labelinspector.ts b/packages/nameai-sdk/src/labelinspector.ts
index 58433a308..146372336 100644
--- a/packages/nameai-sdk/src/labelinspector.ts
+++ b/packages/nameai-sdk/src/labelinspector.ts
@@ -1,6 +1,5 @@
import { LabelStatus } from "./index";
-
export interface InspectorGraphemeResult {
/** The grapheme string */
value: string;
@@ -43,7 +42,7 @@ export interface InspectorGraphemeResult {
* - null if the grapheme is not assigned to any version
*/
unicode_version: string | null;
-}// Character and grapheme types can potentially evolve independently.
+} // Character and grapheme types can potentially evolve independently.
export enum CharacterType {
/** A lowercase letter [a-z] */
@@ -74,7 +73,7 @@ export enum CharacterType {
Invisible = "invisible",
/** Any character that doesn't match other classifications */
- Special = "special"
+ Special = "special",
}
export enum GraphemeType {
/** Only lowercase letters [a-z] */
@@ -106,7 +105,7 @@ export enum GraphemeType {
/** Either a grapheme that doesn't match other classifications, or a multi-character
* grapheme containing characters of different types */
- Special = "special"
+ Special = "special",
}
export interface InspectorCharResult {
/** Character being inspected */
@@ -138,7 +137,8 @@ export interface InspectorCharResult {
unicode_version: string | null;
}
-export interface InspectorConfusableGraphemeResult extends InspectorGraphemeResult { }
+export interface InspectorConfusableGraphemeResult
+ extends InspectorGraphemeResult {}
export interface InspectorConfusableMultiGraphemeResult {
/** The confusable string */
value: string;
@@ -146,9 +146,11 @@ export interface InspectorConfusableMultiGraphemeResult {
/** List of characters in the confusable */
chars: InspectorCharResult[];
}
-export type InspectorConfusableResult = InspectorConfusableGraphemeResult |
- InspectorConfusableMultiGraphemeResult;
-export interface InspectorGraphemeWithConfusablesResult extends InspectorGraphemeResult {
+export type InspectorConfusableResult =
+ | InspectorConfusableGraphemeResult
+ | InspectorConfusableMultiGraphemeResult;
+export interface InspectorGraphemeWithConfusablesResult
+ extends InspectorGraphemeResult {
/** Canonical form of confusable grapheme.
* - may be null if canonical form is not known/does not exist
* - may be null when simple_confusables is enabled and the canonical is not single-grapheme or not normalized
@@ -175,7 +177,7 @@ export enum PunycodeCompatibility {
InvalidLabelExtension = "INVALID_LABEL_EXTENSION",
/** The Punycode encoded label exceeds 63 characters */
- LabelTooLong = "LABEL_TOO_LONG"
+ LabelTooLong = "LABEL_TOO_LONG",
}
export interface InspectorResultBase {
/** Input label */
@@ -286,5 +288,6 @@ export interface InspectorResultUnnormalized extends InspectorResultBase {
*/
suggested_replacement: InspectorCharResult[] | null;
}
-export type InspectorResult = InspectorResultNormalized | InspectorResultUnnormalized;
-
+export type InspectorResult =
+ | InspectorResultNormalized
+ | InspectorResultUnnormalized;
diff --git a/packages/namegraph-sdk/README.md b/packages/namegraph-sdk/README.md
index 36af43122..e39f96006 100644
--- a/packages/namegraph-sdk/README.md
+++ b/packages/namegraph-sdk/README.md
@@ -9,7 +9,6 @@ A TypeScript SDK for interacting with the NameGraph APIs, providing access to th
- **Smart Sampling**: Sample and fetch top members from collections
- **Advanced Search**: Search collections by string or by collection ID
-
## Installation
```bash
@@ -67,7 +66,10 @@ const members = await client.sampleCollectionMembers("collection_id");
```typescript
// with pagination
-const members = await client.fetchCollectionMembers("collection_id", {offset: 0, limit: 20});
+const members = await client.fetchCollectionMembers("collection_id", {
+ offset: 0,
+ limit: 20,
+});
// Top members
const topMembers = await client.fetchTopCollectionMembers("collection_id");
@@ -76,7 +78,9 @@ const topMembers = await client.fetchTopCollectionMembers("collection_id");
#### Generate Scrambled Variations of Collection Tokens
```typescript
-const scrambled = await client.scrambleCollectionTokens('collection_id', {seed: 42});
+const scrambled = await client.scrambleCollectionTokens("collection_id", {
+ seed: 42,
+});
```
#### Find Collections
@@ -103,6 +107,7 @@ const memberCount = await client.countCollectionsByMember("zeus");
```
#### Get Collection by ID
+
```typescript
const collection = await client.getCollectionById("collection_id");
```
@@ -158,12 +163,14 @@ The SDK supports various grouping categories for name suggestions:
The SDK supports three modes for processing requests:
- Instant Mode (`instant`):
+
- Fastest response time
- More basic name generations
- Some advanced generators like W2VGenerator are disabled (weight multiplier = 0)
- Often used for real-time suggestions
- Domain Detail Mode (`domain_detail`):
+
- Intermediate between instant and full
- More comprehensive than instant, but still optimized for performance
- Some generators have reduced weights compared to full mode
@@ -176,7 +183,6 @@ The SDK supports three modes for processing requests:
- Accesses advanced generators like `Wikipedia2VGenerator` and `W2VGenerator`
- Takes longer to process, but provides the most diverse results
-
## Contact Us
Visit our [website](https://namehashlabs.org/) to get in contact.
diff --git a/packages/namegraph-sdk/src/index.test.ts b/packages/namegraph-sdk/src/index.test.ts
index 9ded6c4ad..170e23466 100644
--- a/packages/namegraph-sdk/src/index.test.ts
+++ b/packages/namegraph-sdk/src/index.test.ts
@@ -12,13 +12,12 @@ const exampleQuery = "zeus god";
const exampleCollectionId = "3vkCFOZ101p1"; // "Greek mythological figures"
const labelWithDots = "zeus.eth";
-
// No mocking (we should probably mock)
describe("groupedByCategory", () => {
it("should fetch suggestions grouped by category for a label", async () => {
const response = await namegraph.groupedByCategory(exampleLabel);
-
+
expect(response).toBeDefined();
expect(response.categories).toBeDefined();
expect(Array.isArray(response.categories)).toBe(true);
@@ -27,7 +26,7 @@ describe("groupedByCategory", () => {
it("shouldn't reject empty label", async () => {
const response = await namegraph.groupedByCategory("");
-
+
expect(response).toBeDefined();
expect(response.categories).toBeDefined();
expect(Array.isArray(response.categories)).toBe(true);
@@ -42,7 +41,7 @@ describe("groupedByCategory", () => {
describe("suggestionsByCategory", () => {
it("should fetch suggestions with related collections", async () => {
const response = await namegraph.suggestionsByCategory(exampleLabel);
-
+
expect(response).toBeDefined();
expect(response.categories).toBeDefined();
expect(Array.isArray(response.categories)).toBe(true);
@@ -51,56 +50,75 @@ describe("suggestionsByCategory", () => {
it("should respect maxRelatedCollections parameter", async () => {
const maxRelated = 2;
- const response = await namegraph.suggestionsByCategory(exampleLabel, maxRelated);
-
- const relatedCategories = response.categories.filter(c => c.type === NameGraphGroupingCategory.related);
+ const response = await namegraph.suggestionsByCategory(
+ exampleLabel,
+ maxRelated,
+ );
+
+ const relatedCategories = response.categories.filter(
+ (c) => c.type === NameGraphGroupingCategory.related,
+ );
expect(relatedCategories.length).toBeLessThanOrEqual(maxRelated);
});
it("should respect max_labels_per_related_collection parameter", async () => {
const response = await namegraph.suggestionsByCategory(exampleLabel);
- const relatedCategories = response.categories.filter(c => c.type === NameGraphGroupingCategory.related);
- relatedCategories.forEach(c => {
+ const relatedCategories = response.categories.filter(
+ (c) => c.type === NameGraphGroupingCategory.related,
+ );
+ relatedCategories.forEach((c) => {
expect(c.suggestions.length).toBeLessThanOrEqual(10);
});
});
it("should reject label with dots", async () => {
- await expect(namegraph.suggestionsByCategory(labelWithDots)).rejects.toThrow();
+ await expect(
+ namegraph.suggestionsByCategory(labelWithDots),
+ ).rejects.toThrow();
});
it("should throw error for invalid max_suggestion_per_grouping_category", async () => {
- await expect(namegraph.suggestionsByCategory(exampleLabel, undefined, {
- max_suggestion_per_grouping_category: 31 // Above max allowed value of 30
- })).rejects.toThrow();
+ await expect(
+ namegraph.suggestionsByCategory(exampleLabel, undefined, {
+ max_suggestion_per_grouping_category: 31, // Above max allowed value of 30
+ }),
+ ).rejects.toThrow();
});
it("should respect min_suggestion_per_grouping_category parameter", async () => {
const minSuggestions = 2;
- const response = await namegraph.suggestionsByCategory(exampleLabel, undefined, {
- min_suggestion_per_grouping_category: minSuggestions
- });
+ const response = await namegraph.suggestionsByCategory(
+ exampleLabel,
+ undefined,
+ {
+ min_suggestion_per_grouping_category: minSuggestions,
+ },
+ );
- response.categories.forEach(category => {
+ response.categories.forEach((category) => {
if (category.type === NameGraphGroupingCategory.related) {
- expect(category.suggestions.length).toBeGreaterThanOrEqual(minSuggestions);
+ expect(category.suggestions.length).toBeGreaterThanOrEqual(
+ minSuggestions,
+ );
}
});
});
it("should throw error for invalid min_suggestion_per_grouping_category", async () => {
- await expect(namegraph.suggestionsByCategory(exampleLabel, undefined, {
- min_suggestion_per_grouping_category: -1 // Below min allowed value of 0
- })).rejects.toThrow();
+ await expect(
+ namegraph.suggestionsByCategory(exampleLabel, undefined, {
+ min_suggestion_per_grouping_category: -1, // Below min allowed value of 0
+ }),
+ ).rejects.toThrow();
});
});
-
describe("sampleCollectionMembers", () => {
it("should fetch random sample of collection members", async () => {
- const response = await namegraph.sampleCollectionMembers(exampleCollectionId);
-
+ const response =
+ await namegraph.sampleCollectionMembers(exampleCollectionId);
+
expect(response).toBeDefined();
expect(Array.isArray(response)).toBe(true);
expect(response.length).toBeLessThanOrEqual(5); // max_sample_size is 5
@@ -108,36 +126,50 @@ describe("sampleCollectionMembers", () => {
it("should return reproducible results with same seed", async () => {
const seed = 42;
- const sample1 = await namegraph.sampleCollectionMembers(exampleCollectionId, { seed });
- const sample2 = await namegraph.sampleCollectionMembers(exampleCollectionId, { seed });
-
+ const sample1 = await namegraph.sampleCollectionMembers(
+ exampleCollectionId,
+ { seed },
+ );
+ const sample2 = await namegraph.sampleCollectionMembers(
+ exampleCollectionId,
+ { seed },
+ );
+
expect(sample1).toEqual(sample2);
});
it("should respect max_sample_size parameter", async () => {
const maxSampleSize = 3;
- const response = await namegraph.sampleCollectionMembers(exampleCollectionId, {
- max_sample_size: maxSampleSize
- });
+ const response = await namegraph.sampleCollectionMembers(
+ exampleCollectionId,
+ {
+ max_sample_size: maxSampleSize,
+ },
+ );
expect(response.length).toBeLessThanOrEqual(maxSampleSize);
});
it("should reject float max_sample_size parameter", async () => {
- await expect(namegraph.sampleCollectionMembers(exampleCollectionId, {
- max_sample_size: 2.3
- })).rejects.toThrow();
+ await expect(
+ namegraph.sampleCollectionMembers(exampleCollectionId, {
+ max_sample_size: 2.3,
+ }),
+ ).rejects.toThrow();
});
it("should throw error for invalid max_sample_size", async () => {
- await expect(namegraph.sampleCollectionMembers(exampleCollectionId, {
- max_sample_size: 101 // Above max allowed value of 100
- })).rejects.toThrow();
+ await expect(
+ namegraph.sampleCollectionMembers(exampleCollectionId, {
+ max_sample_size: 101, // Above max allowed value of 100
+ }),
+ ).rejects.toThrow();
});
});
describe("fetchTopCollectionMembers", () => {
it("should fetch top members from collection", async () => {
- const response = await namegraph.fetchTopCollectionMembers(exampleCollectionId);
+ const response =
+ await namegraph.fetchTopCollectionMembers(exampleCollectionId);
expect(response).toBeDefined();
expect(response.suggestions).toBeDefined();
@@ -146,16 +178,17 @@ describe("fetchTopCollectionMembers", () => {
});
it("should fetch at most 10 members", async () => {
- const response = await namegraph.fetchTopCollectionMembers(exampleCollectionId);
+ const response =
+ await namegraph.fetchTopCollectionMembers(exampleCollectionId);
expect(response.suggestions.length).toBeLessThanOrEqual(10);
});
});
describe("scrambleCollectionTokens", () => {
-
it("should generate scrambled variations", async () => {
- const response = await namegraph.scrambleCollectionTokens(exampleCollectionId);
-
+ const response =
+ await namegraph.scrambleCollectionTokens(exampleCollectionId);
+
expect(response).toBeDefined();
expect(Array.isArray(response)).toBe(true);
expect(response.length).toBeGreaterThan(0);
@@ -163,43 +196,56 @@ describe("scrambleCollectionTokens", () => {
it("should respect seed parameter for reproducibility", async () => {
const seed = 42;
- const scrambled1 = await namegraph.scrambleCollectionTokens(exampleCollectionId, { seed });
- const scrambled2 = await namegraph.scrambleCollectionTokens(exampleCollectionId, { seed });
-
+ const scrambled1 = await namegraph.scrambleCollectionTokens(
+ exampleCollectionId,
+ { seed },
+ );
+ const scrambled2 = await namegraph.scrambleCollectionTokens(
+ exampleCollectionId,
+ { seed },
+ );
+
expect(scrambled1).toEqual(scrambled2);
});
it("should return at most 10 scrambled suggestions", async () => {
- const response = await namegraph.scrambleCollectionTokens(exampleCollectionId);
+ const response =
+ await namegraph.scrambleCollectionTokens(exampleCollectionId);
expect(response.length).toBeLessThanOrEqual(10);
});
it("should respect max_suggestions parameter", async () => {
const maxSuggestions = 5;
- const response = await namegraph.scrambleCollectionTokens(exampleCollectionId, {
- max_suggestions: maxSuggestions
- });
+ const response = await namegraph.scrambleCollectionTokens(
+ exampleCollectionId,
+ {
+ max_suggestions: maxSuggestions,
+ },
+ );
expect(response.length).toBeLessThanOrEqual(maxSuggestions);
});
it("should reject float max_suggestions parameter", async () => {
- await expect(namegraph.scrambleCollectionTokens(exampleCollectionId, {
- max_suggestions: 2.3
- })).rejects.toThrow();
+ await expect(
+ namegraph.scrambleCollectionTokens(exampleCollectionId, {
+ max_suggestions: 2.3,
+ }),
+ ).rejects.toThrow();
});
it("should throw error for invalid max_suggestions", async () => {
- await expect(namegraph.scrambleCollectionTokens(exampleCollectionId, {
- max_suggestions: -1 // Below min allowed value of 0
- })).rejects.toThrow();
+ await expect(
+ namegraph.scrambleCollectionTokens(exampleCollectionId, {
+ max_suggestions: -1, // Below min allowed value of 0
+ }),
+ ).rejects.toThrow();
});
});
-
describe("findCollectionsByString", () => {
it("should find collections matching query", async () => {
const response = await namegraph.findCollectionsByString(exampleQuery);
-
+
expect(response).toBeDefined();
expect(response.related_collections).toBeDefined();
expect(Array.isArray(response.related_collections)).toBe(true);
@@ -209,58 +255,88 @@ describe("findCollectionsByString", () => {
it("should respect pagination parameters", async () => {
const offset = 2;
const response = await namegraph.findCollectionsByString(exampleQuery);
- const response_with_offset = await namegraph.findCollectionsByString(exampleQuery, {
- offset,
- });
-
+ const response_with_offset = await namegraph.findCollectionsByString(
+ exampleQuery,
+ {
+ offset,
+ },
+ );
+
const first_two_collections = response.related_collections.slice(0, 2);
- expect(response_with_offset.related_collections).not.toContainEqual(first_two_collections[0]);
- expect(response_with_offset.related_collections).not.toContainEqual(first_two_collections[1]);
+ expect(response_with_offset.related_collections).not.toContainEqual(
+ first_two_collections[0],
+ );
+ expect(response_with_offset.related_collections).not.toContainEqual(
+ first_two_collections[1],
+ );
});
-
it("should respect max and min collection size parameters", async () => {
const min_other_collections = 1;
const max_other_collections = 2;
- const response_other = await namegraph.findCollectionsByString(exampleQuery, {
- min_other_collections: min_other_collections,
- max_other_collections: max_other_collections
- });
+ const response_other = await namegraph.findCollectionsByString(
+ exampleQuery,
+ {
+ min_other_collections: min_other_collections,
+ max_other_collections: max_other_collections,
+ },
+ );
- expect(response_other.other_collections.length).toBeGreaterThanOrEqual(min_other_collections);
- expect(response_other.other_collections.length).toBeLessThanOrEqual(max_other_collections);
+ expect(response_other.other_collections.length).toBeGreaterThanOrEqual(
+ min_other_collections,
+ );
+ expect(response_other.other_collections.length).toBeLessThanOrEqual(
+ max_other_collections,
+ );
const max_related_collections = 1;
- const response_related = await namegraph.findCollectionsByString(exampleQuery, {
- max_related_collections: max_related_collections
- });
+ const response_related = await namegraph.findCollectionsByString(
+ exampleQuery,
+ {
+ max_related_collections: max_related_collections,
+ },
+ );
- expect(response_related.related_collections.length).toBeLessThanOrEqual(max_related_collections);
+ expect(response_related.related_collections.length).toBeLessThanOrEqual(
+ max_related_collections,
+ );
const max_total_collections = 3;
- const response_total = await namegraph.findCollectionsByString(exampleQuery, {
- max_total_collections: max_total_collections
- });
-
- expect(response_total.related_collections.length + response_total.other_collections.length).toBeLessThanOrEqual(max_total_collections);
+ const response_total = await namegraph.findCollectionsByString(
+ exampleQuery,
+ {
+ max_total_collections: max_total_collections,
+ },
+ );
+ expect(
+ response_total.related_collections.length +
+ response_total.other_collections.length,
+ ).toBeLessThanOrEqual(max_total_collections);
});
it("should respect max_per_type parameter", async () => {
const maxPerType = 2;
const response = await namegraph.findCollectionsByString(exampleQuery, {
- max_per_type: maxPerType
+ max_per_type: maxPerType,
});
- const allSuggestions = response.related_collections.concat(response.other_collections)
+ const allSuggestions = response.related_collections.concat(
+ response.other_collections,
+ );
- const typeGroups = allSuggestions.reduce((acc: Record, collection) => {
- collection.types.forEach((type: string) => acc[type] = (acc[type] || 0) + 1);
+ const typeGroups = allSuggestions.reduce(
+ (acc: Record, collection) => {
+ collection.types.forEach(
+ (type: string) => (acc[type] = (acc[type] || 0) + 1),
+ );
return acc;
- }, {});
+ },
+ {},
+ );
- Object.values(typeGroups).forEach(count => {
+ Object.values(typeGroups).forEach((count) => {
expect(count).toBeLessThanOrEqual(maxPerType);
});
});
@@ -268,8 +344,9 @@ describe("findCollectionsByString", () => {
describe("fetchCollectionMembers", () => {
it("should fetch members with pagination", async () => {
- const response = await namegraph.fetchCollectionMembers(exampleCollectionId);
-
+ const response =
+ await namegraph.fetchCollectionMembers(exampleCollectionId);
+
expect(response).toBeDefined();
expect(response.suggestions).toBeDefined();
expect(Array.isArray(response.suggestions)).toBe(true);
@@ -277,30 +354,41 @@ describe("fetchCollectionMembers", () => {
it("should respect limit", async () => {
const limit = 5;
- const response = await namegraph.fetchCollectionMembers(exampleCollectionId, {
- limit,
- });
-
+ const response = await namegraph.fetchCollectionMembers(
+ exampleCollectionId,
+ {
+ limit,
+ },
+ );
+
expect(response.suggestions.length).toBeLessThanOrEqual(limit);
});
it("should respect offset", async () => {
const offset = 2;
- const response = await namegraph.fetchCollectionMembers(exampleCollectionId);
- const response_with_offset = await namegraph.fetchCollectionMembers(exampleCollectionId, {
- offset,
- });
+ const response =
+ await namegraph.fetchCollectionMembers(exampleCollectionId);
+ const response_with_offset = await namegraph.fetchCollectionMembers(
+ exampleCollectionId,
+ {
+ offset,
+ },
+ );
const first_two_collections = response.suggestions.slice(0, 2);
- expect(response_with_offset.related_collections).not.toContainEqual(first_two_collections[0]);
- expect(response_with_offset.related_collections).not.toContainEqual(first_two_collections[1]);
+ expect(response_with_offset.related_collections).not.toContainEqual(
+ first_two_collections[0],
+ );
+ expect(response_with_offset.related_collections).not.toContainEqual(
+ first_two_collections[1],
+ );
});
});
describe("countCollectionsByString", () => {
it("should count collections matching query", async () => {
const response = await namegraph.countCollectionsByString(exampleQuery);
-
+
expect(response).toBeDefined();
expect(response.count).toBeDefined();
@@ -320,50 +408,60 @@ describe("countCollectionsByString", () => {
});
});
-
describe("findCollectionsByCollection", () => {
-
it("should find related collections", async () => {
- const response = await namegraph.findCollectionsByCollection(exampleCollectionId);
-
+ const response =
+ await namegraph.findCollectionsByCollection(exampleCollectionId);
+
expect(response).toBeDefined();
expect(response.related_collections).toBeDefined();
expect(Array.isArray(response.related_collections)).toBe(true);
});
it("should respect max_related_collections parameter", async () => {
- const response = await namegraph.findCollectionsByCollection(exampleCollectionId);
+ const response =
+ await namegraph.findCollectionsByCollection(exampleCollectionId);
expect(response.related_collections.length).toBeLessThanOrEqual(3); // max_related_collections is 3
});
it("should respect max_per_type parameter", async () => {
const maxPerType = 2;
- const response = await namegraph.findCollectionsByCollection(exampleCollectionId, {
- max_per_type: maxPerType
- });
+ const response = await namegraph.findCollectionsByCollection(
+ exampleCollectionId,
+ {
+ max_per_type: maxPerType,
+ },
+ );
- const typeGroups = response.other_collections.reduce((acc: Record, collection) => {
- collection.types.forEach((type: string) => acc[type] = (acc[type] || 0) + 1);
- return acc;
- }, {});
+ const typeGroups = response.other_collections.reduce(
+ (acc: Record, collection) => {
+ collection.types.forEach(
+ (type: string) => (acc[type] = (acc[type] || 0) + 1),
+ );
+ return acc;
+ },
+ {},
+ );
- Object.values(typeGroups).forEach(count => {
+ Object.values(typeGroups).forEach((count) => {
expect(count).toBeLessThanOrEqual(maxPerType);
});
});
it("should throw error for negative max_related_collections", async () => {
- await expect(namegraph.findCollectionsByCollection(exampleCollectionId, {
- max_related_collections: -1
- })).rejects.toThrow();
+ await expect(
+ namegraph.findCollectionsByCollection(exampleCollectionId, {
+ max_related_collections: -1,
+ }),
+ ).rejects.toThrow();
});
});
describe("countCollectionsByMember", () => {
it("should count collections containing member", async () => {
const response = await namegraph.countCollectionsByMember(exampleLabel);
-
+
expect(response).toBeDefined();
expect(response.count).toBeDefined();
@@ -375,7 +473,7 @@ describe("countCollectionsByMember", () => {
describe("findCollectionsByMember", () => {
it("should find collections containing member", async () => {
const response = await namegraph.findCollectionsByMember(exampleLabel);
-
+
expect(response).toBeDefined();
expect(response.collections).toBeDefined();
expect(Array.isArray(response.collections)).toBe(true);
@@ -384,40 +482,48 @@ describe("findCollectionsByMember", () => {
it("should respect max_results parameter", async () => {
const maxResults = 2;
const response = await namegraph.findCollectionsByMember(exampleLabel, {
- max_results: maxResults
+ max_results: maxResults,
});
-
+
expect(response.collections.length).toBeLessThanOrEqual(maxResults);
});
it("should respect offset parameter", async () => {
const offset = 2;
const response = await namegraph.findCollectionsByMember(exampleLabel);
- const response_with_offset = await namegraph.findCollectionsByMember(exampleLabel, {
- offset,
- });
+ const response_with_offset = await namegraph.findCollectionsByMember(
+ exampleLabel,
+ {
+ offset,
+ },
+ );
const first_two_collections = response.collections.slice(0, 2);
- expect(response_with_offset.collections).not.toContainEqual(first_two_collections[0]);
- expect(response_with_offset.collections).not.toContainEqual(first_two_collections[1]);
+ expect(response_with_offset.collections).not.toContainEqual(
+ first_two_collections[0],
+ );
+ expect(response_with_offset.collections).not.toContainEqual(
+ first_two_collections[1],
+ );
});
it("should respect sort parameter", async () => {
const sort = NameGraphSortOrderOptions.AZ;
const response = await namegraph.findCollectionsByMember(exampleLabel, {
- sort_order:sort,
+ sort_order: sort,
});
- const sorted_collections = response.collections.sort((a, b) => a.title.localeCompare(b.title));
+ const sorted_collections = response.collections.sort((a, b) =>
+ a.title.localeCompare(b.title),
+ );
expect(response.collections).toEqual(sorted_collections);
});
});
-
describe("getCollectionById", () => {
it("should fetch collection by ID", async () => {
const response = await namegraph.getCollectionById(exampleCollectionId);
-
+
expect(response).toBeDefined();
expect(response.collection_id).toBe(exampleCollectionId);
});
@@ -444,4 +550,4 @@ describe("Namegraph constructor", () => {
"https://api.namegraph.dev/",
);
});
-});
\ No newline at end of file
+});
diff --git a/packages/namegraph-sdk/src/index.ts b/packages/namegraph-sdk/src/index.ts
index dbedcb34d..a43463301 100644
--- a/packages/namegraph-sdk/src/index.ts
+++ b/packages/namegraph-sdk/src/index.ts
@@ -1,511 +1,558 @@
import fetch from "cross-fetch";
import {
- DEFAULT_ENABLE_LEARNING_TO_RANK,
- DEFAULT_FULL_MODE, DEFAULT_INSTANT_MODE,
- DEFAULT_LABEL_DIVERSITY_RATIO, DEFAULT_LABELS_LIMIT, DEFAULT_MAX_OTHER_COLLECTIONS,
- DEFAULT_MAX_PER_TYPE,
- DEFAULT_MAX_RECURSIVE_RELATED_COLLECTIONS,
- DEFAULT_MAX_RELATED_COLLECTIONS,
- DEFAULT_MAX_SUGGESTIONS, DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY, DEFAULT_MAX_TOTAL_COLLECTIONS,
- DEFAULT_METADATA, DEFAULT_MIN_OTHER_COLLECTIONS,
- DEFAULT_MIN_SUGGESTIONS, DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY, DEFAULT_OFFSET,
- NameGraphCollection,
- NameGraphCollectionByMemberResponse,
- NameGraphCountCollectionsResponse,
- NameGraphError,
- NameGraphFetchTopCollectionMembersResponse,
- NameGraphFindCollectionsResponse,
- NameGraphGroupedByCategoryResponse,
- NameGraphGroupingCategory,
- NameGraphOptions,
- NameGraphSortOrderOptions,
- NameGraphSuggestion,
- ScrambleMethod,
- TypedNameGraphGroupingCategoriesParams,
+ DEFAULT_ENABLE_LEARNING_TO_RANK,
+ DEFAULT_FULL_MODE,
+ DEFAULT_INSTANT_MODE,
+ DEFAULT_LABEL_DIVERSITY_RATIO,
+ DEFAULT_LABELS_LIMIT,
+ DEFAULT_MAX_OTHER_COLLECTIONS,
+ DEFAULT_MAX_PER_TYPE,
+ DEFAULT_MAX_RECURSIVE_RELATED_COLLECTIONS,
+ DEFAULT_MAX_RELATED_COLLECTIONS,
+ DEFAULT_MAX_SUGGESTIONS,
+ DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ DEFAULT_MAX_TOTAL_COLLECTIONS,
+ DEFAULT_METADATA,
+ DEFAULT_MIN_OTHER_COLLECTIONS,
+ DEFAULT_MIN_SUGGESTIONS,
+ DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ DEFAULT_OFFSET,
+ NameGraphCollection,
+ NameGraphCollectionByMemberResponse,
+ NameGraphCountCollectionsResponse,
+ NameGraphError,
+ NameGraphFetchTopCollectionMembersResponse,
+ NameGraphFindCollectionsResponse,
+ NameGraphGroupedByCategoryResponse,
+ NameGraphGroupingCategory,
+ NameGraphOptions,
+ NameGraphSortOrderOptions,
+ NameGraphSuggestion,
+ ScrambleMethod,
+ TypedNameGraphGroupingCategoriesParams,
} from "./utils";
/** The default endpoint URL for the NameGraph API */
const DEFAULT_ENDPOINT = "https://api.namegraph.dev/";
export class NameGraph {
- private namegraphEndpoint: URL;
- private abortController: AbortController;
-
- constructor({namegraphEndpoint = DEFAULT_ENDPOINT}: NameGraphOptions = {}) {
- this.namegraphEndpoint = new URL(namegraphEndpoint);
- this.abortController = new AbortController();
- }
-
- /**
- * Gets name suggestions grouped by category for a given label.
- *
- * @param {string} label - The ENS label to get suggestions for, cannot contain dots (.). If enclosed in double quotes assuming label is pre-tokenized, the separators in the pre-tokenized input are spaces.
- * @returns {Promise} Suggestions grouped by category
- * @example
- * const response = await client.groupedByCategory('zeus');
- */
- public groupedByCategory(
- label: string,
- ): Promise {
- const sorter = "weighted-sampling"; /* sorter algorithm, possible values: round-robin, count, length, weighted-sampling */
- const min_primary_fraction = 0.1; /* minimal fraction of primary labels, ensures at least `min_suggestions * min_primary_fraction` primary labels will be generated */
-
- const payload = {
- label,
- metadata: DEFAULT_METADATA,
- sorter,
- min_suggestions: DEFAULT_MIN_SUGGESTIONS,
- max_suggestions: DEFAULT_MAX_SUGGESTIONS,
- min_primary_fraction,
- params: {
- mode: DEFAULT_FULL_MODE, /* request mode: instant, domain_detail, full */
- enable_learning_to_rank: DEFAULT_ENABLE_LEARNING_TO_RANK, /*enable learning to rank. if true, the results will be sorted by 'learning to rank' algorithm */
- label_diversity_ratio: DEFAULT_LABEL_DIVERSITY_RATIO, /* collection diversity parameter based on labels, adds penalty to collections with similar labels to other collections. If null, then no penalty will be added */
- max_per_type: DEFAULT_MAX_PER_TYPE, /*collection diversity parameter based on collection types, adds penalty to collections with the same type as other collections. If null, then no penalty will be added */
- },
- };
-
- return this.rawRequest(`grouped_by_category`, "POST", payload);
- }
-
- /**
- * Gets name suggestions by category with configurable related collections.
- *
- * @param {string} label - The ENS label to get suggestions for, cannot contain dots (.). If enclosed in double quotes assuming label is pre-tokenized, the separators in the pre-tokenized input are spaces.
- * @param {number} maxRelatedCollections - Maximum number of related collections to return (default: 6)
- * @param {number} options.max_per_type - collection diversity parameter based on collection types, adds penalty to collections with the same type as other collections. If null, then no penalty will be added (default: 2)
- * @param {number} options.max_labels_per_related_collection - Max number of labels returned in any related collection (default: 10)
- * @param {number} options.max_suggestion_per_grouping_category - Maximal number of suggestions to generate in one specific category (default: 10)
- * @param {number} options.min_suggestion_per_grouping_category - Minimal number of suggestions to generate in one specific category. If the number of suggestions generated for this category is below 'min_suggestions'
- * then the entire category should be filtered out from the response. (default: 2)
- * @returns {Promise} Suggestions grouped by category.
- * @example
- * const suggestions = await client.suggestionsByCategory('zeus', 10);
- */
- public suggestionsByCategory(
- label: string,
- maxRelatedCollections = DEFAULT_MAX_RELATED_COLLECTIONS,
- options?: {
- max_per_type?: number,
- max_labels_per_related_collection?: number,
- max_suggestion_per_grouping_category?: number,
- min_suggestion_per_grouping_category?: number,
- },
- ): Promise {
- const categoriesQueryConfig: TypedNameGraphGroupingCategoriesParams = {
- [NameGraphGroupingCategory.related]: {
- enable_learning_to_rank: DEFAULT_ENABLE_LEARNING_TO_RANK,
- max_labels_per_related_collection: options?.max_labels_per_related_collection || 10,
- max_per_type: options?.max_per_type || DEFAULT_MAX_PER_TYPE,
- max_recursive_related_collections: DEFAULT_MAX_RECURSIVE_RELATED_COLLECTIONS, /* Set to 0 to disable the "recursive related collection search". When set to a value between 1 and 10, for each related collection we find,
- we also do a (depth 1 recursive) lookup for this many related collections to the related collection.*/
- max_related_collections: maxRelatedCollections, /* max number of related collections returned. If 0 it effectively turns off any related collection search. */
- label_diversity_ratio: DEFAULT_LABEL_DIVERSITY_RATIO,
- },
- [NameGraphGroupingCategory.wordplay]: {
- max_suggestions: options?.max_suggestion_per_grouping_category || DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
- min_suggestions: options?.min_suggestion_per_grouping_category || DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
- },
-
- [NameGraphGroupingCategory.alternates]: {
- max_suggestions: options?.max_suggestion_per_grouping_category || DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
- min_suggestions: options?.min_suggestion_per_grouping_category || DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
- },
- [NameGraphGroupingCategory.emojify]: {
- max_suggestions: options?.max_suggestion_per_grouping_category || DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
- min_suggestions: options?.min_suggestion_per_grouping_category || DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
- },
- [NameGraphGroupingCategory.community]: {
- max_suggestions: options?.max_suggestion_per_grouping_category || DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
- min_suggestions: options?.min_suggestion_per_grouping_category || DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
- },
- [NameGraphGroupingCategory.expand]: {
- max_suggestions: options?.max_suggestion_per_grouping_category || DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
- min_suggestions: options?.min_suggestion_per_grouping_category || DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
- },
- [NameGraphGroupingCategory.gowild]: {
- max_suggestions: options?.max_suggestion_per_grouping_category || DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
- min_suggestions: options?.min_suggestion_per_grouping_category || DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
- },
- [NameGraphGroupingCategory.other]: {
- max_suggestions: options?.max_suggestion_per_grouping_category || DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
- min_suggestions: 6,
- min_total_suggestions: 50, /* if not enough suggestions then "fallback generator" should be placed into another new category type called "other"
- it may be not fulfilled because of `max_suggestions` limit */
- },
- };
-
- const payload = {
- label,
- categories: categoriesQueryConfig,
- params: {
- mode: DEFAULT_FULL_MODE,
- metadata: DEFAULT_METADATA,
- },
- };
-
- return this.rawRequest(`suggestions_by_category`, "POST", payload);
- }
-
- /**
- * Gets a random sample of members from a collection.
- *
- * @param {string} collection_id - The ID of the collection to sample from
- * @param {number} options.seed - Random seed for reproducible sampling
- * @param {number} options.max_sample_size - the maximum number of members to sample. If the collection has fewer members than max_sample_size, all the members will be returned (default: 5)
- * @returns {Promise} Array of sampled collection members
- * @example
- * const members = await client.sampleCollectionMembers('collection_id', { seed: 42 });
- */
- public sampleCollectionMembers(
- collection_id: string,
- options?: {
- seed?: number;
- max_sample_size?: number;
- },
- ): Promise {
- const max_sample_size = options?.max_sample_size || 5;
- const seed = options?.seed;
-
- const payload = {
- collection_id,
- metadata: DEFAULT_METADATA,
- max_sample_size,
- seed,
- };
-
- return this.rawRequest("sample_collection_members", "POST", payload);
- }
-
- /**
- * Fetches top 10 members from the collection specified by collection_id
- *
- * @param {string} collection_id - The ID of the collection
- * @returns {Promise} Top collection members
- * @example
- * const topMembers = await client.fetchTopCollectionMembers('collection_id');
- */
- public fetchTopCollectionMembers(
- collection_id: string,
- ): Promise {
- const metadata = true;
-
- const payload = {
- metadata,
- collection_id,
- max_recursive_related_collections: DEFAULT_MAX_RECURSIVE_RELATED_COLLECTIONS,
- };
-
- return this.rawRequest("fetch_top_collection_members", "POST", payload);
- }
-
- /**
- * Generates scrambled variations of collection tokens.
- *
- * @param {string} collection_id - The ID of the collection to scramble tokens from
- * @param {number} options.seed - Random seed for reproducible scrambling
- * @param {ScrambleMethod} options.method - Method to use for scrambling. Possible values: "left-right-shuffle", "left-right-shuffle-with-unigrams", "full-shuffle"
- * @param {number} options.n_top_members - Number of collection's top members to include in scrambling (default: 25)
- * @param {number} options.max_suggestions - Maximal number of suggestions to generate, must be a positive integer (default: 10)
- * @returns {Promise} Array of scrambled suggestions
- * @example
- * const scrambled = await client.scrambleCollectionTokens('collection_id', {
- * seed: 42,
- * });
- */
- public scrambleCollectionTokens(
- collection_id: string,
- options?: {
- seed?: number
- method?: ScrambleMethod;
- n_top_members?: number;
- max_suggestions?: number;
- },
- ): Promise {
- const method = options?.method || ScrambleMethod["left-right-shuffle-with-unigrams"];
- const n_top_members = options?.n_top_members || 25;
- const max_suggestions = options?.max_suggestions || 10;
- const seed = options?.seed;
-
- const payload = {
- collection_id,
- metadata: DEFAULT_METADATA,
- method,
- n_top_members,
- max_suggestions,
- seed,
- };
-
- return this.rawRequest("scramble_collection_tokens", "POST", payload);
- }
-
- /**
- * Searches for collections by a string query.
- *
- * @param {string} query - input query (with or without spaces) which is used to search for template collections, cannot contain dots (.)
- * @param {number} options.max_per_type - Number of collections with the same type which are not penalized. Set to null if you want to disable the penalization.
- * If the penalization algorithm is turned on then 3 times more results (than max_related_collections) are retrieved from Elasticsearch (default: 3)
- * @param {number} options.offset - Starting offset for pagination (default: 0)
- * @param {number} options.min_other_collections - Minimum number of other collections to return (default: 0)
- * @param {number} options.max_other_collections - Maximum number of other collections to return (default: 3)
- * @param {number} options.max_related_collections - Maximum number of related collections to return (default: 3)
- * Return collections at [offset, offset + max_related_collections) positions (order as in sort_order). Should be a positive integer (default: 3)
- * @param {number} options.max_total_collections - Maximum number of total (related + other) collections to return (default: 6)
- * @param {NameGraphSortOrderOptions} options.sort_order - Sort order: "AI", "A-Z", "Z-A", or "Relevance" (default: "AI")
- * @returns {Promise} Matching collections
- * @example
- * const collections = await client.findCollectionsByString('zeus god', {
- * offset: 0,
- * max_total_collections: 10,
- * sort_order: NameGraphSortOrderOptions.AI
- * });
- */
- public findCollectionsByString(
- query: string,
- options?: {
- max_per_type?: number;
- offset?: number;
- min_other_collections?: number;
- max_other_collections?: number;
- max_related_collections?: number;
- max_total_collections?: number;
- sort_order?: NameGraphSortOrderOptions;
- },
- ): Promise {
- const max_per_type = options?.max_per_type || 3
- const min_other_collections = options?.min_other_collections || DEFAULT_MIN_OTHER_COLLECTIONS;
- const max_other_collections = options?.max_other_collections || DEFAULT_MAX_OTHER_COLLECTIONS;
- const max_total_collections = options?.max_total_collections || DEFAULT_MAX_TOTAL_COLLECTIONS;
- const max_related_collections = options?.max_related_collections || 3;
-
- const payload = {
- limit_labels: DEFAULT_LABELS_LIMIT,
- offset: options?.offset || DEFAULT_OFFSET,
- sort_order: options?.sort_order || NameGraphSortOrderOptions.AI,
- max_related_collections,
- max_per_type,
- label_diversity_ratio: DEFAULT_LABEL_DIVERSITY_RATIO,
- min_other_collections,
- max_other_collections,
- max_total_collections,
- query,
- mode: DEFAULT_INSTANT_MODE, /* request mode that performs rescoring on top 20 collections instead of 100, should result in faster responses */
- };
-
- return this.rawRequest("find_collections_by_string", "POST", payload);
- }
-
- /**
- * Fetches members from a collection with pagination support
- *
- * @param {string} collection_id - The ID of the collection
- * @param {number} options.offset - Starting offset (number of members to skip) for pagination (default: 0)
- * @param {number} options.limit - Maximum number of members to return (default: 10)
- * @returns {Promise} Collection members.
- * @example
- * const members = await client.fetchCollectionMembers('collection_id', {
- * offset: 0,
- * limit: 20
- * });
- */
- public fetchCollectionMembers(
- collection_id: string,
- options?: {
- offset?: number;
- limit?: number;
- },
- ): Promise {
- const payload = {
- collection_id,
- offset: options?.offset || DEFAULT_OFFSET,
- limit: options?.limit || DEFAULT_LABELS_LIMIT,
- metadata: true,
- };
-
- return this.rawRequest("fetch_collection_members", "POST", payload);
- }
-
- /**
- * Counts collections matching a string query.
- *
- * @param {string} query - input query (with or without spaces) which is used to search for template collections, cannot contain dots (.)
- * @returns {Promise} Count of matching collections
- * @example
- * const stringCount = await client.countCollectionsByString('zeus god');
- */
- public countCollectionsByString(
- query: string,
- ): Promise {
- const payload = {
- query,
- mode: DEFAULT_INSTANT_MODE,
- };
-
- return this.rawRequest("count_collections_by_string", "POST", payload);
- }
-
- /**
- * Finds collections related to a given collection.
- *
- * @param {string} collection_id - The ID of the collection to find related collections for
- * @param {number} options.max_per_type - Number of collections with the same type which are not penalized. Set to null if you want to disable the penalization.
- * If the penalization algorithm is turned on then 3 times more results (than max_related_collections) are retrieved from Elasticsearch (default: 3)
- * @param {number} options.max_related_collections - Max number of related collections to return (for each page).
- * Return collections at [offset, offset + max_related_collections) positions (order as in sort_order). Should be a positive integer (default: 3)
- * @returns {Promise} Related collections
- * @example
- * const related = await client.findCollectionsByCollection('collection_id');
- */
- public findCollectionsByCollection(
- collection_id: string,
- options?: {
- max_related_collections?: number;
- max_per_type?: number;
- },
- ): Promise {
- const max_related_collections = options?.max_related_collections || 3;
- const max_per_type = options?.max_per_type || 3;
-
- const payload = {
- limit_labels: DEFAULT_LABELS_LIMIT,
- offset: DEFAULT_OFFSET,
- sort_order: NameGraphSortOrderOptions.RELEVANCE,
- max_related_collections,
- max_per_type,
- label_diversity_ratio: DEFAULT_LABEL_DIVERSITY_RATIO,
- min_other_collections: DEFAULT_MIN_OTHER_COLLECTIONS,
- max_other_collections: DEFAULT_MAX_OTHER_COLLECTIONS,
- max_total_collections: Math.max(
- max_related_collections + DEFAULT_MAX_OTHER_COLLECTIONS,
- DEFAULT_MAX_TOTAL_COLLECTIONS),
- collection_id,
- };
-
- return this.rawRequest("find_collections_by_collection", "POST", payload);
- }
-
- /**
- * Counts collections containing a specific member.
- *
- * @param {string} label - The member label to count collections for
- * @returns {Promise} Count of collections containing the member
- * @example
- * const memberCount = await client.countCollectionsByMember('zeus');
- */
- public countCollectionsByMember(
- label: string,
- ): Promise {
- const payload = {
- label,
- };
-
- return this.rawRequest("count_collections_by_member", "POST", payload);
+ private namegraphEndpoint: URL;
+ private abortController: AbortController;
+
+ constructor({ namegraphEndpoint = DEFAULT_ENDPOINT }: NameGraphOptions = {}) {
+ this.namegraphEndpoint = new URL(namegraphEndpoint);
+ this.abortController = new AbortController();
+ }
+
+ /**
+ * Gets name suggestions grouped by category for a given label.
+ *
+ * @param {string} label - The ENS label to get suggestions for, cannot contain dots (.). If enclosed in double quotes assuming label is pre-tokenized, the separators in the pre-tokenized input are spaces.
+ * @returns {Promise} Suggestions grouped by category
+ * @example
+ * const response = await client.groupedByCategory('zeus');
+ */
+ public groupedByCategory(
+ label: string,
+ ): Promise {
+ const sorter =
+ "weighted-sampling"; /* sorter algorithm, possible values: round-robin, count, length, weighted-sampling */
+ const min_primary_fraction = 0.1; /* minimal fraction of primary labels, ensures at least `min_suggestions * min_primary_fraction` primary labels will be generated */
+
+ const payload = {
+ label,
+ metadata: DEFAULT_METADATA,
+ sorter,
+ min_suggestions: DEFAULT_MIN_SUGGESTIONS,
+ max_suggestions: DEFAULT_MAX_SUGGESTIONS,
+ min_primary_fraction,
+ params: {
+ mode: DEFAULT_FULL_MODE /* request mode: instant, domain_detail, full */,
+ enable_learning_to_rank:
+ DEFAULT_ENABLE_LEARNING_TO_RANK /*enable learning to rank. if true, the results will be sorted by 'learning to rank' algorithm */,
+ label_diversity_ratio:
+ DEFAULT_LABEL_DIVERSITY_RATIO /* collection diversity parameter based on labels, adds penalty to collections with similar labels to other collections. If null, then no penalty will be added */,
+ max_per_type:
+ DEFAULT_MAX_PER_TYPE /*collection diversity parameter based on collection types, adds penalty to collections with the same type as other collections. If null, then no penalty will be added */,
+ },
+ };
+
+ return this.rawRequest(`grouped_by_category`, "POST", payload);
+ }
+
+ /**
+ * Gets name suggestions by category with configurable related collections.
+ *
+ * @param {string} label - The ENS label to get suggestions for, cannot contain dots (.). If enclosed in double quotes assuming label is pre-tokenized, the separators in the pre-tokenized input are spaces.
+ * @param {number} maxRelatedCollections - Maximum number of related collections to return (default: 6)
+ * @param {number} options.max_per_type - collection diversity parameter based on collection types, adds penalty to collections with the same type as other collections. If null, then no penalty will be added (default: 2)
+ * @param {number} options.max_labels_per_related_collection - Max number of labels returned in any related collection (default: 10)
+ * @param {number} options.max_suggestion_per_grouping_category - Maximal number of suggestions to generate in one specific category (default: 10)
+ * @param {number} options.min_suggestion_per_grouping_category - Minimal number of suggestions to generate in one specific category. If the number of suggestions generated for this category is below 'min_suggestions'
+ * then the entire category should be filtered out from the response. (default: 2)
+ * @returns {Promise} Suggestions grouped by category.
+ * @example
+ * const suggestions = await client.suggestionsByCategory('zeus', 10);
+ */
+ public suggestionsByCategory(
+ label: string,
+ maxRelatedCollections = DEFAULT_MAX_RELATED_COLLECTIONS,
+ options?: {
+ max_per_type?: number;
+ max_labels_per_related_collection?: number;
+ max_suggestion_per_grouping_category?: number;
+ min_suggestion_per_grouping_category?: number;
+ },
+ ): Promise {
+ const categoriesQueryConfig: TypedNameGraphGroupingCategoriesParams = {
+ [NameGraphGroupingCategory.related]: {
+ enable_learning_to_rank: DEFAULT_ENABLE_LEARNING_TO_RANK,
+ max_labels_per_related_collection:
+ options?.max_labels_per_related_collection || 10,
+ max_per_type: options?.max_per_type || DEFAULT_MAX_PER_TYPE,
+ max_recursive_related_collections:
+ DEFAULT_MAX_RECURSIVE_RELATED_COLLECTIONS /* Set to 0 to disable the "recursive related collection search". When set to a value between 1 and 10, for each related collection we find,
+ we also do a (depth 1 recursive) lookup for this many related collections to the related collection.*/,
+ max_related_collections:
+ maxRelatedCollections /* max number of related collections returned. If 0 it effectively turns off any related collection search. */,
+ label_diversity_ratio: DEFAULT_LABEL_DIVERSITY_RATIO,
+ },
+ [NameGraphGroupingCategory.wordplay]: {
+ max_suggestions:
+ options?.max_suggestion_per_grouping_category ||
+ DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ min_suggestions:
+ options?.min_suggestion_per_grouping_category ||
+ DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ },
+
+ [NameGraphGroupingCategory.alternates]: {
+ max_suggestions:
+ options?.max_suggestion_per_grouping_category ||
+ DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ min_suggestions:
+ options?.min_suggestion_per_grouping_category ||
+ DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ },
+ [NameGraphGroupingCategory.emojify]: {
+ max_suggestions:
+ options?.max_suggestion_per_grouping_category ||
+ DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ min_suggestions:
+ options?.min_suggestion_per_grouping_category ||
+ DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ },
+ [NameGraphGroupingCategory.community]: {
+ max_suggestions:
+ options?.max_suggestion_per_grouping_category ||
+ DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ min_suggestions:
+ options?.min_suggestion_per_grouping_category ||
+ DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ },
+ [NameGraphGroupingCategory.expand]: {
+ max_suggestions:
+ options?.max_suggestion_per_grouping_category ||
+ DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ min_suggestions:
+ options?.min_suggestion_per_grouping_category ||
+ DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ },
+ [NameGraphGroupingCategory.gowild]: {
+ max_suggestions:
+ options?.max_suggestion_per_grouping_category ||
+ DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ min_suggestions:
+ options?.min_suggestion_per_grouping_category ||
+ DEFAULT_MIN_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ },
+ [NameGraphGroupingCategory.other]: {
+ max_suggestions:
+ options?.max_suggestion_per_grouping_category ||
+ DEFAULT_MAX_SUGGESTIONS_PER_GROUPING_CATEGORY,
+ min_suggestions: 6,
+ min_total_suggestions: 50 /* if not enough suggestions then "fallback generator" should be placed into another new category type called "other"
+ it may be not fulfilled because of `max_suggestions` limit */,
+ },
+ };
+
+ const payload = {
+ label,
+ categories: categoriesQueryConfig,
+ params: {
+ mode: DEFAULT_FULL_MODE,
+ metadata: DEFAULT_METADATA,
+ },
+ };
+
+ return this.rawRequest(`suggestions_by_category`, "POST", payload);
+ }
+
+ /**
+ * Gets a random sample of members from a collection.
+ *
+ * @param {string} collection_id - The ID of the collection to sample from
+ * @param {number} options.seed - Random seed for reproducible sampling
+ * @param {number} options.max_sample_size - the maximum number of members to sample. If the collection has fewer members than max_sample_size, all the members will be returned (default: 5)
+ * @returns {Promise} Array of sampled collection members
+ * @example
+ * const members = await client.sampleCollectionMembers('collection_id', { seed: 42 });
+ */
+ public sampleCollectionMembers(
+ collection_id: string,
+ options?: {
+ seed?: number;
+ max_sample_size?: number;
+ },
+ ): Promise {
+ const max_sample_size = options?.max_sample_size || 5;
+ const seed = options?.seed;
+
+ const payload = {
+ collection_id,
+ metadata: DEFAULT_METADATA,
+ max_sample_size,
+ seed,
+ };
+
+ return this.rawRequest("sample_collection_members", "POST", payload);
+ }
+
+ /**
+ * Fetches top 10 members from the collection specified by collection_id
+ *
+ * @param {string} collection_id - The ID of the collection
+ * @returns {Promise} Top collection members
+ * @example
+ * const topMembers = await client.fetchTopCollectionMembers('collection_id');
+ */
+ public fetchTopCollectionMembers(
+ collection_id: string,
+ ): Promise {
+ const metadata = true;
+
+ const payload = {
+ metadata,
+ collection_id,
+ max_recursive_related_collections:
+ DEFAULT_MAX_RECURSIVE_RELATED_COLLECTIONS,
+ };
+
+ return this.rawRequest("fetch_top_collection_members", "POST", payload);
+ }
+
+ /**
+ * Generates scrambled variations of collection tokens.
+ *
+ * @param {string} collection_id - The ID of the collection to scramble tokens from
+ * @param {number} options.seed - Random seed for reproducible scrambling
+ * @param {ScrambleMethod} options.method - Method to use for scrambling. Possible values: "left-right-shuffle", "left-right-shuffle-with-unigrams", "full-shuffle"
+ * @param {number} options.n_top_members - Number of collection's top members to include in scrambling (default: 25)
+ * @param {number} options.max_suggestions - Maximal number of suggestions to generate, must be a positive integer (default: 10)
+ * @returns {Promise} Array of scrambled suggestions
+ * @example
+ * const scrambled = await client.scrambleCollectionTokens('collection_id', {
+ * seed: 42,
+ * });
+ */
+ public scrambleCollectionTokens(
+ collection_id: string,
+ options?: {
+ seed?: number;
+ method?: ScrambleMethod;
+ n_top_members?: number;
+ max_suggestions?: number;
+ },
+ ): Promise {
+ const method =
+ options?.method || ScrambleMethod["left-right-shuffle-with-unigrams"];
+ const n_top_members = options?.n_top_members || 25;
+ const max_suggestions = options?.max_suggestions || 10;
+ const seed = options?.seed;
+
+ const payload = {
+ collection_id,
+ metadata: DEFAULT_METADATA,
+ method,
+ n_top_members,
+ max_suggestions,
+ seed,
+ };
+
+ return this.rawRequest("scramble_collection_tokens", "POST", payload);
+ }
+
+ /**
+ * Searches for collections by a string query.
+ *
+ * @param {string} query - input query (with or without spaces) which is used to search for template collections, cannot contain dots (.)
+ * @param {number} options.max_per_type - Number of collections with the same type which are not penalized. Set to null if you want to disable the penalization.
+ * If the penalization algorithm is turned on then 3 times more results (than max_related_collections) are retrieved from Elasticsearch (default: 3)
+ * @param {number} options.offset - Starting offset for pagination (default: 0)
+ * @param {number} options.min_other_collections - Minimum number of other collections to return (default: 0)
+ * @param {number} options.max_other_collections - Maximum number of other collections to return (default: 3)
+ * @param {number} options.max_related_collections - Maximum number of related collections to return (default: 3)
+ * Return collections at [offset, offset + max_related_collections) positions (order as in sort_order). Should be a positive integer (default: 3)
+ * @param {number} options.max_total_collections - Maximum number of total (related + other) collections to return (default: 6)
+ * @param {NameGraphSortOrderOptions} options.sort_order - Sort order: "AI", "A-Z", "Z-A", or "Relevance" (default: "AI")
+ * @returns {Promise} Matching collections
+ * @example
+ * const collections = await client.findCollectionsByString('zeus god', {
+ * offset: 0,
+ * max_total_collections: 10,
+ * sort_order: NameGraphSortOrderOptions.AI
+ * });
+ */
+ public findCollectionsByString(
+ query: string,
+ options?: {
+ max_per_type?: number;
+ offset?: number;
+ min_other_collections?: number;
+ max_other_collections?: number;
+ max_related_collections?: number;
+ max_total_collections?: number;
+ sort_order?: NameGraphSortOrderOptions;
+ },
+ ): Promise {
+ const max_per_type = options?.max_per_type || 3;
+ const min_other_collections =
+ options?.min_other_collections || DEFAULT_MIN_OTHER_COLLECTIONS;
+ const max_other_collections =
+ options?.max_other_collections || DEFAULT_MAX_OTHER_COLLECTIONS;
+ const max_total_collections =
+ options?.max_total_collections || DEFAULT_MAX_TOTAL_COLLECTIONS;
+ const max_related_collections = options?.max_related_collections || 3;
+
+ const payload = {
+ limit_labels: DEFAULT_LABELS_LIMIT,
+ offset: options?.offset || DEFAULT_OFFSET,
+ sort_order: options?.sort_order || NameGraphSortOrderOptions.AI,
+ max_related_collections,
+ max_per_type,
+ label_diversity_ratio: DEFAULT_LABEL_DIVERSITY_RATIO,
+ min_other_collections,
+ max_other_collections,
+ max_total_collections,
+ query,
+ mode: DEFAULT_INSTANT_MODE /* request mode that performs rescoring on top 20 collections instead of 100, should result in faster responses */,
+ };
+
+ return this.rawRequest("find_collections_by_string", "POST", payload);
+ }
+
+ /**
+ * Fetches members from a collection with pagination support
+ *
+ * @param {string} collection_id - The ID of the collection
+ * @param {number} options.offset - Starting offset (number of members to skip) for pagination (default: 0)
+ * @param {number} options.limit - Maximum number of members to return (default: 10)
+ * @returns {Promise} Collection members.
+ * @example
+ * const members = await client.fetchCollectionMembers('collection_id', {
+ * offset: 0,
+ * limit: 20
+ * });
+ */
+ public fetchCollectionMembers(
+ collection_id: string,
+ options?: {
+ offset?: number;
+ limit?: number;
+ },
+ ): Promise {
+ const payload = {
+ collection_id,
+ offset: options?.offset || DEFAULT_OFFSET,
+ limit: options?.limit || DEFAULT_LABELS_LIMIT,
+ metadata: true,
+ };
+
+ return this.rawRequest("fetch_collection_members", "POST", payload);
+ }
+
+ /**
+ * Counts collections matching a string query.
+ *
+ * @param {string} query - input query (with or without spaces) which is used to search for template collections, cannot contain dots (.)
+ * @returns {Promise} Count of matching collections
+ * @example
+ * const stringCount = await client.countCollectionsByString('zeus god');
+ */
+ public countCollectionsByString(
+ query: string,
+ ): Promise {
+ const payload = {
+ query,
+ mode: DEFAULT_INSTANT_MODE,
+ };
+
+ return this.rawRequest("count_collections_by_string", "POST", payload);
+ }
+
+ /**
+ * Finds collections related to a given collection.
+ *
+ * @param {string} collection_id - The ID of the collection to find related collections for
+ * @param {number} options.max_per_type - Number of collections with the same type which are not penalized. Set to null if you want to disable the penalization.
+ * If the penalization algorithm is turned on then 3 times more results (than max_related_collections) are retrieved from Elasticsearch (default: 3)
+ * @param {number} options.max_related_collections - Max number of related collections to return (for each page).
+ * Return collections at [offset, offset + max_related_collections) positions (order as in sort_order). Should be a positive integer (default: 3)
+ * @returns {Promise} Related collections
+ * @example
+ * const related = await client.findCollectionsByCollection('collection_id');
+ */
+ public findCollectionsByCollection(
+ collection_id: string,
+ options?: {
+ max_related_collections?: number;
+ max_per_type?: number;
+ },
+ ): Promise {
+ const max_related_collections = options?.max_related_collections || 3;
+ const max_per_type = options?.max_per_type || 3;
+
+ const payload = {
+ limit_labels: DEFAULT_LABELS_LIMIT,
+ offset: DEFAULT_OFFSET,
+ sort_order: NameGraphSortOrderOptions.RELEVANCE,
+ max_related_collections,
+ max_per_type,
+ label_diversity_ratio: DEFAULT_LABEL_DIVERSITY_RATIO,
+ min_other_collections: DEFAULT_MIN_OTHER_COLLECTIONS,
+ max_other_collections: DEFAULT_MAX_OTHER_COLLECTIONS,
+ max_total_collections: Math.max(
+ max_related_collections + DEFAULT_MAX_OTHER_COLLECTIONS,
+ DEFAULT_MAX_TOTAL_COLLECTIONS,
+ ),
+ collection_id,
+ };
+
+ return this.rawRequest("find_collections_by_collection", "POST", payload);
+ }
+
+ /**
+ * Counts collections containing a specific member.
+ *
+ * @param {string} label - The member label to count collections for
+ * @returns {Promise} Count of collections containing the member
+ * @example
+ * const memberCount = await client.countCollectionsByMember('zeus');
+ */
+ public countCollectionsByMember(
+ label: string,
+ ): Promise {
+ const payload = {
+ label,
+ };
+
+ return this.rawRequest("count_collections_by_member", "POST", payload);
+ }
+
+ /**
+ * Finds collections containing a specific member.
+ *
+ * @param {string} label - The member label to find collections for
+ * @param {number} options.offset - Starting offset for pagination (default: 0)
+ * @param {number} options.max_results - Maximum number of results to return (default: 3)
+ * @param {number} options.limit_labels - Maximum number of labels per collection (default: 10)
+ * @param {NameGraphSortOrderOptions} options.sort_order - Sort order: "AI", "A-Z", "Z-A", or "Relevance" (default: "AI")
+ * @returns {Promise} Collections containing the member.
+ * @example
+ * const memberCollections = await client.findCollectionsByMember('zeus', {
+ * offset: 0,
+ * max_results: 5,
+ * sort_order: NameGraphSortOrderOptions.AI
+ * });
+ */
+ public findCollectionsByMember(
+ label: string,
+ options?: {
+ offset?: number;
+ max_results?: number;
+ limit_labels?: number;
+ sort_order?: NameGraphSortOrderOptions;
+ },
+ ): Promise {
+ const max_results = options?.max_results || 3;
+
+ const payload = {
+ limit_labels: options?.limit_labels || DEFAULT_LABELS_LIMIT,
+ offset: options?.offset || DEFAULT_OFFSET,
+ sort_order: options?.sort_order || NameGraphSortOrderOptions.AI,
+ label,
+ mode: DEFAULT_INSTANT_MODE,
+ max_results,
+ };
+
+ return this.rawRequest("find_collections_by_member", "POST", payload);
+ }
+
+ /**
+ * Gets information about a single collection by its ID.
+ *
+ * @param {string} collection_id - The ID of the collection to retrieve
+ * @returns {Promise} The requested collection
+ * @example
+ * const collection = await client.getCollectionById('collection_id');
+ */
+ public getCollectionById(
+ collection_id: string,
+ ): Promise {
+ const payload = {
+ collection_id,
+ };
+
+ return this.rawRequest("get_collection_by_id", "POST", payload);
+ }
+
+ /**
+ * Performs a raw HTTP request to the NameGraph API.
+ * @param {string} path - The API endpoint path
+ * @param {string} method - The HTTP method (e.g., 'GET', 'POST')
+ * @param {object} body - The request body for POST requests
+ * @param {object} headers - Additional headers for the request
+ * @returns {Promise} The response from the API
+ */
+ async rawRequest(
+ path: string,
+ method: string = "GET",
+ body: object = {},
+ headers: object = {},
+ ): Promise {
+ const url = new URL(path, this.namegraphEndpoint);
+
+ const options: RequestInit = {
+ method,
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ ...headers,
+ },
+ signal: this.abortController.signal,
+ };
+
+ if (method !== "GET") {
+ options.body = JSON.stringify(body);
}
- /**
- * Finds collections containing a specific member.
- *
- * @param {string} label - The member label to find collections for
- * @param {number} options.offset - Starting offset for pagination (default: 0)
- * @param {number} options.max_results - Maximum number of results to return (default: 3)
- * @param {number} options.limit_labels - Maximum number of labels per collection (default: 10)
- * @param {NameGraphSortOrderOptions} options.sort_order - Sort order: "AI", "A-Z", "Z-A", or "Relevance" (default: "AI")
- * @returns {Promise} Collections containing the member.
- * @example
- * const memberCollections = await client.findCollectionsByMember('zeus', {
- * offset: 0,
- * max_results: 5,
- * sort_order: NameGraphSortOrderOptions.AI
- * });
- */
- public findCollectionsByMember(
- label: string,
- options?: {
- offset?: number;
- max_results?: number;
- limit_labels?: number;
- sort_order?: NameGraphSortOrderOptions;
- },
- ): Promise {
- const max_results = options?.max_results || 3;
-
- const payload = {
- limit_labels: options?.limit_labels || DEFAULT_LABELS_LIMIT,
- offset: options?.offset || DEFAULT_OFFSET,
- sort_order: options?.sort_order || NameGraphSortOrderOptions.AI,
- label,
- mode: DEFAULT_INSTANT_MODE,
- max_results,
- };
-
- return this.rawRequest("find_collections_by_member", "POST", payload);
- }
+ const response = await fetch(url, options);
- /**
- * Gets information about a single collection by its ID.
- *
- * @param {string} collection_id - The ID of the collection to retrieve
- * @returns {Promise} The requested collection
- * @example
- * const collection = await client.getCollectionById('collection_id');
- */
- public getCollectionById(
- collection_id: string,
- ): Promise {
- const payload = {
- collection_id,
- };
-
- return this.rawRequest("get_collection_by_id", "POST", payload);
+ if (!response.ok) {
+ throw new NameGraphError(
+ response.status,
+ `Failed to perform request to ${path}.`,
+ );
}
- /**
- * Performs a raw HTTP request to the NameGraph API.
- * @param {string} path - The API endpoint path
- * @param {string} method - The HTTP method (e.g., 'GET', 'POST')
- * @param {object} body - The request body for POST requests
- * @param {object} headers - Additional headers for the request
- * @returns {Promise} The response from the API
- */
- async rawRequest(
- path: string,
- method: string = "GET",
- body: object = {},
- headers: object = {},
- ): Promise {
- const url = new URL(path, this.namegraphEndpoint);
-
- const options: RequestInit = {
- method,
- headers: {
- "Content-Type": "application/json",
- Accept: "application/json",
- ...headers,
- },
- signal: this.abortController.signal,
- };
-
- if (method !== "GET") {
- options.body = JSON.stringify(body);
- }
-
- const response = await fetch(url, options);
-
- if (!response.ok) {
- throw new NameGraphError(
- response.status,
- `Failed to perform request to ${path}.`,
- );
- }
-
- return await response.json();
- }
+ return await response.json();
+ }
- public abortAllRequests(): void {
- this.abortController.abort();
+ public abortAllRequests(): void {
+ this.abortController.abort();
- this.abortController = new AbortController();
- }
+ this.abortController = new AbortController();
+ }
}
/**
@@ -518,7 +565,7 @@ export class NameGraph {
* const namegraph = createNameGraphClient({ ... })
*/
export function createNameGraphClient(options?: NameGraphOptions) {
- return new NameGraph(options);
+ return new NameGraph(options);
}
const defaultClient = createNameGraphClient();
diff --git a/packages/namegraph-sdk/src/utils.test.ts b/packages/namegraph-sdk/src/utils.test.ts
index a834123df..6d0b03877 100644
--- a/packages/namegraph-sdk/src/utils.test.ts
+++ b/packages/namegraph-sdk/src/utils.test.ts
@@ -1,8 +1,5 @@
import { describe, it, expect } from "vitest";
-import {
- sampleWritersBlockSuggestions,
- WritersBlockCollection,
-} from "./utils";
+import { sampleWritersBlockSuggestions, WritersBlockCollection } from "./utils";
describe("sampleWritersBlockSuggestions", () => {
const mockCatalog: WritersBlockCollection[] = [
@@ -45,14 +42,14 @@ describe("sampleWritersBlockSuggestions", () => {
it("should return unique suggestions", () => {
const suggestionsCount = 2;
const result = sampleWritersBlockSuggestions(suggestionsCount, mockCatalog);
- const uniqueSuggestions = new Set(result.map(s => s.suggestedName));
+ const uniqueSuggestions = new Set(result.map((s) => s.suggestedName));
expect(uniqueSuggestions.size).toBe(result.length);
});
it("should return suggestions with correct structure", () => {
const result = sampleWritersBlockSuggestions(1, mockCatalog);
const suggestion = result[0];
-
+
expect(suggestion).toHaveProperty("collectionName");
expect(suggestion).toHaveProperty("suggestedName");
expect(suggestion).toHaveProperty("tokenizedSuggestedName");
@@ -73,7 +70,7 @@ describe("sampleWritersBlockSuggestions", () => {
it("should return suggestions from different collections", () => {
const suggestionsCount = 2;
const result = sampleWritersBlockSuggestions(suggestionsCount, mockCatalog);
- const uniqueCollections = new Set(result.map(s => s.collectionName));
+ const uniqueCollections = new Set(result.map((s) => s.collectionName));
expect(uniqueCollections.size).toBe(result.length);
});
});
diff --git a/packages/namegraph-sdk/src/utils.ts b/packages/namegraph-sdk/src/utils.ts
index 84085a9a4..3c1860f48 100644
--- a/packages/namegraph-sdk/src/utils.ts
+++ b/packages/namegraph-sdk/src/utils.ts
@@ -8,7 +8,7 @@ export const DEFAULT_MIN_SUGGESTIONS = 100;
export const DEFAULT_MAX_SUGGESTIONS = 100;
/* Mode for processing that should result in faster responses.
-*/
+ */
export const DEFAULT_INSTANT_MODE = "instant";
/* Other modes are: full and domain_detail.
@@ -348,9 +348,12 @@ export const sampleWritersBlockSuggestions = (
/** Available methods for scrambling names from collections*/
export const ScrambleMethod = {
- "left-right-shuffle": "left-right-shuffle", /* tokenize labels as bigrams and shuffle the right-side tokens (do not use unigrams) */
- "left-right-shuffle-with-unigrams": "left-right-shuffle-with-unigrams", /* same as above, but with some tokens swapped with unigrams */
- "full-shuffle": "full-shuffle", /* shuffle all tokens from bigrams and unigrams and create random bigrams */
+ "left-right-shuffle":
+ "left-right-shuffle" /* tokenize labels as bigrams and shuffle the right-side tokens (do not use unigrams) */,
+ "left-right-shuffle-with-unigrams":
+ "left-right-shuffle-with-unigrams" /* same as above, but with some tokens swapped with unigrams */,
+ "full-shuffle":
+ "full-shuffle" /* shuffle all tokens from bigrams and unigrams and create random bigrams */,
} as const;
export type ScrambleMethod =
diff --git a/packages/nameguard-js/README.md b/packages/nameguard-js/README.md
index 159648541..0a5d9208f 100644
--- a/packages/nameguard-js/README.md
+++ b/packages/nameguard-js/README.md
@@ -6,20 +6,20 @@
2. Build the NameGuard SDK.
- ```bash
- cd /path/to/namekit/packages/nameguard-sdk
- pnpm build
- ```
+ ```bash
+ cd /path/to/namekit/packages/nameguard-sdk
+ pnpm build
+ ```
3. Install NameGuard JS dependencies.
- ```bash
- cd /path/to/namekit/packages/nameguard-js
- pnpm install
- ```
+ ```bash
+ cd /path/to/namekit/packages/nameguard-js
+ pnpm install
+ ```
4. Run the tests.
- ```bash
- pnpm test
- ```
+ ```bash
+ pnpm test
+ ```
diff --git a/packages/nameguard-js/src/canonical.ts b/packages/nameguard-js/src/canonical.ts
index 6e5ff80c6..41e2f9147 100644
--- a/packages/nameguard-js/src/canonical.ts
+++ b/packages/nameguard-js/src/canonical.ts
@@ -44,7 +44,7 @@ export function getCanonicalLabel(label: string): string | null {
* Some graphemes have no canonical form because of language-specific writing scripts.
*
* If the input label contains confusable graphemes with no canonical form, or if the canonical label cannot be normalized, the function returns null.
- *
+ *
* @param label - The label to retrieve the normalized canonical label for.
* @returns The normalized canonical label, or `null` if the label contains graphemes with no canonical form or if the canonical label cannot be normalized.
*/
diff --git a/packages/nameguard-js/src/confusables.test.ts b/packages/nameguard-js/src/confusables.test.ts
index 44ce924ba..f1024288b 100644
--- a/packages/nameguard-js/src/confusables.test.ts
+++ b/packages/nameguard-js/src/confusables.test.ts
@@ -57,7 +57,7 @@ describe("confusables", () => {
["👩🏿🚒", true, "🧑🚒"],
["🫱🏻🫲🏿", true, "🤝"],
["🤜🏿", true, "🤜"],
- ['*⃣', false, null],
+ ["*⃣", false, null],
["🇺🇦", false, null],
["🏴", false, null],
["⛹🏽", true, "⛹"],
@@ -75,7 +75,7 @@ describe("confusables", () => {
["f̡̨̢̝̭͓̖͉͐͐́̎̇ͪ̚", true, "f"],
["🫱🏻🫲🏿", true, "🤝"],
["🤜🏿", true, "🤜"],
- ['*⃣', false, null],
+ ["*⃣", false, null],
["🇺🇦", false, null],
["¢", true, "¢"],
["¥", true, "¥"],
diff --git a/packages/nameguard-js/src/data/canonicals.ts b/packages/nameguard-js/src/data/canonicals.ts
index 4b4bf1678..07661a346 100644
--- a/packages/nameguard-js/src/data/canonicals.ts
+++ b/packages/nameguard-js/src/data/canonicals.ts
@@ -12,7 +12,7 @@ export interface GraphemeCanonical {
* Always greater than or equal to 0.
*/
numConfusables: number;
-};
+}
/**
* Map containing graphemes and their canonical forms.
@@ -22,10 +22,13 @@ export let GRAPHEME_CANONICALS: Map | null = null;
export function initializeCanonicals() {
// The json stores the data as a map of grapheme -> [canonicalGrapheme, numConfusables]
- const GRAPHEME_CANONICALS_: { [key: string]: [string, number] } = require("./canonicals.json");
- GRAPHEME_CANONICALS =
- new Map(
- Object.entries(GRAPHEME_CANONICALS_)
- .map(([k, v]) => [k, { canonicalGrapheme: v[0], numConfusables: v[1] }])
- );
+ const GRAPHEME_CANONICALS_: {
+ [key: string]: [string, number];
+ } = require("./canonicals.json");
+ GRAPHEME_CANONICALS = new Map(
+ Object.entries(GRAPHEME_CANONICALS_).map(([k, v]) => [
+ k,
+ { canonicalGrapheme: v[0], numConfusables: v[1] },
+ ]),
+ );
}
diff --git a/packages/nameguard-js/src/graphemes.test.ts b/packages/nameguard-js/src/graphemes.test.ts
index 93b977bb8..7f95e0b6b 100644
--- a/packages/nameguard-js/src/graphemes.test.ts
+++ b/packages/nameguard-js/src/graphemes.test.ts
@@ -20,18 +20,7 @@ const graphemeTestOutputs = [
["🇪🇹"],
["\u{1F469}\u{1F3FF}\u{200D}\u{1F9B2}"],
["👩🏿🎓"],
- [
- "H",
- "e",
- "l",
- "l",
- "o",
- " ",
- "🌍",
- "!",
- " ",
- "👋",
- ],
+ ["H", "e", "l", "l", "o", " ", "🌍", "!", " ", "👋"],
];
describe("countGraphemes", () => {
@@ -92,9 +81,19 @@ describe("splitGraphemes", () => {
["abc", ["a", "b", "c"]],
["a\u200db", ["a", "\u200d", "b"]],
["🇪🇹", ["🇪🇹"]],
- ['\u{0001F469}\u{0001F3FF}\u{0000200D}\u{0001F9B2}', ['\u{0001F469}\u{0001F3FF}\u{0000200D}\u{0001F9B2}']],
- ['\u{0001F469}\u{0001F3FF}\u{0000200D}\u{0000200D}\u{0001F9B2}',
- ['\u{0001F469}\u{0001F3FF}', '\u{0000200D}', '\u{0000200D}', '\u{0001F9B2}']],
+ [
+ "\u{0001F469}\u{0001F3FF}\u{0000200D}\u{0001F9B2}",
+ ["\u{0001F469}\u{0001F3FF}\u{0000200D}\u{0001F9B2}"],
+ ],
+ [
+ "\u{0001F469}\u{0001F3FF}\u{0000200D}\u{0000200D}\u{0001F9B2}",
+ [
+ "\u{0001F469}\u{0001F3FF}",
+ "\u{0000200D}",
+ "\u{0000200D}",
+ "\u{0001F9B2}",
+ ],
+ ],
["6\ufe0f9", ["6", "\ufe0f", "9"]],
["\ufe0f9", ["\ufe0f", "9"]],
["6\ufe0f", ["6", "\ufe0f"]],
diff --git a/packages/nameguard-js/src/impersonation.test.ts b/packages/nameguard-js/src/impersonation.test.ts
index 9b144bf2d..72cc7d509 100644
--- a/packages/nameguard-js/src/impersonation.test.ts
+++ b/packages/nameguard-js/src/impersonation.test.ts
@@ -15,7 +15,9 @@ describe("computeImpersonationEstimate", () => {
expect(computeImpersonationEstimate("vitalìk.eth")).toBe("potential");
expect(computeImpersonationEstimate("٧٣٧.eth")).toBe("unlikely");
expect(computeImpersonationEstimate("poet.base.eth")).toBe("unlikely");
- expect(computeImpersonationEstimate("exampleprimary.cb.id")).toBe("unlikely");
+ expect(computeImpersonationEstimate("exampleprimary.cb.id")).toBe(
+ "unlikely",
+ );
expect(computeImpersonationEstimate("888.eth")).toBe("potential");
expect(computeImpersonationEstimate("❤.eth")).toBe("potential");
expect(computeImpersonationEstimate("٠٠۱.eth")).toBe("potential");
diff --git a/packages/nameguard-js/src/impersonation.ts b/packages/nameguard-js/src/impersonation.ts
index 9be313f29..3102bd358 100644
--- a/packages/nameguard-js/src/impersonation.ts
+++ b/packages/nameguard-js/src/impersonation.ts
@@ -19,7 +19,9 @@ function isLabelhash(label: string): boolean {
* @param name - The name to analyze.
* @returns The impersonation estimate for the given name.
*/
-export function computeImpersonationEstimate(name: string): ImpersonationEstimate {
+export function computeImpersonationEstimate(
+ name: string,
+): ImpersonationEstimate {
// We do not need codepoint splitting here, as we only check for empty names.
// If the name is empty, it has 0 labels and .split would return an array with one empty string.
const labels = name.length === 0 ? [] : name.split(".");
diff --git a/packages/nameguard-js/src/nameguard-js.test.ts b/packages/nameguard-js/src/nameguard-js.test.ts
index afabd7d9e..81c550e80 100644
--- a/packages/nameguard-js/src/nameguard-js.test.ts
+++ b/packages/nameguard-js/src/nameguard-js.test.ts
@@ -7,11 +7,15 @@ const PROVIDER_URI_MAINNET = process.env.PROVIDER_URI_MAINNET;
const PROVIDER_URI_SEPOLIA = process.env.PROVIDER_URI_SEPOLIA;
if (!PROVIDER_URI_MAINNET) {
- console.warn("PROVIDER_URI_MAINNET is not defined. Defaulting to viem's default provider, which may have rate limiting and other performance limitations.");
+ console.warn(
+ "PROVIDER_URI_MAINNET is not defined. Defaulting to viem's default provider, which may have rate limiting and other performance limitations.",
+ );
}
if (!PROVIDER_URI_SEPOLIA) {
- console.warn("PROVIDER_URI_SEPOLIA is not defined. Defaulting to viem's default provider, which may have rate limiting and other performance limitations.");
+ console.warn(
+ "PROVIDER_URI_SEPOLIA is not defined. Defaulting to viem's default provider, which may have rate limiting and other performance limitations.",
+ );
}
/**
@@ -50,16 +54,18 @@ describe("NameGuardJS", () => {
const localNameguard = createClient({
// not a real endpoint, will error if used
nameguardEndpoint: INVALID_NAMEGUARD_API_ENDPOINT,
- publicClient
+ publicClient,
});
expect(
// this should try to fetch from the endpoint
localNameguard.getSecurePrimaryName(
"0xb8c2C29ee19D8307cb7255e1Cd9CbDE883A267d5",
- { returnNameGuardReport: true }
- )
- ).rejects.toThrow("request to http://localhost:1234/secure-primary-name/mainnet/0xb8c2C29ee19D8307cb7255e1Cd9CbDE883A267d5?return_nameguard_report=true failed");
+ { returnNameGuardReport: true },
+ ),
+ ).rejects.toThrow(
+ "request to http://localhost:1234/secure-primary-name/mainnet/0xb8c2C29ee19D8307cb7255e1Cd9CbDE883A267d5?return_nameguard_report=true failed",
+ );
});
it("should throw an error for network mismatch on mainnet", () => {
@@ -73,7 +79,9 @@ describe("NameGuardJS", () => {
network: "mainnet",
publicClient: sepoliaClient,
});
- }).toThrow("Network mismatch: expected mainnet (chain id 1), but got chain id 11155111.");
+ }).toThrow(
+ "Network mismatch: expected mainnet (chain id 1), but got chain id 11155111.",
+ );
});
it("should throw an error for network mismatch on sepolia", () => {
@@ -87,7 +95,9 @@ describe("NameGuardJS", () => {
network: "sepolia",
publicClient: mainnetClient,
});
- }).toThrow("Network mismatch: expected sepolia (chain id 11155111), but got chain id 1.");
+ }).toThrow(
+ "Network mismatch: expected sepolia (chain id 11155111), but got chain id 1.",
+ );
});
it("should not throw an error for correct network on mainnet", () => {
diff --git a/packages/nameguard-js/src/secureprimaryName.test.ts b/packages/nameguard-js/src/secureprimaryName.test.ts
index 92fecfbd6..e0153bd16 100644
--- a/packages/nameguard-js/src/secureprimaryName.test.ts
+++ b/packages/nameguard-js/src/secureprimaryName.test.ts
@@ -16,7 +16,9 @@ interface Test {
const PROVIDER_URI_MAINNET = process.env.PROVIDER_URI_MAINNET;
if (!PROVIDER_URI_MAINNET) {
- console.warn("PROVIDER_URI_MAINNET is not defined. Defaulting to viem's default provider, which may have rate limiting and other performance limitations.");
+ console.warn(
+ "PROVIDER_URI_MAINNET is not defined. Defaulting to viem's default provider, which may have rate limiting and other performance limitations.",
+ );
}
const TEST_TIMEOUT_MS = 30000;
@@ -26,138 +28,142 @@ describe("secure primary name", () => {
initializeData();
});
- it("should detect impersonation", async () => {
- const client = createPublicClient({
- chain: mainnet,
- transport: http(PROVIDER_URI_MAINNET),
- });
- // examples taken from Python Nameguard API tests
- const tests: Test[] = [
- {
- address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
- impersonationEstimate: "unlikely",
- primaryNameStatus: "normalized",
- primaryName: "vitalik.eth",
- displayName: "vitalik.eth",
- },
- {
- address: "0x8Ae0e6dd8eACe27045d9e017C8Cf6dAa9D08C776",
- impersonationEstimate: "potential",
- primaryNameStatus: "normalized",
- primaryName: "vitalìk.eth",
- displayName: "vitalìk.eth",
- },
- {
- address: "0x8B7863d67e1083EE1becbDD277cbBFf1c1CCB631",
- impersonationEstimate: "unlikely",
- primaryNameStatus: "normalized",
- primaryName: "٧٣٧.eth",
- displayName: "٧٣٧.eth",
- },
- {
- address: "0x9d32572997DA4948063E3Fc11c2552Eb82F7208E",
- impersonationEstimate: "unlikely",
- primaryNameStatus: "normalized",
- primaryName: "poet.base.eth",
- displayName: "poet.base.eth",
- },
- {
- address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96046",
- impersonationEstimate: null,
- primaryNameStatus: "no_primary_name",
- primaryName: null,
- displayName: "Unnamed d8da",
- },
- {
- address: "0xfA9A134f997b3d48e122d043E12d04E909b11073",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed fa9a",
- },
- {
- address: "0x76fd9b1B2d8F2cd9Ba06c925506627883F97B97C",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed 76fd",
- },
- {
- address: "0xf537a27F31d7A014c5b8008a0069c61f827fA7A1",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed f537",
- },
- {
- address: "0x0ebDfD75d33c05025074fd7845848D44966AB367",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed 0ebd",
- },
- {
- address: "0xaf738F6C83d7D2C46723b727Ce794F9c79Cc47E6",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed af73",
- },
- {
- address: "0xb281405429C3bc91e52707a21754cDaCeCbB035E",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed b281",
- },
- {
- address: "0x0d756ee0e8C250f88f5e0eDd7C723dc3A0BF75cF",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed 0d75",
- },
- {
- address: "0x7Da3CdE891a76416ec9D1c3354B8EfE550Bd4e20",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed 7da3",
- },
- {
- address: "0xC9f598BC5BB554B6A15A96D19954B041C9FDbF14",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed c9f5",
- },
- {
- address: "0x7c7160A23b32402ad24ED5a617b8a83f434642d4",
- impersonationEstimate: "unlikely",
- primaryNameStatus: "normalized",
- primaryName: "vincξnt.eth",
- displayName: "vincΞnt.eth",
- },
- {
- address: "0x744Ec0A91D420c257aE3eE471B79B1A6a0312E36",
- impersonationEstimate: null,
- primaryNameStatus: "unnormalized",
- primaryName: null,
- displayName: "Unnamed 744e",
- },
- ];
- const promises: Promise[] = [];
- for (const test of tests) {
- promises.push(securePrimaryName(test.address, client));
- }
- const results = await Promise.all(promises);
- for (let i = 0; i < results.length; i++) {
- const r = results[i];
- const test = tests[i];
- expect(r.display_name).toBe(test.displayName);
- expect(r.impersonation_estimate).toBe(test.impersonationEstimate);
- expect(r.primary_name_status).toBe(test.primaryNameStatus);
- expect(r.primary_name).toBe(test.primaryName);
- }
- }, TEST_TIMEOUT_MS);
+ it(
+ "should detect impersonation",
+ async () => {
+ const client = createPublicClient({
+ chain: mainnet,
+ transport: http(PROVIDER_URI_MAINNET),
+ });
+ // examples taken from Python Nameguard API tests
+ const tests: Test[] = [
+ {
+ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
+ impersonationEstimate: "unlikely",
+ primaryNameStatus: "normalized",
+ primaryName: "vitalik.eth",
+ displayName: "vitalik.eth",
+ },
+ {
+ address: "0x8Ae0e6dd8eACe27045d9e017C8Cf6dAa9D08C776",
+ impersonationEstimate: "potential",
+ primaryNameStatus: "normalized",
+ primaryName: "vitalìk.eth",
+ displayName: "vitalìk.eth",
+ },
+ {
+ address: "0x8B7863d67e1083EE1becbDD277cbBFf1c1CCB631",
+ impersonationEstimate: "unlikely",
+ primaryNameStatus: "normalized",
+ primaryName: "٧٣٧.eth",
+ displayName: "٧٣٧.eth",
+ },
+ {
+ address: "0x9d32572997DA4948063E3Fc11c2552Eb82F7208E",
+ impersonationEstimate: "unlikely",
+ primaryNameStatus: "normalized",
+ primaryName: "poet.base.eth",
+ displayName: "poet.base.eth",
+ },
+ {
+ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96046",
+ impersonationEstimate: null,
+ primaryNameStatus: "no_primary_name",
+ primaryName: null,
+ displayName: "Unnamed d8da",
+ },
+ {
+ address: "0xfA9A134f997b3d48e122d043E12d04E909b11073",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed fa9a",
+ },
+ {
+ address: "0x76fd9b1B2d8F2cd9Ba06c925506627883F97B97C",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed 76fd",
+ },
+ {
+ address: "0xf537a27F31d7A014c5b8008a0069c61f827fA7A1",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed f537",
+ },
+ {
+ address: "0x0ebDfD75d33c05025074fd7845848D44966AB367",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed 0ebd",
+ },
+ {
+ address: "0xaf738F6C83d7D2C46723b727Ce794F9c79Cc47E6",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed af73",
+ },
+ {
+ address: "0xb281405429C3bc91e52707a21754cDaCeCbB035E",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed b281",
+ },
+ {
+ address: "0x0d756ee0e8C250f88f5e0eDd7C723dc3A0BF75cF",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed 0d75",
+ },
+ {
+ address: "0x7Da3CdE891a76416ec9D1c3354B8EfE550Bd4e20",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed 7da3",
+ },
+ {
+ address: "0xC9f598BC5BB554B6A15A96D19954B041C9FDbF14",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed c9f5",
+ },
+ {
+ address: "0x7c7160A23b32402ad24ED5a617b8a83f434642d4",
+ impersonationEstimate: "unlikely",
+ primaryNameStatus: "normalized",
+ primaryName: "vincξnt.eth",
+ displayName: "vincΞnt.eth",
+ },
+ {
+ address: "0x744Ec0A91D420c257aE3eE471B79B1A6a0312E36",
+ impersonationEstimate: null,
+ primaryNameStatus: "unnormalized",
+ primaryName: null,
+ displayName: "Unnamed 744e",
+ },
+ ];
+ const promises: Promise[] = [];
+ for (const test of tests) {
+ promises.push(securePrimaryName(test.address, client));
+ }
+ const results = await Promise.all(promises);
+ for (let i = 0; i < results.length; i++) {
+ const r = results[i];
+ const test = tests[i];
+ expect(r.display_name).toBe(test.displayName);
+ expect(r.impersonation_estimate).toBe(test.impersonationEstimate);
+ expect(r.primary_name_status).toBe(test.primaryNameStatus);
+ expect(r.primary_name).toBe(test.primaryName);
+ }
+ },
+ TEST_TIMEOUT_MS,
+ );
});
diff --git a/packages/nameguard-js/src/utils.test.ts b/packages/nameguard-js/src/utils.test.ts
index 476997088..9023c7050 100644
--- a/packages/nameguard-js/src/utils.test.ts
+++ b/packages/nameguard-js/src/utils.test.ts
@@ -1,5 +1,11 @@
import { describe, it, expect, beforeAll } from "vitest";
-import { isEmojiChar, isEmojiSequence, isEmojiZwjSequence, isEmoji, isCombiningChar } from "./utils";
+import {
+ isEmojiChar,
+ isEmojiSequence,
+ isEmojiZwjSequence,
+ isEmoji,
+ isCombiningChar,
+} from "./utils";
import { initializeData } from "./data";
describe("isEmojiChar", () => {
@@ -25,7 +31,7 @@ describe("isEmojiChar", () => {
["\u{0002b736}", false], // Unicode 14 CJK
];
for (const [chr, expected] of cases) {
- expect(isEmojiChar(chr)).toBe(expected)
+ expect(isEmojiChar(chr)).toBe(expected);
}
});
});
@@ -49,7 +55,7 @@ describe("isEmojiSequence", () => {
["🦹", true],
];
for (const [text, expected] of cases) {
- expect(isEmojiSequence(text)).toBe(expected)
+ expect(isEmojiSequence(text)).toBe(expected);
}
});
});
@@ -65,11 +71,17 @@ describe("isEmojiZwjSequence", () => {
["a", false],
["\u2705", false], // single emoji
["🇪🇹", false], // RGI
- ["\u{0001F469}\u{0001F3FB}\u{0000200D}\u{0001F91D}\u{0000200D}\u{0001F469}\u{0001F3FC}", true],
- ["\u{0001F469}\u{0001F3FB}\u{0000200D}\u{0001F91D}\u{0000200D}\u{0000200D}\u{0001F469}\u{0001F3FC}", false], // 2 ZWJs
+ [
+ "\u{0001F469}\u{0001F3FB}\u{0000200D}\u{0001F91D}\u{0000200D}\u{0001F469}\u{0001F3FC}",
+ true,
+ ],
+ [
+ "\u{0001F469}\u{0001F3FB}\u{0000200D}\u{0001F91D}\u{0000200D}\u{0000200D}\u{0001F469}\u{0001F3FC}",
+ false,
+ ], // 2 ZWJs
];
for (const [text, expected] of cases) {
- expect(isEmojiZwjSequence(text)).toBe(expected)
+ expect(isEmojiZwjSequence(text)).toBe(expected);
}
});
});
@@ -90,7 +102,7 @@ describe("isEmoji", () => {
["🇵🇱🇺🇦", false],
];
for (const [text, expected] of cases) {
- expect(isEmoji(text)).toBe(expected)
+ expect(isEmoji(text)).toBe(expected);
}
});
});
@@ -108,7 +120,7 @@ describe("isCombiningChar", () => {
"\u{055b7a}",
"\u{06ac1e}",
"\u{063027}",
- "\u{057c5c}"
+ "\u{057c5c}",
];
const combining = [
"\u{000345}",
@@ -120,7 +132,7 @@ describe("isCombiningChar", () => {
"\u{01e133}",
"\u{000e3a}",
"\u{000d3b}",
- "\u{002dfa}"
+ "\u{002dfa}",
];
for (const chr of nonCombining) {
expect(isCombiningChar(chr)).toBe(false);
diff --git a/packages/nameguard-js/src/utils.ts b/packages/nameguard-js/src/utils.ts
index 5a307708e..2a8ee037b 100644
--- a/packages/nameguard-js/src/utils.ts
+++ b/packages/nameguard-js/src/utils.ts
@@ -1,10 +1,15 @@
import { charCount } from "@namehash/ens-utils";
-import { EMOJI_SEQUENCES, EMOJI_ZWJ_SEQUENCES, EMOJI_BLOCK_STARTS, EMOJI_BLOCK_IS_EMOJI } from "./data/unicode";
+import {
+ EMOJI_SEQUENCES,
+ EMOJI_ZWJ_SEQUENCES,
+ EMOJI_BLOCK_STARTS,
+ EMOJI_BLOCK_IS_EMOJI,
+} from "./data/unicode";
import { COMBINING } from "./data/combining";
/**
* Checks if the given string is a single character.
- *
+ *
* @param text - The string to check.
* @returns `true` if the string is a single character, `false` otherwise.
*/
@@ -14,10 +19,10 @@ export function isCharacter(text: string): boolean {
/**
* Checks if the given grapheme is an emoji sequence.
- *
+ *
* An emoji sequence is a specific combination of code points that represent a single emoji.
* This function checks if the provided grapheme is present in the predefined set of emoji sequences.
- *
+ *
* The emoji sequences are based on Unicode 15.1.0 standards.
*
* @param grapheme - The grapheme to check.
@@ -29,11 +34,11 @@ export function isEmojiSequence(grapheme: string): boolean {
/**
* Checks if the given grapheme is an emoji Zero Width Joiner (ZWJ) sequence.
- *
- * An emoji ZWJ sequence is a specific combination of emoji characters joined by
- * Zero Width Joiner (U+200D) characters to create a single emoji. This function
+ *
+ * An emoji ZWJ sequence is a specific combination of emoji characters joined by
+ * Zero Width Joiner (U+200D) characters to create a single emoji. This function
* checks if the provided grapheme is present in the predefined set of emoji ZWJ sequences.
- *
+ *
* The emoji ZWJ sequences are based on Unicode 15.1.0 standards.
*
* @param grapheme - The grapheme to check.
@@ -45,12 +50,12 @@ export function isEmojiZwjSequence(grapheme: string): boolean {
/**
* Checks if the given character is an emoji character.
- *
+ *
* This function determines if a single Unicode character is an emoji by checking
* its code point against predefined emoji blocks.
- *
+ *
* This function is based on the Unicode 15.1.0 standards.
- *
+ *
* Returns `false` for multi-character strings.
*
* @param char - The character to check.
@@ -73,10 +78,10 @@ export function isEmojiChar(char: string): boolean {
/**
* Checks if the given grapheme is an emoji.
- *
+ *
* This function combines the checks from isEmojiSequence, isEmojiZwjSequence, and isEmojiChar
* to determine if a grapheme is any type of emoji recognized by Unicode standards.
- *
+ *
* The function is based on Unicode 15.1.0 standards and covers:
* - Emoji sequences (including emoji modifier sequences and emoji flag sequences)
* - Emoji ZWJ (Zero Width Joiner) sequences
@@ -87,7 +92,11 @@ export function isEmojiChar(char: string): boolean {
*/
export function isEmoji(grapheme: string): boolean {
- return isEmojiSequence(grapheme) || isEmojiZwjSequence(grapheme) || isEmojiChar(grapheme);
+ return (
+ isEmojiSequence(grapheme) ||
+ isEmojiZwjSequence(grapheme) ||
+ isEmojiChar(grapheme)
+ );
}
/**
diff --git a/packages/nameguard-sdk/src/index.test.ts b/packages/nameguard-sdk/src/index.test.ts
index b55fadf8b..efaaff50d 100644
--- a/packages/nameguard-sdk/src/index.test.ts
+++ b/packages/nameguard-sdk/src/index.test.ts
@@ -29,7 +29,10 @@ describe("inspectName", () => {
describe("bulkInspectNames", () => {
it("should fetch the consolidated NameGuard reports of multiple names", async () => {
- const data = await nameguard.bulkInspectNames(["notrab.eth", "vitalik.eth"]);
+ const data = await nameguard.bulkInspectNames([
+ "notrab.eth",
+ "vitalik.eth",
+ ]);
expect(data.results?.length).toBe(2);
expect(data.results?.[0].inspected).toBe(true);
@@ -38,22 +41,24 @@ describe("bulkInspectNames", () => {
describe("inspectNamehash", () => {
it("should return the name for a valid namehash", async () => {
- const data = await nameguard.inspectNamehash("0xEe6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835");
+ const data = await nameguard.inspectNamehash(
+ "0xEe6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
+ );
expect(data.name).toBe("vitalik.eth");
});
it("should throw an error if invalid namehash provided", async () => {
- await expect(nameguard.inspectNamehash("0x1234567890abcdef")).rejects.toThrow(
- "Invalid Keccak256 hash format for namehash."
- );
+ await expect(
+ nameguard.inspectNamehash("0x1234567890abcdef"),
+ ).rejects.toThrow("Invalid Keccak256 hash format for namehash.");
});
});
describe("inspectLabelhash", () => {
it("should throw an error if invalid labelhash provided", async () => {
- await expect(nameguard.inspectLabelhash("0x1234567890abcdef")).rejects.toThrow(
- "Invalid Keccak256 hash format for labelhash."
- );
+ await expect(
+ nameguard.inspectLabelhash("0x1234567890abcdef"),
+ ).rejects.toThrow("Invalid Keccak256 hash format for labelhash.");
});
});
@@ -226,7 +231,7 @@ describe("fakeEthNameCheck", () => {
const data = await nameguard.fakeEthNameCheck(
"0x495f947276749ce646f68ac8c248420045cb7b5e",
"61995921128521442959106650131462633744885269624153038309795231243542768648193",
- { title: "nick.eth" }
+ { title: "nick.eth" },
);
expect(data.status).toBe("impersonated_eth_name");
diff --git a/packages/nameguard-sdk/src/index.ts b/packages/nameguard-sdk/src/index.ts
index 5d0817796..5442f14c3 100644
--- a/packages/nameguard-sdk/src/index.ts
+++ b/packages/nameguard-sdk/src/index.ts
@@ -518,8 +518,8 @@ export class NameGuard {
}: NameGuardOptions = {}) {
this.nameguardEndpoint = new URL(nameguardEndpoint);
// Ensure the endpoint ends with a trailing slash
- if (!this.nameguardEndpoint.pathname.endsWith('/')) {
- this.nameguardEndpoint.pathname += '/';
+ if (!this.nameguardEndpoint.pathname.endsWith("/")) {
+ this.nameguardEndpoint.pathname += "/";
}
this.network = network;
diff --git a/packages/namekit-react/src/components/TruncatedText.tsx b/packages/namekit-react/src/components/TruncatedText.tsx
index da9e517b9..f625cfcd8 100644
--- a/packages/namekit-react/src/components/TruncatedText.tsx
+++ b/packages/namekit-react/src/components/TruncatedText.tsx
@@ -60,12 +60,12 @@ export const TruncatedText = ({
text,
]);
- const getTextElm = (
- classes: string,
- maxWidth?: number,
- ): JSX.Element => {
+ const getTextElm = (classes: string, maxWidth?: number): JSX.Element => {
return (
-
+
{text}
);
@@ -74,21 +74,22 @@ export const TruncatedText = ({
const textDefaultClasses = "nk-truncate";
const renderText = (): JSX.Element => {
- return getTextElm(cc([textStylingClasses, textDefaultClasses]), maxDisplayWidth);
+ return getTextElm(
+ cc([textStylingClasses, textDefaultClasses]),
+ maxDisplayWidth,
+ );
};
const renderTextWithATooltip = (): JSX.Element => {
return (
-
-
- {/*
+ {/*
This invisible div is used to measure the true width of `text` as it
would be rendered in the DOM.
*/}
@@ -118,10 +119,9 @@ export const TruncatedText = ({
>
) : (
-
// `text` doesn't overflow `maxDisplayWidth`, therefore we can render
// it once without any truncation
-
+
renderText()
)}