diff --git a/.changeset/fast-bats-train.md b/.changeset/fast-bats-train.md
new file mode 100644
index 000000000..89d39b3cb
--- /dev/null
+++ b/.changeset/fast-bats-train.md
@@ -0,0 +1,9 @@
+---
+"@ensnode/ensrainbow-sdk": minor
+"ensindexer": minor
+"@docs/ensnode": minor
+"ensadmin": minor
+"ensapi": minor
+---
+
+Altered code references accordingly to the updated `EnsIndexerPublicConfig` data model.
diff --git a/.changeset/lovely-teeth-hunt.md b/.changeset/lovely-teeth-hunt.md
new file mode 100644
index 000000000..588fd8e99
--- /dev/null
+++ b/.changeset/lovely-teeth-hunt.md
@@ -0,0 +1,5 @@
+---
+"@ensnode/ensnode-sdk": minor
+---
+
+Added `ensRainbowPublicConfig` field to `EnsIndexerPublicConfig`.
diff --git a/apps/ensadmin/src/app/mock/config-api.mock.ts b/apps/ensadmin/src/app/mock/config-api.mock.ts
index 8edbde34c..54d0244f9 100644
--- a/apps/ensadmin/src/app/mock/config-api.mock.ts
+++ b/apps/ensadmin/src/app/mock/config-api.mock.ts
@@ -7,6 +7,14 @@ export const ensIndexerPublicConfig = deserializeENSIndexerPublicConfig({
},
indexedChainIds: [1, 8453, 59144, 10, 42161, 534352, 567],
databaseSchemaName: "alphaSchema0.34.0",
+ ensRainbowPublicConfig: {
+ version: "0.34.0",
+ labelSet: {
+ labelSetId: "subgraph",
+ highestLabelSetVersion: 0,
+ },
+ recordsCount: 100,
+ },
isSubgraphCompatible: false,
namespace: "mainnet",
plugins: [
@@ -23,8 +31,6 @@ export const ensIndexerPublicConfig = deserializeENSIndexerPublicConfig({
ponder: "0.11.43",
ensIndexer: "0.35.0",
ensDb: "0.35.0",
- ensRainbow: "0.34.0",
- ensRainbowSchema: 3,
ensNormalize: "1.11.1",
},
});
diff --git a/apps/ensadmin/src/app/mock/config-info/data.json b/apps/ensadmin/src/app/mock/config-info/data.json
index f8d9f90fb..fd9319ecb 100644
--- a/apps/ensadmin/src/app/mock/config-info/data.json
+++ b/apps/ensadmin/src/app/mock/config-info/data.json
@@ -12,6 +12,14 @@
},
"indexedChainIds": [1, 8453, 59144, 10, 42161, 534352, 567],
"databaseSchemaName": "alphaSchema0.34.0",
+ "ensRainbowPublicConfig": {
+ "version": "0.34.0",
+ "labelSet": {
+ "labelSetId": "subgraph",
+ "highestLabelSetVersion": 0
+ },
+ "recordsCount": 100
+ },
"isSubgraphCompatible": false,
"namespace": "mainnet",
"plugins": [
@@ -28,9 +36,7 @@
"ponder": "0.11.43",
"ensDb": "0.35.0",
"ensIndexer": "0.35.0",
- "ensNormalize": "1.11.1",
- "ensRainbow": "0.34.0",
- "ensRainbowSchema": 3
+ "ensNormalize": "1.11.1"
}
}
},
@@ -50,9 +56,7 @@
"ponder": "0.11.43",
"ensDb": "0.35.0",
"ensIndexer": "0.35.0",
- "ensNormalize": "1.11.1",
- "ensRainbow": "0.34.0",
- "ensRainbowSchema": 3
+ "ensNormalize": "1.11.1"
},
"indexedChainIds": [11155111, 84532, 59141, 11155420, 421614, 534351],
"namespace": "sepolia",
@@ -65,6 +69,14 @@
"registrars"
],
"databaseSchemaName": "alphaSepoliaSchema0.34.0",
+ "ensRainbowPublicConfig": {
+ "version": "0.34.0",
+ "labelSet": {
+ "labelSetId": "subgraph",
+ "highestLabelSetVersion": 0
+ },
+ "recordsCount": 100
+ },
"isSubgraphCompatible": false
}
},
@@ -84,14 +96,20 @@
"ponder": "0.11.43",
"ensDb": "0.35.0",
"ensIndexer": "0.35.0",
- "ensNormalize": "1.11.1",
- "ensRainbow": "0.34.0",
- "ensRainbowSchema": 3
+ "ensNormalize": "1.11.1"
},
"indexedChainIds": [1],
"namespace": "mainnet",
"plugins": ["subgraph"],
"databaseSchemaName": "mainnetSchema0.34.0",
+ "ensRainbowPublicConfig": {
+ "version": "0.34.0",
+ "labelSet": {
+ "labelSetId": "subgraph",
+ "highestLabelSetVersion": 0
+ },
+ "recordsCount": 100
+ },
"isSubgraphCompatible": true
}
},
@@ -111,14 +129,20 @@
"ponder": "0.11.43",
"ensDb": "0.35.0",
"ensIndexer": "0.35.0",
- "ensNormalize": "1.11.1",
- "ensRainbow": "0.34.0",
- "ensRainbowSchema": 3
+ "ensNormalize": "1.11.1"
},
"indexedChainIds": [11155111],
"namespace": "sepolia",
"plugins": ["subgraph"],
"databaseSchemaName": "sepoliaSchema0.34.0",
+ "ensRainbowPublicConfig": {
+ "version": "0.34.0",
+ "labelSet": {
+ "labelSetId": "subgraph",
+ "highestLabelSetVersion": 0
+ },
+ "recordsCount": 100
+ },
"isSubgraphCompatible": true
}
},
@@ -138,14 +162,20 @@
"ponder": "",
"ensDb": "",
"ensIndexer": "",
- "ensNormalize": "",
- "ensRainbow": "",
- "ensRainbowSchema": -1
+ "ensNormalize": ""
},
"indexedChainIds": [11155111],
"namespace": "sepolia",
"plugins": ["subgraph"],
"databaseSchemaName": "DeserializationSchema0.34.0",
+ "ensRainbowPublicConfig": {
+ "version": "",
+ "labelSet": {
+ "labelSetId": "",
+ "highestLabelSetVersion": -1
+ },
+ "recordsCount": -1
+ },
"isSubgraphCompatible": true
}
}
diff --git a/apps/ensadmin/src/app/mock/config-info/page.tsx b/apps/ensadmin/src/app/mock/config-info/page.tsx
index a5700d460..be3d5e14c 100644
--- a/apps/ensadmin/src/app/mock/config-info/page.tsx
+++ b/apps/ensadmin/src/app/mock/config-info/page.tsx
@@ -13,7 +13,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
import mockDataJson from "./data.json" with { type: "json" };
-const mockConfigData = mockDataJson as Record;
+const mockConfigData = mockDataJson as unknown as Record;
type LoadingVariant = "Loading" | "Loading Error";
type ConfigVariant = keyof typeof mockConfigData | LoadingVariant;
diff --git a/apps/ensadmin/src/components/connection/cards/ensnode-info.tsx b/apps/ensadmin/src/components/connection/cards/ensnode-info.tsx
index 29210bb11..f33e928db 100644
--- a/apps/ensadmin/src/components/connection/cards/ensnode-info.tsx
+++ b/apps/ensadmin/src/components/connection/cards/ensnode-info.tsx
@@ -507,7 +507,7 @@ function ENSNodeConfigCardContent({
{ensIndexerPublicConfig.plugins.map((plugin) => (
{plugin}
@@ -561,7 +561,7 @@ function ENSNodeConfigCardContent({
icon={}
version={
- v{ensIndexerPublicConfig.versionInfo.ensRainbow}
+ v{ensIndexerPublicConfig.ensRainbowPublicConfig.version}
}
docsLink={new URL("https://ensnode.io/ensrainbow/")}
@@ -571,8 +571,8 @@ function ENSNodeConfigCardContent({
label="Server LabelSet"
value={
- {ensIndexerPublicConfig.labelSet.labelSetId}:
- {ensIndexerPublicConfig.labelSet.labelSetVersion}
+ {ensIndexerPublicConfig.ensRainbowPublicConfig.labelSet.labelSetId}:
+ {ensIndexerPublicConfig.ensRainbowPublicConfig.labelSet.highestLabelSetVersion}
}
additionalInfo={
@@ -586,6 +586,25 @@ function ENSNodeConfigCardContent({
}
/>
+
+
+ {ensIndexerPublicConfig.ensRainbowPublicConfig.recordsCount.toLocaleString()}
+
+ }
+ additionalInfo={
+
+ The total number of Rainbow Records.{" "}
+
+ Learn more.
+
+
+ }
+ />
diff --git a/apps/ensapi/src/config/config.schema.test.ts b/apps/ensapi/src/config/config.schema.test.ts
index f0905c285..407effcb2 100644
--- a/apps/ensapi/src/config/config.schema.test.ts
+++ b/apps/ensapi/src/config/config.schema.test.ts
@@ -32,6 +32,11 @@ const BASE_ENV = {
const ENSINDEXER_PUBLIC_CONFIG = {
namespace: "mainnet",
databaseSchemaName: "ensapi",
+ ensRainbowPublicConfig: {
+ version: packageJson.version,
+ labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
+ recordsCount: 100,
+ },
indexedChainIds: new Set([1]),
isSubgraphCompatible: false,
labelSet: { labelSetId: "subgraph", labelSetVersion: 0 },
@@ -39,8 +44,6 @@ const ENSINDEXER_PUBLIC_CONFIG = {
versionInfo: {
ensDb: packageJson.version,
ensIndexer: packageJson.version,
- ensRainbow: packageJson.version,
- ensRainbowSchema: 1,
ensNormalize: "1.1.1",
nodejs: "1.1.1",
ponder: "1.1.1",
diff --git a/apps/ensapi/src/config/validations.ts b/apps/ensapi/src/config/validations.ts
index 2b06e1e3e..6705ef792 100644
--- a/apps/ensapi/src/config/validations.ts
+++ b/apps/ensapi/src/config/validations.ts
@@ -34,12 +34,12 @@ export function invariant_ensIndexerPublicConfigVersionInfo(
}
// Invariant: ENSApi & ENSRainbow must match version numbers
- if (ensIndexerPublicConfig.versionInfo.ensRainbow !== packageJson.version) {
+ if (ensIndexerPublicConfig.ensRainbowPublicConfig.version !== packageJson.version) {
ctx.issues.push({
code: "custom",
- path: ["ensIndexerPublicConfig.versionInfo.ensRainbow"],
- input: ensIndexerPublicConfig.versionInfo.ensRainbow,
- message: `Version Mismatch: ENSRainbow@${ensIndexerPublicConfig.versionInfo.ensRainbow} !== ENSApi@${packageJson.version}`,
+ path: ["ensIndexerPublicConfig.ensRainbowPublicConfig.version"],
+ input: ensIndexerPublicConfig.ensRainbowPublicConfig.version,
+ message: `Version Mismatch: ENSRainbow@${ensIndexerPublicConfig.ensRainbowPublicConfig.version} !== ENSApi@${packageJson.version}`,
});
}
}
diff --git a/apps/ensindexer/src/config/public.ts b/apps/ensindexer/src/config/public.ts
index 4e533f2e9..b80fa9f07 100644
--- a/apps/ensindexer/src/config/public.ts
+++ b/apps/ensindexer/src/config/public.ts
@@ -1,22 +1,29 @@
-import type { ENSIndexerPublicConfig } from "@ensnode/ensnode-sdk";
+import type { EnsIndexerPublicConfig } from "@ensnode/ensnode-sdk";
+import { getENSRainbowApiClient } from "@/lib/ensraibow-api-client";
import { getENSIndexerVersionInfo } from "@/lib/version-info";
-import type { ENSIndexerConfig } from "./types";
+import type { EnsIndexerConfig } from "./types";
+
+const ensRainbowApiClient = getENSRainbowApiClient();
/**
- * Build a public version of {@link ENSIndexerConfig}.
+ * Build a public version of {@link EnsIndexerConfig}.
*
- * Note: some values required to build an {@link ENSIndexerPublicConfig} object
+ * Note: some values required to build an {@link EnsIndexerPublicConfig} object
* have to fetched over the network.
*/
export async function buildENSIndexerPublicConfig(
- config: ENSIndexerConfig,
-): Promise {
- const versionInfo = await getENSIndexerVersionInfo();
+ config: EnsIndexerConfig,
+): Promise {
+ const [versionInfo, ensRainbowPublicConfig] = await Promise.all([
+ getENSIndexerVersionInfo(),
+ ensRainbowApiClient.config(),
+ ]);
return {
databaseSchemaName: config.databaseSchemaName,
+ ensRainbowPublicConfig,
labelSet: config.labelSet,
indexedChainIds: config.indexedChainIds,
isSubgraphCompatible: config.isSubgraphCompatible,
diff --git a/apps/ensindexer/src/lib/ensdb-client/ensdb-client.mock.ts b/apps/ensindexer/src/lib/ensdb-client/ensdb-client.mock.ts
index 4b7054aa6..7387cc19f 100644
--- a/apps/ensindexer/src/lib/ensdb-client/ensdb-client.mock.ts
+++ b/apps/ensindexer/src/lib/ensdb-client/ensdb-client.mock.ts
@@ -25,6 +25,14 @@ export const databaseSchemaName = "public";
export const publicConfig = {
databaseSchemaName,
+ ensRainbowPublicConfig: {
+ version: "0.32.0",
+ labelSet: {
+ labelSetId: "subgraph",
+ highestLabelSetVersion: 0,
+ },
+ recordsCount: 100,
+ },
labelSet: {
labelSetId: "subgraph",
labelSetVersion: 0,
@@ -39,8 +47,6 @@ export const publicConfig = {
ensDb: "0.32.0",
ensIndexer: "0.32.0",
ensNormalize: "1.11.1",
- ensRainbow: "0.32.0",
- ensRainbowSchema: 2,
},
} satisfies EnsIndexerPublicConfig;
diff --git a/apps/ensindexer/src/lib/version-info.ts b/apps/ensindexer/src/lib/version-info.ts
index aa1efb8d7..55bd8b65f 100644
--- a/apps/ensindexer/src/lib/version-info.ts
+++ b/apps/ensindexer/src/lib/version-info.ts
@@ -9,8 +9,6 @@ import { prettifyError } from "zod/v4";
import type { ENSIndexerVersionInfo, SerializedENSIndexerVersionInfo } from "@ensnode/ensnode-sdk";
import { makeENSIndexerVersionInfoSchema } from "@ensnode/ensnode-sdk/internal";
-import { getENSRainbowApiClient } from "@/lib/ensraibow-api-client";
-
/**
* Get NPM package version.
*
@@ -109,12 +107,6 @@ function getPackageVersionFromPnpmStore(pnpmDir: string, packageName: string): s
* Get complete {@link ENSIndexerVersionInfo} for ENSIndexer app.
*/
export async function getENSIndexerVersionInfo(): Promise {
- const ensRainbowApiClient = getENSRainbowApiClient();
- const { versionInfo: ensRainbowVersionInfo } = await ensRainbowApiClient.version();
-
- // ENSRainbow version (fetched dynamically from the connected ENSRainbow service instance)
- const ensRainbowSchema = ensRainbowVersionInfo.dbSchemaVersion;
-
// ENSIndexer version
const ensIndexerVersion = packageJson.version;
@@ -125,13 +117,11 @@ export async function getENSIndexerVersionInfo(): Promise
// parse unvalidated version info
const schema = makeENSIndexerVersionInfoSchema();
const parsed = schema.safeParse({
- ensRainbow: ensRainbowVersionInfo.version,
nodejs: process.versions.node,
ponder: getPackageVersion("ponder"),
ensDb: ensDbVersion,
ensIndexer: ensIndexerVersion,
ensNormalize: getPackageVersion("@adraffy/ens-normalize"),
- ensRainbowSchema,
} satisfies SerializedENSIndexerVersionInfo);
if (parsed.error) {
diff --git a/docs/ensnode.io/src/content/docs/docs/usage/api.mdx b/docs/ensnode.io/src/content/docs/docs/usage/api.mdx
index 52196100c..4eba56e49 100644
--- a/docs/ensnode.io/src/content/docs/docs/usage/api.mdx
+++ b/docs/ensnode.io/src/content/docs/docs/usage/api.mdx
@@ -86,7 +86,7 @@ The response includes several important configuration categories:
functionality
- **Plugins**: Activated plugins
- **ENSIndexer Version Information**: Node.js version, Ponder framework version,
- ENSRainbow version and schema details, ENSDb version, ENSIndexer version, [ENS Normalize version](https://www.npmjs.com/package/@adraffy/ens-normalize)
+ ENSRainbow public config, ENSDb version, ENSIndexer version, [ENS Normalize version](https://www.npmjs.com/package/@adraffy/ens-normalize)
### Example response
@@ -118,12 +118,15 @@ The response includes several important configuration categories:
],
"versionInfo": {
"nodejs": "22.18.0",
- "ponder": "0.11.43",
- "ensDb": "0.35.0",
- "ensIndexer": "0.35.0",
+ "ponder": "0.16.1",
+ "ensDb": "1.5.1",
+ "ensIndexer": "1.5.1",
"ensNormalize": "1.11.1",
- "ensRainbow": "0.34.0",
- "ensRainbowSchema": 3
+ "ensRainbowPublicConfig": {
+ "version": "1.5.1",
+ "labelSet": { "labelSetId": "subgraph", "highestLabelSetVersion": 0 },
+ "recordsCount": 133856894
+ }
}
}
```
diff --git a/packages/ensnode-sdk/src/ensapi/client.test.ts b/packages/ensnode-sdk/src/ensapi/client.test.ts
index 1c3c6dedc..f53ea9ce0 100644
--- a/packages/ensnode-sdk/src/ensapi/client.test.ts
+++ b/packages/ensnode-sdk/src/ensapi/client.test.ts
@@ -64,6 +64,11 @@ const EXAMPLE_CONFIG_RESPONSE = {
reason: "no-api-key",
},
ensIndexerPublicConfig: {
+ ensRainbowPublicConfig: {
+ version: "0.31.0",
+ labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
+ recordsCount: 100,
+ },
labelSet: {
labelSetId: "subgraph",
labelSetVersion: 0,
@@ -86,8 +91,6 @@ const EXAMPLE_CONFIG_RESPONSE = {
ensDb: "0.32.0",
ensIndexer: "0.32.0",
ensNormalize: "1.11.1",
- ensRainbow: "0.31.0",
- ensRainbowSchema: 2,
},
},
} satisfies SerializedEnsApiPublicConfig;
diff --git a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts
index fb424aa60..ae15afb0c 100644
--- a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts
+++ b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts
@@ -5,6 +5,7 @@ import { ENSNamespaceIds } from "@ensnode/datasources";
import { PluginName } from "../../ensindexer/config/types";
import { deserializeEnsApiPublicConfig } from "./deserialize";
import { serializeEnsApiPublicConfig } from "./serialize";
+import type { SerializedEnsApiPublicConfig } from "./serialized-types";
import type { EnsApiPublicConfig } from "./types";
const MOCK_ENSAPI_PUBLIC_CONFIG = {
@@ -16,6 +17,11 @@ const MOCK_ENSAPI_PUBLIC_CONFIG = {
ensIndexerPublicConfig: {
namespace: ENSNamespaceIds.Mainnet,
databaseSchemaName: "ensapi",
+ ensRainbowPublicConfig: {
+ version: "0.36.0",
+ labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
+ recordsCount: 100,
+ },
indexedChainIds: new Set([1]),
isSubgraphCompatible: false,
labelSet: { labelSetId: "subgraph", labelSetVersion: 0 },
@@ -23,8 +29,6 @@ const MOCK_ENSAPI_PUBLIC_CONFIG = {
versionInfo: {
ensDb: "0.36.0",
ensIndexer: "0.36.0",
- ensRainbow: "0.36.0",
- ensRainbowSchema: 1,
ensNormalize: "1.1.1",
nodejs: "20.0.0",
ponder: "0.5.0",
@@ -48,6 +52,11 @@ describe("ENSApi Config Serialization/Deserialization", () => {
ensIndexerPublicConfig: {
namespace: ENSNamespaceIds.Mainnet,
databaseSchemaName: "ensapi",
+ ensRainbowPublicConfig: {
+ version: "0.36.0",
+ labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
+ recordsCount: 100,
+ },
indexedChainIds: [1],
isSubgraphCompatible: false,
labelSet: { labelSetId: "subgraph", labelSetVersion: 0 },
@@ -55,14 +64,12 @@ describe("ENSApi Config Serialization/Deserialization", () => {
versionInfo: {
ensDb: "0.36.0",
ensIndexer: "0.36.0",
- ensRainbow: "0.36.0",
- ensRainbowSchema: 1,
ensNormalize: "1.1.1",
nodejs: "20.0.0",
ponder: "0.5.0",
},
},
- });
+ } satisfies SerializedEnsApiPublicConfig);
});
});
diff --git a/packages/ensnode-sdk/src/ensindexer/client.mock.ts b/packages/ensnode-sdk/src/ensindexer/client.mock.ts
index 5676b7723..84d0ceaa2 100644
--- a/packages/ensnode-sdk/src/ensindexer/client.mock.ts
+++ b/packages/ensnode-sdk/src/ensindexer/client.mock.ts
@@ -14,6 +14,14 @@ export const configResponseMock = {
},
indexedChainIds: [1, 8453, 59144, 10, 42161, 534352],
databaseSchemaName: "alphaSchema0.31.0",
+ ensRainbowPublicConfig: {
+ version: "0.31.0",
+ labelSet: {
+ labelSetId: "subgraph",
+ highestLabelSetVersion: 0,
+ },
+ recordsCount: 100,
+ },
isSubgraphCompatible: false,
namespace: "mainnet",
plugins: [
@@ -30,8 +38,6 @@ export const configResponseMock = {
ensDb: "0.32.0",
ensIndexer: "0.32.0",
ensNormalize: "1.11.1",
- ensRainbow: "0.31.0",
- ensRainbowSchema: 2,
},
} satisfies SerializedEnsIndexerConfigResponse;
diff --git a/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts b/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts
index 337af0909..2258e2b8d 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts
@@ -2,7 +2,7 @@ import type { EnsIndexerPublicConfig } from "./types";
export type EnsIndexerPublicConfigCompatibilityCheck = Omit<
EnsIndexerPublicConfig,
- "databaseSchemaName" | "versionInfo"
+ "databaseSchemaName" | "ensRainbowPublicConfig" | "versionInfo"
>;
/**
diff --git a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts
index 298dbfbd0..79b1c82c0 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts
@@ -11,6 +11,11 @@ describe("ENSIndexer: Config", () => {
// arrange
const config = {
databaseSchemaName: "public",
+ ensRainbowPublicConfig: {
+ version: "0.32.0",
+ labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
+ recordsCount: 100,
+ },
labelSet: {
labelSetId: "subgraph",
labelSetVersion: 0,
@@ -25,8 +30,6 @@ describe("ENSIndexer: Config", () => {
ensDb: "0.32.0",
ensIndexer: "0.32.0",
ensNormalize: "1.11.1",
- ensRainbow: "0.32.0",
- ensRainbowSchema: 2,
},
} satisfies EnsIndexerPublicConfig;
@@ -51,6 +54,11 @@ describe("ENSIndexer: Config", () => {
describe("deserialization", () => {
const correctSerializedConfig = {
databaseSchemaName: "public",
+ ensRainbowPublicConfig: {
+ version: "0.32.0",
+ labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 },
+ recordsCount: 100,
+ },
labelSet: {
labelSetId: "subgraph",
labelSetVersion: 0,
@@ -65,8 +73,6 @@ describe("ENSIndexer: Config", () => {
ensDb: "0.32.0",
ensIndexer: "0.32.0",
ensNormalize: "1.11.1",
- ensRainbow: "0.32.0",
- ensRainbowSchema: 2,
},
} satisfies SerializedEnsIndexerPublicConfig;
diff --git a/packages/ensnode-sdk/src/ensindexer/config/labelset-utils.ts b/packages/ensnode-sdk/src/ensindexer/config/labelset-utils.ts
index 01ab16613..5661d211c 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/labelset-utils.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/labelset-utils.ts
@@ -4,7 +4,10 @@ import type {
LabelSetId,
LabelSetVersion,
} from "../../ensrainbow";
-import { makeLabelSetIdSchema, makeLabelSetVersionSchema } from "./zod-schemas";
+import {
+ makeLabelSetIdSchema,
+ makeLabelSetVersionSchema,
+} from "../../ensrainbow/zod-schemas/config";
/**
* Builds a valid LabelSetId from a string.
diff --git a/packages/ensnode-sdk/src/ensindexer/config/serialize.ts b/packages/ensnode-sdk/src/ensindexer/config/serialize.ts
index a4e27c5e6..a24838803 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/serialize.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/serialize.ts
@@ -19,20 +19,22 @@ export function serializeEnsIndexerPublicConfig(
config: EnsIndexerPublicConfig,
): SerializedEnsIndexerPublicConfig {
const {
- labelSet,
- indexedChainIds,
databaseSchemaName,
+ ensRainbowPublicConfig,
+ indexedChainIds,
isSubgraphCompatible,
+ labelSet,
namespace,
plugins,
versionInfo,
} = config;
return {
- labelSet,
- indexedChainIds: serializeIndexedChainIds(indexedChainIds),
databaseSchemaName,
+ ensRainbowPublicConfig,
+ indexedChainIds: serializeIndexedChainIds(indexedChainIds),
isSubgraphCompatible,
+ labelSet,
namespace,
plugins,
versionInfo,
diff --git a/packages/ensnode-sdk/src/ensindexer/config/types.ts b/packages/ensnode-sdk/src/ensindexer/config/types.ts
index f3067937d..afc70c50d 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/types.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/types.ts
@@ -1,6 +1,6 @@
import type { ENSNamespaceId } from "@ensnode/datasources";
-import type { EnsRainbowClientLabelSet } from "../../ensrainbow";
+import type { EnsRainbowClientLabelSet, EnsRainbowPublicConfig } from "../../ensrainbow";
import type { ChainId } from "../../shared/types";
/**
@@ -50,18 +50,6 @@ export interface EnsIndexerVersionInfo {
**/
ensIndexer: string;
- /**
- * ENSRainbow service version
- *
- * @see https://ghcr.io/namehash/ensnode/ensindexer
- **/
- ensRainbow: string;
-
- /**
- * ENSRainbow schema version
- **/
- ensRainbowSchema: number;
-
/**
* ENS Normalize package version
*
@@ -108,6 +96,13 @@ export interface EnsIndexerPublicConfig {
*/
databaseSchemaName: string;
+ /**
+ * ENSRainbow public config
+ *
+ * Represents the public config of the connected ENSRainbow instance.
+ */
+ ensRainbowPublicConfig: EnsRainbowPublicConfig;
+
/**
* A set of strings referring to the names of plugins that are active.
*
diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts
index 60bc78860..182251613 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts
@@ -110,8 +110,6 @@ describe("ENSIndexer: Config", () => {
ensDb: "0.32.0",
ensIndexer: "0.32.0",
ensNormalize: "1.11.1",
- ensRainbow: "0.32.0",
- ensRainbowSchema: 2,
} satisfies EnsIndexerVersionInfo),
).toStrictEqual({
nodejs: "v22.22.22",
@@ -119,8 +117,6 @@ describe("ENSIndexer: Config", () => {
ensDb: "0.32.0",
ensIndexer: "0.32.0",
ensNormalize: "1.11.1",
- ensRainbow: "0.32.0",
- ensRainbowSchema: 2,
} satisfies EnsIndexerVersionInfo);
expect(
@@ -131,8 +127,6 @@ describe("ENSIndexer: Config", () => {
ensDb: "",
ensIndexer: "",
ensNormalize: "",
- ensRainbow: "",
- ensRainbowSchema: -1,
} satisfies EnsIndexerVersionInfo),
),
).toStrictEqual(`✖ Value must be a non-empty string.
@@ -144,15 +138,84 @@ describe("ENSIndexer: Config", () => {
✖ Value must be a non-empty string.
→ at ensIndexer
✖ Value must be a non-empty string.
- → at ensNormalize
-✖ Value must be a non-empty string.
- → at ensRainbow
-✖ Value must be a positive integer (>0).
- → at ensRainbowSchema`);
+ → at ensNormalize`);
+ });
+
+ it("validates ensDb and ensIndexer versions match", () => {
+ expect(
+ formatParseError(
+ makeEnsIndexerVersionInfoSchema().safeParse({
+ nodejs: "v22.22.22",
+ ponder: "0.11.25",
+ ensDb: "0.32.0",
+ ensIndexer: "0.33.0", // Different from ensDb
+ ensNormalize: "1.11.1",
+ } satisfies EnsIndexerVersionInfo),
+ ),
+ ).toContain("`ensDb` version must be same as `ensIndexer` version");
+ });
+
+ it("validates ENSRainbow label set and version compatibility", () => {
+ const baseConfig = {
+ ensRainbowPublicConfig: {
+ version: "0.32.0",
+ labelSet: {
+ labelSetId: "subgraph",
+ highestLabelSetVersion: 0,
+ },
+ recordsCount: 100,
+ },
+ indexedChainIds: [1], // Use array for serialized config
+ isSubgraphCompatible: false, // Set to false to bypass isSubgraphCompatible invariant
+ namespace: "mainnet" as const,
+ plugins: [PluginName.Subgraph, PluginName.Registrars], // Multiple plugins allowed when not subgraph compatible
+ databaseSchemaName: "test_schema",
+ versionInfo: {
+ nodejs: "v22.22.22",
+ ponder: "0.11.25",
+ ensDb: "0.32.0",
+ ensIndexer: "0.32.0",
+ ensNormalize: "1.11.1",
+ },
+ };
+
+ // Test mismatched label set IDs
+ expect(
+ formatParseError(
+ makeEnsIndexerPublicConfigSchema().safeParse(
+ buildUnvalidatedEnsIndexerPublicConfig({
+ ...baseConfig,
+ labelSet: { labelSetId: "custom-labels", labelSetVersion: 0 },
+ }),
+ ),
+ ),
+ ).toContain(
+ 'Server label set ID "subgraph" does not match client\'s requested label set ID "custom-labels"',
+ );
+
+ // Test server version too low
+ expect(
+ formatParseError(
+ makeEnsIndexerPublicConfigSchema().safeParse(
+ buildUnvalidatedEnsIndexerPublicConfig({
+ ...baseConfig,
+ labelSet: { labelSetId: "subgraph", labelSetVersion: 5 },
+ }),
+ ),
+ ),
+ ).toContain("Server highest label set version 0 is less than client's requested version 5");
});
it("can parse full ENSIndexerPublicConfig with label set", () => {
const validConfig = {
+ ensRainbowPublicConfig: {
+ version: "0.32.0",
+ labelSet: {
+ labelSetId: "subgraph",
+ highestLabelSetVersion: 0,
+ },
+ recordsCount: 100,
+ },
labelSet: {
labelSetId: "subgraph",
labelSetVersion: 0,
@@ -168,8 +231,6 @@ describe("ENSIndexer: Config", () => {
ensDb: "0.32.0",
ensIndexer: "0.32.0",
ensNormalize: "1.11.1",
- ensRainbow: "0.32.0",
- ensRainbowSchema: 2,
},
} satisfies SerializedEnsIndexerPublicConfig;
diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts
index 5f221d558..c491b8844 100644
--- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts
+++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts
@@ -8,15 +8,17 @@
*/
import { z } from "zod/v4";
-import { uniq } from "../../shared/collections";
+import type { EnsRainbowClientLabelSet, EnsRainbowServerLabelSet } from "../../ensrainbow/types";
import {
- makeChainIdSchema,
- makeENSNamespaceIdSchema,
- makeNonNegativeIntegerSchema,
- makePositiveIntegerSchema,
-} from "../../shared/zod-schemas";
+ makeEnsRainbowPublicConfigSchema,
+ makeLabelSetIdSchema,
+ makeLabelSetVersionSchema,
+} from "../../ensrainbow/zod-schemas/config";
+import { uniq } from "../../shared/collections";
+import { makeChainIdSchema, makeENSNamespaceIdSchema } from "../../shared/zod-schemas";
import type { ZodCheckFnInput } from "../../shared/zod-types";
import { isSubgraphCompatible } from "./is-subgraph-compatible";
+import { validateSupportedLabelSetAndVersion } from "./labelset-utils";
import type { EnsIndexerPublicConfig } from "./types";
import { PluginName } from "./types";
import { invariant_ensDbVersionIsSameAsEnsIndexerVersion } from "./validations";
@@ -69,38 +71,6 @@ export const makeDatabaseSchemaNameSchema = (valueLabel: string = "Database sche
error: `${valueLabel} is required and must be a non-empty string.`,
});
-/**
- * Makes a schema for parsing a label set ID.
- *
- * The label set ID is guaranteed to be a string between 1-50 characters
- * containing only lowercase letters (a-z) and hyphens (-).
- *
- * @param valueLabel - The label to use in error messages (e.g., "Label set ID", "LABEL_SET_ID")
- */
-export const makeLabelSetIdSchema = (valueLabel: string) => {
- return z
- .string({ error: `${valueLabel} must be a string` })
- .min(1, { error: `${valueLabel} must be 1-50 characters long` })
- .max(50, { error: `${valueLabel} must be 1-50 characters long` })
- .regex(/^[a-z-]+$/, {
- error: `${valueLabel} can only contain lowercase letters (a-z) and hyphens (-)`,
- });
-};
-
-/**
- * Makes a schema for parsing a label set version.
- *
- * The label set version is guaranteed to be a non-negative integer.
- *
- * @param valueLabel - The label to use in error messages (e.g., "Label set version", "LABEL_SET_VERSION")
-
- */
-export const makeLabelSetVersionSchema = (valueLabel: string) => {
- return z.coerce
- .number({ error: `${valueLabel} must be an integer.` })
- .pipe(makeNonNegativeIntegerSchema(valueLabel));
-};
-
/**
* Makes a schema for parsing a label set where both label set ID and label set version are required.
*
@@ -127,15 +97,13 @@ const makeNonEmptyStringSchema = (valueLabel: string = "Value") =>
export const makeEnsIndexerVersionInfoSchema = (valueLabel: string = "Value") =>
z
- .strictObject(
+ .object(
{
nodejs: makeNonEmptyStringSchema(),
ponder: makeNonEmptyStringSchema(),
ensDb: makeNonEmptyStringSchema(),
ensIndexer: makeNonEmptyStringSchema(),
ensNormalize: makeNonEmptyStringSchema(),
- ensRainbow: makeNonEmptyStringSchema(),
- ensRainbowSchema: makePositiveIntegerSchema(),
},
{
error: `${valueLabel} must be a valid ENSIndexerVersionInfo object.`,
@@ -165,6 +133,26 @@ export function invariant_isSubgraphCompatibleRequirements(
}
}
+export function invariant_ensRainbowSupportedLabelSetAndVersion(
+ ctx: ZodCheckFnInput>,
+) {
+ const clientLabelSet = ctx.value.labelSet satisfies EnsRainbowClientLabelSet;
+ const serverLabelSet = ctx.value.ensRainbowPublicConfig
+ .labelSet satisfies EnsRainbowServerLabelSet;
+
+ try {
+ validateSupportedLabelSetAndVersion(serverLabelSet, clientLabelSet);
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
+
+ ctx.issues.push({
+ code: "custom",
+ input: ctx.value,
+ message: `The ENSRainbow label set and version specified in the config are not supported by the ENSRainbow version specified in ensRainbowPublicConfig. Cause: ${errorMessage}`,
+ });
+ }
+}
+
/**
* ENSIndexer Public Config Schema
*
@@ -174,14 +162,17 @@ export function invariant_isSubgraphCompatibleRequirements(
export const makeEnsIndexerPublicConfigSchema = (valueLabel: string = "ENSIndexerPublicConfig") =>
z
.object({
- labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`),
+ databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),
+ ensRainbowPublicConfig: makeEnsRainbowPublicConfigSchema(
+ `${valueLabel}.ensRainbowPublicConfig`,
+ ),
indexedChainIds: makeIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),
isSubgraphCompatible: z.boolean({
error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`,
}),
+ labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`),
namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),
plugins: makePluginsListSchema(`${valueLabel}.plugins`),
- databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),
versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`),
})
/**
@@ -189,7 +180,8 @@ export const makeEnsIndexerPublicConfigSchema = (valueLabel: string = "ENSIndexe
*
* All required data validations must be performed below.
*/
- .check(invariant_isSubgraphCompatibleRequirements);
+ .check(invariant_isSubgraphCompatibleRequirements)
+ .check(invariant_ensRainbowSupportedLabelSetAndVersion);
/**
* ENSIndexer Public Config Schema
@@ -202,13 +194,16 @@ export const makeSerializedEnsIndexerPublicConfigSchema = (
valueLabel: string = "Serialized ENSIndexerPublicConfig",
) =>
z.object({
- labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`),
+ databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),
+ ensRainbowPublicConfig: makeEnsRainbowPublicConfigSchema(
+ `${valueLabel}.ensRainbowPublicConfig`,
+ ),
indexedChainIds: makeSerializedIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),
isSubgraphCompatible: z.boolean({
error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`,
}),
+ labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`),
namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),
plugins: makePluginsListSchema(`${valueLabel}.plugins`),
- databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`),
versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`),
});
diff --git a/packages/ensnode-sdk/src/ensrainbow/config.ts b/packages/ensnode-sdk/src/ensrainbow/config.ts
new file mode 100644
index 000000000..d5f141c59
--- /dev/null
+++ b/packages/ensnode-sdk/src/ensrainbow/config.ts
@@ -0,0 +1,26 @@
+import type { EnsRainbowServerLabelSet } from "./types";
+
+/**
+ * Complete public configuration object for ENSRainbow.
+ *
+ * Contains all public configuration information about the ENSRainbow service instance,
+ * including version, label set information, and record counts.
+ */
+export interface EnsRainbowPublicConfig {
+ /**
+ * ENSRainbow service version
+ *
+ * @see https://ghcr.io/namehash/ensnode/ensrainbow
+ */
+ version: string;
+
+ /**
+ * The label set reference managed by the ENSRainbow server.
+ */
+ labelSet: EnsRainbowServerLabelSet;
+
+ /**
+ * The total count of records managed by the ENSRainbow service.
+ */
+ recordsCount: number;
+}
diff --git a/packages/ensnode-sdk/src/ensrainbow/index.ts b/packages/ensnode-sdk/src/ensrainbow/index.ts
index eea524d65..b4fb84ab2 100644
--- a/packages/ensnode-sdk/src/ensrainbow/index.ts
+++ b/packages/ensnode-sdk/src/ensrainbow/index.ts
@@ -1 +1,2 @@
+export * from "./config";
export * from "./types";
diff --git a/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts b/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts
new file mode 100644
index 000000000..d0022f310
--- /dev/null
+++ b/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts
@@ -0,0 +1,49 @@
+import { z } from "zod/v4";
+
+import { makeNonNegativeIntegerSchema } from "../../shared/zod-schemas";
+
+/**
+ * Makes a schema for parsing a label set ID.
+ *
+ * The label set ID is guaranteed to be a string between 1-50 characters
+ * containing only lowercase letters (a-z) and hyphens (-).
+ *
+ * @param valueLabel - The label to use in error messages (e.g., "Label set ID", "LABEL_SET_ID")
+ */
+export const makeLabelSetIdSchema = (valueLabel: string = "Label set ID") => {
+ return z
+ .string({ error: `${valueLabel} must be a string` })
+ .min(1, { error: `${valueLabel} must be 1-50 characters long` })
+ .max(50, { error: `${valueLabel} must be 1-50 characters long` })
+ .regex(/^[a-z-]+$/, {
+ error: `${valueLabel} can only contain lowercase letters (a-z) and hyphens (-)`,
+ });
+};
+
+/**
+ * Makes a schema for parsing a label set version.
+ *
+ * The label set version is guaranteed to be a non-negative integer.
+ *
+ * @param valueLabel - The label to use in error messages (e.g., "Label set version", "LABEL_SET_VERSION")
+ */
+export const makeLabelSetVersionSchema = (valueLabel: string = "Label set version") => {
+ return z.coerce
+ .number({ error: `${valueLabel} must be an integer.` })
+ .pipe(makeNonNegativeIntegerSchema(valueLabel));
+};
+
+/**
+ * Makes a schema for parsing the EnsRainbowPublicConfig object.
+ */
+export const makeEnsRainbowPublicConfigSchema = (valueLabel: string = "EnsRainbowPublicConfig") =>
+ z.object({
+ version: z.string().nonempty({ error: `${valueLabel}.version must be a non-empty string.` }),
+ labelSet: z.object({
+ labelSetId: makeLabelSetIdSchema(`${valueLabel}.labelSet.labelSetId`),
+ highestLabelSetVersion: makeLabelSetVersionSchema(
+ `${valueLabel}.labelSet.highestLabelSetVersion`,
+ ),
+ }),
+ recordsCount: makeNonNegativeIntegerSchema(`${valueLabel}.recordsCount`),
+ });
diff --git a/packages/ensrainbow-sdk/src/client.ts b/packages/ensrainbow-sdk/src/client.ts
index 3a81a5dc5..5f8fe0d87 100644
--- a/packages/ensrainbow-sdk/src/client.ts
+++ b/packages/ensrainbow-sdk/src/client.ts
@@ -3,6 +3,7 @@ import {
type Cache,
type EncodedLabelHash,
type EnsRainbowClientLabelSet,
+ type EnsRainbowPublicConfig,
type EnsRainbowServerLabelSet,
type Label,
type LabelHash,
@@ -168,24 +169,7 @@ export namespace EnsRainbow {
* Contains all public configuration information about the ENSRainbow service instance,
* including version, label set information, and record counts.
*/
- export interface ENSRainbowPublicConfig {
- /**
- * ENSRainbow service version
- *
- * @see https://ghcr.io/namehash/ensnode/ensrainbow
- */
- version: string;
-
- /**
- * The label set reference managed by the ENSRainbow server.
- */
- labelSet: EnsRainbowServerLabelSet;
-
- /**
- * The total count of records managed by the ENSRainbow service.
- */
- recordsCount: number;
- }
+ export type ENSRainbowPublicConfig = EnsRainbowPublicConfig;
}
export interface EnsRainbowApiClientOptions {