@ensnode/ensnode-sdk 0.0.0-next-20260519084124 → 0.0.0-next-20260520162918
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/internal.cjs +10 -0
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +19 -1
- package/dist/internal.d.ts +19 -1
- package/dist/internal.js +10 -0
- package/dist/internal.js.map +1 -1
- package/package.json +4 -4
package/dist/internal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ensapi/config/zod-schemas.ts","../src/ensindexer/config/zod-schemas.ts","../src/ensrainbow/zod-schemas/config.ts","../src/shared/zod-schemas.ts","../src/ens/index.ts","../src/shared/currencies.ts","../src/shared/collections.ts","../src/ensindexer/config/is-subgraph-compatible.ts","../src/ensindexer/config/labelset-utils.ts","../src/ensindexer/config/validations.ts","../src/shared/config/thegraph.ts","../src/ensnode/api/indexing-status/zod-schemas.ts","../src/indexing-status/zod-schema/realtime-indexing-status-projection.ts","../src/indexing-status/zod-schema/cross-chain-indexing-status-snapshot.ts","../src/shared/block-ref.ts","../src/shared/blockrange.ts","../src/indexing-status/chain-indexing-status-snapshot.ts","../src/indexing-status/cross-chain-indexing-status-snapshot.ts","../src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts","../src/indexing-status/omnichain-indexing-status-snapshot.ts","../src/indexing-status/zod-schema/chain-indexing-status-snapshot.ts","../src/stack-info/zod-schemas/ensindexer-stack-info.ts","../src/ensdb/zod-schemas/config.ts","../src/stack-info/zod-schemas/ensnode-stack-info.ts","../src/ensnode/api/indexing-status/response.ts","../src/ensnode/api/name-tokens/examples.ts","../src/ensnode/api/name-tokens/zod-schemas.ts","../src/tokenscope/name-token.ts","../src/shared/account-id.ts","../src/shared/datasource-contract.ts","../src/tokenscope/assets.ts","../src/tokenscope/zod-schemas.ts","../src/ensnode/api/shared/errors/zod-schemas.ts","../src/ensnode/api/name-tokens/response.ts","../src/ensnode/api/realtime/zod-schemas.ts","../src/ensnode/api/registrar-actions/examples.ts","../src/ensnode/api/registrar-actions/zod-schemas.ts","../src/registrars/zod-schemas.ts","../src/registrars/encoded-referrer.ts","../src/shared/serialize.ts","../src/registrars/registrar-action.ts","../src/ensnode/api/shared/pagination/zod-schemas.ts","../src/ensnode/api/shared/pagination/request.ts","../src/ensnode/api/registrar-actions/response.ts","../src/ensnode/api/resolution/examples.ts","../src/ensnode/api/resolution/zod-schemas.ts","../src/ensnode/api/shared/errors/examples.ts","../src/omnigraph-api/example-queries.ts","../src/rpc/eip-165.ts","../src/rpc/is-extended-resolver.ts","../src/shared/config/build-rpc-urls.ts","../src/shared/config/pretty-printing.ts","../src/shared/config/redacting.ts","../src/shared/config/rpc-configs-from-env.ts","../src/shared/config/validatons.ts","../src/shared/url.ts","../src/shared/config/zod-schemas.ts","../src/shared/deserialize.ts","../src/shared/config-templates.ts","../src/shared/datasources-with-ensv2-contracts.ts","../src/shared/datasources-with-resolvers.ts","../src/shared/interpretation/interpret-address.ts","../src/shared/interpretation/interpret-record-values.ts","../src/shared/null-bytes.ts","../src/shared/interpretation/interpret-resolver-values.ts","../src/shared/log-level.ts","../src/shared/protocol-acceleration/is-bridged-resolver.ts","../src/shared/managed-names.ts","../src/shared/to-json.ts","../src/shared/root-registry.ts","../src/shared/protocol-acceleration/is-ensip-19-reverse-resolver.ts","../src/shared/protocol-acceleration/is-static-resolver.ts","../src/shared/thegraph.ts"],"sourcesContent":["import { z } from \"zod/v4\";\n\nimport {\n makeEnsIndexerPublicConfigSchema,\n makeSerializedEnsIndexerPublicConfigSchema,\n} from \"../../ensindexer/config/zod-schemas\";\nimport {\n TheGraphCannotFallbackReasonSchema,\n TheGraphFallbackSchema,\n} from \"../../shared/config/thegraph\";\n\nexport { TheGraphCannotFallbackReasonSchema, TheGraphFallbackSchema };\n\nconst makeEnsApiVersionInfoSchema = (valueLabel: string = \"ENS API version info\") =>\n z.object({\n ensApi: z.string().nonempty(`${valueLabel}.ensApi must be a non-empty string`),\n ensNormalize: z.string().nonempty(`${valueLabel}.ensNormalize must be a non-empty string`),\n });\n\n/**\n * Create a Zod schema for validating ENSApiPublicConfig.\n *\n * @param valueLabel - Optional label for the value being validated (used in error messages)\n */\nexport function makeEnsApiPublicConfigSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSApiPublicConfig\";\n\n return z.object({\n theGraphFallback: TheGraphFallbackSchema,\n ensIndexerPublicConfig: makeEnsIndexerPublicConfigSchema(`${label}.ensIndexerPublicConfig`),\n versionInfo: makeEnsApiVersionInfoSchema(`${label}.versionInfo`),\n });\n}\n\n/**\n * Create a Zod schema for validating a serialized ENSApiPublicConfig.\n *\n * @deprecated Use {@link makeEnsApiPublicConfigSchema} instead.\n */\nexport const makeENSApiPublicConfigSchema = makeEnsApiPublicConfigSchema;\n\nexport function makeSerializedEnsApiPublicConfigSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSApiPublicConfig\";\n\n return z.object({\n ensIndexerPublicConfig: makeSerializedEnsIndexerPublicConfigSchema(\n `${label}.ensIndexerPublicConfig`,\n ),\n theGraphFallback: TheGraphFallbackSchema,\n versionInfo: makeEnsApiVersionInfoSchema(`${label}.versionInfo`),\n });\n}\n","/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport { z } from \"zod/v4\";\n\nimport {\n makeEnsRainbowPublicConfigSchema,\n makeLabelSetIdSchema,\n makeLabelSetVersionStringSchema,\n} from \"../../ensrainbow/zod-schemas/config\";\nimport { uniq } from \"../../shared/collections\";\nimport { makeChainIdSchema, makeENSNamespaceIdSchema } from \"../../shared/zod-schemas\";\nimport type { ZodCheckFnInput } from \"../../shared/zod-types\";\nimport { isSubgraphCompatible } from \"./is-subgraph-compatible\";\nimport { validateSupportedLabelSetAndVersion } from \"./labelset-utils\";\nimport type { EnsIndexerPublicConfig } from \"./types\";\nimport { PluginName } from \"./types\";\nimport { invariant_ensDbVersionIsSameAsEnsIndexerVersion } from \"./validations\";\n\n/**\n * Makes a schema for parsing {@link IndexedChainIds}.\n */\nexport const makeIndexedChainIdsSchema = (valueLabel: string = \"Indexed Chain IDs\") =>\n z.set(makeChainIdSchema(valueLabel), { error: `${valueLabel} must be a set` }).min(1, {\n error: `${valueLabel} must be a set with at least one chain ID.`,\n });\n\nexport const makeSerializedIndexedChainIdsSchema = (valueLabel: string = \"Indexed Chain IDs\") =>\n z\n .array(makeChainIdSchema(valueLabel), {\n error: `${valueLabel} must be an array.`,\n })\n .min(1, {\n error: `${valueLabel} must be an array with at least one chain ID.`,\n });\n\n/**\n * Makes a schema for parsing a list of strings that (for future-proofing)\n * may or may not be current {@link PluginName} values.\n *\n * The list is guaranteed to include at least one string and no duplicates.\n */\nexport const makePluginsListSchema = (valueLabel: string = \"Plugins\") =>\n z\n .array(z.string(), {\n error: `${valueLabel} must be a list of strings.`,\n })\n .min(1, {\n error: `${valueLabel} must be a list of strings with at least one string value`,\n })\n .refine((arr) => arr.length === uniq(arr).length, {\n error: `${valueLabel} cannot contain duplicate values.`,\n });\n\n/**\n * Makes a schema for parsing a name for a database schema.\n *\n * The name is guaranteed to be a non-empty string.\n */\nexport const makeEnsIndexerSchemaNameSchema = (valueLabel: string = \"ENS Indexer Schema Name\") =>\n z\n .string({ error: `${valueLabel} must be a string` })\n .trim()\n .nonempty({\n error: `${valueLabel} is required and must be a non-empty string.`,\n });\n\n/**\n * Makes a schema for parsing a label set where both label set ID and label set version are required.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set\", \"LABEL_SET\")\n */\nexport const makeFullyPinnedLabelSetSchema = (valueLabel: string = \"Label set\") => {\n let valueLabelLabelSetId = valueLabel;\n let valueLabelLabelSetVersion = valueLabel;\n if (valueLabel === \"LABEL_SET\") {\n valueLabelLabelSetId = \"LABEL_SET_ID\";\n valueLabelLabelSetVersion = \"LABEL_SET_VERSION\";\n } else {\n valueLabelLabelSetId = `${valueLabel}.labelSetId`;\n valueLabelLabelSetVersion = `${valueLabel}.labelSetVersion`;\n }\n return z.object({\n labelSetId: makeLabelSetIdSchema(valueLabelLabelSetId),\n labelSetVersion: makeLabelSetVersionStringSchema(valueLabelLabelSetVersion),\n });\n};\n\nconst makeNonEmptyStringSchema = (valueLabel: string = \"Value\") =>\n z.string().nonempty({ error: `${valueLabel} must be a non-empty string.` });\n\nexport const makeEnsIndexerVersionInfoSchema = (valueLabel: string = \"Value\") =>\n z\n .object(\n {\n ponder: makeNonEmptyStringSchema(),\n ensDb: makeNonEmptyStringSchema(),\n ensIndexer: makeNonEmptyStringSchema(),\n ensNormalize: makeNonEmptyStringSchema(),\n },\n {\n error: `${valueLabel} must be a valid ENSIndexerVersionInfo object.`,\n },\n )\n .check(invariant_ensDbVersionIsSameAsEnsIndexerVersion);\n\n/**\n * @deprecated Use {@link makeEnsIndexerVersionInfoSchema} instead.\n */\nexport const makeENSIndexerVersionInfoSchema = makeEnsIndexerVersionInfoSchema;\n\n// Invariant: If config.isSubgraphCompatible, the config must pass isSubgraphCompatible(config)\nexport function invariant_isSubgraphCompatibleRequirements(\n ctx: ZodCheckFnInput<\n Pick<\n EnsIndexerPublicConfig,\n \"namespace\" | \"plugins\" | \"isSubgraphCompatible\" | \"clientLabelSet\"\n >\n >,\n) {\n const { value: config } = ctx;\n\n if (config.isSubgraphCompatible && !isSubgraphCompatible(config)) {\n ctx.issues.push({\n code: \"custom\",\n input: config,\n message: `'isSubgraphCompatible' requires only the '${PluginName.Subgraph}' plugin to be active and 'clientLabelSet' must be {labelSetId: \"subgraph\", labelSetVersion: 0}`,\n });\n }\n}\n\nexport function invariant_ensRainbowSupportedLabelSetAndVersion(\n ctx: ZodCheckFnInput<Pick<EnsIndexerPublicConfig, \"clientLabelSet\" | \"ensRainbowPublicConfig\">>,\n) {\n const { clientLabelSet } = ctx.value;\n const { serverLabelSet } = ctx.value.ensRainbowPublicConfig;\n\n try {\n validateSupportedLabelSetAndVersion(serverLabelSet, clientLabelSet);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `The ENSRainbow label set and version specified in the config are not supported by the ENSRainbow version specified in ensRainbowPublicConfig. Cause: ${errorMessage}`,\n });\n }\n}\n\n/**\n * ENSIndexer Public Config Schema\n *\n * Makes a Zod schema definition for validating all important settings used\n * during runtime of the ENSIndexer instance.\n */\nexport const makeEnsIndexerPublicConfigSchema = (valueLabel: string = \"ENSIndexerPublicConfig\") =>\n z\n .object({\n ensIndexerSchemaName: makeEnsIndexerSchemaNameSchema(`${valueLabel}.ensIndexerSchemaName`),\n ensRainbowPublicConfig: makeEnsRainbowPublicConfigSchema(\n `${valueLabel}.ensRainbowPublicConfig`,\n ),\n indexedChainIds: makeIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),\n isSubgraphCompatible: z.boolean({\n error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`,\n }),\n clientLabelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.clientLabelSet`),\n namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),\n plugins: makePluginsListSchema(`${valueLabel}.plugins`),\n versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`),\n })\n /**\n * Validations\n *\n * All required data validations must be performed below.\n */\n .check(invariant_isSubgraphCompatibleRequirements)\n .check(invariant_ensRainbowSupportedLabelSetAndVersion);\n\n/**\n * ENSIndexer Public Config Schema\n *\n * @deprecated Use {@link makeEnsIndexerPublicConfigSchema} instead.\n */\nexport const makeENSIndexerPublicConfigSchema = makeEnsIndexerPublicConfigSchema;\n\nexport const makeSerializedEnsIndexerPublicConfigSchema = (\n valueLabel: string = \"Serialized ENSIndexerPublicConfig\",\n) =>\n z.object({\n ensIndexerSchemaName: makeEnsIndexerSchemaNameSchema(`${valueLabel}.ensIndexerSchemaName`),\n ensRainbowPublicConfig: makeEnsRainbowPublicConfigSchema(\n `${valueLabel}.ensRainbowPublicConfig`,\n ),\n indexedChainIds: makeSerializedIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),\n isSubgraphCompatible: z.boolean({\n error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`,\n }),\n clientLabelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.clientLabelSet`),\n namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),\n plugins: makePluginsListSchema(`${valueLabel}.plugins`),\n versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`),\n });\n","import { z } from \"zod/v4\";\n\nimport { makeNonNegativeIntegerSchema } from \"../../shared/zod-schemas\";\n\n/**\n * Makes a schema for parsing a label set ID.\n *\n * The label set ID is guaranteed to be a string between 1-50 characters\n * containing only lowercase letters (a-z) and hyphens (-).\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set ID\", \"LABEL_SET_ID\")\n */\nexport const makeLabelSetIdSchema = (valueLabel: string = \"Label set ID\") => {\n return z\n .string({ error: `${valueLabel} must be a string` })\n .min(1, { error: `${valueLabel} must be 1-50 characters long` })\n .max(50, { error: `${valueLabel} must be 1-50 characters long` })\n .regex(/^[a-z-]+$/, {\n error: `${valueLabel} can only contain lowercase letters (a-z) and hyphens (-)`,\n });\n};\n\n/**\n * Makes a schema for parsing a label set version.\n *\n * The label set version is guaranteed to be a non-negative integer.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set version\", \"LABEL_SET_VERSION\")\n */\nexport const makeLabelSetVersionSchema = (valueLabel: string = \"Label set version\") =>\n makeNonNegativeIntegerSchema(valueLabel);\n\n/**\n * Makes a schema for parsing a label set version string.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set version\", \"LABEL_SET_VERSION\")\n */\nexport const makeLabelSetVersionStringSchema = (valueLabel: string = \"Label set version\") =>\n z.coerce\n .number<number>({ error: `${valueLabel} must be a non-negative integer` })\n .pipe(makeLabelSetVersionSchema(valueLabel));\n\n/**\n * Makes a schema for parsing the EnsRainbowPublicConfig object.\n */\nexport const makeEnsRainbowPublicConfigSchema = (valueLabel: string = \"EnsRainbowPublicConfig\") =>\n z.object({\n serverLabelSet: z.object({\n labelSetId: makeLabelSetIdSchema(`${valueLabel}.serverLabelSet.labelSetId`),\n highestLabelSetVersion: makeLabelSetVersionSchema(\n `${valueLabel}.serverLabelSet.highestLabelSetVersion`,\n ),\n }),\n\n versionInfo: z.object({\n ensRainbow: z\n .string()\n .nonempty({ error: `${valueLabel}.versionInfo.ensRainbow must be a non-empty string.` }),\n }),\n });\n","import type { CoinType } from \"@ensdomains/address-encoder\";\nimport { AccountId as CaipAccountId } from \"caip\";\nimport type {\n AccountId,\n AccountIdString,\n ChainId,\n DefaultableChainId,\n Duration,\n Hex,\n InterpretedName,\n Node,\n} from \"enssdk\";\nimport { reinterpretName, toNormalizedAddress } from \"enssdk\";\nimport { isAddress, isHex, size } from \"viem\";\n/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport { z } from \"zod/v4\";\n\nimport { ENSNamespaceIds } from \"../ens\";\nimport {\n type CurrencyId,\n CurrencyIds,\n type PriceDai,\n type PriceEnsTokens,\n type PriceEth,\n type PriceUsdc,\n type SerializedPriceEth,\n} from \"./currencies\";\nimport type { BlockRef, Datetime } from \"./types\";\n\n/**\n * Parses a string value as a boolean.\n */\nexport const makeBooleanStringSchema = (valueLabel: string = \"Value\") =>\n z\n .string()\n .pipe(\n z.enum([\"true\", \"false\"], {\n error: `${valueLabel} must be 'true' or 'false'.`,\n }),\n )\n .transform((val) => val === \"true\");\n\n/**\n * Parses a numeric value as a finite non-negative number.\n */\nexport const makeFiniteNonNegativeNumberSchema = (valueLabel: string = \"Value\") =>\n z\n .number({\n // NOTE: Zod's implementation of `number` automatically rejects NaN and Infinity values.\n // and therefore the finite check is implicit.\n error: `${valueLabel} must be a finite number.`,\n })\n .nonnegative({\n error: `${valueLabel} must be a non-negative number (>=0).`,\n });\n\n/**\n * Parses a numeric value as an integer.\n */\nexport const makeIntegerSchema = (valueLabel: string = \"Value\") =>\n z.int({\n error: `${valueLabel} must be an integer.`,\n });\n\n/**\n * Parses a numeric value as a positive integer.\n */\nexport const makePositiveIntegerSchema = (valueLabel: string = \"Value\") =>\n makeIntegerSchema(valueLabel).positive({\n error: `${valueLabel} must be a positive integer (>0).`,\n });\n\n/**\n * Parses a numeric value as a non-negative integer.\n */\nexport const makeNonNegativeIntegerSchema = (valueLabel: string = \"Value\") =>\n makeIntegerSchema(valueLabel).nonnegative({\n error: `${valueLabel} must be a non-negative integer (>=0).`,\n });\n\n/**\n * Parses a numeric value as {@link Duration}\n */\nexport const makeDurationSchema = (valueLabel: string = \"Value\") =>\n z\n .number({\n error: `${valueLabel} must be a number.`,\n })\n .pipe(makeNonNegativeIntegerSchema(valueLabel));\n\n/**\n * Parses Chain ID\n *\n * {@link ChainId}\n */\nexport const makeChainIdSchema = (valueLabel: string = \"Chain ID\") =>\n makePositiveIntegerSchema(valueLabel).transform((val) => val as ChainId);\n\n/**\n * Parses a serialized representation of {@link ChainId}.\n */\nexport const makeChainIdStringSchema = (valueLabel: string = \"Chain ID String\") =>\n z\n .string({ error: `${valueLabel} must be a string representing a chain ID.` })\n .pipe(z.coerce.number({ error: `${valueLabel} must represent a positive integer (>0).` }))\n .pipe(makeChainIdSchema(`The numeric value represented by ${valueLabel}`));\n\n/**\n * Parses Defaultable Chain ID\n *\n * {@link DefaultableChainId}\n */\nexport const makeDefaultableChainIdSchema = (valueLabel: string = \"Defaultable Chain ID\") =>\n makeNonNegativeIntegerSchema(valueLabel).transform((val) => val as DefaultableChainId);\n\n/**\n * Parses a serialized representation of {@link DefaultableChainId}.\n */\nexport const makeDefaultableChainIdStringSchema = (\n valueLabel: string = \"Defaultable Chain ID String\",\n) =>\n z\n .string({ error: `${valueLabel} must be a string representing a chain ID.` })\n .pipe(z.coerce.number({ error: `${valueLabel} must represent a non-negative integer (>=0).` }))\n .pipe(makeDefaultableChainIdSchema(`The numeric value represented by ${valueLabel}`));\n\n/**\n * Parses {@link CoinType}.\n */\nexport const makeCoinTypeSchema = (valueLabel: string = \"Coin Type\") =>\n z\n .number({ error: `${valueLabel} must be a number.` })\n .int({ error: `${valueLabel} must be an integer.` })\n .nonnegative({ error: `${valueLabel} must be a non-negative integer (>=0).` })\n .transform((val) => val as CoinType);\n\n/**\n * Parses a serialized representation of {@link CoinType}.\n */\nexport const makeCoinTypeStringSchema = (valueLabel: string = \"Coin Type String\") =>\n z\n .string({ error: `${valueLabel} must be a string representing a coin type.` })\n .pipe(z.coerce.number({ error: `${valueLabel} must represent a non-negative integer (>=0).` }))\n .pipe(makeCoinTypeSchema(`The numeric value represented by ${valueLabel}`));\n\n/**\n * Parses a serialized representation of an EVM address into a {@link NormalizedAddress}.\n */\nexport const makeNormalizedAddressSchema = (valueLabel: string = \"EVM address\") =>\n z\n .string()\n .check((ctx) => {\n // NOTE: we intentionally use isAddress here instead of isNormalizedAddress, which allows this\n // schema to transform (via toNormalizedAddress) the input into a normalized address.\n if (!isAddress(ctx.value, { strict: false })) {\n ctx.issues.push({\n code: \"custom\",\n message: `${valueLabel} must be a valid EVM address`,\n input: ctx.value,\n });\n }\n })\n .transform((val) => toNormalizedAddress(val));\n\n/**\n * Parses an ISO 8601 string representations of {@link Datetime}\n */\nexport const makeDatetimeSchema = (valueLabel: string = \"Datetime string\") =>\n z.iso\n .datetime({ error: `${valueLabel} must be a string in ISO 8601 format.` })\n .transform((v) => new Date(v));\n\n/**\n * Parses value as {@link UnixTimestamp}.\n */\nexport const makeUnixTimestampSchema = (valueLabel: string = \"Timestamp\") =>\n makeIntegerSchema(valueLabel);\n\n/**\n * Parses a string representations of {@link URL}\n */\nexport const makeUrlSchema = (valueLabel: string = \"Value\") =>\n z\n .url({\n error: `${valueLabel} must be a valid URL string (e.g., http://localhost:8080 or https://example.com).`,\n abort: true,\n })\n .transform((v) => new URL(v));\n\n/**\n * Parses a serialized representation of a comma separated list.\n */\nexport const makeCommaSeparatedList = (valueLabel: string = \"Value\") =>\n z\n .string({ error: `${valueLabel} must be a comma separated list.` })\n .transform((val) => val.split(\",\").filter(Boolean))\n .refine((val) => val.length > 0, {\n error: `${valueLabel} must be a comma separated list with at least one value.`,\n });\n\n/**\n * Parses a numeric value as a block number.\n */\nexport const makeBlockNumberSchema = (valueLabel: string = \"Block number\") =>\n makeNonNegativeIntegerSchema(valueLabel);\n\n/**\n * Parses an object value as the {@link BlockRef} object.\n */\nexport const makeBlockRefSchema = (valueLabel: string = \"Value\") =>\n z.strictObject(\n {\n timestamp: makeUnixTimestampSchema(`${valueLabel}.timestamp`),\n number: makeBlockNumberSchema(`${valueLabel}.number`),\n },\n {\n error: `${valueLabel} must be a valid BlockRef object.`,\n },\n );\n\n/**\n * Parses a string value as ENSNamespaceId.\n */\nexport const makeENSNamespaceIdSchema = (valueLabel: string = \"ENSNamespaceId\") =>\n z.enum(ENSNamespaceIds, {\n error() {\n return `Invalid ${valueLabel}. Supported ENS namespace IDs are: ${Object.keys(ENSNamespaceIds).join(\", \")}`;\n },\n });\n\nconst makePriceAmountSchema = (valueLabel: string = \"Amount\") =>\n z.coerce\n .bigint({\n error: `${valueLabel} must represent a bigint.`,\n })\n .nonnegative({\n error: `${valueLabel} must not be negative.`,\n });\n\nconst makeSerializedCurrencyAmountSchema = (valueLabel: string = \"Serialized Currency Amount\") =>\n z.string({ error: `${valueLabel} must be a string.` }).regex(/^\\d+$/, {\n error: `${valueLabel} can only contain digits (0-9) and must represent a non-negative integer.`,\n });\n\nexport const makePriceCurrencySchema = (\n currency: CurrencyId,\n valueLabel: string = \"Price Currency\",\n) =>\n z.strictObject({\n amount: makePriceAmountSchema(`${valueLabel} amount`),\n\n currency: z.literal(currency, {\n error: `${valueLabel} currency must be set to '${currency}'.`,\n }),\n });\n\nexport const makeSerializedPriceCurrencySchema = (\n currency: CurrencyId,\n valueLabel: string = \"Price Currency\",\n) =>\n z.strictObject({\n amount: makeSerializedCurrencyAmountSchema(`${valueLabel} amount`),\n\n currency: z.literal(currency, {\n error: `${valueLabel} currency must be set to '${currency}'.`,\n }),\n });\n\n/**\n * Schema for {@link Price} type.\n */\nexport const makePriceSchema = (valueLabel: string = \"Price\") =>\n z.discriminatedUnion(\n \"currency\",\n [\n makePriceCurrencySchema(CurrencyIds.ETH, valueLabel),\n makePriceCurrencySchema(CurrencyIds.USDC, valueLabel),\n makePriceCurrencySchema(CurrencyIds.DAI, valueLabel),\n makePriceCurrencySchema(CurrencyIds.ENSTokens, valueLabel),\n ],\n { error: `${valueLabel} currency must be one of ${Object.values(CurrencyIds).join(\", \")}` },\n );\n\n/**\n * Schema for {@link PriceEth} type.\n */\nexport const makePriceEthSchema = (valueLabel: string = \"Price ETH\") =>\n makePriceCurrencySchema(CurrencyIds.ETH, valueLabel).transform((v) => v as PriceEth);\n\nexport const makeSerializedPriceEthSchema = (valueLabel: string = \"Serialized Price ETH\") =>\n makeSerializedPriceCurrencySchema(CurrencyIds.ETH, valueLabel).transform(\n (v) => v as SerializedPriceEth,\n );\n\n/**\n * Schema for {@link PriceUsdc} type.\n */\nexport const makePriceUsdcSchema = (valueLabel: string = \"Price USDC\") =>\n makePriceCurrencySchema(CurrencyIds.USDC, valueLabel).transform((v) => v as PriceUsdc);\n\n/**\n * Schema for {@link PriceDai} type.\n */\nexport const makePriceDaiSchema = (valueLabel: string = \"Price DAI\") =>\n makePriceCurrencySchema(CurrencyIds.DAI, valueLabel).transform((v) => v as PriceDai);\n\n/**\n * Schema for {@link PriceEnsTokens} type.\n */\nexport const makePriceEnsTokensSchema = (valueLabel: string = \"Price ENSTokens\") =>\n makePriceCurrencySchema(CurrencyIds.ENSTokens, valueLabel).transform((v) => v as PriceEnsTokens);\n\n/**\n * Schema for {@link AccountId} type.\n */\nexport const makeAccountIdSchema = (valueLabel: string = \"AccountId\") =>\n z.strictObject({\n chainId: makeChainIdSchema(`${valueLabel} chain ID`),\n address: makeNormalizedAddressSchema(`${valueLabel} address`),\n });\n\n/**\n * Schema for {@link AccountIdString} type.\n */\nexport const makeAccountIdStringSchema = (valueLabel: string = \"Account ID String\") =>\n z.coerce\n .string()\n .transform((v) => {\n const result = new CaipAccountId(v);\n\n return {\n chainId: Number(result.chainId.reference),\n address: result.address,\n };\n })\n .pipe(makeAccountIdSchema(valueLabel));\n\n/**\n * Make a schema for {@link Hex} representation of bytes array.\n *\n * @param {number} options.bytesCount expected count of bytes to be hex-encoded\n */\nexport const makeHexStringSchema = (\n options: { bytesCount: number },\n valueLabel: string = \"String representation of bytes array\",\n) =>\n z\n .string()\n .check(function invariant_isHexEncoded(ctx) {\n if (!isHex(ctx.value)) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `${valueLabel} must be a hexadecimal value which starts with '0x'.`,\n });\n }\n })\n .transform((v) => v as Hex)\n .check(function invariant_encodesRequiredBytesCount(ctx) {\n const expectedBytesCount = options.bytesCount;\n const actualBytesCount = size(ctx.value);\n\n if (actualBytesCount !== expectedBytesCount) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `${valueLabel} must represent exactly ${expectedBytesCount} bytes. Currently represented bytes count: ${actualBytesCount}.`,\n });\n }\n });\n\n/**\n * Make schema for {@link Node}.\n */\nexport const makeNodeSchema = (valueLabel: string = \"Node\") =>\n makeHexStringSchema({ bytesCount: 32 }, valueLabel);\n\n/**\n * Make schema for Transaction Hash\n */\nexport const makeTransactionHashSchema = (valueLabel: string = \"Transaction hash\") =>\n makeHexStringSchema({ bytesCount: 32 }, valueLabel);\n\n/**\n * Make schema for {@link ReinterpretedName}.\n */\nexport const makeReinterpretedNameSchema = (valueLabel: string = \"Reinterpreted Name\") =>\n z\n .string()\n .transform((v) => v as InterpretedName)\n .check((ctx) => {\n try {\n reinterpretName(ctx.value);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `${valueLabel} cannot be reinterpreted: ${errorMessage}`,\n });\n }\n })\n .transform(reinterpretName);\n","export type { ENSNamespaceId } from \"@ensnode/datasources\";\nexport { ENSNamespaceIds, getENSRootChainId } from \"@ensnode/datasources\";\n\nexport * from \"./fuses\";\n","import { parseUnits } from \"viem\";\n\nimport { scaleBigintByNumber } from \"./numbers\";\n\n/**\n * Identifiers for supported currencies.\n *\n * TODO: Add support for WETH\n */\nexport const CurrencyIds = {\n ETH: \"ETH\",\n USDC: \"USDC\",\n DAI: \"DAI\",\n ENSTokens: \"ENSTokens\",\n} as const;\n\nexport type CurrencyId = (typeof CurrencyIds)[keyof typeof CurrencyIds];\n\n/**\n * The amount of the currency in the smallest unit of the currency\n * (see {@link CurrencyInfo.decimals} for the currency).\n *\n * Guaranteed to be non-negative.\n */\nexport type CurrencyAmount = bigint;\n\n/**\n * Serialized representation of {@link CurrencyAmount}.\n */\nexport type SerializedCurrencyAmount = string;\n\nexport interface PriceEth {\n currency: typeof CurrencyIds.ETH;\n\n amount: CurrencyAmount;\n}\n\nexport interface PriceDai {\n currency: typeof CurrencyIds.DAI;\n\n amount: CurrencyAmount;\n}\n\nexport interface PriceUsdc {\n currency: typeof CurrencyIds.USDC;\n\n amount: CurrencyAmount;\n}\n\nexport interface PriceEnsTokens {\n currency: typeof CurrencyIds.ENSTokens;\n\n amount: CurrencyAmount;\n}\n\nexport type Price = PriceEth | PriceDai | PriceUsdc | PriceEnsTokens;\n\n/**\n * Serialized representation of {@link PriceEth}.\n */\nexport interface SerializedPriceEth extends Omit<PriceEth, \"amount\"> {\n amount: SerializedCurrencyAmount;\n}\n\n/**\n * Serialized representation of {@link PriceDai}.\n */\nexport interface SerializedPriceDai extends Omit<PriceDai, \"amount\"> {\n amount: SerializedCurrencyAmount;\n}\n\n/**\n * Serialized representation of {@link PriceUsdc}.\n */\nexport interface SerializedPriceUsdc extends Omit<PriceUsdc, \"amount\"> {\n amount: SerializedCurrencyAmount;\n}\n\n/**\n * Serialized representation of {@link PriceEnsTokens}.\n */\nexport interface SerializedPriceEnsTokens extends Omit<PriceEnsTokens, \"amount\"> {\n amount: SerializedCurrencyAmount;\n}\n\n/**\n * Serialized representation of {@link Price}.\n */\nexport type SerializedPrice =\n | SerializedPriceEth\n | SerializedPriceDai\n | SerializedPriceUsdc\n | SerializedPriceEnsTokens;\n\nexport interface CurrencyInfo {\n id: CurrencyId;\n name: string;\n decimals: number;\n}\n\nconst currencyInfo: Record<CurrencyId, CurrencyInfo> = {\n [CurrencyIds.ETH]: {\n id: CurrencyIds.ETH,\n name: \"ETH\",\n decimals: 18,\n },\n [CurrencyIds.USDC]: {\n id: CurrencyIds.USDC,\n name: \"USDC\",\n decimals: 6,\n },\n [CurrencyIds.DAI]: {\n id: CurrencyIds.DAI,\n name: \"Dai Stablecoin\",\n decimals: 18,\n },\n [CurrencyIds.ENSTokens]: {\n id: CurrencyIds.ENSTokens,\n name: \"$ENS Tokens\",\n decimals: 18,\n },\n};\n\n/**\n * Get currency info for a provided currency.\n */\nexport function getCurrencyInfo(currencyId: CurrencyId): CurrencyInfo {\n return currencyInfo[currencyId];\n}\n\n/**\n * Create price in ETH for given amount.\n */\nexport function priceEth(amount: Price[\"amount\"]): PriceEth {\n return {\n amount,\n currency: CurrencyIds.ETH,\n };\n}\n\n/**\n * Create price in USDC for given amount.\n */\nexport function priceUsdc(amount: Price[\"amount\"]): PriceUsdc {\n return {\n amount,\n currency: CurrencyIds.USDC,\n };\n}\n\n/**\n * Create price in DAI for given amount.\n */\nexport function priceDai(amount: Price[\"amount\"]): PriceDai {\n return {\n amount,\n currency: CurrencyIds.DAI,\n };\n}\n\n/**\n * Create price in ENS Tokens for given amount.\n */\nexport function priceEnsTokens(amount: Price[\"amount\"]): PriceEnsTokens {\n return {\n amount,\n currency: CurrencyIds.ENSTokens,\n };\n}\n\n/**\n * Check if two prices have the same currency.\n */\nexport function isPriceCurrencyEqual(priceA: Price, priceB: Price): boolean {\n return priceA.currency === priceB.currency;\n}\n\n/**\n * Check if two {@link Price} values have the same currency and amount.\n */\nexport function isPriceEqual(priceA: Price, priceB: Price): boolean {\n return isPriceCurrencyEqual(priceA, priceB) && priceA.amount === priceB.amount;\n}\n\n/**\n * Add prices\n *\n * @param prices at least two {@link Price} values to be added together.\n * @returns total of all prices.\n * @throws if not all prices have the same currency.\n */\nexport function addPrices<const PriceType extends Price = Price>(\n ...prices: [PriceType, PriceType, ...PriceType[]]\n): PriceType {\n const firstPrice = prices[0];\n const allPricesInSameCurrency = prices.every((price) => isPriceCurrencyEqual(firstPrice, price));\n\n if (allPricesInSameCurrency === false) {\n throw new Error(\"All prices must have the same currency to be added together.\");\n }\n\n const { currency } = firstPrice;\n\n return prices.reduce(\n (acc, price) => ({\n amount: acc.amount + price.amount,\n currency,\n }),\n {\n amount: 0n,\n currency: firstPrice.currency,\n },\n ) as PriceType;\n}\n\n/**\n * Subtract price B from price A.\n *\n * @param a the minuend {@link Price} value.\n * @param b the subtrahend {@link Price} value.\n * @returns the resulting {@link Price} (`a - b`) with the same currency as the inputs.\n * @throws if the prices have different currencies.\n * @throws if the result would be negative ({@link CurrencyAmount} must be non-negative).\n */\nexport function subtractPrice<const PriceType extends Price = Price>(\n a: PriceType,\n b: PriceType,\n): PriceType {\n if (!isPriceCurrencyEqual(a, b)) {\n throw new Error(\"All prices must have the same currency to be subtracted.\");\n }\n\n const resultAmount = a.amount - b.amount;\n\n if (resultAmount < 0n) {\n throw new Error(\"subtractPrice result must be non-negative.\");\n }\n\n return { amount: resultAmount, currency: a.currency } as PriceType;\n}\n\n/**\n * Return the smallest of the given {@link Price} values.\n *\n * @param prices at least two {@link Price} values to compare.\n * @returns the {@link Price} with the smallest amount. Ties return the first\n * such value in argument order.\n * @throws if not all prices have the same currency.\n */\nexport function minPrice<const PriceType extends Price = Price>(\n ...prices: [PriceType, PriceType, ...PriceType[]]\n): PriceType {\n const firstPrice = prices[0];\n const allPricesInSameCurrency = prices.every((price) => isPriceCurrencyEqual(firstPrice, price));\n\n if (allPricesInSameCurrency === false) {\n throw new Error(\"All prices must have the same currency to be compared.\");\n }\n\n return prices.reduce((acc, price) => (price.amount < acc.amount ? price : acc));\n}\n\n/**\n * Return the largest of the given {@link Price} values.\n *\n * @param prices at least two {@link Price} values to compare.\n * @returns the {@link Price} with the largest amount. Ties return the first\n * such value in argument order.\n * @throws if not all prices have the same currency.\n */\nexport function maxPrice<const PriceType extends Price = Price>(\n ...prices: [PriceType, PriceType, ...PriceType[]]\n): PriceType {\n const firstPrice = prices[0];\n const allPricesInSameCurrency = prices.every((price) => isPriceCurrencyEqual(firstPrice, price));\n\n if (allPricesInSameCurrency === false) {\n throw new Error(\"All prices must have the same currency to be compared.\");\n }\n\n return prices.reduce((acc, price) => (price.amount > acc.amount ? price : acc));\n}\n\n/**\n * Scales a Price object by a floating-point number while maintaining precision.\n *\n * **Important:** The precision of this method is bound to the precision of float\n * in JavaScript. For more information, see {@link scaleBigintByNumber}.\n *\n * @param price - The Price object to scale\n * @param scaleFactor - The number to multiply by (can be a decimal like 0.5)\n * @returns A new Price object with the scaled amount and same currency\n *\n * @throws {Error} If scaleFactor is negative, NaN, or infinite\n * @throws {Error} If price amount is negative\n *\n * @example\n * // Scale USDC price by 0.5\n * const price = priceUsdc(1000000n); // 1 USDC\n * const scaled = scalePrice(price, 0.5); // 0.5 USDC\n * // scaled = { currency: \"USDC\", amount: 500000n }\n *\n * @example\n * // Calculate 33.3% of ETH price\n * const ethPrice = priceEth(1000000000000000000n); // 1 ETH\n * const share = scalePrice(ethPrice, 0.333);\n * // share = { currency: \"ETH\", amount: 333000000000000000n }\n */\nexport function scalePrice<T extends Price>(price: T, scaleFactor: number): T {\n const scaledAmount = scaleBigintByNumber(price.amount, scaleFactor);\n\n return {\n ...price,\n amount: scaledAmount,\n };\n}\n\n/**\n * Validates a decimal string for currency parsing.\n *\n * @param value - The decimal string to validate\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n */\nfunction validateAmountToParse(value: string): void {\n const trimmed = value.trim();\n if (trimmed === \"\") {\n throw new Error(\"amount must be a non-negative decimal string\");\n }\n if (value !== trimmed) {\n throw new Error(\"amount must not have leading or trailing whitespace\");\n }\n if (trimmed.startsWith(\"-\")) {\n throw new Error(\"amount must be a non-negative decimal string\");\n }\n}\n\n/**\n * Parses a string representation of ETH into a {@link PriceEth} object.\n *\n * Uses {@link getCurrencyInfo} to get the correct number of decimals (18) for ETH\n * and {@link parseUnits} from viem to convert the decimal string to a bigint.\n *\n * **Note:** Values with more than 18 decimal places will be truncated/rounded by viem's `parseUnits`.\n *\n * @param value - The decimal string to parse (e.g., \"0.015\" for 0.015 ETH)\n * @returns A PriceEth object with the amount in wei (smallest unit)\n *\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n * @throws {Error} If value is not a valid decimal string (e.g., \"abc\", \"1.2.3\")\n *\n * @example\n * parseEth(\"0.015\") // returns { currency: \"ETH\", amount: 15000000000000000n }\n * parseEth(\"1\") // returns { currency: \"ETH\", amount: 1000000000000000000n }\n * parseEth(\"123.456789012345678\") // returns { currency: \"ETH\", amount: 123456789012345678000n }\n */\nexport function parseEth(value: string): PriceEth {\n validateAmountToParse(value);\n const currencyInfo = getCurrencyInfo(CurrencyIds.ETH);\n const amount = parseUnits(value, currencyInfo.decimals);\n return priceEth(amount);\n}\n\n/**\n * Parses a string representation of USDC into a {@link PriceUsdc} object.\n *\n * Uses {@link getCurrencyInfo} to get the correct number of decimals (6) for USDC\n * and {@link parseUnits} from viem to convert the decimal string to a bigint.\n *\n * **Note:** Values with more than 6 decimal places will be truncated/rounded by viem's `parseUnits`.\n *\n * @param value - The decimal string to parse (e.g., \"123.45678\" for $123.45678)\n * @returns A PriceUsdc object with the amount in the smallest unit (6 decimals)\n *\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n * @throws {Error} If value is not a valid decimal string (e.g., \"abc\", \"1.2.3\")\n *\n * @example\n * parseUsdc(\"123.45678\") // returns { currency: \"USDC\", amount: 123456780n }\n * parseUsdc(\"1\") // returns { currency: \"USDC\", amount: 1000000n }\n * parseUsdc(\"0.001\") // returns { currency: \"USDC\", amount: 1000n }\n */\nexport function parseUsdc(value: string): PriceUsdc {\n validateAmountToParse(value);\n const currencyInfo = getCurrencyInfo(CurrencyIds.USDC);\n const amount = parseUnits(value, currencyInfo.decimals);\n return priceUsdc(amount);\n}\n\n/**\n * Parses a string representation of DAI into a {@link PriceDai} object.\n *\n * Uses {@link getCurrencyInfo} to get the correct number of decimals (18) for DAI\n * and {@link parseUnits} from viem to convert the decimal string to a bigint.\n *\n * **Note:** Values with more than 18 decimal places will be truncated/rounded by viem's `parseUnits`.\n *\n * @param value - The decimal string to parse (e.g., \"123.456789012345678\" for 123.456789012345678 DAI)\n * @returns A PriceDai object with the amount in the smallest unit (18 decimals)\n *\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n * @throws {Error} If value is not a valid decimal string (e.g., \"abc\", \"1.2.3\")\n *\n * @example\n * parseDai(\"123.456789012345678\") // returns { currency: \"DAI\", amount: 123456789012345678000n }\n * parseDai(\"1\") // returns { currency: \"DAI\", amount: 1000000000000000000n }\n * parseDai(\"0.001\") // returns { currency: \"DAI\", amount: 1000000000000000n }\n */\nexport function parseDai(value: string): PriceDai {\n validateAmountToParse(value);\n const currencyInfo = getCurrencyInfo(CurrencyIds.DAI);\n const amount = parseUnits(value, currencyInfo.decimals);\n return priceDai(amount);\n}\n\n/**\n * Parses a string representation of ENS Tokens into a {@link PriceEnsTokens} object.\n *\n * Uses {@link getCurrencyInfo} to get the correct number of decimals (18) for ENS Tokens\n * and {@link parseUnits} from viem to convert the decimal string to a bigint.\n *\n * **Note:** Values with more than 18 decimal places will be truncated/rounded by viem's `parseUnits`.\n *\n * @param value - The decimal string to parse (e.g., \"123.456789012345678\" for 123.456789012345678 ENS Tokens)\n * @returns A PriceEnsTokens object with the amount in the smallest unit (18 decimals)\n *\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n * @throws {Error} If value is not a valid decimal string (e.g., \"abc\", \"1.2.3\")\n *\n * @example\n * parseEnsTokens(\"123.456789012345678\") // returns { currency: \"ENSTokens\", amount: 123456789012345678000n }\n * parseEnsTokens(\"1\") // returns { currency: \"ENSTokens\", amount: 1000000000000000000n }\n * parseEnsTokens(\"0.001\") // returns { currency: \"ENSTokens\", amount: 1000000000000000n }\n */\nexport function parseEnsTokens(value: string): PriceEnsTokens {\n validateAmountToParse(value);\n const currencyInfo = getCurrencyInfo(CurrencyIds.ENSTokens);\n const amount = parseUnits(value, currencyInfo.decimals);\n return priceEnsTokens(amount);\n}\n","/**\n * Filter out duplicates.\n */\nexport const uniq = <T>(arr: T[]): T[] => [...new Set(arr)];\n","import { ENSNamespaceIds } from \"@ensnode/datasources\";\n\nimport { type EnsIndexerPublicConfig, PluginName } from \"./types\";\n\n/**\n * Determines if the provided `config` results in indexing behavior compatible with the legacy ENS\n * Subgraph.\n *\n * @see https://ensnode.io/docs/concepts/what-is-the-ens-subgraph\n */\nexport function isSubgraphCompatible(\n config: Pick<EnsIndexerPublicConfig, \"namespace\" | \"plugins\" | \"clientLabelSet\">,\n): boolean {\n // 1. only the subgraph plugin is active\n const onlySubgraphPluginActivated =\n config.plugins.length === 1 && config.plugins[0] === PluginName.Subgraph;\n\n // 2. label set id must be \"subgraph\" and version must be 0\n const isSubgraphLabelSet =\n config.clientLabelSet.labelSetId === \"subgraph\" && config.clientLabelSet.labelSetVersion === 0;\n\n const isEnsTestEnvLabelSet =\n config.clientLabelSet.labelSetId === \"ens-test-env\" &&\n config.clientLabelSet.labelSetVersion === 0;\n\n // config should be considered subgraph-compatible if in ens-test-env namespace with ens-test-env labelset\n const labelSetIsSubgraphCompatible =\n isSubgraphLabelSet || (config.namespace === ENSNamespaceIds.EnsTestEnv && isEnsTestEnvLabelSet);\n\n return onlySubgraphPluginActivated && labelSetIsSubgraphCompatible;\n}\n","import type {\n EnsRainbowClientLabelSet,\n EnsRainbowServerLabelSet,\n LabelSetId,\n LabelSetVersion,\n} from \"../../ensrainbow\";\nimport {\n makeLabelSetIdSchema,\n makeLabelSetVersionStringSchema,\n} from \"../../ensrainbow/zod-schemas/config\";\n\n/**\n * Builds a valid LabelSetId from a string.\n * @param maybeLabelSetId - The string to validate and convert to a LabelSetId.\n * @returns A valid LabelSetId.\n * @throws If the input string is not a valid LabelSetId.\n */\nexport function buildLabelSetId(maybeLabelSetId: string): LabelSetId {\n return makeLabelSetIdSchema(\"LabelSetId\").parse(maybeLabelSetId);\n}\n\n/**\n * Builds a valid LabelSetVersion from a number or string.\n * @param maybeLabelSetVersion - The number or string to validate and convert to a LabelSetVersion.\n * @returns A valid LabelSetVersion.\n * @throws If the input is not a valid LabelSetVersion.\n */\nexport function buildLabelSetVersion(maybeLabelSetVersion: number | string): LabelSetVersion {\n return makeLabelSetVersionStringSchema(\"LabelSetVersion\").parse(maybeLabelSetVersion);\n}\n\n/**\n * Builds an EnsRainbowClientLabelSet.\n * @param labelSetId - The label set ID.\n * @param labelSetVersion - The label set version.\n * @returns A valid EnsRainbowClientLabelSet object.\n * @throws If `labelSetVersion` is defined without `labelSetId`.\n */\nexport function buildEnsRainbowClientLabelSet(\n labelSetId?: LabelSetId,\n labelSetVersion?: LabelSetVersion,\n): EnsRainbowClientLabelSet {\n if (labelSetVersion !== undefined && labelSetId === undefined) {\n throw new Error(\"When a labelSetVersion is defined, labelSetId must also be defined.\");\n }\n\n return { labelSetId, labelSetVersion };\n}\n\n/**\n * Validates that the server's label set is compatible with the client's requested label set.\n * @param serverSet - The label set provided by the server.\n * @param clientSet - The label set requested by the client.\n * @throws If the server set is not compatible with the client set.\n */\nexport function validateSupportedLabelSetAndVersion(\n serverSet: EnsRainbowServerLabelSet,\n clientSet: EnsRainbowClientLabelSet,\n): void {\n if (clientSet.labelSetId === undefined) {\n // Client did not specify a label set, so any server set is acceptable.\n return;\n }\n\n if (serverSet.labelSetId !== clientSet.labelSetId) {\n throw new Error(\n `Server label set ID \"${serverSet.labelSetId}\" does not match client's requested label set ID \"${clientSet.labelSetId}\".`,\n );\n }\n\n if (\n clientSet.labelSetVersion !== undefined &&\n serverSet.highestLabelSetVersion < clientSet.labelSetVersion\n ) {\n throw new Error(\n `Server highest label set version ${serverSet.highestLabelSetVersion} is less than client's requested version ${clientSet.labelSetVersion} for label set ID \"${clientSet.labelSetId}\".`,\n );\n }\n}\n","import type { ZodCheckFnInput } from \"../../shared/zod-types\";\nimport type { EnsIndexerVersionInfo } from \"./types\";\n\n/**\n * Invariant: ensDb version is same as ensIndexer version\n */\nexport function invariant_ensDbVersionIsSameAsEnsIndexerVersion(\n ctx: ZodCheckFnInput<EnsIndexerVersionInfo>,\n) {\n const versionInfo = ctx.value;\n\n if (versionInfo.ensDb !== versionInfo.ensIndexer) {\n ctx.issues.push({\n code: \"custom\",\n input: versionInfo,\n message: \"`ensDb` version must be same as `ensIndexer` version\",\n });\n }\n}\n","import { z } from \"zod/v4\";\n\n/**\n * Reasons why TheGraph fallback cannot be used.\n */\nexport const TheGraphCannotFallbackReasonSchema = z.enum({\n NotSubgraphCompatible: \"not-subgraph-compatible\",\n NoApiKey: \"no-api-key\",\n NoSubgraphUrl: \"no-subgraph-url\",\n});\n\nexport type TheGraphCannotFallbackReason = z.infer<typeof TheGraphCannotFallbackReasonSchema>;\n\n/**\n * Configuration for TheGraph fallback behavior.\n * Indicates whether fallback to TheGraph is possible and the reason if not.\n */\nexport const TheGraphFallbackSchema = z.discriminatedUnion(\"canFallback\", [\n z.strictObject({\n canFallback: z.literal(true),\n url: z.string(),\n }),\n z.strictObject({\n canFallback: z.literal(false),\n reason: TheGraphCannotFallbackReasonSchema,\n }),\n]);\n\nexport type TheGraphFallback = z.infer<typeof TheGraphFallbackSchema>;\n","import { z } from \"zod/v4\";\n\nimport {\n makeRealtimeIndexingStatusProjectionSchema,\n makeSerializedRealtimeIndexingStatusProjectionSchema,\n} from \"../../../indexing-status/zod-schema/realtime-indexing-status-projection\";\nimport {\n makeEnsNodeStackInfoSchema,\n makeSerializedEnsNodeStackInfoSchema,\n} from \"../../../stack-info/zod-schemas/ensnode-stack-info\";\nimport {\n type EnsApiIndexingStatusResponse,\n EnsApiIndexingStatusResponseCodes,\n type EnsApiIndexingStatusResponseError,\n type EnsApiIndexingStatusResponseOk,\n} from \"./response\";\nimport {\n SerializedEnsApiIndexingStatusResponse,\n SerializedEnsApiIndexingStatusResponseOk,\n} from \"./serialized-response\";\n\n/**\n * Schema for {@link EnsApiIndexingStatusResponseOk}\n **/\nexport const makeEnsApiIndexingStatusResponseOkSchema = (\n valueLabel: string = \"Indexing Status Response OK\",\n) =>\n z.strictObject({\n responseCode: z.literal(EnsApiIndexingStatusResponseCodes.Ok),\n realtimeProjection: makeRealtimeIndexingStatusProjectionSchema(valueLabel),\n stackInfo: makeEnsNodeStackInfoSchema(valueLabel),\n });\n\n/**\n * Schema for {@link EnsApiIndexingStatusResponseError}\n **/\nexport const makeEnsApiIndexingStatusResponseErrorSchema = (\n _valueLabel: string = \"Indexing Status Response Error\",\n) =>\n z.strictObject({\n responseCode: z.literal(EnsApiIndexingStatusResponseCodes.Error),\n });\n\n/**\n * Schema for {@link EnsApiIndexingStatusResponse}\n **/\nexport const makeEnsApiIndexingStatusResponseSchema = (\n valueLabel: string = \"Indexing Status Response\",\n) =>\n z.discriminatedUnion(\"responseCode\", [\n makeEnsApiIndexingStatusResponseOkSchema(valueLabel),\n makeEnsApiIndexingStatusResponseErrorSchema(valueLabel),\n ]);\n\n/**\n * Schema for {@link EnsApiIndexingStatusResponse}\n * @deprecated Use {@link makeEnsApiIndexingStatusResponseSchema} instead.\n */\nexport const makeIndexingStatusResponseSchema = makeEnsApiIndexingStatusResponseSchema;\n\n/**\n * Schema for {@link SerializedEnsApiIndexingStatusResponseOk}\n **/\nexport const makeSerializedEnsApiIndexingStatusResponseOkSchema = (\n valueLabel: string = \"Serialized Indexing Status Response OK\",\n) =>\n z.object({\n responseCode: z.literal(EnsApiIndexingStatusResponseCodes.Ok),\n realtimeProjection: makeSerializedRealtimeIndexingStatusProjectionSchema(valueLabel),\n stackInfo: makeSerializedEnsNodeStackInfoSchema(valueLabel),\n });\n\n/**\n * Schema for {@link SerializedEnsApiIndexingStatusResponse}\n **/\nexport const makeSerializedEnsApiIndexingStatusResponseSchema = (\n valueLabel: string = \"Serialized Indexing Status Response\",\n) =>\n z.discriminatedUnion(\"responseCode\", [\n makeSerializedEnsApiIndexingStatusResponseOkSchema(valueLabel),\n makeEnsApiIndexingStatusResponseErrorSchema(valueLabel),\n ]);\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport { makeDurationSchema, makeUnixTimestampSchema } from \"../../shared/zod-schemas\";\nimport type { RealtimeIndexingStatusProjection } from \"../realtime-indexing-status-projection\";\nimport {\n makeCrossChainIndexingStatusSnapshotSchema,\n makeSerializedCrossChainIndexingStatusSnapshotSchema,\n} from \"./cross-chain-indexing-status-snapshot\";\n\n/**\n * Invariant: For realtime indexing status projection,\n * `projectedAt` is after or same as `snapshot.snapshotTime`.\n */\nexport function invariant_realtimeIndexingStatusProjectionProjectedAtIsAfterOrEqualToSnapshotTime(\n ctx: ParsePayload<RealtimeIndexingStatusProjection>,\n) {\n const projection = ctx.value;\n\n const { snapshot, projectedAt } = projection;\n\n if (snapshot.snapshotTime > projectedAt) {\n ctx.issues.push({\n code: \"custom\",\n input: projection,\n message: \"`projectedAt` must be after or same as `snapshot.snapshotTime`.\",\n });\n }\n}\n\n/**\n * Invariant: For realtime indexing status projection,\n * `worstCaseDistance` is the difference between `projectedAt`\n * and `snapshot.slowestChainIndexingCursor`.\n */\nexport function invariant_realtimeIndexingStatusProjectionWorstCaseDistanceIsCorrect(\n ctx: ParsePayload<RealtimeIndexingStatusProjection>,\n) {\n const projection = ctx.value;\n const { projectedAt, snapshot, worstCaseDistance } = projection;\n const expectedWorstCaseDistance = projectedAt - snapshot.slowestChainIndexingCursor;\n\n if (worstCaseDistance !== expectedWorstCaseDistance) {\n ctx.issues.push({\n code: \"custom\",\n input: projection,\n message:\n \"`worstCaseDistance` must be the exact difference between `projectedAt` and `snapshot.slowestChainIndexingCursor`.\",\n });\n }\n}\n\n/**\n * Makes Zod schema for {@link RealtimeIndexingStatusProjection}\n */\nexport const makeRealtimeIndexingStatusProjectionSchema = (\n valueLabel: string = \"Realtime Indexing Status Projection\",\n) =>\n z\n .object({\n projectedAt: makeUnixTimestampSchema(valueLabel).describe(\n \"The timestamp representing 'now' as of the time this projection was generated.\",\n ),\n worstCaseDistance: makeDurationSchema(valueLabel).describe(\n \"The distance between `projectedAt` and `snapshot.slowestChainIndexingCursor` in seconds. This is a worst-case distance because it assumes no indexing progress has been made since `snapshot.snapshotTime` and that each indexed chain has added a new block as of `projectedAt`.\",\n ),\n snapshot: makeCrossChainIndexingStatusSnapshotSchema(valueLabel).describe(\n \"The cross-chain indexing status snapshot that this projection is based on.\",\n ),\n })\n .check(invariant_realtimeIndexingStatusProjectionProjectedAtIsAfterOrEqualToSnapshotTime)\n .check(invariant_realtimeIndexingStatusProjectionWorstCaseDistanceIsCorrect);\n\n/**\n * Makes Zod schema for {@link SerializedRealtimeIndexingStatusProjection}.\n */\nexport const makeSerializedRealtimeIndexingStatusProjectionSchema = (\n valueLabel: string = \"Value\",\n) =>\n z.object({\n snapshot: makeSerializedCrossChainIndexingStatusSnapshotSchema(valueLabel).describe(\n \"The cross-chain indexing status snapshot that this projection is based on.\",\n ),\n projectedAt: makeUnixTimestampSchema(valueLabel).describe(\n \"The timestamp representing 'now' as of the time this projection was generated.\",\n ),\n worstCaseDistance: makeDurationSchema(valueLabel).describe(\n \"The distance between `projectedAt` and `snapshot.slowestChainIndexingCursor` in seconds. This is a worst-case distance because it assumes no indexing progress has been made since `snapshot.snapshotTime` and that each indexed chain has added a new block as of `projectedAt`.\",\n ),\n });\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport { makeUnixTimestampSchema } from \"../../shared/zod-schemas\";\nimport {\n type CrossChainIndexingStatusSnapshotOmnichain,\n CrossChainIndexingStrategyIds,\n getHighestKnownBlockTimestamp,\n} from \"../cross-chain-indexing-status-snapshot\";\nimport type { SerializedCrossChainIndexingStatusSnapshot } from \"../serialize/cross-chain-indexing-status-snapshot\";\nimport {\n makeOmnichainIndexingStatusSnapshotSchema,\n makeSerializedOmnichainIndexingStatusSnapshotSchema,\n} from \"./omnichain-indexing-status-snapshot\";\n\n/**\n * Invariant: for cross-chain indexing status snapshot omnichain,\n * slowestChainIndexingCursor equals to omnichainSnapshot.omnichainIndexingCursor\n */\nexport function invariant_slowestChainEqualsToOmnichainSnapshotTime(\n ctx: ParsePayload<CrossChainIndexingStatusSnapshotOmnichain>,\n) {\n const { slowestChainIndexingCursor, omnichainSnapshot } = ctx.value;\n const { omnichainIndexingCursor } = omnichainSnapshot;\n\n if (slowestChainIndexingCursor !== omnichainIndexingCursor) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'slowestChainIndexingCursor' must be equal to 'omnichainSnapshot.omnichainIndexingCursor'`,\n });\n }\n}\n\n/**\n * Invariant: for cross-chain indexing status snapshot omnichain,\n * snapshotTime is greater than or equal to the \"highest known block\" timestamp.\n */\nexport function invariant_snapshotTimeIsTheHighestKnownBlockTimestamp(\n ctx: ParsePayload<CrossChainIndexingStatusSnapshotOmnichain>,\n) {\n const { snapshotTime, omnichainSnapshot } = ctx.value;\n const chains = Array.from(omnichainSnapshot.chains.values());\n const highestKnownBlockTimestamp = getHighestKnownBlockTimestamp(chains);\n\n if (snapshotTime < highestKnownBlockTimestamp) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'snapshotTime' (${snapshotTime}) must be greater than or equal to the \"highest known block timestamp\" (${highestKnownBlockTimestamp})`,\n });\n }\n}\n\n/**\n * Makes Zod schema for {@link CrossChainIndexingStatusSnapshotOmnichain}\n */\nconst makeCrossChainIndexingStatusSnapshotOmnichainSchema = (\n valueLabel: string = \"Cross-chain Indexing Status Snapshot Omnichain\",\n) =>\n z\n .object({\n strategy: z.literal(CrossChainIndexingStrategyIds.Omnichain),\n slowestChainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n snapshotTime: makeUnixTimestampSchema(valueLabel),\n omnichainSnapshot: makeOmnichainIndexingStatusSnapshotSchema(valueLabel),\n })\n .check(invariant_slowestChainEqualsToOmnichainSnapshotTime)\n .check(invariant_snapshotTimeIsTheHighestKnownBlockTimestamp);\n\n/**\n * Makes Zod schema for {@link CrossChainIndexingStatusSnapshot}\n */\nexport const makeCrossChainIndexingStatusSnapshotSchema = (\n valueLabel: string = \"Cross-chain Indexing Status Snapshot\",\n) =>\n z.discriminatedUnion(\"strategy\", [\n makeCrossChainIndexingStatusSnapshotOmnichainSchema(valueLabel),\n ]);\n\n/**\n * Makes Zod schema for {@link SerializedCrossChainIndexingStatusSnapshot}\n */\nexport const makeSerializedCrossChainIndexingStatusSnapshotSchema = (\n valueLabel: string = \"Serialized Cross-chain Indexing Status Snapshot\",\n) =>\n z.object({\n strategy: z.enum(CrossChainIndexingStrategyIds),\n slowestChainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n snapshotTime: makeUnixTimestampSchema(valueLabel),\n omnichainSnapshot: makeSerializedOmnichainIndexingStatusSnapshotSchema(valueLabel),\n });\n","import type { BlockRef } from \"./types\";\n\n/**\n * Compare two {@link BlockRef} objects to check\n * if blockA is before blockB.\n *\n * Ordering is determined by block number, which is the canonical\n * ordering on a single chain. Timestamp is not used because EVM\n * chains allow consecutive blocks to share the same timestamp.\n */\nexport function isBefore(blockA: BlockRef, blockB: BlockRef) {\n return blockA.number < blockB.number;\n}\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is equal to blockB.\n */\nexport function isEqualTo(blockA: BlockRef, blockB: BlockRef) {\n return blockA.number === blockB.number && blockA.timestamp === blockB.timestamp;\n}\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is before or equal to blockB.\n */\nexport function isBeforeOrEqualTo(blockA: BlockRef, blockB: BlockRef) {\n return isBefore(blockA, blockB) || isEqualTo(blockA, blockB);\n}\n","import { isBeforeOrEqualTo as isBlockRefBeforeOrEqualTo } from \"./block-ref\";\nimport type { BlockNumber, BlockRef } from \"./types\";\n\nexport const RangeTypeIds = {\n Unbounded: \"unbounded\",\n LeftBounded: \"left-bounded\",\n RightBounded: \"right-bounded\",\n Bounded: \"bounded\",\n} as const;\n\nexport type RangeType = (typeof RangeTypeIds)[keyof typeof RangeTypeIds];\n\n/************************\n * Block number range\n ***********************/\n\n/**\n * Block number range unbounded\n */\nexport interface BlockNumberRangeUnbounded {\n rangeType: typeof RangeTypeIds.Unbounded;\n startBlock?: undefined;\n endBlock?: undefined;\n}\n\n/**\n * Block number range left bounded\n *\n * Range is inclusive of its left bound.\n */\nexport interface BlockNumberRangeLeftBounded {\n rangeType: typeof RangeTypeIds.LeftBounded;\n startBlock: BlockNumber;\n endBlock?: undefined;\n}\n\n/**\n * Block number range right bounded\n *\n * Range is inclusive of its right bound.\n */\nexport interface BlockNumberRangeRightBounded {\n rangeType: typeof RangeTypeIds.RightBounded;\n startBlock?: undefined;\n endBlock: BlockNumber;\n}\n\n/**\n * Block number range bounded\n *\n * Range is inclusive of its bounds.\n *\n * Invariants:\n * - `startBlock` is lower than or equal to `endBlock`\n */\nexport interface BlockNumberRangeBounded {\n rangeType: typeof RangeTypeIds.Bounded;\n startBlock: BlockNumber;\n endBlock: BlockNumber;\n}\n\n/**\n * Block number range with start block defined.\n *\n * This is a useful type for representing block ranges for indexed chains.\n */\nexport type BlockNumberRangeWithStartBlock = BlockNumberRangeLeftBounded | BlockNumberRangeBounded;\n\n/**\n * Block number range\n *\n * Use the `rangeType` field to determine the specific type interpretation\n * at runtime.\n */\nexport type BlockNumberRange =\n | BlockNumberRangeUnbounded\n | BlockNumberRangeLeftBounded\n | BlockNumberRangeRightBounded\n | BlockNumberRangeBounded;\n\n/**\n * Build a block number range object.\n */\nexport function buildBlockNumberRange(\n startBlock: undefined,\n endBlock: undefined,\n): BlockNumberRangeUnbounded;\nexport function buildBlockNumberRange(\n startBlock: BlockNumber,\n endBlock: undefined,\n): BlockNumberRangeLeftBounded;\nexport function buildBlockNumberRange(\n startBlock: undefined,\n endBlock: BlockNumber,\n): BlockNumberRangeRightBounded;\nexport function buildBlockNumberRange(\n startBlock: BlockNumber,\n endBlock: BlockNumber,\n): BlockNumberRangeBounded;\nexport function buildBlockNumberRange(\n startBlock?: BlockNumber,\n endBlock?: BlockNumber,\n): BlockNumberRange;\nexport function buildBlockNumberRange(\n startBlock?: BlockNumber,\n endBlock?: BlockNumber,\n): BlockNumberRange {\n if (startBlock === undefined && endBlock === undefined) {\n return {\n rangeType: RangeTypeIds.Unbounded,\n } satisfies BlockNumberRangeUnbounded;\n }\n\n if (startBlock !== undefined && endBlock === undefined) {\n return {\n rangeType: RangeTypeIds.LeftBounded,\n startBlock,\n } satisfies BlockNumberRangeLeftBounded;\n }\n\n if (startBlock === undefined && endBlock !== undefined) {\n return {\n rangeType: RangeTypeIds.RightBounded,\n endBlock,\n } satisfies BlockNumberRangeRightBounded;\n }\n\n if (startBlock !== undefined && endBlock !== undefined) {\n // Invariant: `startBlock` is lower than or equal to `endBlock`\n if (startBlock > endBlock) {\n throw new Error(\n `For a block number range startBlock must be lower than or equal to endBlock.`,\n );\n }\n\n return {\n rangeType: RangeTypeIds.Bounded,\n startBlock,\n endBlock,\n } satisfies BlockNumberRangeBounded;\n }\n\n // This should be unreachable, but TypeScript needs the exhaustive check\n throw new Error(\"Invalid block number range. This should be unreachable.\");\n}\n\n/**\n * Merge multiple block number ranges into a single range.\n *\n * The resulting range is a union that covers all input ranges:\n * - Uses the minimum start block when every input range has a start block\n * - Uses the maximum end block when every input range has an end block\n * - Leaves a side unbounded when any input range is unbounded on that side\n *\n * Returns an unbounded range if no ranges are provided.\n *\n * @param ranges - The block number ranges to merge\n * @returns A single merged block number range covering all inputs\n */\nexport function mergeBlockNumberRanges(...ranges: BlockNumberRange[]): BlockNumberRange {\n if (ranges.length === 0) {\n return buildBlockNumberRange(undefined, undefined);\n }\n\n let minStartBlock: BlockNumber | undefined;\n let maxEndBlock: BlockNumber | undefined;\n let hasUnboundedStart = false;\n let hasUnboundedEnd = false;\n\n for (const range of ranges) {\n if (range.startBlock === undefined) {\n hasUnboundedStart = true;\n } else if (minStartBlock === undefined || range.startBlock < minStartBlock) {\n minStartBlock = range.startBlock;\n }\n\n if (range.endBlock === undefined) {\n hasUnboundedEnd = true;\n } else if (maxEndBlock === undefined || range.endBlock > maxEndBlock) {\n maxEndBlock = range.endBlock;\n }\n\n // Early return if the merged range is already unbounded\n if (hasUnboundedStart && hasUnboundedEnd) {\n return buildBlockNumberRange(undefined, undefined);\n }\n }\n\n // The merged range has an unbounded start if any input range has\n // an unbounded start\n if (hasUnboundedStart) {\n minStartBlock = undefined;\n }\n\n // The merged range has an unbounded end if any input range has\n // an unbounded end\n if (hasUnboundedEnd) {\n maxEndBlock = undefined;\n }\n\n return buildBlockNumberRange(minStartBlock, maxEndBlock);\n}\n\n/************************\n * Block ref range\n ***********************/\n\n/**\n * Block ref range unbounded\n */\nexport interface BlockRefRangeUnbounded {\n rangeType: typeof RangeTypeIds.Unbounded;\n startBlock?: undefined;\n endBlock?: undefined;\n}\n\n/**\n * Block ref range left bounded\n *\n * Range is inclusive of its left bound.\n */\nexport interface BlockRefRangeLeftBounded {\n rangeType: typeof RangeTypeIds.LeftBounded;\n startBlock: BlockRef;\n endBlock?: undefined;\n}\n\n/**\n * Block ref range right bounded\n *\n * Range is inclusive of its right bound.\n */\nexport interface BlockRefRangeRightBounded {\n rangeType: typeof RangeTypeIds.RightBounded;\n startBlock?: undefined;\n endBlock: BlockRef;\n}\n\n/**\n * Block ref range bounded\n *\n * Range is inclusive of its bounds.\n *\n * Invariants:\n * - `startBlock` is before or equal to `endBlock`\n */\nexport interface BlockRefRangeBounded {\n rangeType: typeof RangeTypeIds.Bounded;\n startBlock: BlockRef;\n endBlock: BlockRef;\n}\n\n/**\n * Block ref range\n *\n * Use the `rangeType` field to determine the specific type interpretation\n * at runtime.\n */\nexport type BlockRefRange =\n | BlockRefRangeUnbounded\n | BlockRefRangeLeftBounded\n | BlockRefRangeRightBounded\n | BlockRefRangeBounded;\n\n/**\n * Block ref range with start block defined.\n *\n * This is a useful type for representing block ranges for indexed chains.\n */\nexport type BlockRefRangeWithStartBlock = BlockRefRangeLeftBounded | BlockRefRangeBounded;\n\n/**\n * Build a block ref range object.\n */\nexport function buildBlockRefRange(\n startBlock: undefined,\n endBlock: undefined,\n): BlockRefRangeUnbounded;\nexport function buildBlockRefRange(\n startBlock: BlockRef,\n endBlock: undefined,\n): BlockRefRangeLeftBounded;\nexport function buildBlockRefRange(\n startBlock: undefined,\n endBlock: BlockRef,\n): BlockRefRangeRightBounded;\nexport function buildBlockRefRange(startBlock: BlockRef, endBlock: BlockRef): BlockRefRangeBounded;\nexport function buildBlockRefRange(startBlock?: BlockRef, endBlock?: BlockRef): BlockRefRange;\nexport function buildBlockRefRange(startBlock?: BlockRef, endBlock?: BlockRef): BlockRefRange {\n if (startBlock === undefined && endBlock === undefined) {\n return {\n rangeType: RangeTypeIds.Unbounded,\n } satisfies BlockRefRangeUnbounded;\n }\n\n if (startBlock !== undefined && endBlock === undefined) {\n return {\n rangeType: RangeTypeIds.LeftBounded,\n startBlock,\n } satisfies BlockRefRangeLeftBounded;\n }\n\n if (startBlock === undefined && endBlock !== undefined) {\n return {\n rangeType: RangeTypeIds.RightBounded,\n endBlock,\n } satisfies BlockRefRangeRightBounded;\n }\n\n if (startBlock !== undefined && endBlock !== undefined) {\n // Invariant: `startBlock` is before or equal to `endBlock`\n if (isBlockRefBeforeOrEqualTo(startBlock, endBlock) === false) {\n throw new Error(`For a block ref range startBlock must be before or equal to endBlock.`);\n }\n\n return {\n rangeType: RangeTypeIds.Bounded,\n startBlock,\n endBlock,\n } satisfies BlockRefRangeBounded;\n }\n\n // This should be unreachable, but TypeScript needs the exhaustive check\n throw new Error(\"Invalid block ref range. This should be unreachable.\");\n}\n","import type { ChainId, UnixTimestamp } from \"enssdk\";\n\nimport {\n type BlockRefRangeBounded,\n type BlockRefRangeLeftBounded,\n type BlockRefRangeWithStartBlock,\n RangeTypeIds,\n} from \"../shared/blockrange\";\nimport type { BlockRef } from \"../shared/types\";\n\n/**\n * The status of indexing a chain at the time an indexing status snapshot\n * is captured.\n */\nexport const ChainIndexingStatusIds = {\n /**\n * Represents that indexing of the chain is not ready to begin yet because:\n * - ENSIndexer is in its initialization phase and the data to build a\n * \"true\" {@link ChainIndexingStatusSnapshot} for the chain is still being loaded; or\n * - ENSIndexer is using an omnichain indexing strategy and the\n * `omnichainIndexingCursor` is <= `config.startBlock.timestamp` for the chain's\n * {@link ChainIndexingStatusSnapshot}.\n */\n Queued: \"chain-queued\",\n\n /**\n * Represents that indexing of the chain is in progress and under a special\n * \"backfill\" phase that optimizes for accelerated indexing until reaching the\n * \"fixed target\" `backfillEndBlock`.\n */\n Backfill: \"chain-backfill\",\n\n /**\n * Represents that the \"backfill\" phase of indexing the chain is completed\n * and that the chain is configured to be indexed for an indefinite range.\n * Therefore, indexing of the chain remains indefinitely in progress where\n * ENSIndexer will continuously work to discover and index new blocks as they\n * are added to the chain across time.\n */\n Following: \"chain-following\",\n\n /**\n * Represents that indexing of the chain is completed as the chain is configured\n * to be indexed for a definite range and the indexing of all blocks through\n * that definite range is completed.\n */\n Completed: \"chain-completed\",\n} as const;\n\n/**\n * The derived string union of possible {@link ChainIndexingStatusIds}.\n */\nexport type ChainIndexingStatusId =\n (typeof ChainIndexingStatusIds)[keyof typeof ChainIndexingStatusIds];\n\n/**\n * Chain indexing status snapshot for a chain whose `chainStatus` is\n * {@link ChainIndexingStatusIds.Queued}.\n *\n * Invariants:\n * - `chainStatus` is always {@link ChainIndexingStatusIds.Queued}.\n */\nexport interface ChainIndexingStatusSnapshotQueued {\n /**\n * The status of indexing the chain at the time the indexing status snapshot\n * was captured.\n */\n chainStatus: typeof ChainIndexingStatusIds.Queued;\n\n /**\n * The indexing configuration of the chain.\n */\n config: BlockRefRangeWithStartBlock;\n}\n\n/**\n * Chain indexing status snapshot for a chain whose `chainStatus` is\n * {@link ChainIndexingStatusIds.Backfill}.\n *\n * During a backfill, special performance optimizations are applied to\n * index all blocks between `config.startBlock` and `backfillEndBlock`\n * as fast as possible.\n *\n * Note how `backfillEndBlock` is a \"fixed target\" that does not change during\n * the lifetime of an ENSIndexer process instance:\n * - If the `config` is {@link BlockRefRangeBounded}:\n * `backfillEndBlock` is always the same as `config.endBlock`.\n * - If the `config` is {@link BlockRefRangeLeftBounded}:\n * `backfillEndBlock` is a {@link BlockRef} to what was the latest block on the\n * chain when the ENSIndexer process was performing its initialization. Note how\n * this means that if the backfill process takes X hours to complete, because the\n * `backfillEndBlock` is a \"fixed target\", when `chainStatus` transitions to\n * {@link ChainIndexingStatusIds.Following} the chain will be X hours behind\n * \"realtime\" indexing.\n *\n * When `latestIndexedBlock` reaches `backfillEndBlock` the backfill is complete.\n * The moment backfill is complete the `chainStatus` may not immediately transition.\n * Instead, internal processing is completed for a period of time while\n * `chainStatus` remains {@link ChainIndexingStatusIds.Backfill}. After this internal\n * processing is completed `chainStatus` will transition:\n * - to {@link ChainIndexingStatusIds.Following} if the `config` is\n * {@link BlockRefRangeLeftBounded}.\n * - to {@link ChainIndexingStatusIds.Completed} if the `config` is\n * {@link BlockRefRangeBounded}.\n *\n * Invariants:\n * - `chainStatus` is always {@link ChainIndexingStatusIds.Backfill}.\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `config.endBlock` is always the same as `backfillEndBlock` if and only if\n * the config is {@link BlockRefRangeBounded}.\n * - `latestIndexedBlock` is always before or the same as `backfillEndBlock`\n */\nexport interface ChainIndexingStatusSnapshotBackfill {\n /**\n * The status of indexing the chain at the time the indexing status snapshot\n * was captured.\n */\n chainStatus: typeof ChainIndexingStatusIds.Backfill;\n\n /**\n * The indexing configuration of the chain.\n */\n config: BlockRefRangeWithStartBlock;\n\n /**\n * A {@link BlockRef} to the block that was most recently indexed as of the time the\n * indexing status snapshot was captured.\n */\n latestIndexedBlock: BlockRef;\n\n /**\n * A {@link BlockRef} to the block where the backfill will end.\n */\n backfillEndBlock: BlockRef;\n}\n\n/**\n * Chain indexing status snapshot for a chain whose `chainStatus` is\n * {@link ChainIndexingStatusIds.Following}.\n *\n * Invariants:\n * - `chainStatus` is always {@link ChainIndexingStatusIds.Following}.\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always before or the same as `latestKnownBlock`\n */\nexport interface ChainIndexingStatusSnapshotFollowing {\n /**\n * The status of indexing the chain at the time the indexing status snapshot\n * was captured.\n */\n chainStatus: typeof ChainIndexingStatusIds.Following;\n\n /**\n * The indexing configuration of the chain.\n */\n config: BlockRefRangeLeftBounded;\n\n /**\n * A {@link BlockRef} to the block that was most recently indexed as of the time the\n * indexing status snapshot was captured.\n */\n latestIndexedBlock: BlockRef;\n\n /**\n * A {@link BlockRef} to the \"highest\" block that has been discovered by RPCs\n * and stored in the RPC cache as of the time the indexing status snapshot was\n * captured.\n */\n latestKnownBlock: BlockRef;\n}\n\n/**\n * Chain indexing status snapshot for a chain whose `chainStatus` is\n * {@link ChainIndexingStatusIds.Completed}.\n *\n * After the backfill of a chain is completed, if the chain was configured\n * to be indexed for a definite range, the chain indexing status will transition to\n * {@link ChainIndexingStatusIds.Completed}.\n *\n * Invariants:\n * - `chainStatus` is always {@link ChainIndexingStatusIds.Completed}.\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always the same as `config.endBlock`.\n */\nexport interface ChainIndexingStatusSnapshotCompleted {\n /**\n * The status of indexing the chain at the time the indexing status snapshot\n * was captured.\n */\n chainStatus: typeof ChainIndexingStatusIds.Completed;\n\n /**\n * The indexing configuration of the chain.\n */\n config: BlockRefRangeBounded;\n\n /**\n * A {@link BlockRef} to the block that was most recently indexed as of the time the\n * indexing status snapshot was captured.\n */\n latestIndexedBlock: BlockRef;\n}\n\n/**\n * Indexing status snapshot for a single chain.\n *\n * Use the `chainStatus` field to determine the specific type interpretation\n * at runtime.\n */\nexport type ChainIndexingStatusSnapshot =\n | ChainIndexingStatusSnapshotQueued\n | ChainIndexingStatusSnapshotBackfill\n | ChainIndexingStatusSnapshotFollowing\n | ChainIndexingStatusSnapshotCompleted;\n\n/**\n * Get the timestamp of the lowest `config.startBlock` across all chains\n * in the provided array of {@link ChainIndexingStatusSnapshot}.\n *\n * Such timestamp is useful when presenting the \"lowest\" block\n * to be indexed across all chains.\n */\nexport function getTimestampForLowestOmnichainStartBlock(\n chains: ChainIndexingStatusSnapshot[],\n): UnixTimestamp {\n const earliestKnownBlockTimestamps: UnixTimestamp[] = chains.map(\n (chain) => chain.config.startBlock.timestamp,\n );\n\n // Invariant: earliestKnownBlockTimestamps is guaranteed to have at least one element\n if (earliestKnownBlockTimestamps.length === 0) {\n throw new Error(\n \"Invariant violation: at least one chain is required to determine the lowest omnichain start block timestamp\",\n );\n }\n\n return Math.min(...earliestKnownBlockTimestamps);\n}\n\n/**\n * Get the timestamp of the \"highest known block\" across all chains\n * in the provided array of {@link ChainIndexingStatusSnapshot}.\n *\n * Such timestamp is useful when presenting the \"highest known block\"\n * to be indexed across all chains.\n *\n * The \"highest known block\" for a chain depends on its status:\n * - `config.endBlock` for a \"queued\" chain (only if the config range type is `Bounded`),\n * - `backfillEndBlock` for a \"backfill\" chain,\n * - `latestIndexedBlock` for a \"completed\" chain,\n * - `latestKnownBlock` for a \"following\" chain.\n */\nexport function getTimestampForHighestOmnichainKnownBlock(\n chains: ChainIndexingStatusSnapshot[],\n): UnixTimestamp {\n const latestKnownBlockTimestamps: UnixTimestamp[] = [];\n\n for (const chain of chains) {\n switch (chain.chainStatus) {\n case ChainIndexingStatusIds.Queued:\n if (chain.config.rangeType === RangeTypeIds.Bounded) {\n latestKnownBlockTimestamps.push(chain.config.endBlock.timestamp);\n }\n break;\n\n case ChainIndexingStatusIds.Backfill:\n latestKnownBlockTimestamps.push(chain.backfillEndBlock.timestamp);\n\n break;\n\n case ChainIndexingStatusIds.Completed:\n latestKnownBlockTimestamps.push(chain.latestIndexedBlock.timestamp);\n break;\n\n case ChainIndexingStatusIds.Following:\n latestKnownBlockTimestamps.push(chain.latestKnownBlock.timestamp);\n break;\n }\n }\n\n // Invariant: at least one chain must contribute a known block timestamp\n // (e.g., Queued chains with Indefinite config do not contribute)\n if (latestKnownBlockTimestamps.length === 0) {\n throw new Error(\n \"Invariant: at least one chain must contribute a known block timestamp to determine the highest omnichain known block timestamp\",\n );\n }\n\n return Math.max(...latestKnownBlockTimestamps);\n}\n\n/**\n * Sort a list of [{@link ChainId}, {@link ChainIndexingStatusSnapshot}] tuples\n * by the omnichain start block timestamp in ascending order.\n */\nexport function sortChainStatusesByStartBlockAsc<\n ChainStatusType extends ChainIndexingStatusSnapshot,\n>(chains: [ChainId, ChainStatusType][]): [ChainId, ChainStatusType][] {\n // Sort the chain statuses by the omnichain first block to index timestamp\n return [...chains].sort(\n ([, chainA], [, chainB]) =>\n chainA.config.startBlock.timestamp - chainB.config.startBlock.timestamp,\n );\n}\n","import type { ChainId, UnixTimestamp } from \"enssdk\";\n\nimport { RangeTypeIds } from \"../shared/blockrange\";\nimport type { BlockRef } from \"../shared/types\";\nimport {\n ChainIndexingStatusIds,\n type ChainIndexingStatusSnapshot,\n} from \"./chain-indexing-status-snapshot\";\nimport type { OmnichainIndexingStatusSnapshot } from \"./omnichain-indexing-status-snapshot\";\nimport { validateCrossChainIndexingStatusSnapshot } from \"./validate/cross-chain-indexing-status-snapshot\";\n\n/**\n * The strategy used for indexing one or more chains.\n *\n * @see https://ponder.sh/docs/api-reference/ponder/config#parameters\n */\nexport const CrossChainIndexingStrategyIds = {\n /**\n * Represents that the indexing of events across all indexed chains will\n * proceed in a deterministic \"omnichain\" ordering by block timestamp, chain ID,\n * and block number.\n *\n * This strategy is \"deterministic\" in that the order of processing cross-chain indexed\n * events and each resulting indexed data state transition recorded in ENSDb is always\n * the same for each ENSIndexer instance operating with an equivalent\n * `ENSIndexerConfig` and ENSIndexer version. However it also has the drawbacks of:\n * - increased indexing latency that must wait for the slowest indexed chain to\n * add new blocks or to discover new blocks through the configured RPCs.\n * - if any indexed chain gets \"stuck\" due to chain or RPC failures, all indexed chains\n * will be affected.\n */\n Omnichain: \"omnichain\",\n} as const;\n\n/**\n * The derived string union of possible {@link CrossChainIndexingStrategyIds}.\n */\nexport type CrossChainIndexingStrategyId =\n (typeof CrossChainIndexingStrategyIds)[keyof typeof CrossChainIndexingStrategyIds];\n\n/**\n * Cross-chain indexing status snapshot when the `strategy` is\n * {@link CrossChainIndexingStrategyId.Omnichain}.\n *\n * Invariants:\n * - `strategy` is always {@link CrossChainIndexingStrategyId.Omnichain}.\n * - `slowestChainIndexingCursor` is always equal to\n * `omnichainSnapshot.omnichainIndexingCursor`.\n * - `snapshotTime` is always >= the \"highest known block timestamp\", defined as the max of:\n * - the `slowestChainIndexingCursor`.\n * - the `config.startBlock.timestamp` for all indexed chains.\n * - the `config.endBlock.timestamp` for all indexed chains with a `config.rangeType` of\n * {@link RangeTypeIds.Bounded}.\n * - the `backfillEndBlock.timestamp` for all chains with `chainStatus` of\n * {@link ChainIndexingStatusIds.Backfill}.\n * - the `latestKnownBlock.timestamp` for all chains with `chainStatus` of\n * {@link ChainIndexingStatusIds.Following}.\n */\nexport interface CrossChainIndexingStatusSnapshotOmnichain {\n /**\n * The strategy used for indexing one or more chains.\n */\n strategy: typeof CrossChainIndexingStrategyIds.Omnichain;\n\n /**\n * The timestamp of the \"slowest\" latest indexed block timestamp\n * across all indexed chains.\n */\n slowestChainIndexingCursor: UnixTimestamp;\n\n /**\n * The timestamp when the cross-chain indexing status snapshot was generated.\n *\n * Due to possible clock skew between different systems this value must be set\n * to the max of each of the following values to ensure all invariants are followed:\n * - the current system time of the system generating this cross-chain indexing\n * status snapshot.\n * - the \"highest known block timestamp\" (see invariants above for full definition).\n */\n snapshotTime: UnixTimestamp;\n\n /**\n * The omnichain indexing status snapshot for one or more chains.\n */\n omnichainSnapshot: OmnichainIndexingStatusSnapshot;\n}\n\n/**\n * Cross-chain indexing status snapshot for one or more chains.\n *\n * Use the `strategy` field to determine the specific type interpretation\n * at runtime.\n *\n * Currently, only omnichain indexing is supported. This type could theoretically\n * be extended to support other cross-chain indexing strategies in the future,\n * such as Ponder's \"multichain\" indexing strategy that indexes each chain\n * independently without deterministic ordering.\n */\nexport type CrossChainIndexingStatusSnapshot = CrossChainIndexingStatusSnapshotOmnichain;\n\n/**\n * Gets the latest indexed {@link BlockRef} for the given {@link ChainId}.\n *\n * @returns the latest indexed {@link BlockRef} for the given {@link ChainId}, or null if the chain\n * isn't being indexed at all or is queued and therefore hasn't started indexing yet.\n */\nexport function getLatestIndexedBlockRef(\n indexingStatus: CrossChainIndexingStatusSnapshot,\n chainId: ChainId,\n): BlockRef | null {\n const chainIndexingStatus = indexingStatus.omnichainSnapshot.chains.get(chainId);\n\n if (chainIndexingStatus === undefined) {\n // chain isn't being indexed at all\n return null;\n }\n\n if (chainIndexingStatus.chainStatus === ChainIndexingStatusIds.Queued) {\n // chain is queued, so no data for the chain has been indexed yet\n return null;\n }\n\n return chainIndexingStatus.latestIndexedBlock;\n}\n\n/**\n * Get the \"highest known block timestamp\" from chain indexing status snapshots.\n *\n * Returns the maximum timestamp referenced anywhere in the provided chain snapshots,\n * across all of:\n * - `config.startBlock` timestamps for all chains\n * - `config.endBlock` timestamps for bounded chains\n * - `backfillEndBlock` timestamps for chains in backfill status\n * - `latestKnownBlock` timestamps for chains in following status\n *\n * This is used to enforce the invariant that `snapshotTime` must be >= all\n * referenced block timestamps. It differs from {@link getTimestampForHighestOmnichainKnownBlock},\n * which computes the highest \"target\" block timestamp for progress display and\n * does not include `startBlock` timestamps.\n *\n * @throws Error if `chains` is empty.\n */\nexport function getHighestKnownBlockTimestamp(\n chains: ChainIndexingStatusSnapshot[],\n): UnixTimestamp {\n if (chains.length === 0) {\n throw new Error(\n \"Invariant violation: at least one chain is required to determine the highest known block timestamp\",\n );\n }\n\n const startBlockTimestamps = chains.map((chain) => chain.config.startBlock.timestamp);\n\n const endBlockTimestamps = chains\n .map((chain) => chain.config)\n .filter((chainConfig) => chainConfig.rangeType === RangeTypeIds.Bounded)\n .map((chainConfig) => chainConfig.endBlock.timestamp);\n\n const backfillEndBlockTimestamps = chains\n .filter((chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill)\n .map((chain) => chain.backfillEndBlock.timestamp);\n\n const latestKnownBlockTimestamps = chains\n .filter((chain) => chain.chainStatus === ChainIndexingStatusIds.Following)\n .map((chain) => chain.latestKnownBlock.timestamp);\n\n return Math.max(\n ...startBlockTimestamps,\n ...endBlockTimestamps,\n ...backfillEndBlockTimestamps,\n ...latestKnownBlockTimestamps,\n );\n}\n\n/**\n * Build a Cross-Chain Indexing Status Snapshot based on the omnichain indexing status snapshot.\n *\n * @param omnichainSnapshot - The omnichain indexing status snapshot.\n * @param snapshotTime - The timestamp when the cross-chain indexing status snapshot was generated.\n * Will be adjusted upward if necessary to satisfy the invariant that snapshotTime must\n * be >= the highest known block timestamp (handles clock skew and future block timestamps).\n * @returns The cross-chain indexing status snapshot.\n * @throws if the generated snapshot does not satisfy the invariants defined\n * in {@link CrossChainIndexingStatusSnapshotOmnichain}\n */\nexport function buildCrossChainIndexingStatusSnapshotOmnichain(\n omnichainSnapshot: OmnichainIndexingStatusSnapshot,\n snapshotTime: UnixTimestamp,\n): CrossChainIndexingStatusSnapshotOmnichain {\n const chains = Array.from(omnichainSnapshot.chains.values());\n const adjustedSnapshotTime = Math.max(snapshotTime, getHighestKnownBlockTimestamp(chains));\n\n return validateCrossChainIndexingStatusSnapshot({\n strategy: CrossChainIndexingStrategyIds.Omnichain,\n slowestChainIndexingCursor: omnichainSnapshot.omnichainIndexingCursor,\n omnichainSnapshot,\n snapshotTime: adjustedSnapshotTime,\n });\n}\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport {\n makeChainIdSchema,\n makeChainIdStringSchema,\n makeUnixTimestampSchema,\n} from \"../../shared/zod-schemas\";\nimport { ChainIndexingStatusIds } from \"../chain-indexing-status-snapshot\";\nimport {\n checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill,\n checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted,\n checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing,\n checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted,\n getOmnichainIndexingStatus,\n OmnichainIndexingStatusIds,\n type OmnichainIndexingStatusSnapshot,\n type OmnichainIndexingStatusSnapshotBackfill,\n type OmnichainIndexingStatusSnapshotCompleted,\n type OmnichainIndexingStatusSnapshotFollowing,\n type OmnichainIndexingStatusSnapshotUnstarted,\n} from \"../omnichain-indexing-status-snapshot\";\nimport {\n SerializedOmnichainIndexingStatusSnapshot,\n SerializedOmnichainIndexingStatusSnapshotBackfill,\n SerializedOmnichainIndexingStatusSnapshotCompleted,\n SerializedOmnichainIndexingStatusSnapshotFollowing,\n SerializedOmnichainIndexingStatusSnapshotUnstarted,\n} from \"../serialize/omnichain-indexing-status-snapshot\";\nimport {\n makeChainIndexingStatusSnapshotBackfillSchema,\n makeChainIndexingStatusSnapshotCompletedSchema,\n makeChainIndexingStatusSnapshotFollowingSchema,\n makeChainIndexingStatusSnapshotQueuedSchema,\n} from \"./chain-indexing-status-snapshot\";\n\n/**\n * Invariant: For omnichain snapshot,\n * `omnichainStatus` is set based on the snapshots of individual chains.\n */\nexport function invariant_omnichainSnapshotStatusIsConsistentWithChainSnapshot(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshot>,\n) {\n const snapshot = ctx.value;\n const chains = Array.from(snapshot.chains.values());\n const expectedOmnichainStatus = getOmnichainIndexingStatus(chains);\n const actualOmnichainStatus = snapshot.omnichainStatus;\n\n if (expectedOmnichainStatus !== actualOmnichainStatus) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: `'${actualOmnichainStatus}' is an invalid omnichainStatus. Expected '${expectedOmnichainStatus}' based on the statuses of individual chains.`,\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot,\n * `omnichainIndexingCursor` is lower than the earliest start block\n * across all queued chains.\n *\n * Note: if there are no queued chains, the invariant holds.\n */\nexport function invariant_omnichainIndexingCursorLowerThanEarliestStartBlockAcrossQueuedChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshot>,\n) {\n const snapshot = ctx.value;\n const queuedChains = Array.from(snapshot.chains.values()).filter(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Queued,\n );\n\n // there are no queued chains\n if (queuedChains.length === 0) {\n // the invariant holds\n return;\n }\n\n const queuedChainStartBlocks = queuedChains.map((chain) => chain.config.startBlock.timestamp);\n const queuedChainEarliestStartBlock = Math.min(...queuedChainStartBlocks);\n\n // there are queued chains\n // the invariant holds if the omnichain indexing cursor is lower than\n // the earliest start block across all queued chains\n if (snapshot.omnichainIndexingCursor >= queuedChainEarliestStartBlock) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message:\n \"`omnichainIndexingCursor` must be lower than the earliest start block across all queued chains.\",\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot,\n * `omnichainIndexingCursor` is lower than or equal to\n * the highest `backfillEndBlock` across all backfill chains.\n *\n * Note: if there are no backfill chains, the invariant holds.\n */\nexport function invariant_omnichainIndexingCursorLowerThanOrEqualToLatestBackfillEndBlockAcrossBackfillChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshot>,\n) {\n const snapshot = ctx.value;\n const backfillChains = Array.from(snapshot.chains.values()).filter(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill,\n );\n\n // there are no backfill chains\n if (backfillChains.length === 0) {\n // the invariant holds\n return;\n }\n\n const backfillEndBlocks = backfillChains.map((chain) => chain.backfillEndBlock.timestamp);\n const highestBackfillEndBlock = Math.max(...backfillEndBlocks);\n\n // there are backfill chains\n // the invariant holds if the omnichainIndexingCursor is lower than or\n // equal to the highest backfillEndBlock across all backfill chains.\n if (snapshot.omnichainIndexingCursor > highestBackfillEndBlock) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message:\n \"`omnichainIndexingCursor` must be lower than or equal to the highest `backfillEndBlock` across all backfill chains.\",\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot,\n * `omnichainIndexingCursor` is same as the highest latestIndexedBlock\n * across all indexed chains.\n *\n * Note: if there are no indexed chains, the invariant holds.\n */\nexport function invariant_omnichainIndexingCursorIsEqualToHighestLatestIndexedBlockAcrossIndexedChain(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshot>,\n) {\n const snapshot = ctx.value;\n const indexedChains = Array.from(snapshot.chains.values()).filter(\n (chain) =>\n chain.chainStatus === ChainIndexingStatusIds.Backfill ||\n chain.chainStatus === ChainIndexingStatusIds.Completed ||\n chain.chainStatus === ChainIndexingStatusIds.Following,\n );\n\n // there are no indexed chains\n if (indexedChains.length === 0) {\n // the invariant holds\n return;\n }\n\n const indexedChainLatestIndexedBlocks = indexedChains.map(\n (chain) => chain.latestIndexedBlock.timestamp,\n );\n const indexedChainHighestLatestIndexedBlock = Math.max(...indexedChainLatestIndexedBlocks);\n\n // there are indexed chains\n // the invariant holds if the omnichain indexing cursor is same as\n // the highest latestIndexedBlock across all indexed chains\n if (snapshot.omnichainIndexingCursor !== indexedChainHighestLatestIndexedBlock) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message:\n \"`omnichainIndexingCursor` must be same as the highest `latestIndexedBlock` across all indexed chains.\",\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot 'unstarted',\n * all chains must have \"queued\" status.\n */\nexport function invariant_omnichainSnapshotUnstartedHasValidChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshotUnstarted>,\n) {\n const snapshot = ctx.value;\n const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(\n Array.from(snapshot.chains.values()),\n );\n\n if (hasValidChains === false) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: `For omnichain status snapshot 'unstarted', all chains must have \"queued\" status.`,\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot 'backfill',\n * at least one chain must be in \"backfill\" status and\n * each chain has to have a status of either \"queued\", \"backfill\"\n * or \"completed\".\n */\nexport function invariant_omnichainStatusSnapshotBackfillHasValidChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshotBackfill>,\n) {\n const snapshot = ctx.value;\n const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(\n Array.from(snapshot.chains.values()),\n );\n\n if (hasValidChains === false) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: `For omnichain status snapshot 'backfill', at least one chain must be in \"backfill\" status and each chain has to have a status of either \"queued\", \"backfill\" or \"completed\".`,\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot 'completed',\n * all chains must have \"completed\" status.\n */\nexport function invariant_omnichainStatusSnapshotCompletedHasValidChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshotCompleted>,\n) {\n const snapshot = ctx.value;\n const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(\n Array.from(snapshot.chains.values()),\n );\n\n if (hasValidChains === false) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: `For omnichain status snapshot 'completed', all chains must have \"completed\" status.`,\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot 'following',\n * at least one chain must be in 'following' status.\n */\nexport function invariant_omnichainStatusSnapshotFollowingHasValidChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshotFollowing>,\n) {\n const snapshot = ctx.value;\n const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(\n Array.from(snapshot.chains.values()),\n );\n\n if (hasValidChains === false) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: \"For omnichainStatus 'following', at least one chain must be in 'following' status.\",\n });\n }\n}\n\n/**\n * Makes Zod schema for {@link OmnichainIndexingStatusSnapshotUnstarted}\n */\nconst makeOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel?: string) =>\n z\n .object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Unstarted),\n chains: z.map(\n makeChainIdSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n ]),\n {\n error:\n \"Chains indexing statuses must be a Map with ChainId as keys and ChainIndexingStatusSnapshot as values.\",\n },\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .check(invariant_omnichainSnapshotUnstartedHasValidChains);\n\n/**\n * Makes Zod schema for {@link OmnichainIndexingStatusSnapshotBackfill}\n */\nconst makeOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel?: string) =>\n z\n .object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Backfill),\n chains: z.map(\n makeChainIdSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n {\n error:\n \"Chains indexing statuses must be a Map with ChainId as keys and ChainIndexingStatusSnapshot as values.\",\n },\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .check(invariant_omnichainStatusSnapshotBackfillHasValidChains);\n\n/**\n * Makes Zod schema for {@link OmnichainIndexingStatusSnapshotCompleted}\n */\nconst makeOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel?: string) =>\n z\n .object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Completed),\n chains: z.map(\n makeChainIdSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n {\n error:\n \"Chains indexing statuses must be a Map with ChainId as keys and ChainIndexingStatusSnapshot as values.\",\n },\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .check(invariant_omnichainStatusSnapshotCompletedHasValidChains);\n\n/**\n * Makes Zod schema for {@link OmnichainIndexingStatusSnapshotFollowing}\n */\nconst makeOmnichainIndexingStatusSnapshotFollowingSchema = (valueLabel?: string) =>\n z\n .object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Following),\n chains: z.map(\n makeChainIdSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotFollowingSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n {\n error:\n \"Chains indexing statuses must be a Map with ChainId as keys and ChainIndexingStatusSnapshot as values.\",\n },\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .check(invariant_omnichainStatusSnapshotFollowingHasValidChains);\n\n/**\n * Omnichain Indexing Snapshot Schema\n *\n * Makes a Zod schema definition for validating indexing snapshot\n * across all chains indexed by ENSIndexer instance.\n */\nexport const makeOmnichainIndexingStatusSnapshotSchema = (\n valueLabel: string = \"Omnichain Indexing Snapshot\",\n) =>\n z\n .discriminatedUnion(\"omnichainStatus\", [\n makeOmnichainIndexingStatusSnapshotUnstartedSchema(valueLabel),\n makeOmnichainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeOmnichainIndexingStatusSnapshotCompletedSchema(valueLabel),\n makeOmnichainIndexingStatusSnapshotFollowingSchema(valueLabel),\n ])\n .check(invariant_omnichainSnapshotStatusIsConsistentWithChainSnapshot)\n .check(invariant_omnichainIndexingCursorLowerThanEarliestStartBlockAcrossQueuedChains)\n .check(\n invariant_omnichainIndexingCursorLowerThanOrEqualToLatestBackfillEndBlockAcrossBackfillChains,\n )\n .check(invariant_omnichainIndexingCursorIsEqualToHighestLatestIndexedBlockAcrossIndexedChain);\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshotUnstarted}\n */\nconst makeSerializedOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel?: string) =>\n z.object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Unstarted),\n chains: z.record(\n makeChainIdStringSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n ]),\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n });\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshotBackfill}\n */\nconst makeSerializedOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel?: string) =>\n z.object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Backfill),\n chains: z.record(\n makeChainIdStringSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n });\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshotCompleted}\n */\nconst makeSerializedOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel?: string) =>\n z.object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Completed),\n chains: z.record(\n makeChainIdStringSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n });\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshotFollowing}\n */\nconst makeSerializedOmnichainIndexingStatusSnapshotFollowingSchema = (valueLabel?: string) =>\n z.object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Following),\n chains: z.record(\n makeChainIdStringSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotFollowingSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n });\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshot}.\n */\nexport const makeSerializedOmnichainIndexingStatusSnapshotSchema = (valueLabel: string = \"Value\") =>\n z.discriminatedUnion(\"omnichainStatus\", [\n makeSerializedOmnichainIndexingStatusSnapshotUnstartedSchema(valueLabel),\n makeSerializedOmnichainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeSerializedOmnichainIndexingStatusSnapshotCompletedSchema(valueLabel),\n makeSerializedOmnichainIndexingStatusSnapshotFollowingSchema(valueLabel),\n ]);\n","import type { ChainId, UnixTimestamp } from \"enssdk\";\n\nimport type { Unvalidated } from \"../shared/types\";\nimport {\n ChainIndexingStatusIds,\n type ChainIndexingStatusSnapshot,\n type ChainIndexingStatusSnapshotBackfill,\n type ChainIndexingStatusSnapshotCompleted,\n type ChainIndexingStatusSnapshotQueued,\n} from \"./chain-indexing-status-snapshot\";\nimport { validateOmnichainIndexingStatusSnapshot } from \"./validate/omnichain-indexing-status-snapshot\";\n\n/**\n * The status of omnichain indexing at the time an omnichain indexing status\n * snapshot is captured.\n */\nexport const OmnichainIndexingStatusIds = {\n /**\n * Represents that omnichain indexing is not ready to begin yet because\n * ENSIndexer is in its initialization phase and the data to build a \"true\"\n * {@link OmnichainIndexingStatusSnapshot} is still being loaded.\n */\n Unstarted: \"omnichain-unstarted\",\n\n /**\n * Represents that omnichain indexing is in an overall \"backfill\" status because\n * - At least one indexed chain has a `chainStatus` of\n * {@link ChainIndexingStatusIds.Backfill}; and\n * - No indexed chain has a `chainStatus` of {@link ChainIndexingStatusIds.Following}.\n */\n Backfill: \"omnichain-backfill\",\n\n /**\n * Represents that omnichain indexing is in an overall \"following\" status because\n * at least one indexed chain has a `chainStatus` of\n * {@link ChainIndexingStatusIds.Following}.\n */\n Following: \"omnichain-following\",\n\n /**\n * Represents that omnichain indexing has completed because all indexed chains have\n * a `chainStatus` of {@link ChainIndexingStatusIds.Completed}.\n */\n Completed: \"omnichain-completed\",\n} as const;\n\n/**\n * The derived string union of possible {@link OmnichainIndexingStatusIds}.\n */\nexport type OmnichainIndexingStatusId =\n (typeof OmnichainIndexingStatusIds)[keyof typeof OmnichainIndexingStatusIds];\n\n/**\n * Omnichain indexing status snapshot when the overall `omnichainStatus` is\n * {@link OmnichainIndexingStatusIds.Unstarted}.\n *\n * Invariants:\n * - `omnichainStatus` is always {@link OmnichainIndexingStatusIds.Unstarted}.\n * - `chains` is always a map to {@link ChainIndexingStatusSnapshotQueued} values exclusively.\n * - `omnichainIndexingCursor` is always < the `config.startBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Queued}.\n */\nexport interface OmnichainIndexingStatusSnapshotUnstarted {\n /**\n * The status of omnichain indexing.\n */\n omnichainStatus: typeof OmnichainIndexingStatusIds.Unstarted;\n\n /**\n * The indexing status snapshot for each indexed chain.\n */\n chains: Map<ChainId, ChainIndexingStatusSnapshotQueued>;\n\n /**\n * The timestamp of omnichain indexing progress across all indexed chains.\n */\n omnichainIndexingCursor: UnixTimestamp;\n}\n\n/**\n * The range of {@link ChainIndexingSnapshot} types allowed when the\n * overall omnichain indexing status is {@link OmnichainIndexingStatusIds.Backfill}.\n *\n * Note that this is all of the {@link ChainIndexingSnapshot} types with the exception\n * of {@link ChainIndexingStatusSnapshotFollowing}.\n */\nexport type ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill =\n | ChainIndexingStatusSnapshotQueued\n | ChainIndexingStatusSnapshotBackfill\n | ChainIndexingStatusSnapshotCompleted;\n\n/**\n * Omnichain indexing status snapshot when the `omnichainStatus` is\n * {@link OmnichainIndexingStatusIds.Backfill}.\n *\n * Invariants:\n * - `omnichainStatus` is always {@link OmnichainIndexingStatusIds.Backfill}.\n * - `chains` is guaranteed to contain at least one chain with a `chainStatus` of\n * {@link ChainIndexingStatusIds.Backfill}.\n * - `chains` is guaranteed to not to contain any chain with a `chainStatus` of\n * {@link ChainIndexingStatusIds.Following}\n * - `omnichainIndexingCursor` is always < the `config.startBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Queued}.\n * - `omnichainIndexingCursor` is always <= the `backfillEndBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Backfill}.\n * - `omnichainIndexingCursor` is always >= the `latestIndexedBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Completed}.\n * - `omnichainIndexingCursor` is always equal to the timestamp of the highest\n * `latestIndexedBlock` across all chains that have started indexing\n * (`chainStatus` is not {@link ChainIndexingStatusIds.Queued}).\n */\nexport interface OmnichainIndexingStatusSnapshotBackfill {\n /**\n * The status of omnichain indexing.\n */\n omnichainStatus: typeof OmnichainIndexingStatusIds.Backfill;\n\n /**\n * The indexing status snapshot for each indexed chain.\n */\n chains: Map<ChainId, ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill>;\n\n /**\n * The timestamp of omnichain indexing progress across all indexed chains.\n */\n omnichainIndexingCursor: UnixTimestamp;\n}\n\n/**\n * Omnichain indexing status snapshot when the overall `omnichainStatus` is\n * {@link OmnichainIndexingStatusIds.Following}.\n *\n * Invariants:\n * - `omnichainStatus` is always {@link OmnichainIndexingStatusIds.Following}.\n * - `chains` is guaranteed to contain at least one chain with a `status` of\n * {@link ChainIndexingStatusIds.Following}.\n * - `omnichainIndexingCursor` is always < the `config.startBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Queued}.\n * - `omnichainIndexingCursor` is always <= the `backfillEndBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Backfill}.\n * - `omnichainIndexingCursor` is always >= the `latestIndexedBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Completed}.\n * - `omnichainIndexingCursor` is always equal to the timestamp of the highest\n * `latestIndexedBlock` across all chains that have started indexing\n * (`chainStatus` is not {@link ChainIndexingStatusIds.Queued}).\n */\nexport interface OmnichainIndexingStatusSnapshotFollowing {\n /**\n * The status of omnichain indexing.\n */\n omnichainStatus: typeof OmnichainIndexingStatusIds.Following;\n\n /**\n * The indexing status snapshot for each indexed chain.\n */\n chains: Map<ChainId, ChainIndexingStatusSnapshot>;\n\n /**\n * The timestamp of omnichain indexing progress across all indexed chains.\n */\n omnichainIndexingCursor: UnixTimestamp;\n}\n\n/**\n * Omnichain indexing status snapshot when the overall `omnichainStatus` is\n * {@link OmnichainIndexingStatusIds.Completed}.\n *\n * Invariants:\n * - `omnichainStatus` is always {@link OmnichainIndexingStatusIds.Completed}.\n * - `chains` is always a map to {@link ChainIndexingStatusSnapshotCompleted} values exclusively.\n * - `omnichainIndexingCursor` is always equal to the highest\n * `latestIndexedBlock.timestamp` for all chains.\n */\nexport interface OmnichainIndexingStatusSnapshotCompleted {\n /**\n * The status of omnichain indexing.\n */\n omnichainStatus: typeof OmnichainIndexingStatusIds.Completed;\n\n /**\n * The indexing status snapshot for each indexed chain.\n */\n chains: Map<ChainId, ChainIndexingStatusSnapshotCompleted>;\n\n /**\n * The timestamp of omnichain indexing progress across all indexed chains.\n */\n omnichainIndexingCursor: UnixTimestamp;\n}\n\n/**\n * Omnichain indexing status snapshot for one or more chains.\n *\n * Use the `omnichainStatus` field to determine the specific type interpretation\n * at runtime.\n */\nexport type OmnichainIndexingStatusSnapshot =\n | OmnichainIndexingStatusSnapshotUnstarted\n | OmnichainIndexingStatusSnapshotBackfill\n | OmnichainIndexingStatusSnapshotCompleted\n | OmnichainIndexingStatusSnapshotFollowing;\n\n/**\n * Check if Chain Indexing Status Snapshots fit the 'unstarted' overall status\n * snapshot requirements:\n * - All chains are guaranteed to have a status of \"queued\".\n *\n * Note: This function narrows the {@link ChainIndexingStatusSnapshot} type to\n * {@link ChainIndexingStatusSnapshotQueued}.\n */\nexport function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(\n chains: ChainIndexingStatusSnapshot[],\n): chains is ChainIndexingStatusSnapshotQueued[] {\n return chains.every((chain) => chain.chainStatus === ChainIndexingStatusIds.Queued);\n}\n\n/**\n * Check if Chain Indexing Status Snapshots fit the 'backfill' overall status\n * snapshot requirements:\n * - At least one chain is guaranteed to be in the \"backfill\" status.\n * - Each chain is guaranteed to have a status of either \"queued\",\n * \"backfill\" or \"completed\".\n *\n * Note: This function narrows the {@link ChainIndexingStatusSnapshot} type to\n * {@link ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill}.\n */\nexport function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(\n chains: ChainIndexingStatusSnapshot[],\n): chains is ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill[] {\n const atLeastOneChainInTargetStatus = chains.some(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill,\n );\n const otherChainsHaveValidStatuses = chains.every(\n (chain) =>\n chain.chainStatus === ChainIndexingStatusIds.Queued ||\n chain.chainStatus === ChainIndexingStatusIds.Backfill ||\n chain.chainStatus === ChainIndexingStatusIds.Completed,\n );\n\n return atLeastOneChainInTargetStatus && otherChainsHaveValidStatuses;\n}\n\n/**\n * Checks if Chain Indexing Status Snapshots fit the 'completed' overall status\n * snapshot requirements:\n * - All chains are guaranteed to have a status of \"completed\".\n *\n * Note: This function narrows the {@link ChainIndexingStatusSnapshot} type to\n * {@link ChainIndexingStatusSnapshotCompleted}.\n */\nexport function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(\n chains: ChainIndexingStatusSnapshot[],\n): chains is ChainIndexingStatusSnapshotCompleted[] {\n const allChainsHaveValidStatuses = chains.every(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Completed,\n );\n\n return allChainsHaveValidStatuses;\n}\n\n/**\n * Checks Chain Indexing Status Snapshots fit the 'following' overall status\n * snapshot requirements:\n * - At least one chain is guaranteed to be in the \"following\" status.\n * - Any other chain can have any status.\n */\nexport function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(\n chains: ChainIndexingStatusSnapshot[],\n): boolean {\n const allChainsHaveValidStatuses = chains.some(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Following,\n );\n\n return allChainsHaveValidStatuses;\n}\n\n/**\n * Get {@link OmnichainIndexingStatusId} based on indexed chains' statuses.\n *\n * This function decides what is the `OmnichainIndexingStatusId` is,\n * based on provided chain indexing statuses.\n *\n * @throws an error if unable to determine overall indexing status\n */\nexport function getOmnichainIndexingStatus(\n chains: ChainIndexingStatusSnapshot[],\n): OmnichainIndexingStatusId {\n if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(chains)) {\n return OmnichainIndexingStatusIds.Following;\n }\n\n if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(chains)) {\n return OmnichainIndexingStatusIds.Backfill;\n }\n\n if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(chains)) {\n return OmnichainIndexingStatusIds.Unstarted;\n }\n\n if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(chains)) {\n return OmnichainIndexingStatusIds.Completed;\n }\n\n // if none of the chain statuses matched, throw an error\n throw new Error(`Unable to determine omnichain indexing status for provided chains.`);\n}\n\n/**\n * Get Omnichain Indexing Cursor\n *\n * The cursor tracks the \"highest\" latest indexed block timestamp across\n * all indexed chains. If all chains are queued, the cursor tracks the moment\n * just before the earliest start block timestamp across those chains.\n *\n * @throws an error if no chains are provided\n */\nexport function getOmnichainIndexingCursor(chains: ChainIndexingStatusSnapshot[]): UnixTimestamp {\n if (chains.length === 0) {\n throw new Error(`Unable to determine omnichain indexing cursor when no chains were provided.`);\n }\n\n // for omnichain indexing status snapshot 'unstarted', the cursor tracks\n // the moment just before the indexing would start from.\n if (getOmnichainIndexingStatus(chains) === OmnichainIndexingStatusIds.Unstarted) {\n const earliestStartBlockTimestamps = chains.map((chain) => chain.config.startBlock.timestamp);\n\n return Math.min(...earliestStartBlockTimestamps) - 1;\n }\n\n // otherwise, the cursor tracks the \"highest\" latest indexed block timestamp\n // across all indexed chains\n const latestIndexedBlockTimestamps = chains\n .filter((chain) => chain.chainStatus !== ChainIndexingStatusIds.Queued)\n .map((chain) => chain.latestIndexedBlock.timestamp);\n\n // Invariant: there's at least one element in `latestIndexedBlockTimestamps` array\n // This is theoretically impossible based on the 2 checks above,\n // but the invariant is explicitly added here as a formality.\n if (latestIndexedBlockTimestamps.length < 1) {\n throw new Error(\"latestIndexedBlockTimestamps array must include at least one element\");\n }\n\n return Math.max(...latestIndexedBlockTimestamps);\n}\n\n/**\n * Build an Omnichain Indexing Status Snapshot based on the indexing status snapshots of all indexed chains.\n *\n * @param chainStatusSnapshots - A map of chain IDs to their chain indexing status snapshots.\n * @returns The omnichain indexing status snapshot.\n */\nexport function buildOmnichainIndexingStatusSnapshot(\n chainStatusSnapshots: Map<ChainId, ChainIndexingStatusSnapshot>,\n): OmnichainIndexingStatusSnapshot {\n if (chainStatusSnapshots.size === 0) {\n throw new Error(\n \"At least one chain indexing status snapshot is required to build an OmnichainIndexingStatusSnapshot\",\n );\n }\n\n const chains = Array.from(chainStatusSnapshots.values());\n const omnichainStatus = getOmnichainIndexingStatus(chains);\n const omnichainIndexingCursor = getOmnichainIndexingCursor(chains);\n\n switch (omnichainStatus) {\n case OmnichainIndexingStatusIds.Unstarted: {\n return validateOmnichainIndexingStatusSnapshot({\n omnichainStatus: OmnichainIndexingStatusIds.Unstarted,\n chains: chainStatusSnapshots as Map<\n ChainId,\n Unvalidated<ChainIndexingStatusSnapshotQueued>\n >, // narrowing the type here, will be validated in the following 'check' step\n omnichainIndexingCursor,\n } satisfies Unvalidated<OmnichainIndexingStatusSnapshotUnstarted>);\n }\n\n case OmnichainIndexingStatusIds.Backfill: {\n return validateOmnichainIndexingStatusSnapshot({\n omnichainStatus: OmnichainIndexingStatusIds.Backfill,\n chains: chainStatusSnapshots as Map<\n ChainId,\n Unvalidated<ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill>\n >, // narrowing the type here, will be validated in the following 'check' step\n omnichainIndexingCursor,\n } satisfies Unvalidated<OmnichainIndexingStatusSnapshotBackfill>);\n }\n\n case OmnichainIndexingStatusIds.Completed: {\n return validateOmnichainIndexingStatusSnapshot({\n omnichainStatus: OmnichainIndexingStatusIds.Completed,\n chains: chainStatusSnapshots as Map<\n ChainId,\n Unvalidated<ChainIndexingStatusSnapshotCompleted>\n >, // narrowing the type here, will be validated in the following 'check' step\n omnichainIndexingCursor,\n } satisfies Unvalidated<OmnichainIndexingStatusSnapshotCompleted>);\n }\n\n case OmnichainIndexingStatusIds.Following:\n return validateOmnichainIndexingStatusSnapshot({\n omnichainStatus: OmnichainIndexingStatusIds.Following,\n chains: chainStatusSnapshots,\n omnichainIndexingCursor,\n } satisfies Unvalidated<OmnichainIndexingStatusSnapshotFollowing>);\n }\n}\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport * as blockRef from \"../../shared/block-ref\";\nimport { RangeTypeIds } from \"../../shared/blockrange\";\nimport { makeBlockRefSchema } from \"../../shared/zod-schemas\";\nimport {\n ChainIndexingStatusIds,\n type ChainIndexingStatusSnapshot,\n type ChainIndexingStatusSnapshotBackfill,\n type ChainIndexingStatusSnapshotCompleted,\n type ChainIndexingStatusSnapshotFollowing,\n type ChainIndexingStatusSnapshotQueued,\n} from \"../chain-indexing-status-snapshot\";\n\n/**\n * Invariants for chain snapshot in 'queued' status:\n * - `config.endBlock` (if set) is after `config.startBlock`.\n */\nexport function invariant_chainSnapshotQueuedBlocks(\n ctx: ParsePayload<ChainIndexingStatusSnapshotQueued>,\n) {\n const { config } = ctx.value;\n\n // The `config.endBlock` does not exist for `left-bounded` config range type\n if (config.rangeType === RangeTypeIds.LeftBounded) {\n // invariant holds\n return;\n }\n\n if (blockRef.isBeforeOrEqualTo(config.startBlock, config.endBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`config.startBlock` must be before or same as `config.endBlock`.\",\n });\n }\n}\n\n/**\n * Invariants for chain snapshot in 'backfill' status:\n * - `config.startBlock` is before or same as `latestIndexedBlock`.\n * - `latestIndexedBlock` is before or same as `backfillEndBlock`.\n * - `backfillEndBlock` is the same as `config.endBlock` (if set).\n */\nexport function invariant_chainSnapshotBackfillBlocks(\n ctx: ParsePayload<ChainIndexingStatusSnapshotBackfill>,\n) {\n const { config, latestIndexedBlock, backfillEndBlock } = ctx.value;\n\n if (blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`config.startBlock` must be before or same as `latestIndexedBlock`.\",\n });\n }\n\n if (blockRef.isBeforeOrEqualTo(latestIndexedBlock, backfillEndBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`latestIndexedBlock` must be before or same as `backfillEndBlock`.\",\n });\n }\n\n // The `config.endBlock` does not exist for `left-bounded` config range type\n if (config.rangeType === RangeTypeIds.LeftBounded) {\n // invariant holds\n return;\n }\n\n if (blockRef.isEqualTo(backfillEndBlock, config.endBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`backfillEndBlock` must be the same as `config.endBlock`.\",\n });\n }\n}\n\n/**\n * Invariants for chain snapshot in 'completed' status:\n * - `config.startBlock` is before or same as `latestIndexedBlock`.\n * - `latestIndexedBlock` is before or same as `config.endBlock`.\n */\nexport function invariant_chainSnapshotCompletedBlocks(\n ctx: ParsePayload<ChainIndexingStatusSnapshotCompleted>,\n) {\n const { config, latestIndexedBlock } = ctx.value;\n\n if (blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`config.startBlock` must be before or same as `latestIndexedBlock`.\",\n });\n }\n\n if (blockRef.isBeforeOrEqualTo(latestIndexedBlock, config.endBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`latestIndexedBlock` must be before or same as `config.endBlock`.\",\n });\n }\n}\n\n/**\n * Invariants for chain snapshot in 'following' status:\n * - `config.startBlock` is before or same as `latestIndexedBlock`.\n * - `latestIndexedBlock` is before or same as `latestKnownBlock`.\n */\nexport function invariant_chainSnapshotFollowingBlocks(\n ctx: ParsePayload<ChainIndexingStatusSnapshotFollowing>,\n) {\n const { config, latestIndexedBlock, latestKnownBlock } = ctx.value;\n\n if (blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`config.startBlock` must be before or same as `latestIndexedBlock`.\",\n });\n }\n\n if (blockRef.isBeforeOrEqualTo(latestIndexedBlock, latestKnownBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`latestIndexedBlock` must be before or same as `latestKnownBlock`.\",\n });\n }\n}\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshotQueued} type.\n */\nexport const makeChainIndexingStatusSnapshotQueuedSchema = (valueLabel: string = \"Value\") =>\n z\n .object({\n chainStatus: z.literal(ChainIndexingStatusIds.Queued),\n config: z.discriminatedUnion(\"rangeType\", [\n z.object({\n rangeType: z.literal(RangeTypeIds.LeftBounded),\n startBlock: makeBlockRefSchema(valueLabel),\n }),\n z.object({\n rangeType: z.literal(RangeTypeIds.Bounded),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n ]),\n })\n .check(invariant_chainSnapshotQueuedBlocks);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshotBackfill} type.\n */\nexport const makeChainIndexingStatusSnapshotBackfillSchema = (valueLabel: string = \"Value\") =>\n z\n .object({\n chainStatus: z.literal(ChainIndexingStatusIds.Backfill),\n config: z.discriminatedUnion(\"rangeType\", [\n z.object({\n rangeType: z.literal(RangeTypeIds.LeftBounded),\n startBlock: makeBlockRefSchema(valueLabel),\n }),\n z.object({\n rangeType: z.literal(RangeTypeIds.Bounded),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n ]),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n backfillEndBlock: makeBlockRefSchema(valueLabel),\n })\n .check(invariant_chainSnapshotBackfillBlocks);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshotCompleted} type.\n */\nexport const makeChainIndexingStatusSnapshotCompletedSchema = (valueLabel: string = \"Value\") =>\n z\n .object({\n chainStatus: z.literal(ChainIndexingStatusIds.Completed),\n config: z.object({\n rangeType: z.literal(RangeTypeIds.Bounded),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n })\n .check(invariant_chainSnapshotCompletedBlocks);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshotFollowing} type.\n */\nexport const makeChainIndexingStatusSnapshotFollowingSchema = (valueLabel: string = \"Value\") =>\n z\n .object({\n chainStatus: z.literal(ChainIndexingStatusIds.Following),\n config: z.object({\n rangeType: z.literal(RangeTypeIds.LeftBounded),\n startBlock: makeBlockRefSchema(valueLabel),\n }),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n latestKnownBlock: makeBlockRefSchema(valueLabel),\n })\n .check(invariant_chainSnapshotFollowingBlocks);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshot}\n */\nexport const makeChainIndexingStatusSnapshotSchema = (valueLabel: string = \"Value\") =>\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n makeChainIndexingStatusSnapshotFollowingSchema(valueLabel),\n ]);\n","import { z } from \"zod/v4\";\n\nimport { makeEnsDbPublicConfigSchema } from \"../../ensdb/zod-schemas/config\";\nimport {\n makeEnsIndexerPublicConfigSchema,\n makeSerializedEnsIndexerPublicConfigSchema,\n} from \"../../ensindexer/config/zod-schemas\";\nimport { makeEnsRainbowPublicConfigSchema } from \"../../ensrainbow/zod-schemas/config\";\nimport type { ZodCheckFnInput } from \"../../shared/zod-types\";\nimport type { EnsIndexerStackInfo } from \"../ensindexer-stack-info\";\n\nexport function makeSerializedEnsIndexerStackInfoSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSIndexerStackInfo\";\n\n return z.object({\n ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`),\n ensIndexer: makeSerializedEnsIndexerPublicConfigSchema(`${label}.ensIndexer`),\n ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`),\n });\n}\n\nexport function invariant_ensRainbowCompatibilityWithEnsIndexer(\n ctx: ZodCheckFnInput<EnsIndexerStackInfo>,\n) {\n const { ensIndexer, ensRainbow } = ctx.value;\n const { clientLabelSet } = ensIndexer;\n const { serverLabelSet } = ensRainbow;\n\n if (clientLabelSet.labelSetId !== serverLabelSet.labelSetId) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `ENSRainbow's label set (id: ${serverLabelSet.labelSetId}) must be the same as ENSIndexer's label set (id: ${clientLabelSet.labelSetId}).`,\n });\n }\n\n if (clientLabelSet.labelSetVersion > serverLabelSet.highestLabelSetVersion) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `ENSRainbow's server label set version (highest: ${serverLabelSet.highestLabelSetVersion}) must be greater than or equal to ENSIndexer's client label set version (current: ${clientLabelSet.labelSetVersion}).`,\n });\n }\n}\n\nexport function makeEnsIndexerStackInfoSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSIndexerStackInfo\";\n\n return z\n .object({\n ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`),\n ensIndexer: makeEnsIndexerPublicConfigSchema(`${label}.ensIndexer`),\n ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`),\n })\n .check(invariant_ensRainbowCompatibilityWithEnsIndexer);\n}\n","import { z } from \"zod/v4\";\n\nconst makeEnsDbVersionInfoSchema = (valueLabel?: string) => {\n const label = valueLabel ?? \"EnsDbVersionInfo\";\n\n return z.object({\n postgresql: z\n .string()\n .nonempty(`${label}.postgresql must be a non-empty string`)\n .describe(\"Version of the PostgreSQL server hosting the ENSDb instance.\"),\n });\n};\n\nexport const makeEnsDbPublicConfigSchema = (valueLabel?: string) => {\n const label = valueLabel ?? \"EnsDbPublicConfig\";\n\n return z.object({\n versionInfo: makeEnsDbVersionInfoSchema(`${label}.versionInfo`),\n });\n};\n","import {\n makeEnsApiPublicConfigSchema,\n makeSerializedEnsApiPublicConfigSchema,\n} from \"../../ensapi/config/zod-schemas\";\nimport type { ZodCheckFnInput } from \"../../shared/zod-types\";\nimport type { EnsNodeStackInfo } from \"../ensnode-stack-info\";\nimport {\n invariant_ensRainbowCompatibilityWithEnsIndexer,\n makeEnsIndexerStackInfoSchema,\n makeSerializedEnsIndexerStackInfoSchema,\n} from \"./ensindexer-stack-info\";\n\nfunction invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow(\n ctx: ZodCheckFnInput<EnsNodeStackInfo>,\n) {\n const { ensApi, ensIndexer, ensRainbow } = ctx.value;\n\n // Invariant: ENSApi & ENSDB must match version numbers\n if (ensIndexer.versionInfo.ensDb !== ensApi.versionInfo.ensApi) {\n ctx.issues.push({\n code: \"custom\",\n path: [\"ensIndexer\", \"versionInfo\", \"ensDb\"],\n input: ensIndexer.versionInfo.ensDb,\n message: `Version Mismatch: ENSDB@${ensIndexer.versionInfo.ensDb} !== ENSApi@${ensApi.versionInfo.ensApi}`,\n });\n }\n\n // Invariant: ENSApi & ENSIndexer must match version numbers\n if (ensIndexer.versionInfo.ensIndexer !== ensApi.versionInfo.ensApi) {\n ctx.issues.push({\n code: \"custom\",\n path: [\"ensIndexer\", \"versionInfo\", \"ensIndexer\"],\n input: ensIndexer.versionInfo.ensIndexer,\n message: `Version Mismatch: ENSIndexer@${ensIndexer.versionInfo.ensIndexer} !== ENSApi@${ensApi.versionInfo.ensApi}`,\n });\n }\n\n // Invariant: ENSApi & ENSRainbow must match version numbers\n if (ensRainbow.versionInfo.ensRainbow !== ensApi.versionInfo.ensApi) {\n ctx.issues.push({\n code: \"custom\",\n path: [\"ensRainbow\", \"versionInfo\", \"ensRainbow\"],\n input: ensRainbow.versionInfo.ensRainbow,\n message: `Version Mismatch: ENSRainbow@${ensRainbow.versionInfo.ensRainbow} !== ENSApi@${ensApi.versionInfo.ensApi}`,\n });\n }\n\n // Invariant: `@adraffy/ens-normalize` package version must match between ENSApi & ENSIndexer\n if (ensIndexer.versionInfo.ensNormalize !== ensApi.versionInfo.ensNormalize) {\n ctx.issues.push({\n code: \"custom\",\n path: [\"ensIndexer\", \"versionInfo\", \"ensNormalize\"],\n input: ensIndexer.versionInfo.ensNormalize,\n message: `Dependency Version Mismatch: '@adraffy/ens-normalize' version must be the same between ENSIndexer and ENSApi. Found ENSApi@${ensApi.versionInfo.ensNormalize} and ENSIndexer@${ensIndexer.versionInfo.ensNormalize}`,\n });\n }\n}\n\nexport function makeSerializedEnsNodeStackInfoSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSNodeStackInfo\";\n\n return makeSerializedEnsIndexerStackInfoSchema(label).extend({\n ensApi: makeSerializedEnsApiPublicConfigSchema(`${label}.ensApi`),\n });\n}\n\nexport function makeEnsNodeStackInfoSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSNodeStackInfo\";\n\n return makeEnsIndexerStackInfoSchema(label)\n .extend({\n ensApi: makeEnsApiPublicConfigSchema(`${label}.ensApi`),\n })\n .check(invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow)\n .check(invariant_ensRainbowCompatibilityWithEnsIndexer);\n}\n","import type { RealtimeIndexingStatusProjection } from \"../../../indexing-status/realtime-indexing-status-projection\";\nimport type { EnsNodeStackInfo } from \"../../../stack-info/ensnode-stack-info\";\n\n/**\n * A status code for indexing status responses.\n */\nexport const EnsApiIndexingStatusResponseCodes = {\n /**\n * Represents that the indexing status is available.\n */\n Ok: \"ok\",\n\n /**\n * Represents that the indexing status is unavailable.\n */\n Error: \"error\",\n} as const;\n\n/**\n * A status code for indexing status responses.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponseCodes} instead.\n */\nexport const IndexingStatusResponseCodes = EnsApiIndexingStatusResponseCodes;\n\n/**\n * The derived string union of possible {@link EnsApiIndexingStatusResponseCodes}.\n */\nexport type EnsApiIndexingStatusResponseCode =\n (typeof EnsApiIndexingStatusResponseCodes)[keyof typeof EnsApiIndexingStatusResponseCodes];\n\n/**\n * The derived string union of possible {@link EnsApiIndexingStatusResponseCodes}.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponseCode} instead.\n */\nexport type IndexingStatusResponseCode = EnsApiIndexingStatusResponseCode;\n\n/**\n * An indexing status response when the indexing status is available.\n */\nexport type EnsApiIndexingStatusResponseOk = {\n responseCode: typeof EnsApiIndexingStatusResponseCodes.Ok;\n realtimeProjection: RealtimeIndexingStatusProjection;\n stackInfo: EnsNodeStackInfo;\n};\n\n/**\n * An indexing status response when the indexing status is available.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponseOk} instead.\n */\nexport type IndexingStatusResponseOk = EnsApiIndexingStatusResponseOk;\n\n/**\n * An indexing status response when the indexing status is unavailable.\n */\nexport type EnsApiIndexingStatusResponseError = {\n responseCode: typeof EnsApiIndexingStatusResponseCodes.Error;\n};\n\n/**\n * An indexing status response when the indexing status is unavailable.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponseError} instead.\n */\nexport type IndexingStatusResponseError = EnsApiIndexingStatusResponseError;\n\n/**\n * Indexing status response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type EnsApiIndexingStatusResponse =\n | EnsApiIndexingStatusResponseOk\n | EnsApiIndexingStatusResponseError;\n\n/**\n * Indexing status response.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponse} instead.\n */\nexport type IndexingStatusResponse = EnsApiIndexingStatusResponse;\n","import type { InterpretedName } from \"enssdk\";\n\nimport type {\n SerializedNameTokensResponseError,\n SerializedNameTokensResponseOk,\n} from \"./serialized-response\";\n\n/**\n * Example value for {@link SerializedNameTokensResponseOk}, for use in OpenAPI documentation.\n *\n * - domainId and tokenId correspond to \"vitalik.eth\"\n * - contract is the ENS BaseRegistrar (ERC-721) on Ethereum mainnet\n */\nexport const nameTokensResponseOkExample = {\n responseCode: \"ok\",\n registeredNameTokens: {\n domainId: \"0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835\",\n name: \"vitalik.eth\" as InterpretedName,\n tokens: [\n {\n token: {\n assetNamespace: \"erc721\",\n contract: {\n chainId: 1,\n address: \"0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85\",\n },\n tokenId: \"0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc\",\n },\n ownership: {\n ownershipType: \"fully-onchain\",\n owner: {\n chainId: 1,\n address: \"0x220866b1a2219f40e72f5c628b65d54268ca3a9d\",\n },\n },\n mintStatus: \"minted\",\n },\n ],\n expiresAt: 2461152330,\n accurateAsOf: 1700000000,\n },\n} satisfies SerializedNameTokensResponseOk;\n\n/**\n * Example value for {@link SerializedNameTokensResponseError} representing a 503 Service Unavailable\n * when the Name Tokens API prerequisites are not met, for use in OpenAPI documentation.\n */\nexport const nameTokensServiceUnavailableExample = {\n responseCode: \"error\",\n errorCode: \"unsupported-ensindexer-config\",\n error: {\n message: \"Name Tokens API is not available\",\n details: \"Connected ENSIndexer must have all following plugins active: registrars, tokenscope\",\n },\n} satisfies SerializedNameTokensResponseError;\n\n/**\n * Example value for {@link NameTokensResponseErrorNameTokensNotIndexed} representing a 404 Not Found\n * when no name tokens are indexed for the requested name or domainId, for use in OpenAPI documentation.\n */\nexport const nameTokensNotIndexedExample = {\n responseCode: \"error\",\n errorCode: \"name-tokens-not-indexed\",\n error: {\n message: \"No indexed Name Tokens found\",\n details:\n \"This ENSNode instance has not been configured to index tokens for the requested name: 'vitalik.eth'\",\n },\n} satisfies SerializedNameTokensResponseError;\n","import { namehashInterpretedName } from \"enssdk\";\nimport { z } from \"zod/v4\";\n\nimport {\n makeNodeSchema,\n makeReinterpretedNameSchema,\n makeUnixTimestampSchema,\n} from \"../../../shared/zod-schemas\";\nimport { NameTokenOwnershipTypes } from \"../../../tokenscope/name-token\";\nimport { makeNameTokenSchema } from \"../../../tokenscope/zod-schemas\";\nimport { makeErrorResponseSchema } from \"../shared/errors/zod-schemas\";\nimport {\n NameTokensResponse,\n NameTokensResponseCodes,\n NameTokensResponseError,\n NameTokensResponseErrorCodes,\n NameTokensResponseErrorEnsIndexerConfigUnsupported,\n NameTokensResponseErrorIndexingStatusUnsupported,\n NameTokensResponseErrorNameTokensNotIndexed,\n NameTokensResponseOk,\n type RegisteredNameTokens,\n} from \"./response\";\n\n/**\n * Schema for {@link RegisteredNameTokens}.\n */\nexport const makeRegisteredNameTokenSchema = <const SerializableType extends boolean>(\n valueLabel: string = \"Registered Name Token\",\n serializable?: SerializableType,\n) =>\n z\n .object({\n domainId: makeNodeSchema(`${valueLabel}.domainId`),\n name: makeReinterpretedNameSchema(valueLabel),\n tokens: z.array(makeNameTokenSchema(`${valueLabel}.tokens`, serializable)).nonempty(),\n expiresAt: makeUnixTimestampSchema(`${valueLabel}.expiresAt`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n })\n .check(function invariant_nameIsAssociatedWithDomainId(ctx) {\n const { name, domainId } = ctx.value;\n\n if (namehashInterpretedName(name) !== domainId) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'name' must be associated with 'domainId': ${domainId}`,\n });\n }\n })\n .check(\n function invariant_nameTokensOwnershipTypeNameWrapperRequiresOwnershipTypeFullyOnchainOrUnknown(\n ctx,\n ) {\n const { tokens } = ctx.value;\n const containsOwnershipNameWrapper = tokens.some(\n (t) => t.ownership.ownershipType === NameTokenOwnershipTypes.NameWrapper,\n );\n const containsOwnershipFullyOnchainOrUnknown = tokens.some(\n (t) =>\n t.ownership.ownershipType === NameTokenOwnershipTypes.FullyOnchain ||\n t.ownership.ownershipType === NameTokenOwnershipTypes.Unknown,\n );\n if (containsOwnershipNameWrapper && !containsOwnershipFullyOnchainOrUnknown) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'tokens' must contain name token with ownership type 'fully-onchain' or 'unknown' when name token with ownership type 'namewrapper' in listed`,\n });\n }\n },\n )\n .check(function invariant_nameTokensContainAtMostOneWithOwnershipTypeEffective(ctx) {\n const { tokens } = ctx.value;\n const tokensCountWithOwnershipFullyOnchain = tokens.filter(\n (t) => t.ownership.ownershipType === NameTokenOwnershipTypes.FullyOnchain,\n ).length;\n if (tokensCountWithOwnershipFullyOnchain > 1) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'tokens' must contain at most one name token with ownership type 'fully-onchain', current count: ${tokensCountWithOwnershipFullyOnchain}`,\n });\n }\n });\n\n/**\n * Schema for {@link NameTokensResponseOk}\n */\nexport const makeNameTokensResponseOkSchema = <const SerializableType extends boolean>(\n valueLabel: string = \"Name Tokens Response OK\",\n serializable?: SerializableType,\n) =>\n z.strictObject({\n responseCode: z.literal(NameTokensResponseCodes.Ok),\n registeredNameTokens: makeRegisteredNameTokenSchema(`${valueLabel}.nameTokens`, serializable),\n });\n\n/**\n * Schema for {@link NameTokensResponseErrorNameTokensNotIndexed}\n */\nexport const makeNameTokensResponseErrorNameTokensNotIndexedSchema = (\n _valueLabel: string = \"Name Tokens Response Error Name Not Indexed\",\n) =>\n z.strictObject({\n responseCode: z.literal(NameTokensResponseCodes.Error),\n errorCode: z.literal(NameTokensResponseErrorCodes.NameTokensNotIndexed),\n error: makeErrorResponseSchema(),\n });\n\n/**\n * Schema for {@link NameTokensResponseErrorEnsIndexerConfigUnsupported}\n */\nexport const makeNameTokensResponseErrorEnsIndexerConfigUnsupported = (\n _valueLabel: string = \"Name Tokens Response Error ENSIndexer Config Unsupported\",\n) =>\n z.strictObject({\n responseCode: z.literal(NameTokensResponseCodes.Error),\n errorCode: z.literal(NameTokensResponseErrorCodes.EnsIndexerConfigUnsupported),\n error: makeErrorResponseSchema(),\n });\n/**\n * Schema for {@link NameTokensResponseErrorIndexingStatusUnsupported}\n */\nexport const makeNameTokensResponseErrorNameIndexingStatusUnsupported = (\n _valueLabel: string = \"Name Tokens Response Error Indexing Status Unsupported\",\n) =>\n z.strictObject({\n responseCode: z.literal(NameTokensResponseCodes.Error),\n errorCode: z.literal(NameTokensResponseErrorCodes.IndexingStatusUnsupported),\n error: makeErrorResponseSchema(),\n });\n/**\n * Schema for {@link NameTokensResponseError}\n */\nexport const makeNameTokensResponseErrorSchema = (\n valueLabel: string = \"Name Tokens Response Error\",\n) =>\n z.discriminatedUnion(\"errorCode\", [\n makeNameTokensResponseErrorNameTokensNotIndexedSchema(valueLabel),\n makeNameTokensResponseErrorEnsIndexerConfigUnsupported(valueLabel),\n makeNameTokensResponseErrorNameIndexingStatusUnsupported(valueLabel),\n ]);\n\n/**\n * Schema for {@link NameTokensResponse}\n */\nexport const makeNameTokensResponseSchema = <const SerializableType extends boolean = false>(\n valueLabel: string = \"Name Tokens Response\",\n serializable?: SerializableType,\n) => {\n return z.discriminatedUnion(\"responseCode\", [\n makeNameTokensResponseOkSchema(valueLabel, serializable ?? false),\n makeNameTokensResponseErrorSchema(valueLabel),\n ]);\n};\n","import type { AccountId, AssetId, InterpretedName } from \"enssdk\";\nimport { getParentInterpretedName } from \"enssdk\";\nimport { isAddressEqual, zeroAddress } from \"viem\";\n\nimport { DatasourceNames, type ENSNamespaceId } from \"@ensnode/datasources\";\n\nimport { accountIdEqual } from \"../shared/account-id\";\nimport { getDatasourceContract, maybeGetDatasourceContract } from \"../shared/datasource-contract\";\nimport { type NFTMintStatus, type SerializedAssetId, serializeAssetId } from \"./assets\";\n\n/**\n * An enum representing the possible Name Token Ownership types.\n */\nexport const NameTokenOwnershipTypes = {\n /**\n * Name Token is owned by NameWrapper account.\n */\n NameWrapper: \"namewrapper\",\n\n /**\n * Name Token is owned fully onchain.\n *\n * This ownership type can only apply to direct subnames of `.eth`\n */\n FullyOnchain: \"fully-onchain\",\n\n /**\n * Name Token ownership has been transferred to the null address.\n */\n Burned: \"burned\",\n\n /**\n * Name Token ownership is unknown.\n */\n Unknown: \"unknown\",\n} as const;\n\nexport type NameTokenOwnershipType =\n (typeof NameTokenOwnershipTypes)[keyof typeof NameTokenOwnershipTypes];\n\nexport interface NameTokenOwnershipNameWrapper {\n ownershipType: typeof NameTokenOwnershipTypes.NameWrapper;\n\n /**\n * Owner\n *\n * Guarantees:\n * - `owner.address` is not the zero address.\n * - `owner.chainId` is same as the chainId of the associated NFT,\n * even if that NFT has been burned.\n */\n owner: AccountId;\n}\n\nexport interface NameTokenOwnershipFullyOnchain {\n ownershipType: typeof NameTokenOwnershipTypes.FullyOnchain;\n\n /**\n * Owner\n *\n * Guarantees:\n * - `owner.address` is not the zero address.\n * - `owner.chainId` is same as the chainId of the associated NFT,\n * even if that NFT has been burned.\n */\n owner: AccountId;\n}\n\nexport interface NameTokenOwnershipBurned {\n ownershipType: typeof NameTokenOwnershipTypes.Burned;\n\n /**\n * Owner\n *\n * Guarantees:\n * - `owner.address` is the zero address.\n * - `owner.chainId` is same as the chainId of the associated NFT,\n * even if that NFT has been burned.\n */\n owner: AccountId;\n}\n\nexport interface NameTokenOwnershipUnknown {\n ownershipType: typeof NameTokenOwnershipTypes.Unknown;\n\n /**\n * Owner\n *\n * Guarantees:\n * - `owner.address` is the zero address.\n * - `owner.chainId` is same as the chainId of the associated NFT,\n * even if that NFT has been burned.\n */\n owner: AccountId;\n}\n\nexport type NameTokenOwnership =\n | NameTokenOwnershipNameWrapper\n | NameTokenOwnershipFullyOnchain\n | NameTokenOwnershipBurned\n | NameTokenOwnershipUnknown;\n\nexport interface NameToken {\n /**\n * Token\n *\n * References the NFT that currently or previously tokenized ownership of\n * `name`.\n */\n token: AssetId;\n\n /**\n * Owner\n *\n * Identifies the ownership state of the token.\n *\n * Guarantees:\n * - The `ownership.owner.chainId` of this address is the same as is referenced\n * in `domainAsset.contract.chainId`.\n */\n ownership: NameTokenOwnership;\n\n /**\n * The mint status of the token.\n *\n * After ENSNode indexes the token for a name, even if that token is burned,\n * ENSNode will never forget how the token once represented the name.\n * When the token for a name is burned, ENSNode remembers this token but\n * updates its `mintStatus` to `burned`. If this token becomes minted again\n * after it was burned, its `mintStatus` is updated to `minted` again.\n *\n * NOTE: Tokens managed by the .eth BaseRegistrar for\n * direct subnames of .eth can only be burned when undergoing\n * a state transition of `minted` -> `burned` -> `minted` all within\n * the same registrar action for the case that a direct subname of .eth\n * has expired and has been fully released and is now being registered again.\n * Since all of those mint status state transitions are processed within\n * a single block, once the token managed by the .eth BaseRegistrar for\n * a direct subname of .eth has been minted, our state model will forever\n * represent it as `minted`.\n *\n * Guarantees:\n * - The `mintStatus` will be burned if and only\n * if `ownership.ownershipType` is `NameTokenOwnershipTypes.Burned`.\n */\n mintStatus: NFTMintStatus;\n}\n\n/**\n * Serialized representation of {@link NameToken}.\n */\nexport interface SerializedNameToken extends Omit<NameToken, \"token\"> {\n token: SerializedAssetId;\n}\n\nexport function serializeNameToken(nameToken: NameToken): SerializedNameToken {\n return {\n token: serializeAssetId(nameToken.token),\n ownership: nameToken.ownership,\n mintStatus: nameToken.mintStatus,\n };\n}\n\n/**\n * Get all NameWrapper accounts within provided ENS Namespace.\n *\n * Guaranteed to return at least one account for ENSRoot Datasource.\n */\nexport function getNameWrapperAccounts(namespaceId: ENSNamespaceId): [AccountId, ...AccountId[]] {\n const ethnamesNameWrapperAccount = getDatasourceContract(\n namespaceId,\n DatasourceNames.ENSRoot,\n \"NameWrapper\",\n );\n\n const lineanamesNameWrapperAccount = maybeGetDatasourceContract(\n namespaceId,\n DatasourceNames.Lineanames,\n \"NameWrapper\",\n );\n\n const nameWrapperAccounts: [AccountId, ...AccountId[]] = [\n // NameWrapper for direct subnames of .eth is defined for all ENS namespaces\n ethnamesNameWrapperAccount,\n ];\n\n if (lineanamesNameWrapperAccount) {\n // NameWrapper for Lineanames is only defined for some ENS namespaces\n nameWrapperAccounts.push(lineanamesNameWrapperAccount);\n }\n\n return nameWrapperAccounts;\n}\n\n/**\n * Get name token ownership for provided owner account within selected ENS Namespace.\n */\nexport function getNameTokenOwnership(\n namespaceId: ENSNamespaceId,\n name: InterpretedName,\n owner: AccountId,\n): NameTokenOwnership {\n const nameWrapperAccounts = getNameWrapperAccounts(namespaceId);\n const hasNameWrapperOwnership = nameWrapperAccounts.some((nameWrapperAccount) =>\n accountIdEqual(owner, nameWrapperAccount),\n );\n\n if (hasNameWrapperOwnership) {\n return {\n ownershipType: NameTokenOwnershipTypes.NameWrapper,\n owner,\n } satisfies NameTokenOwnershipNameWrapper;\n }\n\n if (isAddressEqual(owner.address, zeroAddress)) {\n return {\n ownershipType: NameTokenOwnershipTypes.Burned,\n owner,\n } satisfies NameTokenOwnershipBurned;\n }\n\n const parentName = getParentInterpretedName(name);\n if (parentName === null) throw new Error(`Invariant: '${name}' has no parent Name.`);\n\n // set ownershipType as 'fully-onchain' if `name` is a direct subname of .eth\n if (parentName === \"eth\") {\n return {\n ownershipType: NameTokenOwnershipTypes.FullyOnchain,\n owner,\n } satisfies NameTokenOwnershipFullyOnchain;\n }\n\n return {\n ownershipType: NameTokenOwnershipTypes.Unknown,\n owner,\n } satisfies NameTokenOwnershipUnknown;\n}\n","import type { AccountId } from \"enssdk\";\nimport { isAddressEqual } from \"viem\";\n\n/**\n * Determines where the provided AccountId values represent the same address on the same chain.\n */\nexport const accountIdEqual = (a: AccountId, b: AccountId): boolean => {\n return a.chainId === b.chainId && isAddressEqual(a.address, b.address);\n};\n","import type { AccountId } from \"enssdk\";\n\nimport {\n type Datasource,\n type DatasourceName,\n type ENSNamespaceId,\n maybeGetDatasource,\n} from \"@ensnode/datasources\";\n\nimport { accountIdEqual } from \"./account-id\";\n\n/**\n * Gets the AccountId for the contract in the specified namespace, datasource, and\n * contract name, or undefined if it is not defined or is not a single AccountId.\n *\n * This is useful when you want to retrieve the AccountId for a contract by its name\n * where it may or may not actually be defined for the given namespace and datasource.\n *\n * @param namespaceId - The ENSNamespace identifier (e.g. 'mainnet', 'sepolia', 'ens-test-env')\n * @param datasourceName - The name of the Datasource to search for contractName in\n * @param contractName - The name of the contract to retrieve\n * @returns The AccountId of the contract with the given namespace, datasource,\n * and contract name, or undefined if it is not found or is not a single AccountId\n */\nexport const maybeGetDatasourceContract = <\n N extends ENSNamespaceId,\n D extends DatasourceName,\n C extends string,\n>(\n namespaceId: N,\n datasourceName: D,\n contractName: C,\n): AccountId | undefined => {\n const datasource = maybeGetDatasource(namespaceId, datasourceName) as Datasource | undefined;\n if (!datasource) return undefined;\n\n const address = datasource.contracts[contractName]?.address;\n if (address === undefined || Array.isArray(address)) return undefined;\n\n return {\n chainId: datasource.chain.id,\n address,\n };\n};\n\n/**\n * Gets the AccountId for the contract in the specified namespace, datasource, and\n * contract name, or throws an error if it is not defined or is not a single AccountId.\n *\n * @param namespaceId - The ENSNamespace identifier (e.g. 'mainnet', 'sepolia', 'ens-test-env')\n * @param datasourceName - The name of the Datasource to search for contractName in\n * @param contractName - The name of the contract to retrieve\n * @returns The AccountId of the contract with the given namespace, datasource,\n * and contract name\n * @throws Error if the contract is not found or is not a single AccountId\n */\nexport const getDatasourceContract = (\n namespaceId: ENSNamespaceId,\n datasourceName: DatasourceName,\n contractName: string,\n): AccountId => {\n const contract = maybeGetDatasourceContract(namespaceId, datasourceName, contractName);\n if (!contract) {\n throw new Error(\n `Expected contract not found for ${namespaceId} ${datasourceName} ${contractName}`,\n );\n }\n return contract;\n};\n\n/**\n * Makes a comparator fn for `b` against the contract described by `namespace`, `datasourceName`, and `contractName`.\n */\nexport const makeContractMatcher =\n (namespace: ENSNamespaceId, b: AccountId) =>\n (datasourceName: DatasourceName, contractName: string) => {\n const a = maybeGetDatasourceContract(namespace, datasourceName, contractName);\n return a && accountIdEqual(a, b);\n };\n","import type { Address, Hex } from \"enssdk\";\nimport {\n type AccountId,\n type AssetId,\n type AssetIdString,\n type AssetNamespace,\n type ChainId,\n type Node,\n stringifyAssetId,\n type TokenId,\n} from \"enssdk\";\nimport { isAddressEqual, zeroAddress } from \"viem\";\nimport { prettifyError } from \"zod/v4\";\n\nimport { makeAssetIdSchema, makeAssetIdStringSchema } from \"./zod-schemas\";\n\n/**\n * Serialized representation of {@link TokenId}.\n */\nexport type SerializedTokenId = string;\n\n/**\n * Serialized representation of {@link AssetId}.\n */\nexport interface SerializedAssetId extends Omit<AssetId, \"tokenId\"> {\n tokenId: SerializedTokenId;\n}\n\n/**\n * Serializes {@link AssetId} object to a structured form.\n */\nexport function serializeAssetId(assetId: AssetId): SerializedAssetId {\n return {\n assetNamespace: assetId.assetNamespace,\n contract: assetId.contract,\n tokenId: assetId.tokenId.toString(),\n };\n}\n\n/**\n * Deserialize a {@link AssetId} object.\n */\nexport function deserializeAssetId(maybeAssetId: unknown, valueLabel?: string): AssetId {\n const schema = makeAssetIdSchema(valueLabel);\n const parsed = schema.safeParse(maybeAssetId);\n\n if (parsed.error) {\n throw new RangeError(`Cannot deserialize AssetId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\n/**\n * Parse a stringified representation of {@link AssetId} object.\n */\nexport function parseAssetId(maybeAssetId: AssetIdString, valueLabel?: string): AssetId {\n const schema = makeAssetIdStringSchema(valueLabel);\n const parsed = schema.safeParse(maybeAssetId);\n\n if (parsed.error) {\n throw new RangeError(`Cannot parse AssetId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\n/**\n * Builds an AssetId for the NFT represented by the given contract,\n * tokenId, and assetNamespace.\n *\n * @param contract - The contract that manages the NFT\n * @param tokenId - The tokenId of the NFT\n * @param assetNamespace - The assetNamespace of the NFT\n * @returns The AssetId for the NFT represented by the given contract,\n * tokenId, and assetNamespace\n */\nexport const buildAssetId = (\n contract: AccountId,\n tokenId: TokenId,\n assetNamespace: AssetNamespace,\n): AssetId => {\n return {\n assetNamespace,\n contract,\n tokenId,\n };\n};\n\n/**\n * A globally unique reference to an NFT tokenizing the ownership of a domain.\n */\nexport interface DomainAssetId extends AssetId {\n /**\n * The namehash (node) of the domain who's ownership is tokenized by\n * this `AssetId`.\n */\n domainId: Node;\n}\n\n/**\n * Serialized representation of {@link DomainAssetId}.\n */\nexport interface SerializedDomainAssetId extends SerializedAssetId {\n domainId: Node;\n}\n\nexport function serializeDomainAssetId(domainAsset: DomainAssetId): SerializedDomainAssetId {\n return {\n ...serializeAssetId(domainAsset),\n domainId: domainAsset.domainId,\n };\n}\n\n/**\n * An enum representing the mint status of a DomainAssetId.\n *\n * After we index a NFT we never delete it from our index. Instead, when an\n * indexed NFT is burned onchain we retain its record and update its mint\n * status as `burned`. If a NFT is minted again after it is burned its mint\n * status is updated to `minted`.\n */\nexport const NFTMintStatuses = {\n Minted: \"minted\",\n Burned: \"burned\",\n} as const;\n\nexport type NFTMintStatus = (typeof NFTMintStatuses)[keyof typeof NFTMintStatuses];\n\n/**\n * Metadata about a NFT transfer event.\n *\n * This metadata can be used for building more helpful messages when processing\n * NFT transfer events.\n */\nexport interface NFTTransferEventMetadata {\n chainId: ChainId;\n blockNumber: bigint;\n transactionHash: Hex;\n eventHandlerName: string;\n nft: DomainAssetId;\n}\n\nexport const formatNFTTransferEventMetadata = (metadata: NFTTransferEventMetadata): string => {\n const assetIdString = stringifyAssetId(metadata.nft);\n\n return [\n `Event: ${metadata.eventHandlerName}`,\n `Chain ID: ${metadata.chainId}`,\n `Block Number: ${metadata.blockNumber}`,\n `Transaction Hash: ${metadata.transactionHash}`,\n `NFT: ${assetIdString}`,\n ]\n .map((line) => ` - ${line}`)\n .join(\"\\n\");\n};\n\n/**\n * An enum representing the type of transfer that has occurred to a DomainAssetId.\n */\nexport const NFTTransferTypes = {\n /**\n * Initial transfer from zeroAddress to a non-zeroAddress\n * Can happen at most once to a NFT AssetId\n *\n * Invariants:\n * - NFT is not indexed and therefore has no previous mint status or owner\n * - new NFT mint status is `minted`\n * - new NFT owner is a non-zeroAddress\n */\n Mint: \"mint\",\n\n /**\n * Subsequent transfer from zeroAddress to a non-zeroAddress\n * Can happen any number of times to a NFT AssetId as it passes in a cycle from\n * mint -> burn -> remint -> burn -> remint -> ...\n *\n * Invariants:\n * - NFT is indexed\n * - previous NFT mint status was `burned`\n * - previous NFT owner is the zeroAddress\n * - new NFT mint status is `minted`\n * - new NFT owner is a non-zeroAddress\n */\n Remint: \"remint\",\n\n /**\n * Special transfer type for improperly implemented NFT contracts that allow a NFT\n * that is currently minted to be reminted before an intermediate burn.\n *\n * Transfer from zeroAddress to non-zeroAddress for an indexed NFT where the\n * previously indexed nft had status `minted` with a non-zeroAddress owner.\n *\n * Invariants:\n * - NFT is indexed\n * - previous NFT mint status was `minted`\n * - previous NFT owner was a non-zeroAddress\n * - new NFT mint status is `minted`\n * - new NFT owner is a non-zeroAddress\n */\n MintedRemint: \"minted-remint\",\n\n /**\n * Transfer from a non-zeroAddress to zeroAddress\n *\n * Invariants:\n * - NFT is indexed\n * - previous NFT mint status was `minted`\n * - previous NFT owner is a non-zeroAddress\n * - new NFT mint status is `burned`\n * - new NFT owner is the zeroAddress\n */\n Burn: \"burn\",\n\n /**\n * Transfer from a non-zeroAddress to a distinct non-zeroAddress\n *\n * Invariants:\n * - NFT is indexed\n * - previous and new NFT mint status is `minted`\n * - previous and new NFT owner are distinct non-zeroAddress\n */\n Transfer: \"transfer\",\n\n /**\n * Transfer from a non-zeroAddress to the same non-zeroAddress\n *\n * Invariants:\n * - NFT is indexed\n * - previous and new NFT mint status is `minted`\n * - previous and new NFT owner are equivalent non-zeroAddress\n */\n SelfTransfer: \"self-transfer\",\n\n /**\n * Transfer from zeroAddress to zeroAddress for an indexed NFT\n *\n * Invariants:\n * - NFT is indexed\n * - previous and new NFT mint status is `burned`\n * - previous and new NFT owner are zeroAddress\n */\n RemintBurn: \"remint-burn\",\n\n /**\n * Special transfer type for improperly implemented NFT contracts that allow a NFT\n * that is currently minted to be reminted again before an intermediate burn.\n *\n * Transfer from zeroAddress to zeroAddress for an indexed NFT where the\n * previously indexed nft had status `minted` with a non-zeroAddress owner.\n *\n * Invariants:\n * - NFT is indexed\n * - previous NFT mint status was `minted`\n * - previous NFT owner was a non-zeroAddress\n * - new NFT mint status is `burned`\n * - new NFT owner is the zeroAddress\n */\n MintedRemintBurn: \"minted-remint-burn\",\n\n /**\n * Transfer from zeroAddress to zeroAddress for an unindexed NFT\n *\n * Invariants:\n * - NFT is not indexed and therefore has no previous mint status or owner\n * - NFT should remain unindexed and without any mint status or owner\n */\n MintBurn: \"mint-burn\",\n} as const;\n\nexport type NFTTransferType = (typeof NFTTransferTypes)[keyof typeof NFTTransferTypes];\n\nexport const getNFTTransferType = (\n from: Address,\n to: Address,\n allowMintedRemint: boolean,\n metadata: NFTTransferEventMetadata,\n currentlyIndexedOwner?: Address,\n): NFTTransferType => {\n const isIndexed = currentlyIndexedOwner !== undefined;\n const isIndexedAsMinted = isIndexed && !isAddressEqual(currentlyIndexedOwner, zeroAddress);\n\n // a transfer from the zeroAddress to a non-zeroAddress represents minting\n const isMint = isAddressEqual(from, zeroAddress);\n\n // a transfer from a non-zeroAddress to the zeroAddress represents burning\n const isBurn = isAddressEqual(to, zeroAddress);\n\n // it's possible to transfer to and from the same address\n const isSelfTransfer = isAddressEqual(from, to);\n\n if (isIndexed && !isAddressEqual(currentlyIndexedOwner, from)) {\n if (isMint && allowMintedRemint) {\n // special case to allow minted remint from improperly implemented NFT contracts\n } else {\n throw new Error(\n `Error: Sending from ${from} conflicts with currently indexed owner ${currentlyIndexedOwner}.\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n }\n }\n\n if (isSelfTransfer) {\n if (isMint) {\n // a self-transfer to and from the zeroAddress represents either mint-burn, remint-burn,\n // or minted-remint-burn\n if (!isIndexed) {\n // mint-burn with !isIndexed && !isIndexedAsMinted\n return NFTTransferTypes.MintBurn;\n } else if (!isIndexedAsMinted) {\n // remint-burn with isIndexed && !isIndexedAsMinted\n return NFTTransferTypes.RemintBurn;\n } else if (allowMintedRemint) {\n // minted-remint-burn with isIndexed && isIndexedAsMinted && allowMintedRemint\n //\n // this is a non-standard special case for improperly implemented NFT contracts\n // that allow a NFT that is currently minted to be reminted again before an\n // intermediate burn.\n //\n // this is a self-transfer from zeroAddress to zeroAddress for an indexed NFT\n // where the previously indexed nft had status `minted` with a non-zeroAddress owner.\n return NFTTransferTypes.MintedRemintBurn;\n } else {\n // remint-burn with isIndexed && isIndexedAsMinted && !allowMintedRemint\n // invalid state transition to be minted and then remint again\n throw new Error(\n `Error: Invalid state transition from minted -> remint-burn\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n }\n } else {\n // a self-transfer to and from the same non-zero address\n if (!isIndexed) {\n // self-transfer with !isIndexed && !isIndexedAsMinted\n // this branch is unreachable because:\n // - from !== zeroAddress; and\n // - !isIndexedAsMinted requires that from === zeroAddress\n // throw an error to validate above assertions\n throw new Error(\n `Error: Invalid state transition from unindexed -> self-transfer\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else if (!isIndexedAsMinted) {\n // self-transfer with isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: invalid state transition from burned -> self-transfer\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else {\n // self-transfer with isIndexed && isIndexedAsMinted\n return NFTTransferTypes.SelfTransfer;\n }\n }\n } else if (isMint) {\n if (!isIndexed) {\n // mint with !isIndexed && !isIndexedAsMinted\n return NFTTransferTypes.Mint;\n } else if (!isIndexedAsMinted) {\n // mint with isIndexed && !isIndexedAsMinted\n return NFTTransferTypes.Remint;\n } else if (allowMintedRemint) {\n // mint with isIndexed && isIndexedAsMinted && allowMintedRemint\n //\n // this is a non-standard special case for improperly implemented NFT contracts\n // that allow a NFT that is currently minted to be reminted again before an\n // intermediate burn.\n //\n // this is a transfer from zeroAddress to non-zeroAddress for an indexed NFT\n // where the previously indexed nft had status `minted` with a non-zeroAddress owner.\n return NFTTransferTypes.MintedRemint;\n } else {\n // mint with isIndexed && isIndexedAsMinted && !allowMintedRemint\n throw new Error(\n `Error: Invalid state transition from minted -> mint\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n }\n } else if (isBurn) {\n if (!isIndexed) {\n // burn with !isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: Invalid state transition from unindexed -> burn\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else if (!isIndexedAsMinted) {\n // burn with isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: Invalid state transition from burned -> burn\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else {\n // burn with isIndexed && isIndexedAsMinted\n return NFTTransferTypes.Burn;\n }\n } else {\n // a transfer from a non-zeroAddress to a non-zeroAddress represents a transfer\n if (!isIndexed) {\n // transfer with !isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: Invalid state transition from unindexed -> transfer\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else if (!isIndexedAsMinted) {\n // transfer with isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: Invalid state transition from burned -> transfer\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else {\n // transfer with isIndexed && isIndexedAsMinted\n return NFTTransferTypes.Transfer;\n }\n }\n};\n","import { AssetId as CaipAssetId } from \"caip\";\nimport { type AssetId, AssetNamespaces } from \"enssdk\";\nimport { zeroAddress } from \"viem\";\nimport { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport { makeAccountIdSchema, makeNodeSchema } from \"../shared/zod-schemas\";\nimport { type DomainAssetId, NFTMintStatuses, type SerializedAssetId } from \"./assets\";\nimport {\n type NameToken,\n type NameTokenOwnershipBurned,\n type NameTokenOwnershipFullyOnchain,\n type NameTokenOwnershipNameWrapper,\n NameTokenOwnershipTypes,\n type NameTokenOwnershipUnknown,\n} from \"./name-token\";\n\nconst tokenIdSchemaSerializable = z.string();\nconst tokenIdSchemaNative = z.preprocess(\n (v) => (typeof v === \"string\" ? BigInt(v) : v),\n z.bigint().positive(),\n);\n\nexport function makeTokenIdSchema<const SerializableType extends boolean>(\n _valueLabel: string,\n serializable: SerializableType,\n): SerializableType extends true ? typeof tokenIdSchemaSerializable : typeof tokenIdSchemaNative;\nexport function makeTokenIdSchema(\n _valueLabel: string = \"Token ID Schema\",\n serializable: true | false = false,\n): typeof tokenIdSchemaSerializable | typeof tokenIdSchemaNative {\n if (serializable) {\n return tokenIdSchemaSerializable;\n } else {\n return tokenIdSchemaNative;\n }\n}\n\n/**\n * Make schema for {@link AssetId}.\n *\n */\nexport const makeAssetIdSchema = <const SerializableType extends boolean = false>(\n valueLabel: string = \"Asset ID Schema\",\n serializable?: SerializableType,\n) => {\n return z.object({\n assetNamespace: z.enum(AssetNamespaces),\n contract: makeAccountIdSchema(valueLabel),\n tokenId: makeTokenIdSchema(valueLabel, serializable ?? false),\n });\n};\n\n/**\n * Make schema for {@link AssetIdString}.\n */\nexport const makeAssetIdStringSchema = (valueLabel: string = \"Asset ID String Schema\") =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n const result = new CaipAssetId(v);\n return {\n assetNamespace: result.assetName.namespace,\n contract: {\n chainId: Number(result.chainId.reference),\n address: result.assetName.reference,\n },\n tokenId: result.tokenId,\n } as SerializedAssetId;\n }\n\n return v;\n }, makeAssetIdSchema(valueLabel));\n\n/**\n * Make schema for {@link DomainAssetId}.\n */\nexport const makeDomainAssetSchema = (valueLabel: string = \"Domain Asset Schema\") =>\n makeAssetIdSchema(valueLabel).extend({\n domainId: makeNodeSchema(`${valueLabel}.domainId`),\n });\n\nfunction invariant_nameTokenOwnershipHasNonZeroAddressOwner(\n ctx: ParsePayload<\n NameTokenOwnershipNameWrapper | NameTokenOwnershipFullyOnchain | NameTokenOwnershipUnknown\n >,\n) {\n const ownership = ctx.value;\n if (ctx.value.owner.address === zeroAddress) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `Name Token Ownership with '${ownership.ownershipType}' must have 'address' other than the zero address.`,\n });\n }\n}\n\nexport const makeNameTokenOwnershipNameWrapperSchema = (\n valueLabel: string = \"Name Token Ownership NameWrapper\",\n) =>\n z\n .object({\n ownershipType: z.literal(NameTokenOwnershipTypes.NameWrapper),\n owner: makeAccountIdSchema(`${valueLabel}.owner`),\n })\n .check(invariant_nameTokenOwnershipHasNonZeroAddressOwner);\n\nexport const makeNameTokenOwnershipFullyOnchainSchema = (\n valueLabel: string = \"Name Token Ownership Fully Onchain\",\n) =>\n z\n .object({\n ownershipType: z.literal(NameTokenOwnershipTypes.FullyOnchain),\n owner: makeAccountIdSchema(`${valueLabel}.owner`),\n })\n .check(invariant_nameTokenOwnershipHasNonZeroAddressOwner);\n\nexport const makeNameTokenOwnershipBurnedSchema = (\n valueLabel: string = \"Name Token Ownership Burned\",\n) =>\n z\n .object({\n ownershipType: z.literal(NameTokenOwnershipTypes.Burned),\n owner: makeAccountIdSchema(`${valueLabel}.owner`),\n })\n .check(invariant_nameTokenOwnershipHasZeroAddressOwner);\n\nexport const makeNameTokenOwnershipUnknownSchema = (\n valueLabel: string = \"Name Token Ownership Unknown\",\n) =>\n z\n .object({\n ownershipType: z.literal(NameTokenOwnershipTypes.Unknown),\n owner: makeAccountIdSchema(`${valueLabel}.owner`),\n })\n .check(invariant_nameTokenOwnershipHasNonZeroAddressOwner);\n\nfunction invariant_nameTokenOwnershipHasZeroAddressOwner(\n ctx: ParsePayload<NameTokenOwnershipBurned>,\n) {\n const ownership = ctx.value;\n if (ctx.value.owner.address !== zeroAddress) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `Name Token Ownership with '${ownership.ownershipType}' must have 'address' set to the zero address.`,\n });\n }\n}\n\nexport const makeNameTokenOwnershipSchema = (valueLabel: string = \"Name Token Ownership\") =>\n z.discriminatedUnion(\"ownershipType\", [\n makeNameTokenOwnershipNameWrapperSchema(valueLabel),\n makeNameTokenOwnershipFullyOnchainSchema(valueLabel),\n makeNameTokenOwnershipBurnedSchema(valueLabel),\n makeNameTokenOwnershipUnknownSchema(valueLabel),\n ]);\n\n/**\n * Make schema for {@link NameToken}.\n */\nexport const makeNameTokenSchema = <const SerializableType extends boolean>(\n valueLabel: string = \"Name Token Schema\",\n serializable?: SerializableType,\n) =>\n z.object({\n token: makeAssetIdSchema(`${valueLabel}.token`, serializable),\n\n ownership: makeNameTokenOwnershipSchema(`${valueLabel}.ownership`),\n\n mintStatus: z.enum(NFTMintStatuses),\n });\n","import { z } from \"zod/v4\";\n\nimport type { ErrorResponse } from \"./response\";\n\n/**\n * Schema for {@link ErrorResponse}.\n */\nexport const makeErrorResponseSchema = () =>\n z.object({\n message: z.string().describe(\"A description of the error that occurred.\"),\n details: z.optional(z.unknown()).describe(\"Additional details about the error.\"),\n });\n","import type { InterpretedName, Node, UnixTimestamp } from \"enssdk\";\n\nimport type { NameToken, NameTokenOwnershipTypes } from \"../../../tokenscope/name-token\";\nimport type { ErrorResponse } from \"../shared/errors\";\n\n/**\n * A status code for Name Tokens API responses.\n */\nexport const NameTokensResponseCodes = {\n /**\n * Represents a response when Name Tokens API can respond with requested data.\n */\n Ok: \"ok\",\n\n /**\n * Represents a response when Name Tokens API could not respond with requested data.\n */\n Error: \"error\",\n} as const;\n\n/**\n * The derived string union of possible {@link NameTokensResponseCodes}.\n */\nexport type NameTokensResponseCode =\n (typeof NameTokensResponseCodes)[keyof typeof NameTokensResponseCodes];\n\n/**\n * Error codes for Name Tokens API responses with 'error' response code.\n */\nexport const NameTokensResponseErrorCodes = {\n /**\n * Name tokens not indexed\n *\n * Represents an error when tokens for the requested name are not indexed by\n * the ENSNode instance's configuration.\n */\n NameTokensNotIndexed: \"name-tokens-not-indexed\",\n\n /**\n * Unsupported ENSIndexer Config\n *\n * Represents a prerequisites error when connected ENSIndexer config lacks\n * params required to enable Name Tokens API.\n */\n EnsIndexerConfigUnsupported: \"unsupported-ensindexer-config\",\n\n /**\n * Unsupported Indexing Status\n *\n * Represents a prerequisites error when Indexing Status has not yet reached\n * status required to enable Name Tokens API.\n */\n IndexingStatusUnsupported: \"unsupported-indexing-status\",\n} as const;\n\n/**\n * The derived string union of possible {@link NameTokensResponseErrorCodes}.\n */\nexport type NameTokensResponseErrorCode =\n (typeof NameTokensResponseErrorCodes)[keyof typeof NameTokensResponseErrorCodes];\n\n/**\n * Name Tokens for a name who's tokens are configured to\n * be indexed by the ENSNode instance's configuration.\n */\nexport interface RegisteredNameTokens {\n /**\n * Domain ID\n */\n domainId: Node;\n\n /**\n * Name\n *\n * FQDN of the name associated with `domainId`.\n *\n * Guarantees:\n * - `namehash(name)` is always `domainId`.\n */\n name: InterpretedName;\n\n /**\n * Name Tokens associated with the `domainId`.\n *\n * It contains every tokenized representation of `name` that\n * has ever been indexed for the given name as of `accurateAsOf`,\n * even if the given token has been burned or expired.\n *\n * Guarantees:\n * - Always includes at least one name token.\n * - When it includes more than one name token, it means that:\n * 1) More than 1 distinct tokenized representation of the ownership of\n * the `name` has been indexed as of `accurateAsOf`.\n * 2) All possible permutations of mint statuses of these tokens are\n * possible:\n * a) Multiple could be actively minted.\n * b) Multiple could be burned.\n * c) Some could be burned, others could be minted.\n * - Order of name tokens follows the order of onchain events that were\n * indexed when a token was minted, or burned.\n * - Each name token has a distinct `token` value which references\n * the NFT that currently or previously tokenized ownership of `name`.\n * - Each name token has ownership type (`ownership.ownershipType`) assigned:\n * - If there's a name token with ownership type\n * {@link NameTokenOwnershipTypes.NameWrapper}, it means that there must be also\n * another name token with ownership type either\n * {@link NameTokenOwnershipTypes.FullyOnchain}, or\n * {@link NameTokenOwnershipTypes.Unknown}.\n * - There can be at most one name token with ownership type\n * {@link NameTokenOwnershipTypes.FullyOnchain}.\n * - There can be any number of name tokens with ownership type\n * {@link NameTokenOwnershipTypes.Burned}.\n *\n * NOTE: It can be useful to get tokenized representations of the name that\n * are now burned: This can be helpful for looking up historical activity for\n * the name, including past buy orders, sell orders, and sales.\n *\n * How will the direct subnames of .eth that are wrapped by the NameWrapper\n * be represented?\n * 1) A direct subname of .eth that has been registered but\n * has never been wrapped by the NameWrapper, and:\n * a) Is still actively minted (independent of its expiry state).\n * b) Has been burned by sending it to the null address.\n * 2) A direct subname of .eth that has been registered and\n * has been wrapped by the NameWrapper, and:\n * a) Is still actively wrapped by the NameWrapper (independent of its\n * expiry state).\n * b) Is no longer wrapped by the NameWrapper, but is still actively\n * minted by the BaseRegistrar (independent of its expiry state).\n * c) Is no longer wrapped by the NameWrapper, and is also no longer\n * minted by the BaseRegistrar (both tokens now burned by sending to\n * the null address).\n */\n tokens: NameToken[];\n\n /**\n * Expiry date for the Registration Lifecycle\n *\n * The latest Registration Lifecycle for a node referenced in `domainId`.\n */\n expiresAt: UnixTimestamp;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link NameTokensResponseOk.nameTokens} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\n/**\n * A response when Name Tokens API can respond with requested data.\n */\nexport type NameTokensResponseOk = {\n responseCode: typeof NameTokensResponseCodes.Ok;\n\n /**\n * Name Tokens for the requested name.\n */\n registeredNameTokens: RegisteredNameTokens;\n};\n\n/**\n * Represents an error response when requested name was not indexed by ENSNode.\n */\nexport interface NameTokensResponseErrorNameTokensNotIndexed {\n responseCode: typeof NameTokensResponseCodes.Error;\n errorCode: typeof NameTokensResponseErrorCodes.NameTokensNotIndexed;\n error: ErrorResponse;\n}\n\n/**\n * Represents an error response when connected ENSIndexer config lacks\n * params required to enable Name Tokens API.\n */\nexport interface NameTokensResponseErrorEnsIndexerConfigUnsupported {\n responseCode: typeof NameTokensResponseCodes.Error;\n errorCode: typeof NameTokensResponseErrorCodes.EnsIndexerConfigUnsupported;\n error: ErrorResponse;\n}\n\n/**\n * Represents an error response when Indexing Status has not yet reached\n * status required to enable Name Tokens API.\n */\nexport interface NameTokensResponseErrorIndexingStatusUnsupported {\n responseCode: typeof NameTokensResponseCodes.Error;\n errorCode: typeof NameTokensResponseErrorCodes.IndexingStatusUnsupported;\n error: ErrorResponse;\n}\n\nexport type NameTokensResponseError =\n | NameTokensResponseErrorNameTokensNotIndexed\n | NameTokensResponseErrorEnsIndexerConfigUnsupported\n | NameTokensResponseErrorIndexingStatusUnsupported;\n\n/**\n * Name Tokens response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type NameTokensResponse = NameTokensResponseOk | NameTokensResponseError;\n","import { z } from \"zod/v4\";\n\nimport { makeDurationSchema, makeUnixTimestampSchema } from \"../../../shared/zod-schemas\";\nimport { makeErrorResponseSchema } from \"../shared/errors/zod-schemas\";\n\nexport const realtimeResponseSchemaOk = z.object({\n maxWorstCaseDistance: makeDurationSchema().describe(\n \"The requested maximum acceptable worst-case indexing distance in seconds.\",\n ),\n slowestChainIndexingCursor: makeUnixTimestampSchema().describe(\n \"The timestamp of the slowest chain's latest indexed block.\",\n ),\n worstCaseDistance: makeDurationSchema().describe(\n \"The actual worst-case distance in seconds between 'now' and the slowest chain's indexing cursor. \" +\n \"This allows your client to programmatically determine whether the ENSNode instance is sufficiently synchronized for your use case.\",\n ),\n});\n\nexport const realtimeResponseSchemaError = makeErrorResponseSchema();\n","import type { InterpretedName } from \"enssdk\";\n\nimport type { SerializedRegistrarActionsResponseOk } from \"./serialized-response\";\n\n/**\n * Example value for {@link SerializedRegistrarActionsResponseOk}, for use in OpenAPI documentation.\n *\n * - registrationLifecycle.node is namehash(\"vitalik.eth\")\n * - subregistry.node is namehash(\"eth\")\n * - subregistry.subregistryId is the ETH Registrar Controller on Ethereum mainnet\n */\nexport const registrarActionsResponseOkExample = {\n responseCode: \"ok\",\n registrarActions: [\n {\n action: {\n type: \"registration\",\n id: \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n incrementalDuration: 31536000,\n registrant: \"0xd8da6bf26964af9d7eed9e03e53415d37aa96045\",\n registrationLifecycle: {\n subregistry: {\n subregistryId: {\n chainId: 1,\n address: \"0x253553366da8546fc250f225fe3d25d0c782303b\",\n },\n node: \"0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae\",\n },\n node: \"0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835\",\n expiresAt: 1893456000,\n },\n pricing: {\n baseCost: { amount: \"1000000000000000\", currency: \"ETH\" },\n premium: { amount: \"0\", currency: \"ETH\" },\n total: { amount: \"1000000000000000\", currency: \"ETH\" },\n },\n referral: { encodedReferrer: null, decodedReferrer: null },\n block: { timestamp: 1700000000, number: 18500000 },\n transactionHash: \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n eventIds: [\"0x0000000000000000000000000000000000000000000000000000000000000001\"],\n },\n name: \"vitalik.eth\" as InterpretedName,\n },\n ],\n pageContext: {\n page: 1,\n recordsPerPage: 25,\n totalRecords: 1,\n totalPages: 1,\n hasNext: false,\n hasPrev: false,\n startIndex: 0,\n endIndex: 0,\n },\n accurateAsOf: 1700000000,\n} satisfies SerializedRegistrarActionsResponseOk;\n","import { namehashInterpretedName } from \"enssdk\";\nimport { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport {\n makeRegistrarActionSchema,\n makeSerializedRegistrarActionSchema,\n} from \"../../../registrars/zod-schemas\";\nimport { makeReinterpretedNameSchema, makeUnixTimestampSchema } from \"../../../shared/zod-schemas\";\nimport { makeErrorResponseSchema } from \"../shared/errors/zod-schemas\";\nimport { makeResponsePageContextSchema } from \"../shared/pagination/zod-schemas\";\nimport { type NamedRegistrarAction, RegistrarActionsResponseCodes } from \"./response\";\nimport {\n SerializedNamedRegistrarAction,\n SerializedRegistrarActionsResponseOk,\n} from \"./serialized-response\";\n\nfunction invariant_registrationLifecycleNodeMatchesName(ctx: ParsePayload<NamedRegistrarAction>) {\n const { name, action } = ctx.value;\n const expectedNode = action.registrationLifecycle.node;\n const actualNode = namehashInterpretedName(name);\n\n if (actualNode !== expectedNode) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `The 'action.registrationLifecycle.node' must match namehash of 'name'`,\n });\n }\n}\n\n/**\n * Schema for {@link NamedRegistrarAction}.\n */\nexport const makeNamedRegistrarActionSchema = (valueLabel: string = \"Named Registrar Action\") =>\n z\n .object({\n action: makeRegistrarActionSchema(valueLabel),\n name: makeReinterpretedNameSchema(valueLabel),\n })\n .check(invariant_registrationLifecycleNodeMatchesName);\n\n/**\n * Schema for {@link SerializedNamedRegistrarAction}.\n */\nconst makeSerializedNamedRegistrarActionSchema = (\n valueLabel: string = \"Serialized Named Registrar Action\",\n) =>\n z.object({\n action: makeSerializedRegistrarActionSchema(valueLabel),\n name: makeReinterpretedNameSchema(valueLabel),\n });\n\n/**\n * Schema for {@link RegistrarActionsResponseOk}\n */\nexport const makeRegistrarActionsResponseOkSchema = (\n valueLabel: string = \"Registrar Actions Response OK\",\n) =>\n z.object({\n responseCode: z.literal(RegistrarActionsResponseCodes.Ok),\n registrarActions: z.array(makeNamedRegistrarActionSchema(valueLabel)),\n pageContext: makeResponsePageContextSchema(`${valueLabel}.pageContext`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n\n/**\n * Schema for {@link RegistrarActionsResponseError}\n */\nexport const makeRegistrarActionsResponseErrorSchema = (\n _valueLabel: string = \"Registrar Actions Response Error\",\n) =>\n z.strictObject({\n responseCode: z.literal(RegistrarActionsResponseCodes.Error),\n error: makeErrorResponseSchema(),\n });\n\n/**\n * Schema for {@link RegistrarActionsResponse}\n */\nexport const makeRegistrarActionsResponseSchema = (\n valueLabel: string = \"Registrar Actions Response\",\n) =>\n z.discriminatedUnion(\"responseCode\", [\n makeRegistrarActionsResponseOkSchema(valueLabel),\n makeRegistrarActionsResponseErrorSchema(valueLabel),\n ]);\n\n/**\n * Schema for {@link SerializedRegistrarActionsResponseOk}\n */\nexport const makeSerializedRegistrarActionsResponseOkSchema = (\n valueLabel: string = \"Serialized Registrar Actions Response OK\",\n) =>\n z.object({\n responseCode: z.literal(RegistrarActionsResponseCodes.Ok),\n registrarActions: z.array(makeSerializedNamedRegistrarActionSchema(valueLabel)),\n pageContext: makeResponsePageContextSchema(`${valueLabel}.pageContext`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport { addPrices, isPriceEqual } from \"../shared/currencies\";\nimport {\n makeAccountIdSchema,\n makeBlockRefSchema,\n makeDurationSchema,\n makeHexStringSchema,\n makeNodeSchema,\n makeNormalizedAddressSchema,\n makePriceEthSchema,\n makeSerializedPriceEthSchema,\n makeTransactionHashSchema,\n makeUnixTimestampSchema,\n} from \"../shared/zod-schemas\";\nimport { decodeEncodedReferrer, ENCODED_REFERRER_BYTE_LENGTH } from \"./encoded-referrer\";\nimport {\n type RegistrarAction,\n type RegistrarActionEventId,\n RegistrarActionPricing,\n type RegistrarActionPricingAvailable,\n type RegistrarActionPricingUnknown,\n type RegistrarActionReferralAvailable,\n RegistrarActionTypes,\n SerializedRegistrarAction,\n SerializedRegistrarActionPricing,\n} from \"./registrar-action\";\nimport type { RegistrationLifecycle } from \"./registration-lifecycle\";\nimport { Subregistry } from \"./subregistry\";\n\n/**\n * Schema for parsing objects into {@link Subregistry}.\n */\nconst makeSubregistrySchema = (valueLabel: string = \"Subregistry\") =>\n z.object({\n subregistryId: makeAccountIdSchema(`${valueLabel} Subregistry ID`),\n node: makeNodeSchema(`${valueLabel} Node`),\n });\n\n/**\n * Schema for parsing objects into {@link RegistrationLifecycle}.\n */\nexport const makeRegistrationLifecycleSchema = (valueLabel: string = \"Registration Lifecycle\") =>\n z.object({\n subregistry: makeSubregistrySchema(`${valueLabel} Subregistry`),\n node: makeNodeSchema(`${valueLabel} Node`),\n expiresAt: makeUnixTimestampSchema(`${valueLabel} Expires at`),\n });\n\n/** Invariant: total is sum of baseCost and premium */\nfunction invariant_registrarActionPricingTotalIsSumOfBaseCostAndPremium(\n ctx: ParsePayload<RegistrarActionPricingAvailable>,\n) {\n const { baseCost, premium, total } = ctx.value;\n const actualTotal = addPrices(baseCost, premium);\n\n if (!isPriceEqual(actualTotal, total)) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'total' must be equal to the sum of 'baseCost' and 'premium'`,\n });\n }\n}\n\n/**\n * Schema for parsing objects into {@link RegistrarActionPricing}.\n */\nconst makeRegistrarActionPricingSchema = (valueLabel: string = \"Registrar Action Pricing\") =>\n z.union([\n // pricing available\n z\n .object({\n baseCost: makePriceEthSchema(`${valueLabel} Base Cost`),\n premium: makePriceEthSchema(`${valueLabel} Premium`),\n total: makePriceEthSchema(`${valueLabel} Total`),\n })\n .check(invariant_registrarActionPricingTotalIsSumOfBaseCostAndPremium)\n .transform((v) => v as RegistrarActionPricingAvailable),\n\n // pricing unknown\n z\n .object({\n baseCost: z.null(),\n premium: z.null(),\n total: z.null(),\n })\n .transform((v) => v as RegistrarActionPricingUnknown),\n ]);\n\n/**\n * Schema for parsing objects into {@link SerializedRegistrarActionPricing}.\n */\nexport const makeSerializedRegistrarActionPricingSchema = (\n valueLabel: string = \"Serialized Registrar Action Pricing\",\n) =>\n z.union([\n // pricing available\n z.object({\n baseCost: makeSerializedPriceEthSchema(`${valueLabel} Base Cost`),\n premium: makeSerializedPriceEthSchema(`${valueLabel} Premium`),\n total: makeSerializedPriceEthSchema(`${valueLabel} Total`),\n }),\n // pricing unknown\n z.object({\n baseCost: z.null(),\n premium: z.null(),\n total: z.null(),\n }),\n ]);\n\n/** Invariant: decodedReferrer is based on encodedReferrer */\nfunction invariant_registrarActionDecodedReferrerBasedOnRawReferrer(\n ctx: ParsePayload<RegistrarActionReferralAvailable>,\n) {\n const { encodedReferrer, decodedReferrer } = ctx.value;\n\n try {\n const expectedDecodedReferrer = decodeEncodedReferrer(encodedReferrer);\n\n if (decodedReferrer !== expectedDecodedReferrer) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'decodedReferrer' must be based on 'encodedReferrer'`,\n });\n }\n } catch (error) {\n // in case decoding the encodedReferrer value could not succeed\n // pass the decoding error message\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: errorMessage,\n });\n }\n}\n\nconst makeRegistrarActionReferralSchema = (valueLabel: string = \"Registrar Action Referral\") =>\n z.union([\n // referral available\n z\n .object({\n encodedReferrer: makeHexStringSchema(\n { bytesCount: ENCODED_REFERRER_BYTE_LENGTH },\n `${valueLabel} Encoded Referrer`,\n ),\n decodedReferrer: makeNormalizedAddressSchema(`${valueLabel} Decoded Referrer`),\n })\n .check(invariant_registrarActionDecodedReferrerBasedOnRawReferrer),\n\n // referral not applicable\n z.object({\n encodedReferrer: z.null(),\n decodedReferrer: z.null(),\n }),\n ]);\n\nfunction invariant_eventIdsInitialElementIsTheActionId(\n ctx: ParsePayload<Pick<RegistrarAction, \"id\" | \"eventIds\">>,\n) {\n const { id, eventIds } = ctx.value;\n\n if (eventIds[0] !== id) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"The initial element of `eventIds` must be the `id` value\",\n });\n }\n}\n\nconst EventIdSchema = z.string().nonempty();\n\nconst EventIdsSchema = z\n .array(EventIdSchema)\n .min(1)\n .transform((v) => v as [RegistrarActionEventId, ...RegistrarActionEventId[]]);\n\n// Base schema without refinements - can be extended\nconst makeBaseRegistrarActionSchemaWithoutCheck = (valueLabel: string = \"Base Registrar Action\") =>\n z.object({\n id: EventIdSchema,\n incrementalDuration: makeDurationSchema(`${valueLabel} Incremental Duration`),\n registrant: makeNormalizedAddressSchema(`${valueLabel} Registrant`),\n registrationLifecycle: makeRegistrationLifecycleSchema(`${valueLabel} Registration Lifecycle`),\n pricing: makeRegistrarActionPricingSchema(`${valueLabel} Pricing`),\n referral: makeRegistrarActionReferralSchema(`${valueLabel} Referral`),\n block: makeBlockRefSchema(`${valueLabel} Block`),\n transactionHash: makeTransactionHashSchema(`${valueLabel} Transaction Hash`),\n eventIds: EventIdsSchema,\n });\n\n// Base schema with refinements - used for parsing/validation\nexport const makeBaseRegistrarActionSchema = (valueLabel: string = \"Base Registrar Action\") =>\n makeBaseRegistrarActionSchemaWithoutCheck(valueLabel).check(\n invariant_eventIdsInitialElementIsTheActionId,\n );\n\nexport const makeRegistrarActionRegistrationSchema = (valueLabel: string = \"Registration \") =>\n makeBaseRegistrarActionSchema(valueLabel).extend({\n type: z.literal(RegistrarActionTypes.Registration),\n });\n\nexport const makeRegistrarActionRenewalSchema = (valueLabel: string = \"Renewal\") =>\n makeBaseRegistrarActionSchema(valueLabel).extend({\n type: z.literal(RegistrarActionTypes.Renewal),\n });\n\n/**\n * Schema for {@link RegistrarAction}.\n */\nexport const makeRegistrarActionSchema = (valueLabel: string = \"Registrar Action\") =>\n z.discriminatedUnion(\"type\", [\n makeRegistrarActionRegistrationSchema(`${valueLabel} Registration`),\n makeRegistrarActionRenewalSchema(`${valueLabel} Renewal`),\n ]);\n\nconst makeSerializedBaseRegistrarActionSchema = (\n valueLabel: string = \"Serialized Base Registrar Action\",\n) =>\n makeBaseRegistrarActionSchemaWithoutCheck(valueLabel).extend({\n pricing: makeSerializedRegistrarActionPricingSchema(`${valueLabel} Pricing`),\n });\n\nconst makeSerializedRegistrarActionRegistrationSchema = (\n valueLabel: string = \"Serialized Registration\",\n) =>\n makeSerializedBaseRegistrarActionSchema(valueLabel).extend({\n type: z.literal(RegistrarActionTypes.Registration),\n });\n\nconst makeSerializedRegistrarActionRenewalSchema = (valueLabel: string = \"Serialized Renewal\") =>\n makeSerializedBaseRegistrarActionSchema(valueLabel).extend({\n type: z.literal(RegistrarActionTypes.Renewal),\n });\n\n/**\n * Schema for {@link SerializedRegistrarAction}\n */\nexport const makeSerializedRegistrarActionSchema = (\n valueLabel: string = \"Serialized Registrar Action\",\n) =>\n z.discriminatedUnion(\"type\", [\n makeSerializedRegistrarActionRegistrationSchema(`${valueLabel} Registration`),\n makeSerializedRegistrarActionRenewalSchema(`${valueLabel} Renewal`),\n ]);\n","import { type Hex, isNormalizedAddress, type NormalizedAddress, toNormalizedAddress } from \"enssdk\";\nimport { pad, size, slice, zeroAddress } from \"viem\";\n\n/**\n * Encoded Referrer\n *\n * Represents a \"raw\" ENS referrer value.\n *\n * Registrar controllers emit referrer data as bytes32 values. This type represents\n * that raw 32-byte hex string.\n *\n * @invariant Guaranteed to be a hex string representation of a 32-byte value.\n */\nexport type EncodedReferrer = Hex;\n\n/**\n * Encoded Referrer byte offset\n *\n * The count of left-padded bytes in an {@link EncodedReferrer} value.\n */\nexport const ENCODED_REFERRER_BYTE_OFFSET = 12;\n\n/**\n * Encoded Referrer byte length\n *\n * The count of bytes the {@link EncodedReferrer} value consists of.\n */\nexport const ENCODED_REFERRER_BYTE_LENGTH = 32;\n\n/**\n * Expected padding for a valid encoded referrer\n *\n * Properly encoded referrers must have exactly 12 zero bytes of left padding\n * before the 20-byte Ethereum address.\n */\nexport const EXPECTED_ENCODED_REFERRER_PADDING: Hex = pad(\"0x\", {\n size: ENCODED_REFERRER_BYTE_OFFSET,\n dir: \"left\",\n});\n\n/**\n * Zero Encoded Referrer\n *\n * Guaranteed to be a hex string representation of a 32-byte zero value.\n */\nexport const ZERO_ENCODED_REFERRER: EncodedReferrer = pad(\"0x\", {\n size: ENCODED_REFERRER_BYTE_LENGTH,\n dir: \"left\",\n});\n\n/**\n * Build an {@link EncodedReferrer} value for the given {@link NormalizedAddress}\n * according to the referrer encoding with left-zero-padding.\n */\nexport function buildEncodedReferrer(address: NormalizedAddress): EncodedReferrer {\n if (!isNormalizedAddress(address)) throw new Error(`Address '${address}' is not normalized.`);\n\n return pad(address, { size: ENCODED_REFERRER_BYTE_LENGTH, dir: \"left\" });\n}\n\n/**\n * Decode an {@link EncodedReferrer} value into a {@link NormalizedAddress}\n * according to the referrer encoding with left-zero-padding.\n *\n * @param encodedReferrer - The \"raw\" {@link EncodedReferrer} value to decode.\n * @returns The decoded referrer address.\n * @throws when encodedReferrer value is not represented by\n * {@link ENCODED_REFERRER_BYTE_LENGTH} bytes.\n * @throws when decodedReferrer is not a valid EVM address.\n */\nexport function decodeEncodedReferrer(encodedReferrer: EncodedReferrer): NormalizedAddress {\n // Invariant: encoded referrer must be of expected size\n if (size(encodedReferrer) !== ENCODED_REFERRER_BYTE_LENGTH) {\n throw new Error(\n `Encoded referrer value must be represented by ${ENCODED_REFERRER_BYTE_LENGTH} bytes.`,\n );\n }\n\n const padding = slice(encodedReferrer, 0, ENCODED_REFERRER_BYTE_OFFSET);\n\n // strict validation: padding must be all zeros\n // if any byte in the padding is non-zero, treat as Zero Encoded Referrer\n if (padding !== EXPECTED_ENCODED_REFERRER_PADDING) return zeroAddress;\n\n const decodedReferrer = slice(encodedReferrer, ENCODED_REFERRER_BYTE_OFFSET);\n\n try {\n // return normalized address\n return toNormalizedAddress(decodedReferrer);\n } catch {\n throw new Error(`Decoded referrer value must be a valid EVM address.`);\n }\n}\n","import type { ChainId, ChainIdString, DatetimeISO8601, UrlString } from \"enssdk\";\n\nimport type {\n Price,\n PriceDai,\n PriceEnsTokens,\n PriceEth,\n PriceUsdc,\n SerializedPrice,\n SerializedPriceDai,\n SerializedPriceEnsTokens,\n SerializedPriceEth,\n SerializedPriceUsdc,\n} from \"./currencies\";\nimport type { Datetime } from \"./types\";\n\n/**\n * Serializes a {@link ChainId} value into its string representation.\n */\nexport function serializeChainId(chainId: ChainId): ChainIdString {\n return chainId.toString();\n}\n\n/**\n * Serializes a {@link Datetime} value into its string representation.\n */\nexport function serializeDatetime(datetime: Datetime): DatetimeISO8601 {\n return datetime.toISOString();\n}\n\n/**\n * Serializes a {@link URL} value into its string representation.\n */\nexport function serializeUrl(url: URL): UrlString {\n return url.toString();\n}\n\n/**\n * Serializes a {@link Price} object.\n */\nexport function serializePrice(price: Price): SerializedPrice {\n return {\n currency: price.currency,\n amount: price.amount.toString(),\n };\n}\n\n/**\n * Serializes a {@link PriceEth} object.\n */\nexport function serializePriceEth(price: PriceEth): SerializedPriceEth {\n return serializePrice(price) as SerializedPriceEth;\n}\n\n/**\n * Serializes a {@link PriceUsdc} object.\n */\nexport function serializePriceUsdc(price: PriceUsdc): SerializedPriceUsdc {\n return serializePrice(price) as SerializedPriceUsdc;\n}\n\n/**\n * Serializes a {@link PriceDai} object.\n */\nexport function serializePriceDai(price: PriceDai): SerializedPriceDai {\n return serializePrice(price) as SerializedPriceDai;\n}\n\n/**\n * Serializes a {@link PriceEnsTokens} object.\n */\nexport function serializePriceEnsTokens(price: PriceEnsTokens): SerializedPriceEnsTokens {\n return serializePrice(price) as SerializedPriceEnsTokens;\n}\n","import type { Address, Duration } from \"enssdk\";\nimport type { Hash } from \"viem\";\n\nimport type { EncodedReferrer } from \"./encoded-referrer\";\n\nexport type { EncodedReferrer } from \"./encoded-referrer\";\nexport { decodeEncodedReferrer, ZERO_ENCODED_REFERRER } from \"./encoded-referrer\";\n\nimport type { PriceEth, SerializedPriceEth } from \"../shared/currencies\";\nimport { serializePriceEth } from \"../shared/serialize\";\nimport type { BlockRef } from \"../shared/types\";\nimport type { RegistrationLifecycle } from \"./registration-lifecycle\";\n\n/**\n * Globally unique, deterministic ID of an indexed onchain event\n * associated with the \"logical registrar action\".\n */\nexport type RegistrarActionEventId = string;\n\n/**\n * Types of \"logical registrar action\".\n */\nexport const RegistrarActionTypes = {\n Registration: \"registration\",\n Renewal: \"renewal\",\n} as const;\n\nexport type RegistrarActionType = (typeof RegistrarActionTypes)[keyof typeof RegistrarActionTypes];\n\n/**\n * Pricing information for a \"logical registrar action\".\n */\nexport interface RegistrarActionPricingAvailable {\n /**\n * Base cost\n *\n * Base cost (before any `premium`) of Ether measured in units of Wei\n * paid to execute the \"logical registrar action\".\n *\n * May be 0.\n */\n baseCost: PriceEth;\n\n /**\n * Premium\n *\n * \"premium\" cost (in excesses of the `baseCost`) of Ether measured in\n * units of Wei paid to execute the \"logical registrar action\".\n *\n * May be 0.\n */\n premium: PriceEth;\n\n /**\n * Total\n *\n * Total cost of Ether measured in units of Wei paid to execute\n * the \"logical registrar action\".\n *\n * May be 0.\n */\n total: PriceEth;\n}\n\n/**\n * Pricing information for a \"logical registrar action\" when\n * there is no known pricing data.\n */\nexport interface RegistrarActionPricingUnknown {\n /**\n * Base cost\n *\n * Base cost (before any `premium`) of Ether measured in units of Wei\n * paid to execute the \"logical registrar action\".\n */\n baseCost: null;\n\n /**\n * Premium\n *\n * \"premium\" cost (in excesses of the `baseCost`) of Ether measured in\n * units of Wei paid to execute the \"logical registrar action\".\n */\n premium: null;\n\n /**\n * Total\n *\n * Total cost of Ether measured in units of Wei paid to execute\n * the \"logical registrar action\".\n */\n total: null;\n}\n\nexport type RegistrarActionPricing =\n | RegistrarActionPricingAvailable\n | RegistrarActionPricingUnknown;\n\nexport function isRegistrarActionPricingAvailable(\n registrarActionPricing: RegistrarActionPricing,\n): registrarActionPricing is RegistrarActionPricingAvailable {\n const { baseCost, premium, total } = registrarActionPricing;\n\n return baseCost !== null && premium !== null && total !== null;\n}\n\n/**\n * * Referral information for performing a \"logical registrar action\".\n */\nexport interface RegistrarActionReferralAvailable {\n /**\n * Encoded Referrer\n *\n * Represents the \"raw\" 32-byte \"referrer\" value emitted onchain in\n * association with the registrar action.\n */\n encodedReferrer: EncodedReferrer;\n\n /**\n * Decoded Referrer\n *\n * The referrer address decoded from {@link encodedReferrer} using strict\n * left-zero-padding validation.\n *\n * Identifies the interpreted address of the referrer.\n * The \"chainId\" of this address is the same as is referenced in\n * `subregistryId`.\n *\n * May be the \"zero address\" to represent that an `encodedReferrer` is\n * defined but that it is interpreted as no referrer.\n */\n decodedReferrer: Address;\n}\n\n/**\n * Referral information for performing a \"logical registrar action\" when\n * registrar controller does not implement referrals.\n */\nexport interface RegistrarActionReferralNotApplicable {\n /**\n * Encoded Referrer\n *\n * Represents the \"raw\" 32-byte \"referrer\" value emitted onchain in\n * association with the registrar action.\n */\n encodedReferrer: null;\n\n /**\n * Decoded Referrer\n *\n * The referrer address decoded from {@link encodedReferrer} using strict\n * left-zero-padding validation. Null when the registrar controller does not implement referrals.\n */\n decodedReferrer: null;\n}\n\nexport type RegistrarActionReferral =\n | RegistrarActionReferralAvailable\n | RegistrarActionReferralNotApplicable;\n\nexport function isRegistrarActionReferralAvailable(\n registrarActionReferral: RegistrarActionReferral,\n): registrarActionReferral is RegistrarActionReferralAvailable {\n const { encodedReferrer, decodedReferrer } = registrarActionReferral;\n\n return encodedReferrer !== null && decodedReferrer !== null;\n}\n\n/**\n * \"Logical registrar action\"\n *\n * Represents a state of \"logical registrar action\". May be built using data\n * from multiple events within the same \"logical\" registration / renewal action.\n */\nexport interface RegistrarAction {\n /**\n * \"Logical registrar action\" ID\n *\n * The `id` value is a deterministic and globally unique identifier for\n * the \"logical registrar action\".\n *\n * The `id` value represents the *initial* onchain event associated with\n * the \"logical registrar action\", but the full state of\n * the \"logical registrar action\" is an aggregate across each of\n * the onchain events referenced in the `eventIds` field.\n *\n * Guaranteed to be the very first element in `eventIds` array.\n */\n id: RegistrarActionEventId;\n\n /**\n * The type of the \"logical registrar action\".\n */\n type: RegistrarActionType;\n\n /**\n *\n * Incremental Duration\n *\n * If `type` is \"registration\":\n * - Represents the duration between `block.timestamp` and\n * the initial `registrationLifecycle.expiresAt` value that the associated\n * \"registration lifecycle\" will be initialized with.\n * If `type` is \"renewal\":\n * - Represents the incremental increase in duration made to\n * the `registrationLifecycle.expiresAt` value in the associated\n * \"registration lifecycle\".\n *\n * A \"registration lifecycle\" may be extended via renewal even after it\n * expires if it is still within its grace period.\n *\n * Consider the following scenario:\n *\n * The \"registration lifecycle\" of a direct subname of .eth is scheduled to\n * expire on Jan 1, midnight UTC. It is currently 30 days after this\n * expiration time. Therefore, there are currently another 60 days of grace\n * period remaining for this name. Anyone can still make a renewal to\n * extend the \"registration lifecycle\" of this name.\n *\n * Given this scenario, consider the following examples:\n *\n * 1. If a renewal is made with 10 days incremental duration,\n * the \"registration lifecycle\" for this name will remain in\n * an \"expired\" state, but it will now have another 70 days of\n * grace period remaining.\n *\n * 2. If a renewal is made with 50 days incremental duration,\n * the \"registration lifecycle\" for this name will no longer be\n * \"expired\" and will become \"active\", but the \"registration lifecycle\"\n * will now be scheduled to expire again in 20 days.\n *\n * After the \"registration lifecycle\" for a name becomes expired by more\n * than its grace period, it can no longer be renewed by anyone and is\n * considered \"released\". The name must first be registered again, starting\n * a new \"registration lifecycle\" of\n * active / expired / grace period / released.\n *\n * May be 0.\n *\n * Guaranteed to be a non-negative bigint value.\n */\n incrementalDuration: Duration;\n\n /**\n * Registrant\n *\n * Identifies the address that initiated the \"logical registrar action\" and\n * is paying the `pricing.total` cost (if applicable).\n *\n * It may not be the owner of the name:\n * 1. When a name is registered, the initial owner of the name may be\n * distinct from the registrant.\n * 2. There are no restrictions on who may renew a name.\n * Therefore the owner of the name may be distinct from the registrant.\n *\n * The \"chainId\" of this address is the same as is referenced in\n * `registrationLifecycle.subregistry.subregistryId`.\n */\n registrant: Address;\n\n /**\n * Registration Lifecycle associated with this \"logical registrar action\".\n */\n registrationLifecycle: RegistrationLifecycle;\n\n /**\n * Pricing information associated with this \"logical registrar action\".\n */\n pricing: RegistrarActionPricing;\n\n /**\n * Referral information associated with this \"logical registrar action\".\n */\n referral: RegistrarActionReferral;\n\n /**\n * Block ref\n *\n * References the block where the \"logical registrar action\" was executed.\n *\n * The \"chainId\" of this block is the same as is referenced in\n * `registrationLifecycle.subregistry.subregistryId`.\n */\n block: BlockRef;\n\n /**\n * Transaction hash\n *\n * Transaction hash of the transaction associated with\n * the \"logical registrar action\".\n *\n * The \"chainId\" of this transaction is the same as is referenced in\n * `registrationLifecycle.subregistry.subregistryId`.\n *\n * Note that a single transaction may be associated with any number of\n * \"logical registrar actions\".\n */\n transactionHash: Hash;\n\n /**\n * Event IDs\n *\n * Array of the eventIds that have contributed to the state of\n * the \"logical registrar action\" record.\n *\n * Each eventId is a deterministic and globally unique onchain event\n * identifier.\n *\n * Guarantees:\n * - Each eventId is of events that occurred within the block\n * referenced by `block.number`.\n * - At least 1 eventId.\n * - Ordered chronologically (ascending) by logIndex within `block.number`.\n * - The first element in the array is equal to the `id` of\n * the overall \"logical registrar action\" record.\n *\n * The following ideas are not generalized for ENS overall but happen to\n * be a characteristic of the scope of our current indexing logic:\n * 1. These id's always reference events emitted by\n * a related \"BaseRegistrar\" contract.\n * 2. These id's optionally reference events emitted by\n * a related \"Registrar Controller\" contract. This is because our\n * current indexing logic doesn't guarantee to index\n * all \"Registrar Controller\" contracts.\n */\n eventIds: [RegistrarActionEventId, ...RegistrarActionEventId[]];\n}\n\n/**\n * Serialized representation of {@link RegistrarActionPricingUnknown}.\n */\nexport type SerializedRegistrarActionPricingUnknown = RegistrarActionPricingUnknown;\n\n/**\n * Serialized representation of {@link RegistrarActionPricingAvailable}.\n */\nexport interface SerializedRegistrarActionPricingAvailable {\n baseCost: SerializedPriceEth;\n\n premium: SerializedPriceEth;\n\n total: SerializedPriceEth;\n}\n\n/**\n * Serialized representation of {@link RegistrarActionPricing}.\n */\nexport type SerializedRegistrarActionPricing =\n | SerializedRegistrarActionPricingAvailable\n | SerializedRegistrarActionPricingUnknown;\n\n/**\n * Serialized representation of {@link RegistrarAction}.\n */\nexport interface SerializedRegistrarAction extends Omit<RegistrarAction, \"pricing\"> {\n pricing: SerializedRegistrarActionPricing;\n}\n\nexport function serializeRegistrarActionPricing(\n pricing: RegistrarActionPricing,\n): SerializedRegistrarActionPricing {\n if (isRegistrarActionPricingAvailable(pricing)) {\n return {\n baseCost: serializePriceEth(pricing.baseCost),\n premium: serializePriceEth(pricing.premium),\n total: serializePriceEth(pricing.total),\n } satisfies SerializedRegistrarActionPricingAvailable;\n }\n\n return pricing satisfies SerializedRegistrarActionPricingUnknown;\n}\n\nexport function serializeRegistrarAction(\n registrarAction: RegistrarAction,\n): SerializedRegistrarAction {\n return {\n id: registrarAction.id,\n type: registrarAction.type,\n incrementalDuration: registrarAction.incrementalDuration,\n registrant: registrarAction.registrant,\n registrationLifecycle: registrarAction.registrationLifecycle,\n pricing: serializeRegistrarActionPricing(registrarAction.pricing),\n referral: registrarAction.referral,\n block: registrarAction.block,\n transactionHash: registrarAction.transactionHash,\n eventIds: registrarAction.eventIds,\n };\n}\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport {\n makeNonNegativeIntegerSchema,\n makePositiveIntegerSchema,\n} from \"../../../../shared/zod-schemas\";\nimport { RECORDS_PER_PAGE_MAX, RequestPageParams } from \"./request\";\nimport {\n ResponsePageContext,\n ResponsePageContextWithNoRecords,\n type ResponsePageContextWithRecords,\n} from \"./response\";\n\n/**\n * Schema for {@link RequestPageParams}\n */\nexport const makeRequestPageParamsSchema = (valueLabel: string = \"RequestPageParams\") =>\n z.object({\n page: makePositiveIntegerSchema(`${valueLabel}.page`),\n recordsPerPage: makePositiveIntegerSchema(`${valueLabel}.recordsPerPage`).max(\n RECORDS_PER_PAGE_MAX,\n `${valueLabel}.recordsPerPage must not exceed ${RECORDS_PER_PAGE_MAX}`,\n ),\n });\n\n/**\n * Schema for {@link ResponsePageContextWithNoRecords}\n */\nexport const makeResponsePageContextSchemaWithNoRecords = (\n valueLabel: string = \"ResponsePageContextWithNoRecords\",\n) =>\n z\n .object({\n totalRecords: z.literal(0),\n totalPages: z.literal(1),\n hasNext: z.literal(false),\n hasPrev: z.literal(false),\n })\n .extend(makeRequestPageParamsSchema(valueLabel).shape);\n\nfunction invariant_responsePageWithRecordsIsCorrect(\n ctx: ParsePayload<ResponsePageContextWithRecords>,\n) {\n const { hasNext, hasPrev, recordsPerPage, page, totalRecords, startIndex, endIndex } = ctx.value;\n\n const expectedHasNext = page * recordsPerPage < totalRecords;\n if (hasNext !== expectedHasNext) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `hasNext must be equal to '${expectedHasNext ? \"true\" : \"false\"}'`,\n });\n }\n\n const expectedHasPrev = page > 1;\n if (hasPrev !== expectedHasPrev) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `hasPrev must be equal to '${expectedHasPrev ? \"true\" : \"false\"}'`,\n });\n }\n\n if (endIndex < startIndex) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `endIndex must be greater than or equal to startIndex`,\n });\n }\n\n if (endIndex >= totalRecords) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `endIndex must be lower than totalRecords`,\n });\n }\n}\n\n/**\n * Schema for {@link ResponsePageContextWithRecords}\n */\nexport const makeResponsePageContextSchemaWithRecords = (\n valueLabel: string = \"ResponsePageContextWithRecords\",\n) =>\n z\n .object({\n totalRecords: makePositiveIntegerSchema(`${valueLabel}.totalRecords`),\n totalPages: makePositiveIntegerSchema(`${valueLabel}.totalPages`),\n hasNext: z.boolean(),\n hasPrev: z.boolean(),\n startIndex: makeNonNegativeIntegerSchema(`${valueLabel}.startIndex`),\n endIndex: makeNonNegativeIntegerSchema(`${valueLabel}.endIndex`),\n })\n .extend(makeRequestPageParamsSchema(valueLabel).shape)\n .check(invariant_responsePageWithRecordsIsCorrect);\n\n/**\n * Schema for {@link ResponsePageContext}\n */\nexport const makeResponsePageContextSchema = (valueLabel: string = \"ResponsePageContext\") =>\n z.union([\n makeResponsePageContextSchemaWithNoRecords(valueLabel),\n makeResponsePageContextSchemaWithRecords(valueLabel),\n ]);\n","export const RECORDS_PER_PAGE_DEFAULT = 10;\n\nexport const RECORDS_PER_PAGE_MAX = 100;\n\n/**\n * Request page params.\n */\nexport interface RequestPageParams {\n /**\n * Requested page number (1-indexed)\n * @invariant Must be a positive integer (>= 1)\n * @default 1\n */\n page?: number;\n\n /**\n * Maximum number of records to return per page\n * @invariant Must be a positive integer (>= 1) and less than or equal to {@link RECORDS_PER_PAGE_MAX}\n * @default {@link RECORDS_PER_PAGE_DEFAULT}\n */\n recordsPerPage?: number;\n}\n","import type { InterpretedName, UnixTimestamp } from \"enssdk\";\n\nimport type { RegistrarAction } from \"../../../registrars/registrar-action\";\nimport type { IndexingStatusResponseCodes } from \"../indexing-status/response\";\nimport type { ErrorResponse } from \"../shared/errors\";\nimport type { ResponsePageContext } from \"../shared/pagination\";\n\n/**\n * A status code for Registrar Actions API responses.\n */\nexport const RegistrarActionsResponseCodes = {\n /**\n * Represents that Registrar Actions are available.\n */\n Ok: \"ok\",\n\n /**\n * Represents that Registrar Actions are unavailable.\n */\n Error: \"error\",\n} as const;\n\n/**\n * The derived string union of possible {@link RegistrarActionsResponseCodes}.\n */\nexport type RegistrarActionsResponseCode =\n (typeof RegistrarActionsResponseCodes)[keyof typeof RegistrarActionsResponseCodes];\n\n/**\n * \"Logical registrar action\" with its associated name.\n */\nexport interface NamedRegistrarAction {\n action: RegistrarAction;\n\n /**\n * Name\n *\n * FQDN of the name associated with `action`.\n *\n * Guarantees:\n * - `namehash(name)` is always `action.registrationLifecycle.node`.\n */\n name: InterpretedName;\n}\n\n/**\n * A response when Registrar Actions are available.\n */\nexport type RegistrarActionsResponseOk = {\n responseCode: typeof RegistrarActionsResponseCodes.Ok;\n registrarActions: NamedRegistrarAction[];\n pageContext: ResponsePageContext;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the list of {@link NamedRegistrarAction} was accurate as of.\n *\n * @remarks\n * **Note:** This value represents the `omnichainIndexingCursor` from the latest omnichain indexing status\n * snapshot captured by ENSApi. The state returned in the response is guaranteed to be accurate as of this\n * timestamp but may be from a timestamp higher than this value.\n */\n accurateAsOf: UnixTimestamp;\n};\n\n/**\n * A response when Registrar Actions are unavailable.\n */\nexport interface RegistrarActionsResponseError {\n responseCode: typeof IndexingStatusResponseCodes.Error;\n error: ErrorResponse;\n}\n\n/**\n * Registrar Actions response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type RegistrarActionsResponse = RegistrarActionsResponseOk | RegistrarActionsResponseError;\n","import type { ResolverRecordsSelection } from \"../../../resolution\";\nimport type {\n ResolvePrimaryNameResponse,\n ResolvePrimaryNamesResponse,\n ResolveRecordsResponse,\n} from \"./types\";\n\n/**\n * Example values for {@link ResolveRecordsResponse}, for use in OpenAPI documentation.\n */\nexport const resolveRecordsResponseExample = {\n records: {\n addresses: { \"60\": \"0xd8da6bf26964af9d7eed9e03e53415d37aa96045\" },\n texts: {\n description: \"mi pinxe lo crino tcati\",\n },\n },\n accelerationRequested: false,\n accelerationAttempted: false,\n} satisfies ResolveRecordsResponse<ResolverRecordsSelection>;\n\n/**\n * Example values for {@link ResolvePrimaryNameResponse}, for use in OpenAPI documentation.\n */\nexport const resolvePrimaryNameResponseExample = {\n name: \"jesse.base.eth\",\n accelerationRequested: false,\n accelerationAttempted: false,\n} satisfies ResolvePrimaryNameResponse;\n\n/**\n * Example values for {@link ResolvePrimaryNamesResponse}, for use in OpenAPI documentation.\n */\nexport const resolvePrimaryNamesResponseExample = {\n names: {\n \"1\": \"jesse.base.eth\",\n \"10\": null,\n \"8453\": \"jesse.base.eth\",\n \"42161\": null,\n \"59144\": null,\n \"534352\": null,\n },\n accelerationRequested: false,\n accelerationAttempted: false,\n} satisfies ResolvePrimaryNamesResponse;\n","import { z } from \"zod/v4\";\n\n/**\n * Schema for resolver records response.\n *\n * NOTE: `version` and `abi.contentType` arrive over the wire as strings (server serializes\n * bigints via `replaceBigInts(response, String)` to avoid `JSON.stringify` throwing on bigint).\n * Callers that need these as `bigint` should `BigInt(...)` them.\n */\nconst makeResolverRecordsResponseSchema = () =>\n z.object({\n name: z.string().nullable().optional(),\n addresses: z.record(z.string(), z.string().nullable()).optional(),\n texts: z.record(z.string(), z.string().nullable()).optional(),\n contenthash: z.string().nullable().optional(),\n pubkey: z.object({ x: z.string(), y: z.string() }).nullable().optional(),\n dnszonehash: z.string().nullable().optional(),\n version: z.string().nullable().optional(),\n abi: z.object({ contentType: z.string(), data: z.string() }).nullable().optional(),\n interfaces: z.record(z.string(), z.string().nullable()).optional(),\n });\n\n/**\n * Schema for {@link ResolveRecordsResponse}\n */\nexport const makeResolveRecordsResponseSchema = () =>\n z.object({\n records: makeResolverRecordsResponseSchema(),\n accelerationRequested: z.boolean(),\n accelerationAttempted: z.boolean(),\n // TODO: Find a better way to handle recursive types, patch solution is .unknown()\n trace: z.array(z.unknown()).optional(),\n });\n\n/**\n * Schema for {@link ResolvePrimaryNameResponse}\n */\nexport const makeResolvePrimaryNameResponseSchema = () =>\n z.object({\n name: z.string().nullable(),\n accelerationRequested: z.boolean(),\n accelerationAttempted: z.boolean(),\n trace: z.array(z.unknown()).optional(),\n });\n\n/**\n * Schema for {@link ResolvePrimaryNamesResponse}\n */\nexport const makeResolvePrimaryNamesResponseSchema = () =>\n z.object({\n names: z.record(z.number(), z.string().nullable()),\n accelerationRequested: z.boolean(),\n accelerationAttempted: z.boolean(),\n trace: z.array(z.unknown()).optional(),\n });\n","import type { ErrorResponse } from \"./response\";\n\n/**\n * Example value for {@link ErrorResponse} representing a 400 Bad Request, for use in OpenAPI documentation.\n */\nexport const errorResponseBadRequestExample = {\n message: \"Invalid Input\",\n} satisfies ErrorResponse;\n\n/**\n * Example value for {@link ErrorResponse} representing a 400 Bad Request for an invalid ENS name,\n * for use in OpenAPI documentation.\n */\nexport const errorResponseInvalidNameExample = {\n message: \"Invalid Input\",\n details: {\n errors: [],\n properties: {\n name: { errors: [\"Must be normalized, see https://docs.ens.domains/resolution/names/\"] },\n },\n },\n} satisfies ErrorResponse;\n\n/**\n * Example value for {@link ErrorResponse} representing a 400 Bad Request for an invalid address,\n * for use in OpenAPI documentation.\n */\nexport const errorResponseInvalidAddressExample = {\n message: \"Invalid Input\",\n details: {\n errors: [],\n properties: { address: { errors: [\"EVM address must be a valid EVM address\"] } },\n },\n} satisfies ErrorResponse;\n\n/**\n * Example value for {@link ErrorResponse} representing a 500 Internal Server Error, for use in OpenAPI documentation.\n */\nexport const errorResponseInternalServerErrorExample = {\n message: \"Internal Server Error\",\n} satisfies ErrorResponse;\n","import { asInterpretedName, toNormalizedAddress } from \"enssdk\";\n\nimport { DatasourceNames, ENSNamespaceIds } from \"@ensnode/datasources\";\nimport { accounts } from \"@ensnode/datasources/devnet\";\n\nimport { maybeGetDatasourceContract } from \"../shared/datasource-contract\";\nimport type { NamespaceSpecificValue } from \"../shared/namespace-specific-value\";\n\nconst SEPOLIA_V2_V2_ETH_REGISTRY = maybeGetDatasourceContract(\n ENSNamespaceIds.SepoliaV2,\n DatasourceNames.ENSv2Root,\n \"ETHRegistry\",\n);\n\nconst SEPOLIA_V2_V2_ETH_REGISTRAR = maybeGetDatasourceContract(\n ENSNamespaceIds.SepoliaV2,\n DatasourceNames.ENSv2Root,\n \"ETHRegistrar\",\n);\n\nconst ENS_TEST_ENV_V2_ETH_REGISTRY = maybeGetDatasourceContract(\n ENSNamespaceIds.EnsTestEnv,\n DatasourceNames.ENSv2Root,\n \"ETHRegistry\",\n);\n\nconst ENS_TEST_ENV_V2_ETH_REGISTRAR = maybeGetDatasourceContract(\n ENSNamespaceIds.EnsTestEnv,\n DatasourceNames.ENSv2Root,\n \"ETHRegistrar\",\n);\n\nconst VITALIK_ADDRESS = toNormalizedAddress(\"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\");\n\n// owns sfmonicdeb*.eth (mix of v1 + v2) on sepolia-v2 and holds v2 ETHRegistry permissions\nconst _SEPOLIA_V2_USER_ADDRESS = toNormalizedAddress(\"0x2f8e8b1126e75fde0b7f731e7cb5847eba2d2574\");\n\nconst SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES = toNormalizedAddress(\n \"0x205d2686da3bf33f64c17f21462c51b5ead462cf\",\n);\n\nconst DEVNET_NAME_WITH_OWNED_RESOLVER = asInterpretedName(\"example.eth\");\n\nconst SEPOLIA_V2_NAME_WITH_OWNED_RESOLVER = asInterpretedName(\"sfmonicdebmig.eth\");\n\nconst SEPOLIA_V2_TEST_NAME = asInterpretedName(\"test-name.eth\");\n\nexport type GraphqlApiExampleQuery = {\n id: string;\n query: string;\n variables: NamespaceSpecificValue<Record<string, unknown>>;\n};\n\nexport function getGraphqlApiExampleQueryById(id: string): GraphqlApiExampleQuery {\n const found = graphqlApiExampleQueryById.get(id);\n if (!found) {\n throw new Error(`Unknown GraphQL API example query id: ${id}`);\n }\n return found;\n}\n\nexport const GRAPHQL_API_EXAMPLE_QUERIES: GraphqlApiExampleQuery[] = [\n ////////////////\n // Hello World\n ////////////////\n {\n id: \"hello-world\",\n query: `#\n# Welcome to this interactive playground for\n# ENSNode's GraphQL API!\n#\n# You can get started by typing your query here or by using\n# the Explorer on the left to select the data you want to query.\n#\n# There are also example queries in the tabs above ☝️\nquery HelloWorld {\n domain(by: { name: \"eth\" }) { canonical { name { interpreted } } owner { address } }\n}`,\n variables: { default: {} },\n },\n\n /////////////////\n // Find Domains\n /////////////////\n {\n id: \"find-domains\",\n query: `\nquery FindDomains(\n $name: DomainsNameFilter!\n $order: DomainsOrderInput\n) {\n domains(\n where: { name: $name }\n order: $order\n first: 20\n ) {\n edges {\n node {\n __typename\n id\n label { interpreted hash }\n canonical { name { interpreted } }\n\n registration { expiry event { timestamp } }\n }\n }\n }\n}`,\n variables: {\n default: { name: { starts_with: \"vitalik\" }, order: { by: \"NAME\", dir: \"DESC\" } },\n [ENSNamespaceIds.EnsTestEnv]: {\n name: { starts_with: \"c\" },\n order: { by: \"NAME\", dir: \"DESC\" },\n },\n [ENSNamespaceIds.SepoliaV2]: {\n name: { starts_with: \"test-na\" },\n order: { by: \"NAME\", dir: \"DESC\" },\n },\n },\n },\n\n ///////////////////\n // Domain By Name\n ///////////////////\n {\n id: \"domain-by-name\",\n query: `\nquery DomainByName($name: InterpretedName!) {\n domain(by: {name: $name}) {\n __typename\n id\n label { interpreted hash }\n canonical { name { interpreted } node path { id } }\n owner { address }\n subregistry { contract { chainId address } }\n\n ... on ENSv1Domain {\n rootRegistryOwner { address }\n }\n }\n}`,\n variables: {\n default: { name: \"eth\" },\n [ENSNamespaceIds.SepoliaV2]: { name: SEPOLIA_V2_TEST_NAME },\n },\n },\n\n //////////////////////\n // Domain Subdomains\n //////////////////////\n {\n id: \"domain-subdomains\",\n query: `\nquery DomainSubdomains($name: InterpretedName!) {\n domain(by: {name: $name}) {\n canonical { name { interpreted } }\n subdomains(first: 10) {\n edges {\n node {\n canonical { name { interpreted } }\n }\n }\n }\n }\n}`,\n variables: { default: { name: \"eth\" } },\n },\n\n /////////////////\n // Domain Events\n /////////////////\n {\n id: \"domain-events\",\n query: `\nquery DomainEvents($name: InterpretedName!) {\n domain(by: {name: $name}) {\n events {\n totalCount\n edges {\n node {\n from\n to\n topics\n data\n timestamp\n transactionHash\n }\n }\n }\n }\n}`,\n variables: {\n default: { name: \"newowner.eth\" },\n [ENSNamespaceIds.SepoliaV2]: { name: \"sfmonicdebmig.eth\" },\n },\n },\n\n ////////////////////\n // Account Domains\n ////////////////////\n {\n id: \"domains-by-address\",\n query: `\nquery AccountDomains(\n $address: Address!\n) {\n account(by: { address: $address }) {\n domains {\n edges {\n node {\n label { interpreted }\n canonical { name { interpreted } }\n }\n }\n }\n }\n}`,\n variables: {\n default: { address: VITALIK_ADDRESS },\n [ENSNamespaceIds.EnsTestEnv]: { address: accounts.owner.address },\n [ENSNamespaceIds.SepoliaV2]: { address: SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES },\n },\n },\n\n ////////////////////\n // Account Events\n ////////////////////\n {\n id: \"account-events\",\n query: `\nquery AccountEvents(\n $address: Address!\n) {\n account(by: { address: $address }) {\n events { totalCount edges { node { topics data timestamp } } }\n }\n}`,\n variables: {\n default: { address: VITALIK_ADDRESS },\n [ENSNamespaceIds.EnsTestEnv]: { address: accounts.deployer.address },\n [ENSNamespaceIds.SepoliaV2]: { address: SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES },\n },\n },\n\n /////////////////////\n // Registry Domains\n /////////////////////\n {\n id: \"registry-domains\",\n query: `\nquery RegistryDomains(\n $registry: AccountIdInput!\n) {\n registry(by: { contract: $registry }) {\n domains {\n edges {\n node {\n label { interpreted }\n canonical { name { interpreted } }\n }\n }\n }\n }\n}`,\n variables: {\n // TODO: this only accesses v2 registries, so we default to ens-test-env for now\n default: { registry: ENS_TEST_ENV_V2_ETH_REGISTRY },\n [ENSNamespaceIds.SepoliaV2]: { registry: SEPOLIA_V2_V2_ETH_REGISTRY },\n },\n },\n\n ////////////////////////////\n // Permissions By Contract\n ////////////////////////////\n {\n id: \"permissions-by-contract\",\n query: `\nquery PermissionsByContract(\n $contract: AccountIdInput!\n) {\n permissions(by: { contract: $contract }) {\n resources {\n edges {\n node {\n resource\n users {\n edges {\n node {\n id\n user { address }\n roles\n }\n }\n }\n }\n }\n }\n events { totalCount edges { node { topics data timestamp } } }\n }\n}`,\n variables: {\n // TODO: same as above\n default: { contract: ENS_TEST_ENV_V2_ETH_REGISTRAR },\n // TODO: example response is empty for this address on Sepolia V2\n [ENSNamespaceIds.SepoliaV2]: { contract: SEPOLIA_V2_V2_ETH_REGISTRAR },\n },\n },\n\n ////////////////////////\n // Permissions By User\n ////////////////////////\n {\n id: \"permissions-by-user\",\n query: `\nquery PermissionsByUser($address: Address!) {\n account(by: { address: $address }) {\n permissions {\n edges {\n node {\n resource\n roles\n }\n }\n }\n }\n}`,\n variables: {\n default: { address: accounts.deployer.address },\n // TODO: example response is empty for this address on Sepolia V2\n [ENSNamespaceIds.SepoliaV2]: { address: SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES },\n },\n },\n\n //////////////////////////////////\n // Account Resolver Permissions\n //////////////////////////////////\n {\n id: \"account-resolver-permissions\",\n query: `\nquery AccountResolverPermissions($address: Address!) {\n account(by: { address: $address }) {\n resolverPermissions {\n edges {\n node {\n resolver {\n contract {\n address\n }\n }\n }\n }\n }\n }\n}`,\n variables: {\n default: { address: accounts.deployer.address },\n [ENSNamespaceIds.SepoliaV2]: { address: SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES },\n },\n },\n\n //////////////////////////////\n // Domain's Assigned Resolver\n //////////////////////////////\n {\n id: \"domain-resolver\",\n query: `\nquery DomainResolver($name: InterpretedName!) {\n domain(by: { name: $name }) {\n resolver {\n assigned {\n records { edges { node { node keys coinTypes } } }\n permissions { resources { edges { node { resource users { edges { node { user { address } roles } } } } } } }\n events { totalCount edges { node { topics data timestamp } } }\n }\n }\n }\n}`,\n variables: {\n default: { name: \"vitalik.eth\" },\n [ENSNamespaceIds.EnsTestEnv]: { name: DEVNET_NAME_WITH_OWNED_RESOLVER },\n [ENSNamespaceIds.SepoliaV2]: { name: SEPOLIA_V2_NAME_WITH_OWNED_RESOLVER },\n },\n },\n\n //////////////\n // Namegraph\n //////////////\n {\n id: \"namegraph\",\n query: `\nquery Namegraph {\n root {\n id\n domains {\n edges {\n node {\n canonical { name { interpreted } }\n\n subdomains {\n edges {\n node {\n canonical { name { interpreted } }\n\n subdomains {\n edges {\n node {\n canonical { name { interpreted } }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n}`,\n variables: { default: {} },\n },\n];\n\nconst graphqlApiExampleQueryById = new Map(\n GRAPHQL_API_EXAMPLE_QUERIES.map((entry) => [entry.id, entry]),\n);\n","import type { Address, InterfaceId } from \"enssdk\";\n\n/**\n * EIP-165 ABI\n * @see https://eips.ethereum.org/EIPS/eip-165\n */\nconst EIP_165_ABI = [\n {\n inputs: [\n {\n internalType: \"bytes4\",\n name: \"interfaceID\",\n type: \"bytes4\",\n },\n ],\n name: \"supportsInterface\",\n outputs: [\n {\n internalType: \"bool\",\n name: \"\",\n type: \"bool\",\n },\n ],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/**\n * Determines whether a Contract at `address` supports a specific EIP-165 `interfaceId`.\n *\n * Accepts both viem PublicClient and Ponder Context client types.\n */\nasync function supportsInterface<\n TClient extends {\n readContract: (params: {\n abi: typeof EIP_165_ABI;\n functionName: \"supportsInterface\";\n address: Address;\n args: readonly [InterfaceId];\n }) => Promise<boolean>;\n },\n>({\n publicClient,\n interfaceId: selector,\n address,\n}: {\n address: Address;\n interfaceId: InterfaceId;\n publicClient: TClient;\n}) {\n try {\n return await publicClient.readContract({\n abi: EIP_165_ABI,\n functionName: \"supportsInterface\",\n address,\n args: [selector],\n });\n } catch {\n // this call reverted for whatever reason — this contract does not support the interface\n return false;\n }\n}\n\nexport const makeSupportsInterfaceReader =\n (interfaceId: InterfaceId) =>\n (args: Omit<Parameters<typeof supportsInterface>[0], \"interfaceId\">) =>\n supportsInterface({\n ...args,\n interfaceId,\n });\n","import { makeSupportsInterfaceReader } from \"./eip-165\";\n\n/**\n * ENSIP-10 Wildcard Resolution Interface Id\n * @see https://docs.ens.domains/ensip/10\n */\nconst IExtendedResolverInterfaceId = \"0x9061b923\";\n\n/**\n * Determines whether a Resolver contract supports ENSIP-10.\n */\nexport const isExtendedResolver = makeSupportsInterfaceReader(IExtendedResolverInterfaceId);\n","import type { ChainId } from \"enssdk\";\nimport {\n arbitrum,\n arbitrumSepolia,\n base,\n baseSepolia,\n linea,\n lineaSepolia,\n mainnet,\n optimism,\n optimismSepolia,\n scroll,\n scrollSepolia,\n sepolia,\n} from \"viem/chains\";\n\n/**\n * Builds a Alchemy RPC base URL for the specified chain ID.\n *\n * @param chainId - The chain ID to build the RPC base URL for\n * @param key - The Alchemy API key\n * @returns The Alchemy RPC base URL, or undefined if the chain is not supported\n *\n * @example\n * ```typescript\n * const url = buildAlchemyUrl(1, \"your-api-key\");\n * // Returns: \"eth-mainnet.g.alchemy.com/v2/your-api-key\"\n * ```\n */\nexport function buildAlchemyBaseUrl(chainId: ChainId, key: string): string | undefined {\n switch (chainId) {\n case mainnet.id:\n return `eth-mainnet.g.alchemy.com/v2/${key}`;\n case sepolia.id:\n return `eth-sepolia.g.alchemy.com/v2/${key}`;\n case arbitrum.id:\n return `arb-mainnet.g.alchemy.com/v2/${key}`;\n case arbitrumSepolia.id:\n return `arb-sepolia.g.alchemy.com/v2/${key}`;\n case base.id:\n return `base-mainnet.g.alchemy.com/v2/${key}`;\n case baseSepolia.id:\n return `base-sepolia.g.alchemy.com/v2/${key}`;\n case optimism.id:\n return `opt-mainnet.g.alchemy.com/v2/${key}`;\n case optimismSepolia.id:\n return `opt-sepolia.g.alchemy.com/v2/${key}`;\n case linea.id:\n return `linea-mainnet.g.alchemy.com/v2/${key}`;\n case lineaSepolia.id:\n return `linea-sepolia.g.alchemy.com/v2/${key}`;\n case scroll.id:\n return `scroll-mainnet.g.alchemy.com/v2/${key}`;\n case scrollSepolia.id:\n return `scroll-sepolia.g.alchemy.com/v2/${key}`;\n default:\n return undefined;\n }\n}\n\n/**\n * Builds a dRPC RPC URL for the specified chain ID.\n *\n * @param chainId - The chain ID to build the RPC URL for\n * @param key - The dRPC API key\n * @returns The complete dRPC RPC URL, or undefined if the chain is not supported\n *\n * @example\n * ```typescript\n * const url = buildDRPCUrl(1, \"your-api-key\");\n * // Returns: \"https://lb.drpc.live/ethereum/your-api-key\"\n * ```\n */\nexport function buildDRPCUrl(chainId: ChainId, key: string): string | undefined {\n switch (chainId) {\n case mainnet.id:\n return `https://lb.drpc.live/ethereum/${key}`;\n case sepolia.id:\n return `https://lb.drpc.live/ethereum-sepolia/${key}`;\n case arbitrum.id:\n return `https://lb.drpc.live/arbitrum/${key}`;\n case arbitrumSepolia.id:\n return `https://lb.drpc.live/arbitrum-sepolia/${key}`;\n case base.id:\n return `https://lb.drpc.live/base/${key}`;\n case baseSepolia.id:\n return `https://lb.drpc.live/base-sepolia/${key}`;\n case optimism.id:\n return `https://lb.drpc.live/optimism/${key}`;\n case optimismSepolia.id:\n return `https://lb.drpc.live/optimism-sepolia/${key}`;\n case linea.id:\n return `https://lb.drpc.live/linea/${key}`;\n case lineaSepolia.id:\n return `https://lb.drpc.live/linea-sepolia/${key}`;\n case scroll.id:\n return `https://lb.drpc.live/scroll/${key}`;\n case scrollSepolia.id:\n return `https://lb.drpc.live/scroll-sepolia/${key}`;\n default:\n return undefined;\n }\n}\n\n/**\n * Builds a QuickNode RPC base URL for the specified chain ID.\n *\n * @param chainId - The chain ID to build the RPC base URL for\n * @param apiKey - The QuickNode API key\n * @param endpointName - The QuickNode Endpoint name\n * @returns The QuickNode RPC base URL, or undefined if the chain is not supported\n *\n * NOTE:\n * - Only multi-chain QuickNode endpoints are supported.\n * https://www.quicknode.com/guides/quicknode-products/how-to-use-multichain-endpoint\n * - QuickNode platform does not support Linea Sepolia RPC (as of 2025-12-03).\n * https://www.quicknode.com/docs/linea\n *\n * @example\n * ```typescript\n * const url = buildQuickNodeURL(1, \"your-api-key\", \"your-endpoint-name\");\n * // Returns: \"your-endpoint-name.quiknode.pro/your-api-key\"\n * ```\n */\nexport function buildQuickNodeURL(\n chainId: ChainId,\n apiKey: string,\n endpointName: string,\n): string | undefined {\n switch (chainId) {\n case mainnet.id:\n return `${endpointName}.quiknode.pro/${apiKey}`;\n case sepolia.id:\n return `${endpointName}.ethereum-sepolia.quiknode.pro/${apiKey}`;\n case arbitrum.id:\n return `${endpointName}.arbitrum-mainnet.quiknode.pro/${apiKey}`;\n case arbitrumSepolia.id:\n return `${endpointName}.arbitrum-sepolia.quiknode.pro/${apiKey}`;\n case base.id:\n return `${endpointName}.base-mainnet.quiknode.pro/${apiKey}`;\n case baseSepolia.id:\n return `${endpointName}.base-sepolia.quiknode.pro/${apiKey}`;\n case optimism.id:\n return `${endpointName}.optimism.quiknode.pro/${apiKey}`;\n case optimismSepolia.id:\n return `${endpointName}.optimism-sepolia.quiknode.pro/${apiKey}`;\n case linea.id:\n return `${endpointName}.linea-mainnet.quiknode.pro/${apiKey}`;\n case lineaSepolia.id:\n return undefined;\n case scroll.id:\n return `${endpointName}.scroll-mainnet.quiknode.pro/${apiKey}`;\n case scrollSepolia.id:\n return `${endpointName}.scroll-testnet.quiknode.pro/${apiKey}`;\n default:\n return undefined;\n }\n}\n\nexport function alchemySupportsChain(chainId: ChainId) {\n return buildAlchemyBaseUrl(chainId, \"\") !== undefined;\n}\n\nexport function dRPCSupportsChain(chainId: ChainId) {\n return buildDRPCUrl(chainId, \"\") !== undefined;\n}\n\nexport function quickNodeSupportsChain(chainId: ChainId) {\n return buildQuickNodeURL(chainId, \"\", \"\") !== undefined;\n}\n","/**\n * A replacer function to be used with `JSON.stringify` for configuration objects.\n *\n * It handles common patterns like:\n * - Stringifying URL objects\n * - Truncating large ABI objects\n * - Converting Map objects to plain objects for serialization\n */\nfunction configJSONReplacer(key: string, value: unknown): unknown {\n // stringify a URL object\n if (value instanceof URL) return value.href;\n\n // truncate ABI value\n if (key === \"abi\") return \"(truncated ABI output)\";\n\n // convert Map to plain object for serialization\n if (value instanceof Map) return Object.fromEntries(value);\n\n // convert Set to array for serialization\n if (value instanceof Set) return Array.from(value);\n\n // pass-through value\n return value;\n}\n\n/**\n * Stringify a config object.\n *\n * @param json The config object to print\n * @param options.pretty Whether to pretty print the JSON output. Defaults to false (minified).\n * @returns The JSON string representation of the config object\n */\nexport const stringifyConfig = (json: any, options: { pretty: boolean } = { pretty: false }) =>\n JSON.stringify(json, configJSONReplacer, options.pretty ? 2 : undefined);\n","/**\n * Generic utilities for redacting sensitive information from configuration objects.\n */\n\nimport type { RpcConfig, RpcConfigs } from \"./types\";\n\n/**\n * Default redacted value placeholder.\n */\nconst REDACTED = \"*****\";\n\n/**\n * Generic function to redact URL objects by replacing the path with a redacted placeholder.\n */\nexport function redactUrl(url: URL): URL {\n return new URL(`/${REDACTED}`, url.origin);\n}\n\n/**\n * Generic function to redact strings by replacing them with a redacted placeholder.\n */\nexport function redactString(_: string): string {\n return REDACTED;\n}\n\n/**\n * Redact RPC configs by replacing URLs with redacted values.\n */\nexport function redactRpcConfigs(rpcConfigs: RpcConfigs): RpcConfigs {\n const redactedRpcConfigs = new Map<number, RpcConfig>();\n\n for (const [chainId, rpcConfig] of rpcConfigs.entries()) {\n const redactedHttpRPCs = rpcConfig.httpRPCs.map(redactUrl) as [URL, ...URL[]];\n const redactedWebsocketRPC = rpcConfig.websocketRPC\n ? redactUrl(rpcConfig.websocketRPC)\n : undefined;\n\n redactedRpcConfigs.set(chainId, {\n httpRPCs: redactedHttpRPCs,\n websocketRPC: redactedWebsocketRPC,\n });\n }\n\n return redactedRpcConfigs;\n}\n","import type { ChainIdString } from \"enssdk\";\n\nimport {\n type Datasource,\n type ENSNamespaceId,\n ensTestEnvChain,\n getENSNamespace,\n} from \"@ensnode/datasources\";\n\nimport { serializeChainId } from \"../serialize\";\nimport type { Unvalidated } from \"../types\";\nimport {\n alchemySupportsChain,\n buildAlchemyBaseUrl,\n buildDRPCUrl,\n buildQuickNodeURL,\n dRPCSupportsChain,\n quickNodeSupportsChain,\n} from \"./build-rpc-urls\";\nimport type { ChainIdSpecificRpcEnvironmentVariable, RpcEnvironment } from \"./environments\";\n\n/**\n * Mode for auto-generating RPCs across indexed chains.\n */\nconst RpcAutoGenModes = {\n /**\n * Auto-generates only HTTP RPCs for supported chains.\n */\n HttpOnly: \"http-only\",\n\n /**\n * Auto-generates both HTTP and WebSocket RPCs for supported chains.\n */\n HttpAndWs: \"http-and-ws\",\n} as const;\n\n/**\n * The derived string union of possible {@link RpcAutoGenModes}.\n */\ntype RpcAutoGenMode = (typeof RpcAutoGenModes)[keyof typeof RpcAutoGenModes];\n\n/**\n * Default mode for auto-generating RPCs across indexed chains.\n */\nconst DEFAULT_RPC_AUTO_GEN_MODE: RpcAutoGenMode = RpcAutoGenModes.HttpOnly;\n\n/**\n * Build the RPCs auto-generation mode based on environment variables, with validation.\n *\n * Note: if env.RPC_AUTO_GEN_MODE is not set,\n * {@link DEFAULT_RPC_AUTO_GEN_MODE} will be used as the default.\n *\n * @param env The RPC environment variables to determine the auto-generation mode.\n * @returns The RPCs auto-generation mode to use for building RPC configurations.\n * @throws Error if the provided RPC_AUTO_GEN_MODE env var is invalid.\n */\nexport function buildRpcAutoGenMode(env: RpcEnvironment): RpcAutoGenMode {\n const mode = env.RPC_AUTO_GEN_MODE as Unvalidated<RpcAutoGenMode>;\n\n if (!mode) {\n return DEFAULT_RPC_AUTO_GEN_MODE;\n }\n\n if (!Object.values(RpcAutoGenModes).includes(mode)) {\n throw new Error(\n `Invalid RPC_AUTO_GEN_MODE env var: ${mode}. Valid values are: ${Object.values(RpcAutoGenModes).join(\", \")}`,\n );\n }\n\n return mode;\n}\n\n/**\n * Constructs dynamic chain configuration from environment variables, scoped to chain IDs that appear\n * in the specified `namespace`.\n *\n * This function auto-generates RPCs, depending on\n * the configured {@link RpcAutoGenMode}, in the following order:\n * 1. RPC_URL_*, if available in the env\n * 2. Alchemy, if ALCHEMY_API_KEY is available in the env\n * 3. QuickNode, if both, QUICKNODE_API_KEY and QUICKNODE_ENDPOINT_NAME are specified,\n * a QuickNode RPC URL will be provided for each of the chains it supports.\n * 4. DRPC, if DRPC_API_KEY is available in the env\n *\n * It also provides a single Alchemy wss:// url if ALCHEMY_API_KEY is available in the env.\n *\n * NOTE: This function returns raw RpcConfigEnvironment values which are not yet parsed or validated.\n *\n * @throws when only one but not both of the following environment variables are defined:\n * {@link RpcEnvironment.QUICKNODE_API_KEY} or\n * {@link RpcEnvironment.QUICKNODE_ENDPOINT_NAME}.\n */\nexport function buildRpcConfigsFromEnv(\n env: RpcEnvironment,\n namespace: ENSNamespaceId,\n): Record<ChainIdString, ChainIdSpecificRpcEnvironmentVariable> {\n const alchemyApiKey = env.ALCHEMY_API_KEY;\n const quickNodeApiKey = env.QUICKNODE_API_KEY;\n const quickNodeEndpointName = env.QUICKNODE_ENDPOINT_NAME;\n const dRPCKey = env.DRPC_API_KEY;\n\n // Invariant: QuickNode: using API key requires using endpoint name as well.\n if (quickNodeApiKey && !quickNodeEndpointName) {\n throw new Error(\n \"Use of the QUICKNODE_API_KEY environment variable requires use of the QUICKNODE_ENDPOINT_NAME environment variable as well.\",\n );\n }\n\n // Invariant: QuickNode: using endpoint name requires using API key as well.\n if (quickNodeEndpointName && !quickNodeApiKey) {\n throw new Error(\n \"Use of the QUICKNODE_ENDPOINT_NAME environment variable requires use of the QUICKNODE_API_KEY environment variable as well.\",\n );\n }\n\n const chainsInNamespace = Object.entries(getENSNamespace(namespace)).map(\n ([, datasource]) => (datasource as Datasource).chain,\n );\n\n const rpcAutoGenMode = buildRpcAutoGenMode(env);\n const rpcConfigs: Record<ChainIdString, ChainIdSpecificRpcEnvironmentVariable> = {};\n\n for (const chain of chainsInNamespace) {\n // RPC_URL_* takes precedence over convenience generation\n const specificValue = env[`RPC_URL_${chain.id}`];\n if (specificValue) {\n rpcConfigs[serializeChainId(chain.id)] = specificValue;\n continue;\n }\n\n // ens-test-env Chain\n if (chain.id === ensTestEnvChain.id) {\n rpcConfigs[serializeChainId(ensTestEnvChain.id)] = ensTestEnvChain.rpcUrls.default.http[0];\n continue;\n }\n\n const httpUrls = [\n // alchemy, if specified and available\n alchemyApiKey &&\n alchemySupportsChain(chain.id) &&\n `https://${buildAlchemyBaseUrl(chain.id, alchemyApiKey)}`,\n\n // QuickNode, if specified and available\n quickNodeApiKey &&\n quickNodeEndpointName &&\n quickNodeSupportsChain(chain.id) &&\n `https://${buildQuickNodeURL(chain.id, quickNodeApiKey, quickNodeEndpointName)}`,\n\n // dRPC, if specified and available\n dRPCKey && dRPCSupportsChain(chain.id) && buildDRPCUrl(chain.id, dRPCKey),\n ];\n\n const wsUrl =\n rpcAutoGenMode === RpcAutoGenModes.HttpAndWs &&\n alchemyApiKey &&\n alchemySupportsChain(chain.id) && //\n `wss://${buildAlchemyBaseUrl(chain.id, alchemyApiKey)}`;\n\n const urls = [...httpUrls, wsUrl]\n // filter out false/undefined values from the set of urls\n .filter(Boolean);\n\n // add if any urls were constructed\n if (urls.length > 0) {\n rpcConfigs[serializeChainId(chain.id)] = urls.join(\n \",\",\n ) as ChainIdSpecificRpcEnvironmentVariable;\n }\n }\n\n return rpcConfigs;\n}\n","import type { z } from \"zod/v4\";\n\nimport { getENSRootChainId } from \"@ensnode/datasources\";\n\nimport { isHttpProtocol, isWebSocketProtocol } from \"../url\";\nimport type { ZodCheckFnInput } from \"../zod-types\";\nimport type { ENSNamespaceSchema, RpcConfigsSchema } from \"./zod-schemas\";\n\n/**\n * Invariant: RPC endpoint configuration for a chain must include at least one http/https protocol URL.\n */\nexport function invariant_rpcEndpointConfigIncludesAtLeastOneHTTPProtocolURL(\n ctx: ZodCheckFnInput<URL[]>,\n) {\n const endpoints = ctx.value;\n const httpEndpoints = endpoints.filter(isHttpProtocol);\n\n if (httpEndpoints.length < 1) {\n ctx.issues.push({\n code: \"custom\",\n input: endpoints,\n message: `RPC endpoint configuration for a chain must include at least one http/https protocol URL.`,\n });\n }\n}\n\n/**\n * Invariant: RPC configuration for a chain must include at most one WS/WSS protocol URL.\n */\nexport function invariant_rpcEndpointConfigIncludesAtMostOneWebSocketsProtocolURL(\n ctx: ZodCheckFnInput<URL[]>,\n) {\n const endpoints = ctx.value;\n const wsEndpoints = endpoints.filter(isWebSocketProtocol);\n\n if (wsEndpoints.length > 1) {\n ctx.issues.push({\n code: \"custom\",\n input: endpoints,\n message: `RPC endpoint configuration for a chain must include at most one websocket (ws/wss) protocol URL.`,\n });\n }\n}\n\n// Invariant: rpcConfig is specified for the ENS Root Chain of the configured namespace\nexport function invariant_rpcConfigsSpecifiedForRootChain(\n ctx: ZodCheckFnInput<{\n namespace: z.infer<typeof ENSNamespaceSchema>;\n rpcConfigs: z.infer<typeof RpcConfigsSchema>;\n }>,\n) {\n const { value: config } = ctx;\n\n const ensRootChainId = getENSRootChainId(config.namespace);\n\n if (!config.rpcConfigs.has(ensRootChainId)) {\n ctx.issues.push({\n code: \"custom\",\n input: config,\n message: `An RPC Config for the ENS Root Chain ('${ensRootChainId}') is required, but none was specified.`,\n });\n }\n}\n","export function isHttpProtocol(url: URL): boolean {\n return [\"http:\", \"https:\"].includes(url.protocol);\n}\n\nexport function isWebSocketProtocol(url: URL): boolean {\n return [\"ws:\", \"wss:\"].includes(url.protocol);\n}\n","import type { ChainId } from \"enssdk\";\nimport { z } from \"zod/v4\";\n\nimport { ENSNamespaceIds } from \"@ensnode/datasources\";\n\nimport { deserializeChainId } from \"../deserialize\";\nimport { isHttpProtocol, isWebSocketProtocol } from \"../url\";\nimport { makeChainIdStringSchema, makeUrlSchema } from \"../zod-schemas\";\nimport type { RpcConfig } from \"./types\";\nimport {\n invariant_rpcEndpointConfigIncludesAtLeastOneHTTPProtocolURL,\n invariant_rpcEndpointConfigIncludesAtMostOneWebSocketsProtocolURL,\n} from \"./validatons\";\n\nconst RpcConfigSchema = z\n .string()\n .transform((val) => val.split(\",\"))\n .pipe(z.array(makeUrlSchema(\"RPC URL\")))\n .check(invariant_rpcEndpointConfigIncludesAtLeastOneHTTPProtocolURL)\n .check(invariant_rpcEndpointConfigIncludesAtMostOneWebSocketsProtocolURL);\n\nexport const RpcConfigsSchema = z\n .record(makeChainIdStringSchema(\"RPC URL\"), RpcConfigSchema, {\n error: \"Chains configuration must be an object mapping valid chain IDs to their configs.\",\n })\n .transform((records) => {\n const rpcConfigs = new Map<ChainId, RpcConfig>();\n\n for (const [chainIdString, rpcConfig] of Object.entries(records)) {\n // rpcConfig is guaranteed to include at least one HTTP protocol URL\n const httpRPCs = rpcConfig.filter(isHttpProtocol) as [URL, ...URL[]];\n\n // rpcConfig is guaranteed to include at most one WebSocket protocol URL\n const websocketRPC = rpcConfig.find(isWebSocketProtocol);\n\n rpcConfigs.set(deserializeChainId(chainIdString), {\n httpRPCs,\n websocketRPC,\n });\n }\n\n return rpcConfigs;\n });\n\nexport const ENSNamespaceSchema = z.enum(ENSNamespaceIds, {\n error: ({ input }) =>\n `Invalid NAMESPACE. Got '${input}', but supported ENS namespaces are: ${Object.keys(ENSNamespaceIds).join(\", \")}`,\n});\n\nexport const PortNumberSchema = z.coerce\n .number({ error: \"PORT must be a number.\" })\n .int({ error: \"PORT must be an integer.\" })\n .min(1, { error: \"PORT must be greater than or equal to 1.\" })\n .max(65535, { error: \"PORT must be less than or equal to 65535.\" });\n\nexport const OptionalPortNumberSchema = PortNumberSchema.optional();\n\nexport const TheGraphApiKeySchema = z.string().optional();\n","import type { AccountId, ChainId, ChainIdString, Duration, UrlString } from \"enssdk\";\nimport z, { prettifyError } from \"zod/v4\";\n\nimport type { PriceDai, PriceEnsTokens, PriceEth, PriceUsdc } from \"./currencies\";\nimport type { BlockNumber, BlockRef, Datetime } from \"./types\";\nimport {\n makeAccountIdStringSchema,\n makeBlockNumberSchema,\n makeBlockRefSchema,\n makeChainIdStringSchema,\n makeDatetimeSchema,\n makeDurationSchema,\n makePriceDaiSchema,\n makePriceEnsTokensSchema,\n makePriceEthSchema,\n makePriceUsdcSchema,\n makeUnixTimestampSchema,\n makeUrlSchema,\n} from \"./zod-schemas\";\n\nexport function deserializeChainId(maybeChainId: ChainIdString, valueLabel?: string): ChainId {\n const schema = makeChainIdStringSchema(valueLabel);\n const parsed = schema.safeParse(maybeChainId);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ChainId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeDatetime(maybeDatetime: string, valueLabel?: string): Datetime {\n const schema = makeDatetimeSchema(valueLabel);\n const parsed = schema.safeParse(maybeDatetime);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Datetime:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeUnixTimestamp(maybeTimestamp: number, valueLabel?: string) {\n const schema = makeUnixTimestampSchema(valueLabel);\n const parsed = schema.safeParse(maybeTimestamp);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Unix Timestamp:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeUrl(maybeUrl: UrlString, valueLabel?: string): URL {\n const schema = makeUrlSchema(valueLabel);\n const parsed = schema.safeParse(maybeUrl);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize URL:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockNumber(maybeBlockNumber: number, valueLabel?: string): BlockNumber {\n const schema = makeBlockNumberSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockNumber);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize BlockNumber:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockRef(\n maybeBlockRef: Partial<BlockRef>,\n valueLabel?: string,\n): BlockRef {\n const schema = makeBlockRefSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockRef);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize BlockRef:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeDuration(maybeDuration: unknown, valueLabel?: string): Duration {\n const schema = z.coerce.number().pipe(makeDurationSchema(valueLabel));\n const parsed = schema.safeParse(maybeDuration);\n\n if (parsed.error) {\n throw new RangeError(`Cannot deserialize Duration:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function parseAccountId(maybeAccountId: unknown, valueLabel?: string): AccountId {\n const schema = makeAccountIdStringSchema(valueLabel);\n const parsed = schema.safeParse(maybeAccountId);\n\n if (parsed.error) {\n throw new RangeError(`Cannot deserialize AccountId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializePriceEth(maybePrice: unknown, valueLabel?: string): PriceEth {\n const schema = makePriceEthSchema(valueLabel);\n const parsed = schema.safeParse(maybePrice);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize PriceEth:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializePriceUsdc(maybePrice: unknown, valueLabel?: string): PriceUsdc {\n const schema = makePriceUsdcSchema(valueLabel);\n const parsed = schema.safeParse(maybePrice);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize PriceUsdc:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializePriceDai(maybePrice: unknown, valueLabel?: string): PriceDai {\n const schema = makePriceDaiSchema(valueLabel);\n const parsed = schema.safeParse(maybePrice);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize PriceDai:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializePriceEnsTokens(\n maybePrice: unknown,\n valueLabel?: string,\n): PriceEnsTokens {\n const schema = makePriceEnsTokensSchema(valueLabel);\n const parsed = schema.safeParse(maybePrice);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize PriceEnsTokens:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n","import { ENSNamespaceIds } from \"@ensnode/datasources\";\n\n/**\n * Represents the well-known ENSNode configuration templates deployed to the cloud. The value of each\n * key matches the domain segment that identifies this configuration template.\n *\n * @see https://ensnode.io/docs/usage/hosted-ensnode-instances\n */\nexport const ConfigTemplateIds = {\n Mainnet: \"mainnet\",\n Sepolia: \"sepolia\",\n Alpha: \"alpha\",\n AlphaSepolia: \"alpha-sepolia\",\n};\n\nexport type ConfigTemplateId = (typeof ConfigTemplateIds)[keyof typeof ConfigTemplateIds];\n\n/**\n * Determines whether the provided `configTemplateId` is Subgraph Compatible.\n *\n * See packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.ts for additional info.\n *\n * @see https://ensnode.io/docs/concepts/what-is-the-ens-subgraph\n */\nexport function isConfigTemplateSubgraphCompatible(configTemplateId: ConfigTemplateId) {\n switch (configTemplateId) {\n // these ConfigTemplates are run with SUBGRAPH_COMPAT, meaning they are Subgraph Compatible\n case ConfigTemplateIds.Mainnet:\n case ConfigTemplateIds.Sepolia:\n return true;\n\n // these instances are NOT run with SUBGRAPH_COMPAT, meaning they are NOT Subgraph Compatible\n case ConfigTemplateIds.Alpha:\n case ConfigTemplateIds.AlphaSepolia:\n return false;\n default:\n throw new Error(\"never\");\n }\n}\n\n/**\n * Determines the ENSNamespaceId for the provided `configTemplateId`.\n *\n * @see https://ensnode.io/docs/usage/hosted-ensnode-instances\n */\nexport function namespaceForConfigTemplateId(configTemplateId: ConfigTemplateId) {\n switch (configTemplateId) {\n case ConfigTemplateIds.Alpha:\n case ConfigTemplateIds.Mainnet:\n return ENSNamespaceIds.Mainnet;\n case ConfigTemplateIds.AlphaSepolia:\n case ConfigTemplateIds.Sepolia:\n return ENSNamespaceIds.Sepolia;\n default:\n throw new Error(\"never\");\n }\n}\n","import {\n type ContractConfig,\n type Datasource,\n type DatasourceName,\n DatasourceNames,\n type ENSNamespaceId,\n maybeGetDatasource,\n} from \"@ensnode/datasources\";\n\nexport const DATASOURCE_NAMES_WITH_ENSv2_CONTRACTS = [\n DatasourceNames.ENSv2Root,\n] as const satisfies DatasourceName[];\n\n// avoids 'The inferred type of this node exceeds the maximum length the compiler will serialize'\ntype DatasourceWithENSv2Contracts = Datasource & {\n contracts: { Registry: ContractConfig; EnhancedAccessControl: ContractConfig };\n};\n\n/**\n * The set of DatasourceNames that describe ENSv2 contracts that are indexed by the\n * Protocol Acceleration plugin.\n */\nexport const getDatasourcesWithENSv2Contracts = (\n namespace: ENSNamespaceId,\n): DatasourceWithENSv2Contracts[] =>\n DATASOURCE_NAMES_WITH_ENSv2_CONTRACTS.map((datasourceName) =>\n maybeGetDatasource(namespace, datasourceName),\n )\n .filter((datasource) => !!datasource)\n .map((datasource) => {\n // all of the relevant datasources provide a Registry and EnhancedAccessControl ContractConfig\n if (!datasource.contracts.Registry || !datasource.contracts.EnhancedAccessControl) {\n throw new Error(\n `Invariant: Datasource does not define 'Registry' and 'EnhancedAccessControl' contracts. Defined contracts: ${JSON.stringify(Object.keys(datasource.contracts))}`,\n );\n }\n\n return datasource;\n });\n","import {\n type ContractConfig,\n type Datasource,\n type DatasourceName,\n DatasourceNames,\n type ENSNamespaceId,\n maybeGetDatasource,\n} from \"@ensnode/datasources\";\n\nimport { DATASOURCE_NAMES_WITH_ENSv2_CONTRACTS } from \"./datasources-with-ensv2-contracts\";\n\n// avoids 'The inferred type of this node exceeds the maximum length the compiler will serialize'\ntype DatasourceWithResolverContract = Datasource & { contracts: { Resolver: ContractConfig } };\n\nexport const DATASOURCE_NAMES_WITH_RESOLVERS = [\n DatasourceNames.ENSRoot,\n DatasourceNames.Basenames,\n DatasourceNames.Lineanames,\n DatasourceNames.ThreeDNSOptimism,\n DatasourceNames.ThreeDNSBase,\n\n // all datasources that define ENSv2 contracts also define Resolver\n ...DATASOURCE_NAMES_WITH_ENSv2_CONTRACTS,\n] as const satisfies DatasourceName[];\n\n/**\n * The set of DatasourceNames that describe Resolver contracts that are indexed by the\n * Protocol Acceleration plugin.\n */\nexport const getDatasourcesWithResolvers = (\n namespace: ENSNamespaceId,\n): DatasourceWithResolverContract[] =>\n DATASOURCE_NAMES_WITH_RESOLVERS.map((datasourceName) =>\n maybeGetDatasource(namespace, datasourceName),\n )\n .filter((datasource) => !!datasource)\n .map((datasource) => {\n // all of the relevant datasources provide a Resolver ContractConfig with a `startBlock`\n if (!datasource.contracts.Resolver) {\n throw new Error(\n `Invariant: Datasource does not define a 'Resolver' contract. Defined contracts: ${JSON.stringify(Object.keys(datasource.contracts))}`,\n );\n }\n\n return datasource;\n });\n","import type { NormalizedAddress } from \"enssdk\";\nimport { isAddressEqual, zeroAddress } from \"viem\";\n\n/**\n * Interprets a NormalizedAddress. zeroAddress is interpreted as null, otherwise as-is.\n */\nexport const interpretAddress = (owner: NormalizedAddress): NormalizedAddress | null =>\n isAddressEqual(zeroAddress, owner) ? null : owner;\n","import type { InterpretedName, LiteralName } from \"enssdk\";\nimport { isInterpretedName, toNormalizedAddress } from \"enssdk\";\nimport { isAddress, isAddressEqual, zeroAddress } from \"viem\";\n\nimport { hasNullByte } from \"../null-bytes\";\n\n/**\n * Interprets a name record value string and returns null if the value is interpreted as a deletion.\n *\n * The interpreted record value is either:\n * a) null, representing a non-existent or deletion of the record, or\n * b) an {@link InterpretedName}.\n *\n * @param value - The name record value string to interpret.\n * @returns The interpreted name string, or null if deleted.\n */\nexport function interpretNameRecordValue(value: LiteralName): InterpretedName | null {\n // empty string is technically an InterpretedName, representing the ens root node, but in the\n // context of a name record value, empty string is emitted when the user un-sets the record (this\n // is because the abi of this event is only capable of expressing string values, so empty string\n // canonically represents the non-existence or deletion of the record value)\n if (value === \"\") return null;\n\n // if not normalized, is not valid `name` record value\n if (!isInterpretedName(value)) return null;\n\n // otherwise, this is a non-empty-string normalized Name that can be used as a name() record value\n return value;\n}\n\n/**\n * Interprets an address record value string and returns null if the value is interpreted as a deletion.\n *\n * The interpreted record value is either:\n * a) null, representing a non-existent or deletion of the record, or\n * i. contains null bytes\n * ii. empty string\n * iii. empty hex (0x)\n * iv. zeroAddress\n * b) an address record value that\n * i. does not contain null bytes\n * ii. (if is an EVM address) is lowercase\n *\n * @param value - The address record value to interpret.\n * @returns The interpreted address string or null if deleted.\n */\nexport function interpretAddressRecordValue(value: string): string | null {\n // TODO(null-bytes): store null bytes correctly — for now, interpret as deletion\n if (hasNullByte(value)) return null;\n\n // interpret empty string as deletion of address record\n if (value === \"\") return null;\n\n // interpret empty bytes as deletion of address record\n if (value === \"0x\") return null;\n\n // if it's not an EVM address, return as-is\n if (!isAddress(value, { strict: false })) return value;\n\n // interpret zeroAddress as deletion\n if (isAddressEqual(value, zeroAddress)) return null;\n\n // otherwise normalize and return\n return toNormalizedAddress(value);\n}\n\n/**\n * Interprets a text record key string and returns null if the key should be ignored.\n *\n * The interpreted text record key is either:\n * a) null, representing a text record key that should be ignored, or\n * i. contains null bytes\n * ii. empty string\n * b) a text record key that\n * i. does not contain null bytes\n *\n * @param value - The text record key to interpret.\n * @returns The interpreted text string or null if ignored.\n */\nexport function interpretTextRecordKey(key: string): string | null {\n // TODO(null-bytes): store null bytes correctly — for now, ignore\n if (hasNullByte(key)) return null;\n\n // ignore empty-string keys\n if (key === \"\") return null;\n\n // otherwise return the key as-is\n return key;\n}\n\n/**\n * Interprets a text record value string and returns null if the value is interpreted as a deletion.\n *\n * The interpreted record value is either:\n * a) null, representing a non-existent or deletion of the record, or\n * i. contains null bytes\n * ii. empty string\n * b) a text record value that\n * i. does not contain null bytes\n *\n * @param value - The text record value to interpret.\n * @returns The interpreted text string or null if deleted.\n */\nexport function interpretTextRecordValue(value: string): string | null {\n // TODO(null-bytes): store null bytes correctly — for now, interpret as deletion\n if (hasNullByte(value)) return null;\n\n // interpret empty string as deletion of a text record\n if (value === \"\") return null;\n\n // otherwise return the string as-is\n return value;\n}\n","export const hasNullByte = (value: string) => value.indexOf(\"\\u0000\") !== -1;\n\nexport const stripNullBytes = (value: string) => value.replaceAll(\"\\u0000\", \"\");\n","import type { Hex } from \"enssdk\";\nimport { size, zeroHash } from \"viem\";\n\n/**\n * Interprets an ENSIP-7 contenthash value. Empty bytes are interpreted as deletion.\n */\nexport function interpretContenthashValue(value: Hex): Hex | null {\n if (size(value) === 0) return null;\n return value;\n}\n\n/**\n * Interprets a PubkeyResolver (x, y) pair. A (zeroHash, zeroHash) pair is interpreted as deletion.\n *\n * Invariant: both null together, or both set together.\n */\nexport function interpretPubkeyValue(x: Hex, y: Hex): { x: Hex; y: Hex } | null {\n if (x === zeroHash && y === zeroHash) return null;\n return { x, y };\n}\n\n/**\n * Interprets an IDNSZoneResolver zonehash value. Empty bytes are interpreted as deletion.\n */\nexport function interpretDnszonehashValue(value: Hex): Hex | null {\n if (size(value) === 0) return null;\n return value;\n}\n","import { z } from \"zod/v4\";\n\nimport type { LogLevelEnvironment } from \"./config/environments\";\n\n/**\n * Set of valid log levels, mirroring pino#LogLevelWithSilent.\n */\nconst LogLevelSchema = z.enum([\"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\", \"silent\"]);\n\nexport type LogLevel = z.infer<typeof LogLevelSchema>;\n\nexport function getLogLevelFromEnv(env: LogLevelEnvironment, defaultLogLevel: LogLevel): LogLevel {\n try {\n return LogLevelSchema.default(defaultLogLevel).parse(env.LOG_LEVEL);\n } catch {\n console.warn(\n `Invalid LOG_LEVEL '${env.LOG_LEVEL}', expected one of '${Object.values(LogLevelSchema.enum).join(\"' | '\")}' defaulting to '${defaultLogLevel}'`,\n );\n return defaultLogLevel;\n }\n}\n","import {\n type AccountId,\n type DomainId,\n makeENSv1DomainId,\n makeENSv1VirtualRegistryId,\n type RegistryId,\n} from \"enssdk\";\n\nimport { DatasourceNames, maybeGetDatasource } from \"@ensnode/datasources\";\nimport {\n accountIdEqual,\n type ENSNamespaceId,\n getDatasourceContract,\n getENSv1RootRegistry,\n getManagedName,\n} from \"@ensnode/ensnode-sdk\";\n\n// simple cache of BridgedResolverConfig by namespace because it's in an indexing hot-path\nconst cache = new Map<ENSNamespaceId, BridgedResolverConfig[]>();\n\n/**\n * Describes a Bridged Resolver's origin Domain and target Registry.\n */\nexport interface BridgedResolverConfig {\n /**\n * The Bridged Resolver connecting the origin Domain to the target Registry.\n */\n resolver: AccountId;\n\n /**\n * The DomainId of the _legitimate_ originating Domain on the ENS Root chain whose\n * Bridged Resolver attachment canonicalizes the bridged target Registry. Anyone can set a\n * known Bridged Resolver (e.g. `BasenamesL1Resolver`) as their resolver, but only the\n * originating Domain (e.g. mainnet `base.eth`) is the canonical parent of the bridged\n * target Registry.\n */\n originDomainId: DomainId;\n\n /**\n * The RegistryId of the _specific_ (Concrete or Virtual) Registry to which the Bridged Resolver defers.\n */\n targetRegistryId: RegistryId;\n\n /**\n * The AccountId of the Concrete Registry to which the Bridged Resolver defers, necessary for\n * current ENSv1 Protocol Acceleration implementation.\n * TODO: refactor Protocol Acceleration to operate over RegistryId instead of AccountId.\n */\n targetRegistry: AccountId;\n}\n\n/**\n * Constructs the known Bridged Resolver Configurations for the provided `namespace`.\n *\n * These Bridged Resolvers must abide the following pattern:\n * 1. They _always_ emit OffchainLookup for any resolve() call to a well-known CCIP-Read Gateway,\n * 2. That CCIP-Read Gateway exclusively consults a specific (shadow)Registry in order to identify\n * a name's active resolver and resolve records, and\n * 3. Its behavior is unlikely to change (i.e. the contract is not upgradable or is unlikely to be\n * upgraded in a way that violates principles 1. or 2.).\n *\n * The goal is to encode the pattern followed by projects like Basenames and Lineanames where a\n * wildcard resolver is used for subnames of base.eth and that L1Resolver always returns OffchainLookup\n * instructing the caller to consult a well-known CCIP-Read Gateway. This CCIP-Read Gateway then\n * exclusively behaves in the following way: it identifies the name's active resolver via a well-known\n * (shadow)Registry (likely on an L2), and resolves records on that active resolver.\n *\n * In these cases, if the Node-Resolver relationships for the (shadow)Registry in question are indexed,\n * then the CCIP-Read can be short-circuited, in favor of performing an _accelerated_ Forward Resolution\n * against the (shadow)Registry in question.\n *\n * TODO: these relationships could/should be encoded in an ENSIP\n * TODO: once Forward Resolution is updated for ENSv2, this likely just returns RegistryId\n */\nconst getBridgedResolverConfigs = (namespace: ENSNamespaceId): BridgedResolverConfig[] => {\n const cached = cache.get(namespace);\n if (cached) return cached;\n\n const configs: BridgedResolverConfig[] = [];\n\n const basenames = maybeGetDatasource(namespace, DatasourceNames.Basenames);\n if (basenames) {\n const resolver = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"BasenamesL1Resolver\",\n );\n const registry = getDatasourceContract(namespace, DatasourceNames.Basenames, \"Registry\");\n const { node } = getManagedName(namespace, registry);\n configs.push({\n resolver,\n originDomainId: makeENSv1DomainId(getENSv1RootRegistry(namespace), node),\n targetRegistry: registry,\n targetRegistryId: makeENSv1VirtualRegistryId(registry, node),\n });\n }\n\n const lineanames = maybeGetDatasource(namespace, DatasourceNames.Lineanames);\n if (lineanames) {\n const resolver = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"LineanamesL1Resolver\",\n );\n const registry = getDatasourceContract(namespace, DatasourceNames.Lineanames, \"Registry\");\n const { node } = getManagedName(namespace, registry);\n configs.push({\n resolver,\n originDomainId: makeENSv1DomainId(getENSv1RootRegistry(namespace), node),\n targetRegistry: registry,\n targetRegistryId: makeENSv1VirtualRegistryId(registry, node),\n });\n }\n\n cache.set(namespace, configs);\n\n return configs;\n};\n\n/**\n * For a given `resolver`, if it is a known Bridged Resolver, return its Bridged Resolver Config.\n */\nexport function isBridgedResolver(\n namespace: ENSNamespaceId,\n resolver: AccountId,\n): BridgedResolverConfig | null {\n return (\n getBridgedResolverConfigs(namespace).find((config) =>\n accountIdEqual(config.resolver, resolver),\n ) ?? null\n );\n}\n","import {\n type AccountId,\n type AccountIdString,\n asInterpretedName,\n ENS_ROOT_NAME,\n type InterpretedName,\n type Name,\n type Node,\n namehashInterpretedName,\n stringifyAccountId,\n} from \"enssdk\";\n\nimport { DatasourceNames, type ENSNamespaceId } from \"@ensnode/datasources\";\n\nimport { accountIdEqual } from \"./account-id\";\nimport { getDatasourceContract, maybeGetDatasourceContract } from \"./datasource-contract\";\nimport { toJson } from \"./to-json\";\n\n/**\n * Many contracts within the ENSv1 Ecosystem are relative to a parent Name. For example,\n * the .eth BaseRegistrar (and RegistrarControllers) manage direct subnames of .eth. As such, they\n * operate on relative Labels, not fully qualified Names. We must know the parent name whose subnames\n * they manage in order to index them correctly.\n *\n * Because we use shared indexing logic for each instance of these contracts (BaseRegistrar,\n * RegistrarControllers, NameWrapper), the concept of \"which name is this contract operating in\n * the context of\" must be generalizable: this is the contract's 'Managed Name'.\n *\n * Concretely, a .eth RegistrarController will emit a _LabelHash_ indicating a new Registration, but\n * correlating that LabelHash with the NameHash of the Name requires knowing the NameHash of the\n * Registrar's Managed Name ('eth' in this case).\n *\n * The NameWrapper contracts are relevant here as well because they include specialized logic for\n * wrapping direct subnames of specific Managed Names.\n */\n\n/**\n * Each Managed Name group is associated with exactly one concrete ENSv1 Registry (the mainnet ENS\n * Registry, the Basenames shadow Registry, or the Lineanames shadow Registry). The Registry is\n * what `handleNewOwner` writes domains into and what every Registrar/Controller/NameWrapper under\n * the same Managed Name contributes to.\n */\ninterface ManagedNameGroup {\n registry: AccountId;\n contracts: AccountId[];\n}\n\n/**\n * Certain Managed Names are different depending on the ENSNamespace — this encodes that relationship.\n */\nconst MANAGED_NAME_BY_NAMESPACE: Partial<Record<ENSNamespaceId, Record<Name, Name>>> = {\n sepolia: {\n \"base.eth\": \"basetest.eth\",\n \"linea.eth\": \"linea-sepolia.eth\",\n },\n};\n\n/**\n * Produces a mapping of a Managed Name to its concrete Registry and the contracts that operate in\n * its (sub)Registry context.\n */\nconst getContractsByManagedName = (namespace: ENSNamespaceId) => {\n const ensRootRegistry = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"ENSv1Registry\",\n );\n const ensRootRegistryOld = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"ENSv1RegistryOld\",\n );\n const ethnamesNameWrapper = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"NameWrapper\",\n );\n\n const basenamesRegistry = maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Basenames,\n \"Registry\",\n );\n const lineanamesRegistry = maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Lineanames,\n \"Registry\",\n );\n const lineanamesNameWrapper = maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Lineanames,\n \"NameWrapper\",\n );\n\n return {\n [ENS_ROOT_NAME]: {\n registry: ensRootRegistry,\n contracts: [ensRootRegistry, ensRootRegistryOld],\n },\n eth: {\n registry: ensRootRegistry,\n contracts: [\n getDatasourceContract(namespace, DatasourceNames.ENSRoot, \"BaseRegistrar\"),\n getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"UnwrappedEthRegistrarController\",\n ),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"LegacyEthRegistrarController\",\n ),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"WrappedEthRegistrarController\",\n ),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"UniversalRegistrarRenewalWithReferrer\",\n ),\n ethnamesNameWrapper,\n ].filter((c): c is AccountId => !!c),\n },\n ...(basenamesRegistry && {\n \"base.eth\": {\n registry: basenamesRegistry,\n contracts: [\n basenamesRegistry,\n maybeGetDatasourceContract(namespace, DatasourceNames.Basenames, \"BaseRegistrar\"),\n maybeGetDatasourceContract(namespace, DatasourceNames.Basenames, \"EARegistrarController\"),\n maybeGetDatasourceContract(namespace, DatasourceNames.Basenames, \"RegistrarController\"),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Basenames,\n \"UpgradeableRegistrarController\",\n ),\n ].filter((c): c is AccountId => !!c),\n },\n }),\n ...(lineanamesRegistry && {\n \"linea.eth\": {\n registry: lineanamesRegistry,\n contracts: [\n lineanamesRegistry,\n maybeGetDatasourceContract(namespace, DatasourceNames.Lineanames, \"BaseRegistrar\"),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Lineanames,\n \"EthRegistrarController\",\n ),\n lineanamesNameWrapper,\n ].filter((c): c is AccountId => !!c),\n },\n }),\n } satisfies Record<Name, ManagedNameGroup>;\n};\n\ninterface ManagedNameResult {\n name: InterpretedName;\n node: Node;\n registry: AccountId;\n}\n\n/**\n * Cache for the memoization of {@link getManagedName} below.\n */\nconst cache = new Map<`${ENSNamespaceId}:${AccountIdString}`, ManagedNameResult>();\n\n/**\n * Given a `contract` in a `namespace`, identify its Managed Name, Node, and the concrete ENSv1\n * Registry in the context of which it operates.\n *\n * @dev memoized by (namespace, contract).\n * @throws if `contract` is not configured under any Managed Name for `namespace`\n */\nexport const getManagedName = (\n namespace: ENSNamespaceId,\n contract: AccountId,\n): ManagedNameResult => {\n const cacheKey = `${namespace}:${stringifyAccountId(contract)}` as const;\n const cached = cache.get(cacheKey);\n if (cached !== undefined) return cached;\n\n for (const [managedName, group] of Object.entries(getContractsByManagedName(namespace))) {\n const isAnyOfTheContracts = group.contracts.some((_contract) =>\n accountIdEqual(_contract, contract),\n );\n if (isAnyOfTheContracts) {\n const namespaceSpecific = MANAGED_NAME_BY_NAMESPACE[namespace]?.[managedName];\n\n // use the namespace-specific Managed Name if specified, otherwise the default\n const name = asInterpretedName(namespaceSpecific ?? managedName);\n const node = namehashInterpretedName(name);\n\n const result: ManagedNameResult = { name, node, registry: group.registry };\n cache.set(cacheKey, result);\n return result;\n }\n }\n\n throw new Error(\n `The following contract ${toJson(contract, { pretty: true })} does not have a configured Managed Name in namespace '${namespace}'.`,\n );\n};\n\n/**\n * Determines whether `contract` is a NameWrapper in the given `namespace`.\n */\nexport const isNameWrapper = (namespace: ENSNamespaceId, contract: AccountId): boolean => {\n const ethnamesNameWrapper = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"NameWrapper\",\n );\n if (accountIdEqual(ethnamesNameWrapper, contract)) return true;\n\n const lineanamesNameWrapper = maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Lineanames,\n \"NameWrapper\",\n );\n if (lineanamesNameWrapper && accountIdEqual(lineanamesNameWrapper, contract)) return true;\n\n return false;\n};\n","/**\n * `JSON.stringify` with bigints replaced by their string representation.\n *\n * Defaults to compact output. Pass `{ pretty: true }` for 2-space indent\n * (useful for human-readable error messages and console logs).\n *\n * Uses `JSON.stringify`'s replacer callback so native `toJSON` behavior is\n * preserved (e.g. `Date` serializes to its ISO string).\n */\nexport const toJson = (value: unknown, options?: { pretty?: boolean }) =>\n JSON.stringify(\n value,\n (_key, val) => (typeof val === \"bigint\" ? String(val) : val),\n options?.pretty ? 2 : undefined,\n );\n","import { type AccountId, makeENSv1RegistryId, makeENSv2RegistryId, type RegistryId } from \"enssdk\";\n\nimport { DatasourceNames, type ENSNamespaceId } from \"@ensnode/datasources\";\n\nimport { accountIdEqual } from \"./account-id\";\nimport { getDatasourceContract, maybeGetDatasourceContract } from \"./datasource-contract\";\n\n//////////////\n// ENSv1\n//////////////\n\n/**\n * Gets the AccountId representing the ENSv1 Registry in the selected `namespace`.\n */\nexport const getENSv1RootRegistry = (namespace: ENSNamespaceId) =>\n getDatasourceContract(namespace, DatasourceNames.ENSRoot, \"ENSv1Registry\");\n\n/**\n * Gets the ENSv1RegistryId representing the ENSv1 Root Registry in the selected `namespace`.\n */\nexport const getENSv1RootRegistryId = (namespace: ENSNamespaceId) =>\n makeENSv1RegistryId(getENSv1RootRegistry(namespace));\n\n/**\n * Determines whether `contract` is the ENSv1 Registry in `namespace`.\n */\nexport const isENSv1Registry = (namespace: ENSNamespaceId, contract: AccountId) =>\n accountIdEqual(getENSv1RootRegistry(namespace), contract);\n\n//////////////\n// ENSv2\n//////////////\n\n/**\n * Gets the AccountId representing the ENSv2 Root Registry in the selected `namespace`.\n *\n * @throws if the ENSv2Root Datasource or the RootRegistry contract are not defined\n */\nexport const getENSv2RootRegistry = (namespace: ENSNamespaceId) =>\n getDatasourceContract(namespace, DatasourceNames.ENSv2Root, \"RootRegistry\");\n\n/**\n * Gets the RegistryId representing the ENSv2 Root Registry in the selected `namespace`.\n *\n * @throws if the ENSv2Root Datasource or the RootRegistry contract are not defined\n */\nexport const getENSv2RootRegistryId = (namespace: ENSNamespaceId) =>\n makeENSv2RegistryId(getENSv2RootRegistry(namespace));\n\n/**\n * Determines whether `contract` is the ENSv2 Root Registry in `namespace`.\n *\n * @throws if the ENSv2Root Datasource or the RootRegistry contract are not defined\n */\nexport const isENSv2RootRegistry = (namespace: ENSNamespaceId, contract: AccountId) =>\n accountIdEqual(getENSv2RootRegistry(namespace), contract);\n\n/**\n * Gets the AccountId representing the ENSv2 Root Registry in the selected `namespace` if defined,\n * otherwise `undefined`.\n *\n * TODO: remove this function and its usage after all namespaces define ENSv2Root\n */\nexport const maybeGetENSv2RootRegistry = (namespace: ENSNamespaceId) =>\n maybeGetDatasourceContract(namespace, DatasourceNames.ENSv2Root, \"RootRegistry\");\n\n/**\n * Gets the RegistryId representing the ENSv2 Root Registry in the selected `namespace` if defined,\n * otherwise `undefined`.\n *\n * TODO: remove this function and its usage after all namespaces define ENSv2Root\n */\nexport const maybeGetENSv2RootRegistryId = (namespace: ENSNamespaceId) => {\n const root = maybeGetENSv2RootRegistry(namespace);\n if (!root) return undefined;\n return makeENSv2RegistryId(root);\n};\n\n//////////////\n// Root\n//////////////\n\n/**\n * Gets the RegistryId representing the preferred Root Registry for the selected `namespace` —\n * the ENSv2 Root Registry when defined, otherwise the ENSv1 Root Registry. Used as the entry\n * point for resolution-time namegraph traversal.\n */\nexport const getRootRegistryId = (namespace: ENSNamespaceId) =>\n maybeGetENSv2RootRegistryId(namespace) ?? getENSv1RootRegistryId(namespace);\n\n/**\n * Determines whether `registryId` is a Root Registry (ENSv1 Root or, when defined, ENSv2 Root)\n * for the selected `namespace`.\n */\nexport const isRootRegistryId = (namespace: ENSNamespaceId, registryId: RegistryId): boolean =>\n registryId === getENSv1RootRegistryId(namespace) ||\n registryId === maybeGetENSv2RootRegistryId(namespace);\n","import type { AccountId } from \"enssdk\";\n\nimport { DatasourceNames } from \"@ensnode/datasources\";\nimport { type ENSNamespaceId, makeContractMatcher } from \"@ensnode/ensnode-sdk\";\n\n/**\n * ENSIP-19 Reverse Resolvers (i.e. DefaultReverseResolver or ChainReverseResolver) simply:\n * a. read the Name for their specific coinType from their connected StandaloneReverseRegistry, or\n * b. return the default coinType's Name.\n *\n * We encode this behavior here, for the purposes of Protocol Acceleration.\n */\nexport function isKnownENSIP19ReverseResolver(\n namespace: ENSNamespaceId,\n resolver: AccountId,\n): boolean {\n const resolverEq = makeContractMatcher(namespace, resolver);\n\n return [\n // DefaultReverseResolver (default.reverse)\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultReverseResolver3\"),\n\n // the following are each ChainReverseResolver ([coinType].reverse)\n resolverEq(DatasourceNames.ReverseResolverRoot, \"BaseReverseResolver\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"LineaReverseResolver\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"OptimismReverseResolver\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"ArbitrumReverseResolver\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"ScrollReverseResolver\"),\n ].some(Boolean);\n}\n","import type { AccountId } from \"enssdk\";\n\nimport { DatasourceNames } from \"@ensnode/datasources\";\nimport { type ENSNamespaceId, makeContractMatcher } from \"@ensnode/ensnode-sdk\";\n\n/**\n * Returns whether `resolver` is an Static Resolver.\n *\n * Static Resolvers must abide the following pattern:\n * 1. All information necessary for resolution is stored on-chain, and\n * 2. All resolve() calls resolve to the exact value previously emitted by the Resolver in\n * its events (i.e. no post-processing or other logic, a simple return of the on-chain data).\n * 2.a the Resolver MAY implement address record defaulting and still be considered Static (see below).\n * 3. Its behavior is unlikely to change (i.e. the contract is not upgradable or is unlikely to be\n * upgraded in a way that violates principles 1. or 2.).\n *\n * TODO: these relationships could be encoded in an ENSIP\n */\nexport function isStaticResolver(namespace: ENSNamespaceId, resolver: AccountId): boolean {\n const resolverEq = makeContractMatcher(namespace, resolver);\n\n return [\n // ENS Root Chain\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver0\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver1\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver2\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver3\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver4\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver5\"),\n resolverEq(DatasourceNames.ENSRoot, \"ArgentResolver\"),\n resolverEq(DatasourceNames.ENSRoot, \"LoopringResolver\"),\n\n // Basenames\n resolverEq(DatasourceNames.Basenames, \"L2Resolver1\"),\n resolverEq(DatasourceNames.Basenames, \"L2Resolver2\"),\n\n // Lineanames\n resolverEq(DatasourceNames.Lineanames, \"DefaultPublicResolver\"),\n\n // ThreeDNS\n resolverEq(DatasourceNames.ThreeDNSBase, \"Resolver\"),\n resolverEq(DatasourceNames.ThreeDNSOptimism, \"Resolver\"),\n ].some(Boolean);\n}\n\n/**\n * Returns whether `resolver` implements address record defaulting.\n *\n * @see https://docs.ens.domains/ensip/19/#default-address\n */\nexport function staticResolverImplementsAddressRecordDefaulting(\n namespace: ENSNamespaceId,\n resolver: AccountId,\n): boolean {\n const resolverEq = makeContractMatcher(namespace, resolver);\n\n return [\n // ENS Root Chain\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver5\"),\n\n // Base Chain\n resolverEq(DatasourceNames.Basenames, \"L2Resolver2\"),\n ].some(Boolean);\n}\n","import { type ENSNamespaceId, ENSNamespaceIds } from \"@ensnode/datasources\";\n\nimport type { TheGraphFallback } from \"./config/thegraph\";\n\n/**\n * Determines whether, given the provided context, a Subgraph GraphQL API request can be handled by\n * a TheGraph-hosted Subgraph.\n *\n * @see https://ensnode.io/docs/concepts/what-is-the-ens-subgraph\n */\nexport const canFallbackToTheGraph = ({\n namespace,\n theGraphApiKey,\n isSubgraphCompatible,\n}: {\n namespace: ENSNamespaceId;\n theGraphApiKey: string | undefined;\n isSubgraphCompatible: boolean;\n}): TheGraphFallback => {\n // must be subgraph-compatible\n // NOTE: that Subgraph Compatibility requires that 'subgraph' is the only plugin, excluding\n // alpha-style deployments, which are unable to fall back to thegraph due to data inconsistency\n if (!isSubgraphCompatible) return { canFallback: false, reason: \"not-subgraph-compatible\" };\n\n // must have api key for The Graph\n const hasApiKey = theGraphApiKey !== undefined;\n if (!hasApiKey) return { canFallback: false, reason: \"no-api-key\" };\n\n // and namespace must be supported by The Graph\n const url = makeTheGraphSubgraphUrl(namespace, theGraphApiKey);\n if (url === null) return { canFallback: false, reason: \"no-subgraph-url\" };\n\n // otherwise able to fallback\n return { canFallback: true, url };\n};\n\n/**\n * Retrieves the URL of a TheGraph-hosted Subgraph given the provided `namespace`, authenticating\n * with the provided `apiKey`.\n */\nconst makeTheGraphSubgraphUrl = (namespace: ENSNamespaceId, apiKey: string) => {\n switch (namespace) {\n case ENSNamespaceIds.Mainnet:\n return `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH`;\n case ENSNamespaceIds.Sepolia:\n return `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/G1SxZs317YUb9nQX3CC98hDyvxfMJNZH5pPRGpNrtvwN`;\n case ENSNamespaceIds.SepoliaV2:\n case ENSNamespaceIds.EnsTestEnv:\n return null;\n default:\n throw new Error(\"never\");\n }\n};\n"],"mappings":"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","names":["z","z","z","z","ENSNamespaceIds","ENSNamespaceIds","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","isAddressEqual","zeroAddress","isAddressEqual","zeroAddress","z","z","z","z","z","z","namehashInterpretedName","z","z","toNormalizedAddress","size","zeroAddress","size","zeroAddress","toNormalizedAddress","z","z","z","namehashInterpretedName","z","z","toNormalizedAddress","DatasourceNames","ENSNamespaceIds","ENSNamespaceIds","DatasourceNames","toNormalizedAddress","getENSRootChainId","getENSRootChainId","z","ENSNamespaceIds","z","prettifyError","prettifyError","z","ENSNamespaceIds","ENSNamespaceIds","DatasourceNames","maybeGetDatasource","DatasourceNames","maybeGetDatasource","DatasourceNames","maybeGetDatasource","isAddressEqual","zeroAddress","toNormalizedAddress","isAddress","isAddressEqual","zeroAddress","isAddress","isAddressEqual","zeroAddress","toNormalizedAddress","size","z","DatasourceNames","maybeGetDatasource","asInterpretedName","namehashInterpretedName","DatasourceNames","DatasourceNames","asInterpretedName","namehashInterpretedName","DatasourceNames","DatasourceNames","cache","maybeGetDatasource","DatasourceNames","DatasourceNames","DatasourceNames","DatasourceNames","DatasourceNames","ENSNamespaceIds","isSubgraphCompatible"]}
|
|
1
|
+
{"version":3,"sources":["../src/ensapi/config/zod-schemas.ts","../src/ensindexer/config/zod-schemas.ts","../src/ensrainbow/zod-schemas/config.ts","../src/shared/zod-schemas.ts","../src/ens/index.ts","../src/shared/currencies.ts","../src/shared/collections.ts","../src/ensindexer/config/is-subgraph-compatible.ts","../src/ensindexer/config/labelset-utils.ts","../src/ensindexer/config/validations.ts","../src/shared/config/thegraph.ts","../src/ensnode/api/indexing-status/zod-schemas.ts","../src/indexing-status/zod-schema/realtime-indexing-status-projection.ts","../src/indexing-status/zod-schema/cross-chain-indexing-status-snapshot.ts","../src/shared/block-ref.ts","../src/shared/blockrange.ts","../src/indexing-status/chain-indexing-status-snapshot.ts","../src/indexing-status/cross-chain-indexing-status-snapshot.ts","../src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts","../src/indexing-status/omnichain-indexing-status-snapshot.ts","../src/indexing-status/zod-schema/chain-indexing-status-snapshot.ts","../src/stack-info/zod-schemas/ensindexer-stack-info.ts","../src/ensdb/zod-schemas/config.ts","../src/stack-info/zod-schemas/ensnode-stack-info.ts","../src/ensnode/api/indexing-status/response.ts","../src/ensnode/api/name-tokens/examples.ts","../src/ensnode/api/name-tokens/zod-schemas.ts","../src/tokenscope/name-token.ts","../src/shared/account-id.ts","../src/shared/datasource-contract.ts","../src/tokenscope/assets.ts","../src/tokenscope/zod-schemas.ts","../src/ensnode/api/shared/errors/zod-schemas.ts","../src/ensnode/api/name-tokens/response.ts","../src/ensnode/api/realtime/zod-schemas.ts","../src/ensnode/api/registrar-actions/examples.ts","../src/ensnode/api/registrar-actions/zod-schemas.ts","../src/registrars/zod-schemas.ts","../src/registrars/encoded-referrer.ts","../src/shared/serialize.ts","../src/registrars/registrar-action.ts","../src/ensnode/api/shared/pagination/zod-schemas.ts","../src/ensnode/api/shared/pagination/request.ts","../src/ensnode/api/registrar-actions/response.ts","../src/ensnode/api/resolution/examples.ts","../src/ensnode/api/resolution/zod-schemas.ts","../src/ensnode/api/shared/errors/examples.ts","../src/omnigraph-api/example-queries.ts","../src/rpc/eip-165.ts","../src/rpc/is-extended-resolver.ts","../src/shared/config/build-rpc-urls.ts","../src/shared/config/pretty-printing.ts","../src/shared/config/redacting.ts","../src/shared/config/rpc-configs-from-env.ts","../src/shared/config/validatons.ts","../src/shared/url.ts","../src/shared/config/zod-schemas.ts","../src/shared/deserialize.ts","../src/shared/config-templates.ts","../src/shared/datasources-with-ensv2-contracts.ts","../src/shared/datasources-with-resolvers.ts","../src/shared/interpretation/interpret-address.ts","../src/shared/interpretation/interpret-record-values.ts","../src/shared/null-bytes.ts","../src/shared/interpretation/interpret-resolver-values.ts","../src/shared/log-level.ts","../src/shared/protocol-acceleration/is-bridged-resolver.ts","../src/shared/managed-names.ts","../src/shared/to-json.ts","../src/shared/root-registry.ts","../src/shared/protocol-acceleration/is-ensip-19-reverse-resolver.ts","../src/shared/protocol-acceleration/is-static-resolver.ts","../src/shared/thegraph.ts"],"sourcesContent":["import { z } from \"zod/v4\";\n\nimport {\n makeEnsIndexerPublicConfigSchema,\n makeSerializedEnsIndexerPublicConfigSchema,\n} from \"../../ensindexer/config/zod-schemas\";\nimport {\n TheGraphCannotFallbackReasonSchema,\n TheGraphFallbackSchema,\n} from \"../../shared/config/thegraph\";\n\nexport { TheGraphCannotFallbackReasonSchema, TheGraphFallbackSchema };\n\nconst makeEnsApiVersionInfoSchema = (valueLabel: string = \"ENS API version info\") =>\n z.object({\n ensApi: z.string().nonempty(`${valueLabel}.ensApi must be a non-empty string`),\n ensNormalize: z.string().nonempty(`${valueLabel}.ensNormalize must be a non-empty string`),\n });\n\n/**\n * Create a Zod schema for validating ENSApiPublicConfig.\n *\n * @param valueLabel - Optional label for the value being validated (used in error messages)\n */\nexport function makeEnsApiPublicConfigSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSApiPublicConfig\";\n\n return z.object({\n theGraphFallback: TheGraphFallbackSchema,\n ensIndexerPublicConfig: makeEnsIndexerPublicConfigSchema(`${label}.ensIndexerPublicConfig`),\n versionInfo: makeEnsApiVersionInfoSchema(`${label}.versionInfo`),\n });\n}\n\n/**\n * Create a Zod schema for validating a serialized ENSApiPublicConfig.\n *\n * @deprecated Use {@link makeEnsApiPublicConfigSchema} instead.\n */\nexport const makeENSApiPublicConfigSchema = makeEnsApiPublicConfigSchema;\n\nexport function makeSerializedEnsApiPublicConfigSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSApiPublicConfig\";\n\n return z.object({\n ensIndexerPublicConfig: makeSerializedEnsIndexerPublicConfigSchema(\n `${label}.ensIndexerPublicConfig`,\n ),\n theGraphFallback: TheGraphFallbackSchema,\n versionInfo: makeEnsApiVersionInfoSchema(`${label}.versionInfo`),\n });\n}\n","/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport { z } from \"zod/v4\";\n\nimport {\n makeEnsRainbowPublicConfigSchema,\n makeLabelSetIdSchema,\n makeLabelSetVersionStringSchema,\n} from \"../../ensrainbow/zod-schemas/config\";\nimport { uniq } from \"../../shared/collections\";\nimport { makeChainIdSchema, makeENSNamespaceIdSchema } from \"../../shared/zod-schemas\";\nimport type { ZodCheckFnInput } from \"../../shared/zod-types\";\nimport { isSubgraphCompatible } from \"./is-subgraph-compatible\";\nimport { validateSupportedLabelSetAndVersion } from \"./labelset-utils\";\nimport type { EnsIndexerPublicConfig } from \"./types\";\nimport { PluginName } from \"./types\";\nimport { invariant_ensDbVersionIsSameAsEnsIndexerVersion } from \"./validations\";\n\n/**\n * Makes a schema for parsing {@link IndexedChainIds}.\n */\nexport const makeIndexedChainIdsSchema = (valueLabel: string = \"Indexed Chain IDs\") =>\n z.set(makeChainIdSchema(valueLabel), { error: `${valueLabel} must be a set` }).min(1, {\n error: `${valueLabel} must be a set with at least one chain ID.`,\n });\n\nexport const makeSerializedIndexedChainIdsSchema = (valueLabel: string = \"Indexed Chain IDs\") =>\n z\n .array(makeChainIdSchema(valueLabel), {\n error: `${valueLabel} must be an array.`,\n })\n .min(1, {\n error: `${valueLabel} must be an array with at least one chain ID.`,\n });\n\n/**\n * Makes a schema for parsing a list of strings that (for future-proofing)\n * may or may not be current {@link PluginName} values.\n *\n * The list is guaranteed to include at least one string and no duplicates.\n */\nexport const makePluginsListSchema = (valueLabel: string = \"Plugins\") =>\n z\n .array(z.string(), {\n error: `${valueLabel} must be a list of strings.`,\n })\n .min(1, {\n error: `${valueLabel} must be a list of strings with at least one string value`,\n })\n .refine((arr) => arr.length === uniq(arr).length, {\n error: `${valueLabel} cannot contain duplicate values.`,\n });\n\n/**\n * Makes a schema for parsing a name for a database schema.\n *\n * The name is guaranteed to be a non-empty string.\n */\nexport const makeEnsIndexerSchemaNameSchema = (valueLabel: string = \"ENS Indexer Schema Name\") =>\n z\n .string({ error: `${valueLabel} must be a string` })\n .trim()\n .nonempty({\n error: `${valueLabel} is required and must be a non-empty string.`,\n });\n\n/**\n * Makes a schema for parsing a label set where both label set ID and label set version are required.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set\", \"LABEL_SET\")\n */\nexport const makeFullyPinnedLabelSetSchema = (valueLabel: string = \"Label set\") => {\n let valueLabelLabelSetId = valueLabel;\n let valueLabelLabelSetVersion = valueLabel;\n if (valueLabel === \"LABEL_SET\") {\n valueLabelLabelSetId = \"LABEL_SET_ID\";\n valueLabelLabelSetVersion = \"LABEL_SET_VERSION\";\n } else {\n valueLabelLabelSetId = `${valueLabel}.labelSetId`;\n valueLabelLabelSetVersion = `${valueLabel}.labelSetVersion`;\n }\n return z.object({\n labelSetId: makeLabelSetIdSchema(valueLabelLabelSetId),\n labelSetVersion: makeLabelSetVersionStringSchema(valueLabelLabelSetVersion),\n });\n};\n\nconst makeNonEmptyStringSchema = (valueLabel: string = \"Value\") =>\n z.string().nonempty({ error: `${valueLabel} must be a non-empty string.` });\n\nexport const makeEnsIndexerVersionInfoSchema = (valueLabel: string = \"Value\") =>\n z\n .object(\n {\n ponder: makeNonEmptyStringSchema(),\n ensDb: makeNonEmptyStringSchema(),\n ensIndexer: makeNonEmptyStringSchema(),\n ensNormalize: makeNonEmptyStringSchema(),\n },\n {\n error: `${valueLabel} must be a valid ENSIndexerVersionInfo object.`,\n },\n )\n .check(invariant_ensDbVersionIsSameAsEnsIndexerVersion);\n\n/**\n * @deprecated Use {@link makeEnsIndexerVersionInfoSchema} instead.\n */\nexport const makeENSIndexerVersionInfoSchema = makeEnsIndexerVersionInfoSchema;\n\n// Invariant: If config.isSubgraphCompatible, the config must pass isSubgraphCompatible(config)\nexport function invariant_isSubgraphCompatibleRequirements(\n ctx: ZodCheckFnInput<\n Pick<\n EnsIndexerPublicConfig,\n \"namespace\" | \"plugins\" | \"isSubgraphCompatible\" | \"clientLabelSet\"\n >\n >,\n) {\n const { value: config } = ctx;\n\n if (config.isSubgraphCompatible && !isSubgraphCompatible(config)) {\n ctx.issues.push({\n code: \"custom\",\n input: config,\n message: `'isSubgraphCompatible' requires only the '${PluginName.Subgraph}' plugin to be active and 'clientLabelSet' must be {labelSetId: \"subgraph\", labelSetVersion: 0}`,\n });\n }\n}\n\nexport function invariant_ensRainbowSupportedLabelSetAndVersion(\n ctx: ZodCheckFnInput<Pick<EnsIndexerPublicConfig, \"clientLabelSet\" | \"ensRainbowPublicConfig\">>,\n) {\n const { clientLabelSet } = ctx.value;\n const { serverLabelSet } = ctx.value.ensRainbowPublicConfig;\n\n try {\n validateSupportedLabelSetAndVersion(serverLabelSet, clientLabelSet);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `The ENSRainbow label set and version specified in the config are not supported by the ENSRainbow version specified in ensRainbowPublicConfig. Cause: ${errorMessage}`,\n });\n }\n}\n\n/**\n * ENSIndexer Public Config Schema\n *\n * Makes a Zod schema definition for validating all important settings used\n * during runtime of the ENSIndexer instance.\n */\nexport const makeEnsIndexerPublicConfigSchema = (valueLabel: string = \"ENSIndexerPublicConfig\") =>\n z\n .object({\n ensIndexerSchemaName: makeEnsIndexerSchemaNameSchema(`${valueLabel}.ensIndexerSchemaName`),\n ensRainbowPublicConfig: makeEnsRainbowPublicConfigSchema(\n `${valueLabel}.ensRainbowPublicConfig`,\n ),\n indexedChainIds: makeIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),\n isSubgraphCompatible: z.boolean({\n error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`,\n }),\n clientLabelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.clientLabelSet`),\n namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),\n plugins: makePluginsListSchema(`${valueLabel}.plugins`),\n versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`),\n })\n /**\n * Validations\n *\n * All required data validations must be performed below.\n */\n .check(invariant_isSubgraphCompatibleRequirements)\n .check(invariant_ensRainbowSupportedLabelSetAndVersion);\n\n/**\n * ENSIndexer Public Config Schema\n *\n * @deprecated Use {@link makeEnsIndexerPublicConfigSchema} instead.\n */\nexport const makeENSIndexerPublicConfigSchema = makeEnsIndexerPublicConfigSchema;\n\nexport const makeSerializedEnsIndexerPublicConfigSchema = (\n valueLabel: string = \"Serialized ENSIndexerPublicConfig\",\n) =>\n z.object({\n ensIndexerSchemaName: makeEnsIndexerSchemaNameSchema(`${valueLabel}.ensIndexerSchemaName`),\n ensRainbowPublicConfig: makeEnsRainbowPublicConfigSchema(\n `${valueLabel}.ensRainbowPublicConfig`,\n ),\n indexedChainIds: makeSerializedIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`),\n isSubgraphCompatible: z.boolean({\n error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`,\n }),\n clientLabelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.clientLabelSet`),\n namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`),\n plugins: makePluginsListSchema(`${valueLabel}.plugins`),\n versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`),\n });\n","import { z } from \"zod/v4\";\n\nimport { makeNonNegativeIntegerSchema } from \"../../shared/zod-schemas\";\n\n/**\n * Makes a schema for parsing a label set ID.\n *\n * The label set ID is guaranteed to be a string between 1-50 characters\n * containing only lowercase letters (a-z) and hyphens (-).\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set ID\", \"LABEL_SET_ID\")\n */\nexport const makeLabelSetIdSchema = (valueLabel: string = \"Label set ID\") => {\n return z\n .string({ error: `${valueLabel} must be a string` })\n .min(1, { error: `${valueLabel} must be 1-50 characters long` })\n .max(50, { error: `${valueLabel} must be 1-50 characters long` })\n .regex(/^[a-z-]+$/, {\n error: `${valueLabel} can only contain lowercase letters (a-z) and hyphens (-)`,\n });\n};\n\n/**\n * Makes a schema for parsing a label set version.\n *\n * The label set version is guaranteed to be a non-negative integer.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set version\", \"LABEL_SET_VERSION\")\n */\nexport const makeLabelSetVersionSchema = (valueLabel: string = \"Label set version\") =>\n makeNonNegativeIntegerSchema(valueLabel);\n\n/**\n * Makes a schema for parsing a label set version string.\n *\n * @param valueLabel - The label to use in error messages (e.g., \"Label set version\", \"LABEL_SET_VERSION\")\n */\nexport const makeLabelSetVersionStringSchema = (valueLabel: string = \"Label set version\") =>\n z.coerce\n .number<number>({ error: `${valueLabel} must be a non-negative integer` })\n .pipe(makeLabelSetVersionSchema(valueLabel));\n\n/**\n * Makes a schema for parsing the EnsRainbowPublicConfig object.\n */\nexport const makeEnsRainbowPublicConfigSchema = (valueLabel: string = \"EnsRainbowPublicConfig\") =>\n z.object({\n serverLabelSet: z.object({\n labelSetId: makeLabelSetIdSchema(`${valueLabel}.serverLabelSet.labelSetId`),\n highestLabelSetVersion: makeLabelSetVersionSchema(\n `${valueLabel}.serverLabelSet.highestLabelSetVersion`,\n ),\n }),\n\n versionInfo: z.object({\n ensRainbow: z\n .string()\n .nonempty({ error: `${valueLabel}.versionInfo.ensRainbow must be a non-empty string.` }),\n }),\n });\n","import type { CoinType } from \"@ensdomains/address-encoder\";\nimport { AccountId as CaipAccountId } from \"caip\";\nimport type {\n AccountId,\n AccountIdString,\n ChainId,\n DefaultableChainId,\n Duration,\n Hex,\n InterpretedName,\n Node,\n} from \"enssdk\";\nimport { reinterpretName, toNormalizedAddress } from \"enssdk\";\nimport { isAddress, isHex, size } from \"viem\";\n/**\n * All zod schemas we define must remain internal implementation details.\n * We want the freedom to move away from zod in the future without impacting\n * any users of the ensnode-sdk package.\n *\n * The only way to share Zod schemas is to re-export them from\n * `./src/internal.ts` file.\n */\nimport { z } from \"zod/v4\";\n\nimport { ENSNamespaceIds } from \"../ens\";\nimport {\n type CurrencyId,\n CurrencyIds,\n type PriceDai,\n type PriceEnsTokens,\n type PriceEth,\n type PriceUsdc,\n type SerializedPriceEth,\n} from \"./currencies\";\nimport type { BlockRef, Datetime } from \"./types\";\n\n/**\n * Parses a string value as a boolean.\n */\nexport const makeBooleanStringSchema = (valueLabel: string = \"Value\") =>\n z\n .string()\n .pipe(\n z.enum([\"true\", \"false\"], {\n error: `${valueLabel} must be 'true' or 'false'.`,\n }),\n )\n .transform((val) => val === \"true\");\n\n/**\n * Parses a numeric value as a finite non-negative number.\n */\nexport const makeFiniteNonNegativeNumberSchema = (valueLabel: string = \"Value\") =>\n z\n .number({\n // NOTE: Zod's implementation of `number` automatically rejects NaN and Infinity values.\n // and therefore the finite check is implicit.\n error: `${valueLabel} must be a finite number.`,\n })\n .nonnegative({\n error: `${valueLabel} must be a non-negative number (>=0).`,\n });\n\n/**\n * Parses a numeric value as an integer.\n */\nexport const makeIntegerSchema = (valueLabel: string = \"Value\") =>\n z.int({\n error: `${valueLabel} must be an integer.`,\n });\n\n/**\n * Parses a numeric value as a positive integer.\n */\nexport const makePositiveIntegerSchema = (valueLabel: string = \"Value\") =>\n makeIntegerSchema(valueLabel).positive({\n error: `${valueLabel} must be a positive integer (>0).`,\n });\n\n/**\n * Parses a numeric value as a non-negative integer.\n */\nexport const makeNonNegativeIntegerSchema = (valueLabel: string = \"Value\") =>\n makeIntegerSchema(valueLabel).nonnegative({\n error: `${valueLabel} must be a non-negative integer (>=0).`,\n });\n\n/**\n * Parses a numeric value as {@link Duration}\n */\nexport const makeDurationSchema = (valueLabel: string = \"Value\") =>\n z\n .number({\n error: `${valueLabel} must be a number.`,\n })\n .pipe(makeNonNegativeIntegerSchema(valueLabel));\n\n/**\n * Parses Chain ID\n *\n * {@link ChainId}\n */\nexport const makeChainIdSchema = (valueLabel: string = \"Chain ID\") =>\n makePositiveIntegerSchema(valueLabel).transform((val) => val as ChainId);\n\n/**\n * Parses a serialized representation of {@link ChainId}.\n */\nexport const makeChainIdStringSchema = (valueLabel: string = \"Chain ID String\") =>\n z\n .string({ error: `${valueLabel} must be a string representing a chain ID.` })\n .pipe(z.coerce.number({ error: `${valueLabel} must represent a positive integer (>0).` }))\n .pipe(makeChainIdSchema(`The numeric value represented by ${valueLabel}`));\n\n/**\n * Parses Defaultable Chain ID\n *\n * {@link DefaultableChainId}\n */\nexport const makeDefaultableChainIdSchema = (valueLabel: string = \"Defaultable Chain ID\") =>\n makeNonNegativeIntegerSchema(valueLabel).transform((val) => val as DefaultableChainId);\n\n/**\n * Parses a serialized representation of {@link DefaultableChainId}.\n */\nexport const makeDefaultableChainIdStringSchema = (\n valueLabel: string = \"Defaultable Chain ID String\",\n) =>\n z\n .string({ error: `${valueLabel} must be a string representing a chain ID.` })\n .pipe(z.coerce.number({ error: `${valueLabel} must represent a non-negative integer (>=0).` }))\n .pipe(makeDefaultableChainIdSchema(`The numeric value represented by ${valueLabel}`));\n\n/**\n * Parses {@link CoinType}.\n */\nexport const makeCoinTypeSchema = (valueLabel: string = \"Coin Type\") =>\n z\n .number({ error: `${valueLabel} must be a number.` })\n .int({ error: `${valueLabel} must be an integer.` })\n .nonnegative({ error: `${valueLabel} must be a non-negative integer (>=0).` })\n .transform((val) => val as CoinType);\n\n/**\n * Parses a serialized representation of {@link CoinType}.\n */\nexport const makeCoinTypeStringSchema = (valueLabel: string = \"Coin Type String\") =>\n z\n .string({ error: `${valueLabel} must be a string representing a coin type.` })\n .pipe(z.coerce.number({ error: `${valueLabel} must represent a non-negative integer (>=0).` }))\n .pipe(makeCoinTypeSchema(`The numeric value represented by ${valueLabel}`));\n\n/**\n * Parses a serialized representation of an EVM address into a {@link NormalizedAddress}.\n */\nexport const makeNormalizedAddressSchema = (valueLabel: string = \"EVM address\") =>\n z\n .string()\n .check((ctx) => {\n // NOTE: we intentionally use isAddress here instead of isNormalizedAddress, which allows this\n // schema to transform (via toNormalizedAddress) the input into a normalized address.\n if (!isAddress(ctx.value, { strict: false })) {\n ctx.issues.push({\n code: \"custom\",\n message: `${valueLabel} must be a valid EVM address`,\n input: ctx.value,\n });\n }\n })\n .transform((val) => toNormalizedAddress(val));\n\n/**\n * Parses an ISO 8601 string representations of {@link Datetime}\n */\nexport const makeDatetimeSchema = (valueLabel: string = \"Datetime string\") =>\n z.iso\n .datetime({ error: `${valueLabel} must be a string in ISO 8601 format.` })\n .transform((v) => new Date(v));\n\n/**\n * Parses value as {@link UnixTimestamp}.\n */\nexport const makeUnixTimestampSchema = (valueLabel: string = \"Timestamp\") =>\n makeIntegerSchema(valueLabel);\n\n/**\n * Parses a string representations of {@link URL}\n */\nexport const makeUrlSchema = (valueLabel: string = \"Value\") =>\n z\n .url({\n error: `${valueLabel} must be a valid URL string (e.g., http://localhost:8080 or https://example.com).`,\n abort: true,\n })\n .transform((v) => new URL(v));\n\n/**\n * Parses a serialized representation of a comma separated list.\n */\nexport const makeCommaSeparatedList = (valueLabel: string = \"Value\") =>\n z\n .string({ error: `${valueLabel} must be a comma separated list.` })\n .transform((val) => val.split(\",\").filter(Boolean))\n .refine((val) => val.length > 0, {\n error: `${valueLabel} must be a comma separated list with at least one value.`,\n });\n\n/**\n * Parses a numeric value as a block number.\n */\nexport const makeBlockNumberSchema = (valueLabel: string = \"Block number\") =>\n makeNonNegativeIntegerSchema(valueLabel);\n\n/**\n * Parses an object value as the {@link BlockRef} object.\n */\nexport const makeBlockRefSchema = (valueLabel: string = \"Value\") =>\n z.strictObject(\n {\n timestamp: makeUnixTimestampSchema(`${valueLabel}.timestamp`),\n number: makeBlockNumberSchema(`${valueLabel}.number`),\n },\n {\n error: `${valueLabel} must be a valid BlockRef object.`,\n },\n );\n\n/**\n * Parses a string value as ENSNamespaceId.\n */\nexport const makeENSNamespaceIdSchema = (valueLabel: string = \"ENSNamespaceId\") =>\n z.enum(ENSNamespaceIds, {\n error() {\n return `Invalid ${valueLabel}. Supported ENS namespace IDs are: ${Object.keys(ENSNamespaceIds).join(\", \")}`;\n },\n });\n\nconst makePriceAmountSchema = (valueLabel: string = \"Amount\") =>\n z.coerce\n .bigint({\n error: `${valueLabel} must represent a bigint.`,\n })\n .nonnegative({\n error: `${valueLabel} must not be negative.`,\n });\n\nconst makeSerializedCurrencyAmountSchema = (valueLabel: string = \"Serialized Currency Amount\") =>\n z.string({ error: `${valueLabel} must be a string.` }).regex(/^\\d+$/, {\n error: `${valueLabel} can only contain digits (0-9) and must represent a non-negative integer.`,\n });\n\nexport const makePriceCurrencySchema = (\n currency: CurrencyId,\n valueLabel: string = \"Price Currency\",\n) =>\n z.strictObject({\n amount: makePriceAmountSchema(`${valueLabel} amount`),\n\n currency: z.literal(currency, {\n error: `${valueLabel} currency must be set to '${currency}'.`,\n }),\n });\n\nexport const makeSerializedPriceCurrencySchema = (\n currency: CurrencyId,\n valueLabel: string = \"Price Currency\",\n) =>\n z.strictObject({\n amount: makeSerializedCurrencyAmountSchema(`${valueLabel} amount`),\n\n currency: z.literal(currency, {\n error: `${valueLabel} currency must be set to '${currency}'.`,\n }),\n });\n\n/**\n * Schema for {@link Price} type.\n */\nexport const makePriceSchema = (valueLabel: string = \"Price\") =>\n z.discriminatedUnion(\n \"currency\",\n [\n makePriceCurrencySchema(CurrencyIds.ETH, valueLabel),\n makePriceCurrencySchema(CurrencyIds.USDC, valueLabel),\n makePriceCurrencySchema(CurrencyIds.DAI, valueLabel),\n makePriceCurrencySchema(CurrencyIds.ENSTokens, valueLabel),\n ],\n { error: `${valueLabel} currency must be one of ${Object.values(CurrencyIds).join(\", \")}` },\n );\n\n/**\n * Schema for {@link PriceEth} type.\n */\nexport const makePriceEthSchema = (valueLabel: string = \"Price ETH\") =>\n makePriceCurrencySchema(CurrencyIds.ETH, valueLabel).transform((v) => v as PriceEth);\n\nexport const makeSerializedPriceEthSchema = (valueLabel: string = \"Serialized Price ETH\") =>\n makeSerializedPriceCurrencySchema(CurrencyIds.ETH, valueLabel).transform(\n (v) => v as SerializedPriceEth,\n );\n\n/**\n * Schema for {@link PriceUsdc} type.\n */\nexport const makePriceUsdcSchema = (valueLabel: string = \"Price USDC\") =>\n makePriceCurrencySchema(CurrencyIds.USDC, valueLabel).transform((v) => v as PriceUsdc);\n\n/**\n * Schema for {@link PriceDai} type.\n */\nexport const makePriceDaiSchema = (valueLabel: string = \"Price DAI\") =>\n makePriceCurrencySchema(CurrencyIds.DAI, valueLabel).transform((v) => v as PriceDai);\n\n/**\n * Schema for {@link PriceEnsTokens} type.\n */\nexport const makePriceEnsTokensSchema = (valueLabel: string = \"Price ENSTokens\") =>\n makePriceCurrencySchema(CurrencyIds.ENSTokens, valueLabel).transform((v) => v as PriceEnsTokens);\n\n/**\n * Schema for {@link AccountId} type.\n */\nexport const makeAccountIdSchema = (valueLabel: string = \"AccountId\") =>\n z.strictObject({\n chainId: makeChainIdSchema(`${valueLabel} chain ID`),\n address: makeNormalizedAddressSchema(`${valueLabel} address`),\n });\n\n/**\n * Schema for {@link AccountIdString} type.\n */\nexport const makeAccountIdStringSchema = (valueLabel: string = \"Account ID String\") =>\n z.coerce\n .string()\n .transform((v) => {\n const result = new CaipAccountId(v);\n\n return {\n chainId: Number(result.chainId.reference),\n address: result.address,\n };\n })\n .pipe(makeAccountIdSchema(valueLabel));\n\n/**\n * Make a schema for {@link Hex} representation of bytes array.\n *\n * @param {number} options.bytesCount expected count of bytes to be hex-encoded\n */\nexport const makeHexStringSchema = (\n options: { bytesCount: number },\n valueLabel: string = \"String representation of bytes array\",\n) =>\n z\n .string()\n .check(function invariant_isHexEncoded(ctx) {\n if (!isHex(ctx.value)) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `${valueLabel} must be a hexadecimal value which starts with '0x'.`,\n });\n }\n })\n .transform((v) => v as Hex)\n .check(function invariant_encodesRequiredBytesCount(ctx) {\n const expectedBytesCount = options.bytesCount;\n const actualBytesCount = size(ctx.value);\n\n if (actualBytesCount !== expectedBytesCount) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `${valueLabel} must represent exactly ${expectedBytesCount} bytes. Currently represented bytes count: ${actualBytesCount}.`,\n });\n }\n });\n\n/**\n * Make schema for {@link Node}.\n */\nexport const makeNodeSchema = (valueLabel: string = \"Node\") =>\n makeHexStringSchema({ bytesCount: 32 }, valueLabel);\n\n/**\n * Make schema for Transaction Hash\n */\nexport const makeTransactionHashSchema = (valueLabel: string = \"Transaction hash\") =>\n makeHexStringSchema({ bytesCount: 32 }, valueLabel);\n\n/**\n * Make schema for {@link ReinterpretedName}.\n */\nexport const makeReinterpretedNameSchema = (valueLabel: string = \"Reinterpreted Name\") =>\n z\n .string()\n .transform((v) => v as InterpretedName)\n .check((ctx) => {\n try {\n reinterpretName(ctx.value);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `${valueLabel} cannot be reinterpreted: ${errorMessage}`,\n });\n }\n })\n .transform(reinterpretName);\n","export type { ENSNamespaceId } from \"@ensnode/datasources\";\nexport { ENSNamespaceIds, getENSRootChainId } from \"@ensnode/datasources\";\n\nexport * from \"./fuses\";\n","import { parseUnits } from \"viem\";\n\nimport { scaleBigintByNumber } from \"./numbers\";\n\n/**\n * Identifiers for supported currencies.\n *\n * TODO: Add support for WETH\n */\nexport const CurrencyIds = {\n ETH: \"ETH\",\n USDC: \"USDC\",\n DAI: \"DAI\",\n ENSTokens: \"ENSTokens\",\n} as const;\n\nexport type CurrencyId = (typeof CurrencyIds)[keyof typeof CurrencyIds];\n\n/**\n * The amount of the currency in the smallest unit of the currency\n * (see {@link CurrencyInfo.decimals} for the currency).\n *\n * Guaranteed to be non-negative.\n */\nexport type CurrencyAmount = bigint;\n\n/**\n * Serialized representation of {@link CurrencyAmount}.\n */\nexport type SerializedCurrencyAmount = string;\n\nexport interface PriceEth {\n currency: typeof CurrencyIds.ETH;\n\n amount: CurrencyAmount;\n}\n\nexport interface PriceDai {\n currency: typeof CurrencyIds.DAI;\n\n amount: CurrencyAmount;\n}\n\nexport interface PriceUsdc {\n currency: typeof CurrencyIds.USDC;\n\n amount: CurrencyAmount;\n}\n\nexport interface PriceEnsTokens {\n currency: typeof CurrencyIds.ENSTokens;\n\n amount: CurrencyAmount;\n}\n\nexport type Price = PriceEth | PriceDai | PriceUsdc | PriceEnsTokens;\n\n/**\n * Serialized representation of {@link PriceEth}.\n */\nexport interface SerializedPriceEth extends Omit<PriceEth, \"amount\"> {\n amount: SerializedCurrencyAmount;\n}\n\n/**\n * Serialized representation of {@link PriceDai}.\n */\nexport interface SerializedPriceDai extends Omit<PriceDai, \"amount\"> {\n amount: SerializedCurrencyAmount;\n}\n\n/**\n * Serialized representation of {@link PriceUsdc}.\n */\nexport interface SerializedPriceUsdc extends Omit<PriceUsdc, \"amount\"> {\n amount: SerializedCurrencyAmount;\n}\n\n/**\n * Serialized representation of {@link PriceEnsTokens}.\n */\nexport interface SerializedPriceEnsTokens extends Omit<PriceEnsTokens, \"amount\"> {\n amount: SerializedCurrencyAmount;\n}\n\n/**\n * Serialized representation of {@link Price}.\n */\nexport type SerializedPrice =\n | SerializedPriceEth\n | SerializedPriceDai\n | SerializedPriceUsdc\n | SerializedPriceEnsTokens;\n\nexport interface CurrencyInfo {\n id: CurrencyId;\n name: string;\n decimals: number;\n}\n\nconst currencyInfo: Record<CurrencyId, CurrencyInfo> = {\n [CurrencyIds.ETH]: {\n id: CurrencyIds.ETH,\n name: \"ETH\",\n decimals: 18,\n },\n [CurrencyIds.USDC]: {\n id: CurrencyIds.USDC,\n name: \"USDC\",\n decimals: 6,\n },\n [CurrencyIds.DAI]: {\n id: CurrencyIds.DAI,\n name: \"Dai Stablecoin\",\n decimals: 18,\n },\n [CurrencyIds.ENSTokens]: {\n id: CurrencyIds.ENSTokens,\n name: \"$ENS Tokens\",\n decimals: 18,\n },\n};\n\n/**\n * Get currency info for a provided currency.\n */\nexport function getCurrencyInfo(currencyId: CurrencyId): CurrencyInfo {\n return currencyInfo[currencyId];\n}\n\n/**\n * Create price in ETH for given amount.\n */\nexport function priceEth(amount: Price[\"amount\"]): PriceEth {\n return {\n amount,\n currency: CurrencyIds.ETH,\n };\n}\n\n/**\n * Create price in USDC for given amount.\n */\nexport function priceUsdc(amount: Price[\"amount\"]): PriceUsdc {\n return {\n amount,\n currency: CurrencyIds.USDC,\n };\n}\n\n/**\n * Create price in DAI for given amount.\n */\nexport function priceDai(amount: Price[\"amount\"]): PriceDai {\n return {\n amount,\n currency: CurrencyIds.DAI,\n };\n}\n\n/**\n * Create price in ENS Tokens for given amount.\n */\nexport function priceEnsTokens(amount: Price[\"amount\"]): PriceEnsTokens {\n return {\n amount,\n currency: CurrencyIds.ENSTokens,\n };\n}\n\n/**\n * Check if two prices have the same currency.\n */\nexport function isPriceCurrencyEqual(priceA: Price, priceB: Price): boolean {\n return priceA.currency === priceB.currency;\n}\n\n/**\n * Check if two {@link Price} values have the same currency and amount.\n */\nexport function isPriceEqual(priceA: Price, priceB: Price): boolean {\n return isPriceCurrencyEqual(priceA, priceB) && priceA.amount === priceB.amount;\n}\n\n/**\n * Add prices\n *\n * @param prices at least two {@link Price} values to be added together.\n * @returns total of all prices.\n * @throws if not all prices have the same currency.\n */\nexport function addPrices<const PriceType extends Price = Price>(\n ...prices: [PriceType, PriceType, ...PriceType[]]\n): PriceType {\n const firstPrice = prices[0];\n const allPricesInSameCurrency = prices.every((price) => isPriceCurrencyEqual(firstPrice, price));\n\n if (allPricesInSameCurrency === false) {\n throw new Error(\"All prices must have the same currency to be added together.\");\n }\n\n const { currency } = firstPrice;\n\n return prices.reduce(\n (acc, price) => ({\n amount: acc.amount + price.amount,\n currency,\n }),\n {\n amount: 0n,\n currency: firstPrice.currency,\n },\n ) as PriceType;\n}\n\n/**\n * Subtract price B from price A.\n *\n * @param a the minuend {@link Price} value.\n * @param b the subtrahend {@link Price} value.\n * @returns the resulting {@link Price} (`a - b`) with the same currency as the inputs.\n * @throws if the prices have different currencies.\n * @throws if the result would be negative ({@link CurrencyAmount} must be non-negative).\n */\nexport function subtractPrice<const PriceType extends Price = Price>(\n a: PriceType,\n b: PriceType,\n): PriceType {\n if (!isPriceCurrencyEqual(a, b)) {\n throw new Error(\"All prices must have the same currency to be subtracted.\");\n }\n\n const resultAmount = a.amount - b.amount;\n\n if (resultAmount < 0n) {\n throw new Error(\"subtractPrice result must be non-negative.\");\n }\n\n return { amount: resultAmount, currency: a.currency } as PriceType;\n}\n\n/**\n * Return the smallest of the given {@link Price} values.\n *\n * @param prices at least two {@link Price} values to compare.\n * @returns the {@link Price} with the smallest amount. Ties return the first\n * such value in argument order.\n * @throws if not all prices have the same currency.\n */\nexport function minPrice<const PriceType extends Price = Price>(\n ...prices: [PriceType, PriceType, ...PriceType[]]\n): PriceType {\n const firstPrice = prices[0];\n const allPricesInSameCurrency = prices.every((price) => isPriceCurrencyEqual(firstPrice, price));\n\n if (allPricesInSameCurrency === false) {\n throw new Error(\"All prices must have the same currency to be compared.\");\n }\n\n return prices.reduce((acc, price) => (price.amount < acc.amount ? price : acc));\n}\n\n/**\n * Return the largest of the given {@link Price} values.\n *\n * @param prices at least two {@link Price} values to compare.\n * @returns the {@link Price} with the largest amount. Ties return the first\n * such value in argument order.\n * @throws if not all prices have the same currency.\n */\nexport function maxPrice<const PriceType extends Price = Price>(\n ...prices: [PriceType, PriceType, ...PriceType[]]\n): PriceType {\n const firstPrice = prices[0];\n const allPricesInSameCurrency = prices.every((price) => isPriceCurrencyEqual(firstPrice, price));\n\n if (allPricesInSameCurrency === false) {\n throw new Error(\"All prices must have the same currency to be compared.\");\n }\n\n return prices.reduce((acc, price) => (price.amount > acc.amount ? price : acc));\n}\n\n/**\n * Scales a Price object by a floating-point number while maintaining precision.\n *\n * **Important:** The precision of this method is bound to the precision of float\n * in JavaScript. For more information, see {@link scaleBigintByNumber}.\n *\n * @param price - The Price object to scale\n * @param scaleFactor - The number to multiply by (can be a decimal like 0.5)\n * @returns A new Price object with the scaled amount and same currency\n *\n * @throws {Error} If scaleFactor is negative, NaN, or infinite\n * @throws {Error} If price amount is negative\n *\n * @example\n * // Scale USDC price by 0.5\n * const price = priceUsdc(1000000n); // 1 USDC\n * const scaled = scalePrice(price, 0.5); // 0.5 USDC\n * // scaled = { currency: \"USDC\", amount: 500000n }\n *\n * @example\n * // Calculate 33.3% of ETH price\n * const ethPrice = priceEth(1000000000000000000n); // 1 ETH\n * const share = scalePrice(ethPrice, 0.333);\n * // share = { currency: \"ETH\", amount: 333000000000000000n }\n */\nexport function scalePrice<T extends Price>(price: T, scaleFactor: number): T {\n const scaledAmount = scaleBigintByNumber(price.amount, scaleFactor);\n\n return {\n ...price,\n amount: scaledAmount,\n };\n}\n\n/**\n * Validates a decimal string for currency parsing.\n *\n * @param value - The decimal string to validate\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n */\nfunction validateAmountToParse(value: string): void {\n const trimmed = value.trim();\n if (trimmed === \"\") {\n throw new Error(\"amount must be a non-negative decimal string\");\n }\n if (value !== trimmed) {\n throw new Error(\"amount must not have leading or trailing whitespace\");\n }\n if (trimmed.startsWith(\"-\")) {\n throw new Error(\"amount must be a non-negative decimal string\");\n }\n}\n\n/**\n * Parses a string representation of ETH into a {@link PriceEth} object.\n *\n * Uses {@link getCurrencyInfo} to get the correct number of decimals (18) for ETH\n * and {@link parseUnits} from viem to convert the decimal string to a bigint.\n *\n * **Note:** Values with more than 18 decimal places will be truncated/rounded by viem's `parseUnits`.\n *\n * @param value - The decimal string to parse (e.g., \"0.015\" for 0.015 ETH)\n * @returns A PriceEth object with the amount in wei (smallest unit)\n *\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n * @throws {Error} If value is not a valid decimal string (e.g., \"abc\", \"1.2.3\")\n *\n * @example\n * parseEth(\"0.015\") // returns { currency: \"ETH\", amount: 15000000000000000n }\n * parseEth(\"1\") // returns { currency: \"ETH\", amount: 1000000000000000000n }\n * parseEth(\"123.456789012345678\") // returns { currency: \"ETH\", amount: 123456789012345678000n }\n */\nexport function parseEth(value: string): PriceEth {\n validateAmountToParse(value);\n const currencyInfo = getCurrencyInfo(CurrencyIds.ETH);\n const amount = parseUnits(value, currencyInfo.decimals);\n return priceEth(amount);\n}\n\n/**\n * Parses a string representation of USDC into a {@link PriceUsdc} object.\n *\n * Uses {@link getCurrencyInfo} to get the correct number of decimals (6) for USDC\n * and {@link parseUnits} from viem to convert the decimal string to a bigint.\n *\n * **Note:** Values with more than 6 decimal places will be truncated/rounded by viem's `parseUnits`.\n *\n * @param value - The decimal string to parse (e.g., \"123.45678\" for $123.45678)\n * @returns A PriceUsdc object with the amount in the smallest unit (6 decimals)\n *\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n * @throws {Error} If value is not a valid decimal string (e.g., \"abc\", \"1.2.3\")\n *\n * @example\n * parseUsdc(\"123.45678\") // returns { currency: \"USDC\", amount: 123456780n }\n * parseUsdc(\"1\") // returns { currency: \"USDC\", amount: 1000000n }\n * parseUsdc(\"0.001\") // returns { currency: \"USDC\", amount: 1000n }\n */\nexport function parseUsdc(value: string): PriceUsdc {\n validateAmountToParse(value);\n const currencyInfo = getCurrencyInfo(CurrencyIds.USDC);\n const amount = parseUnits(value, currencyInfo.decimals);\n return priceUsdc(amount);\n}\n\n/**\n * Parses a string representation of DAI into a {@link PriceDai} object.\n *\n * Uses {@link getCurrencyInfo} to get the correct number of decimals (18) for DAI\n * and {@link parseUnits} from viem to convert the decimal string to a bigint.\n *\n * **Note:** Values with more than 18 decimal places will be truncated/rounded by viem's `parseUnits`.\n *\n * @param value - The decimal string to parse (e.g., \"123.456789012345678\" for 123.456789012345678 DAI)\n * @returns A PriceDai object with the amount in the smallest unit (18 decimals)\n *\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n * @throws {Error} If value is not a valid decimal string (e.g., \"abc\", \"1.2.3\")\n *\n * @example\n * parseDai(\"123.456789012345678\") // returns { currency: \"DAI\", amount: 123456789012345678000n }\n * parseDai(\"1\") // returns { currency: \"DAI\", amount: 1000000000000000000n }\n * parseDai(\"0.001\") // returns { currency: \"DAI\", amount: 1000000000000000n }\n */\nexport function parseDai(value: string): PriceDai {\n validateAmountToParse(value);\n const currencyInfo = getCurrencyInfo(CurrencyIds.DAI);\n const amount = parseUnits(value, currencyInfo.decimals);\n return priceDai(amount);\n}\n\n/**\n * Parses a string representation of ENS Tokens into a {@link PriceEnsTokens} object.\n *\n * Uses {@link getCurrencyInfo} to get the correct number of decimals (18) for ENS Tokens\n * and {@link parseUnits} from viem to convert the decimal string to a bigint.\n *\n * **Note:** Values with more than 18 decimal places will be truncated/rounded by viem's `parseUnits`.\n *\n * @param value - The decimal string to parse (e.g., \"123.456789012345678\" for 123.456789012345678 ENS Tokens)\n * @returns A PriceEnsTokens object with the amount in the smallest unit (18 decimals)\n *\n * @throws {Error} If value is empty, whitespace-only or untrimmed\n * @throws {Error} If value represents a negative number\n * @throws {Error} If value is not a valid decimal string (e.g., \"abc\", \"1.2.3\")\n *\n * @example\n * parseEnsTokens(\"123.456789012345678\") // returns { currency: \"ENSTokens\", amount: 123456789012345678000n }\n * parseEnsTokens(\"1\") // returns { currency: \"ENSTokens\", amount: 1000000000000000000n }\n * parseEnsTokens(\"0.001\") // returns { currency: \"ENSTokens\", amount: 1000000000000000n }\n */\nexport function parseEnsTokens(value: string): PriceEnsTokens {\n validateAmountToParse(value);\n const currencyInfo = getCurrencyInfo(CurrencyIds.ENSTokens);\n const amount = parseUnits(value, currencyInfo.decimals);\n return priceEnsTokens(amount);\n}\n","/**\n * Filter out duplicates.\n */\nexport const uniq = <T>(arr: T[]): T[] => [...new Set(arr)];\n","import { ENSNamespaceIds } from \"@ensnode/datasources\";\n\nimport { type EnsIndexerPublicConfig, PluginName } from \"./types\";\n\n/**\n * Determines if the provided `config` results in indexing behavior compatible with the legacy ENS\n * Subgraph.\n *\n * @see https://ensnode.io/docs/concepts/what-is-the-ens-subgraph\n */\nexport function isSubgraphCompatible(\n config: Pick<EnsIndexerPublicConfig, \"namespace\" | \"plugins\" | \"clientLabelSet\">,\n): boolean {\n // 1. only the subgraph plugin is active\n const onlySubgraphPluginActivated =\n config.plugins.length === 1 && config.plugins[0] === PluginName.Subgraph;\n\n // 2. label set id must be \"subgraph\" and version must be 0\n const isSubgraphLabelSet =\n config.clientLabelSet.labelSetId === \"subgraph\" && config.clientLabelSet.labelSetVersion === 0;\n\n const isEnsTestEnvLabelSet =\n config.clientLabelSet.labelSetId === \"ens-test-env\" &&\n config.clientLabelSet.labelSetVersion === 0;\n\n // config should be considered subgraph-compatible if in ens-test-env namespace with ens-test-env labelset\n const labelSetIsSubgraphCompatible =\n isSubgraphLabelSet || (config.namespace === ENSNamespaceIds.EnsTestEnv && isEnsTestEnvLabelSet);\n\n return onlySubgraphPluginActivated && labelSetIsSubgraphCompatible;\n}\n","import type {\n EnsRainbowClientLabelSet,\n EnsRainbowServerLabelSet,\n LabelSetId,\n LabelSetVersion,\n} from \"../../ensrainbow\";\nimport {\n makeLabelSetIdSchema,\n makeLabelSetVersionStringSchema,\n} from \"../../ensrainbow/zod-schemas/config\";\n\n/**\n * Builds a valid LabelSetId from a string.\n * @param maybeLabelSetId - The string to validate and convert to a LabelSetId.\n * @returns A valid LabelSetId.\n * @throws If the input string is not a valid LabelSetId.\n */\nexport function buildLabelSetId(maybeLabelSetId: string): LabelSetId {\n return makeLabelSetIdSchema(\"LabelSetId\").parse(maybeLabelSetId);\n}\n\n/**\n * Builds a valid LabelSetVersion from a number or string.\n * @param maybeLabelSetVersion - The number or string to validate and convert to a LabelSetVersion.\n * @returns A valid LabelSetVersion.\n * @throws If the input is not a valid LabelSetVersion.\n */\nexport function buildLabelSetVersion(maybeLabelSetVersion: number | string): LabelSetVersion {\n return makeLabelSetVersionStringSchema(\"LabelSetVersion\").parse(maybeLabelSetVersion);\n}\n\n/**\n * Builds an EnsRainbowClientLabelSet.\n * @param labelSetId - The label set ID.\n * @param labelSetVersion - The label set version.\n * @returns A valid EnsRainbowClientLabelSet object.\n * @throws If `labelSetVersion` is defined without `labelSetId`.\n */\nexport function buildEnsRainbowClientLabelSet(\n labelSetId?: LabelSetId,\n labelSetVersion?: LabelSetVersion,\n): EnsRainbowClientLabelSet {\n if (labelSetVersion !== undefined && labelSetId === undefined) {\n throw new Error(\"When a labelSetVersion is defined, labelSetId must also be defined.\");\n }\n\n return { labelSetId, labelSetVersion };\n}\n\n/**\n * Validates that the server's label set is compatible with the client's requested label set.\n * @param serverSet - The label set provided by the server.\n * @param clientSet - The label set requested by the client.\n * @throws If the server set is not compatible with the client set.\n */\nexport function validateSupportedLabelSetAndVersion(\n serverSet: EnsRainbowServerLabelSet,\n clientSet: EnsRainbowClientLabelSet,\n): void {\n if (clientSet.labelSetId === undefined) {\n // Client did not specify a label set, so any server set is acceptable.\n return;\n }\n\n if (serverSet.labelSetId !== clientSet.labelSetId) {\n throw new Error(\n `Server label set ID \"${serverSet.labelSetId}\" does not match client's requested label set ID \"${clientSet.labelSetId}\".`,\n );\n }\n\n if (\n clientSet.labelSetVersion !== undefined &&\n serverSet.highestLabelSetVersion < clientSet.labelSetVersion\n ) {\n throw new Error(\n `Server highest label set version ${serverSet.highestLabelSetVersion} is less than client's requested version ${clientSet.labelSetVersion} for label set ID \"${clientSet.labelSetId}\".`,\n );\n }\n}\n","import type { ZodCheckFnInput } from \"../../shared/zod-types\";\nimport type { EnsIndexerVersionInfo } from \"./types\";\n\n/**\n * Invariant: ensDb version is same as ensIndexer version\n */\nexport function invariant_ensDbVersionIsSameAsEnsIndexerVersion(\n ctx: ZodCheckFnInput<EnsIndexerVersionInfo>,\n) {\n const versionInfo = ctx.value;\n\n if (versionInfo.ensDb !== versionInfo.ensIndexer) {\n ctx.issues.push({\n code: \"custom\",\n input: versionInfo,\n message: \"`ensDb` version must be same as `ensIndexer` version\",\n });\n }\n}\n","import { z } from \"zod/v4\";\n\n/**\n * Reasons why TheGraph fallback cannot be used.\n */\nexport const TheGraphCannotFallbackReasonSchema = z.enum({\n NotSubgraphCompatible: \"not-subgraph-compatible\",\n NoApiKey: \"no-api-key\",\n NoSubgraphUrl: \"no-subgraph-url\",\n});\n\nexport type TheGraphCannotFallbackReason = z.infer<typeof TheGraphCannotFallbackReasonSchema>;\n\n/**\n * Configuration for TheGraph fallback behavior.\n * Indicates whether fallback to TheGraph is possible and the reason if not.\n */\nexport const TheGraphFallbackSchema = z.discriminatedUnion(\"canFallback\", [\n z.strictObject({\n canFallback: z.literal(true),\n url: z.string(),\n }),\n z.strictObject({\n canFallback: z.literal(false),\n reason: TheGraphCannotFallbackReasonSchema,\n }),\n]);\n\nexport type TheGraphFallback = z.infer<typeof TheGraphFallbackSchema>;\n","import { z } from \"zod/v4\";\n\nimport {\n makeRealtimeIndexingStatusProjectionSchema,\n makeSerializedRealtimeIndexingStatusProjectionSchema,\n} from \"../../../indexing-status/zod-schema/realtime-indexing-status-projection\";\nimport {\n makeEnsNodeStackInfoSchema,\n makeSerializedEnsNodeStackInfoSchema,\n} from \"../../../stack-info/zod-schemas/ensnode-stack-info\";\nimport {\n type EnsApiIndexingStatusResponse,\n EnsApiIndexingStatusResponseCodes,\n type EnsApiIndexingStatusResponseError,\n type EnsApiIndexingStatusResponseOk,\n} from \"./response\";\nimport {\n SerializedEnsApiIndexingStatusResponse,\n SerializedEnsApiIndexingStatusResponseOk,\n} from \"./serialized-response\";\n\n/**\n * Schema for {@link EnsApiIndexingStatusResponseOk}\n **/\nexport const makeEnsApiIndexingStatusResponseOkSchema = (\n valueLabel: string = \"Indexing Status Response OK\",\n) =>\n z.strictObject({\n responseCode: z.literal(EnsApiIndexingStatusResponseCodes.Ok),\n realtimeProjection: makeRealtimeIndexingStatusProjectionSchema(valueLabel),\n stackInfo: makeEnsNodeStackInfoSchema(valueLabel),\n });\n\n/**\n * Schema for {@link EnsApiIndexingStatusResponseError}\n **/\nexport const makeEnsApiIndexingStatusResponseErrorSchema = (\n _valueLabel: string = \"Indexing Status Response Error\",\n) =>\n z.strictObject({\n responseCode: z.literal(EnsApiIndexingStatusResponseCodes.Error),\n });\n\n/**\n * Schema for {@link EnsApiIndexingStatusResponse}\n **/\nexport const makeEnsApiIndexingStatusResponseSchema = (\n valueLabel: string = \"Indexing Status Response\",\n) =>\n z.discriminatedUnion(\"responseCode\", [\n makeEnsApiIndexingStatusResponseOkSchema(valueLabel),\n makeEnsApiIndexingStatusResponseErrorSchema(valueLabel),\n ]);\n\n/**\n * Schema for {@link EnsApiIndexingStatusResponse}\n * @deprecated Use {@link makeEnsApiIndexingStatusResponseSchema} instead.\n */\nexport const makeIndexingStatusResponseSchema = makeEnsApiIndexingStatusResponseSchema;\n\n/**\n * Schema for {@link SerializedEnsApiIndexingStatusResponseOk}\n **/\nexport const makeSerializedEnsApiIndexingStatusResponseOkSchema = (\n valueLabel: string = \"Serialized Indexing Status Response OK\",\n) =>\n z.object({\n responseCode: z.literal(EnsApiIndexingStatusResponseCodes.Ok),\n realtimeProjection: makeSerializedRealtimeIndexingStatusProjectionSchema(valueLabel),\n stackInfo: makeSerializedEnsNodeStackInfoSchema(valueLabel),\n });\n\n/**\n * Schema for {@link SerializedEnsApiIndexingStatusResponse}\n **/\nexport const makeSerializedEnsApiIndexingStatusResponseSchema = (\n valueLabel: string = \"Serialized Indexing Status Response\",\n) =>\n z.discriminatedUnion(\"responseCode\", [\n makeSerializedEnsApiIndexingStatusResponseOkSchema(valueLabel),\n makeEnsApiIndexingStatusResponseErrorSchema(valueLabel),\n ]);\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport { makeDurationSchema, makeUnixTimestampSchema } from \"../../shared/zod-schemas\";\nimport type { RealtimeIndexingStatusProjection } from \"../realtime-indexing-status-projection\";\nimport {\n makeCrossChainIndexingStatusSnapshotSchema,\n makeSerializedCrossChainIndexingStatusSnapshotSchema,\n} from \"./cross-chain-indexing-status-snapshot\";\n\n/**\n * Invariant: For realtime indexing status projection,\n * `projectedAt` is after or same as `snapshot.snapshotTime`.\n */\nexport function invariant_realtimeIndexingStatusProjectionProjectedAtIsAfterOrEqualToSnapshotTime(\n ctx: ParsePayload<RealtimeIndexingStatusProjection>,\n) {\n const projection = ctx.value;\n\n const { snapshot, projectedAt } = projection;\n\n if (snapshot.snapshotTime > projectedAt) {\n ctx.issues.push({\n code: \"custom\",\n input: projection,\n message: \"`projectedAt` must be after or same as `snapshot.snapshotTime`.\",\n });\n }\n}\n\n/**\n * Invariant: For realtime indexing status projection,\n * `worstCaseDistance` is the difference between `projectedAt`\n * and `snapshot.slowestChainIndexingCursor`.\n */\nexport function invariant_realtimeIndexingStatusProjectionWorstCaseDistanceIsCorrect(\n ctx: ParsePayload<RealtimeIndexingStatusProjection>,\n) {\n const projection = ctx.value;\n const { projectedAt, snapshot, worstCaseDistance } = projection;\n const expectedWorstCaseDistance = projectedAt - snapshot.slowestChainIndexingCursor;\n\n if (worstCaseDistance !== expectedWorstCaseDistance) {\n ctx.issues.push({\n code: \"custom\",\n input: projection,\n message:\n \"`worstCaseDistance` must be the exact difference between `projectedAt` and `snapshot.slowestChainIndexingCursor`.\",\n });\n }\n}\n\n/**\n * Makes Zod schema for {@link RealtimeIndexingStatusProjection}\n */\nexport const makeRealtimeIndexingStatusProjectionSchema = (\n valueLabel: string = \"Realtime Indexing Status Projection\",\n) =>\n z\n .object({\n projectedAt: makeUnixTimestampSchema(valueLabel).describe(\n \"The timestamp representing 'now' as of the time this projection was generated.\",\n ),\n worstCaseDistance: makeDurationSchema(valueLabel).describe(\n \"The distance between `projectedAt` and `snapshot.slowestChainIndexingCursor` in seconds. This is a worst-case distance because it assumes no indexing progress has been made since `snapshot.snapshotTime` and that each indexed chain has added a new block as of `projectedAt`.\",\n ),\n snapshot: makeCrossChainIndexingStatusSnapshotSchema(valueLabel).describe(\n \"The cross-chain indexing status snapshot that this projection is based on.\",\n ),\n })\n .check(invariant_realtimeIndexingStatusProjectionProjectedAtIsAfterOrEqualToSnapshotTime)\n .check(invariant_realtimeIndexingStatusProjectionWorstCaseDistanceIsCorrect);\n\n/**\n * Makes Zod schema for {@link SerializedRealtimeIndexingStatusProjection}.\n */\nexport const makeSerializedRealtimeIndexingStatusProjectionSchema = (\n valueLabel: string = \"Value\",\n) =>\n z.object({\n snapshot: makeSerializedCrossChainIndexingStatusSnapshotSchema(valueLabel).describe(\n \"The cross-chain indexing status snapshot that this projection is based on.\",\n ),\n projectedAt: makeUnixTimestampSchema(valueLabel).describe(\n \"The timestamp representing 'now' as of the time this projection was generated.\",\n ),\n worstCaseDistance: makeDurationSchema(valueLabel).describe(\n \"The distance between `projectedAt` and `snapshot.slowestChainIndexingCursor` in seconds. This is a worst-case distance because it assumes no indexing progress has been made since `snapshot.snapshotTime` and that each indexed chain has added a new block as of `projectedAt`.\",\n ),\n });\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport { makeUnixTimestampSchema } from \"../../shared/zod-schemas\";\nimport {\n type CrossChainIndexingStatusSnapshotOmnichain,\n CrossChainIndexingStrategyIds,\n getHighestKnownBlockTimestamp,\n} from \"../cross-chain-indexing-status-snapshot\";\nimport type { SerializedCrossChainIndexingStatusSnapshot } from \"../serialize/cross-chain-indexing-status-snapshot\";\nimport {\n makeOmnichainIndexingStatusSnapshotSchema,\n makeSerializedOmnichainIndexingStatusSnapshotSchema,\n} from \"./omnichain-indexing-status-snapshot\";\n\n/**\n * Invariant: for cross-chain indexing status snapshot omnichain,\n * slowestChainIndexingCursor equals to omnichainSnapshot.omnichainIndexingCursor\n */\nexport function invariant_slowestChainEqualsToOmnichainSnapshotTime(\n ctx: ParsePayload<CrossChainIndexingStatusSnapshotOmnichain>,\n) {\n const { slowestChainIndexingCursor, omnichainSnapshot } = ctx.value;\n const { omnichainIndexingCursor } = omnichainSnapshot;\n\n if (slowestChainIndexingCursor !== omnichainIndexingCursor) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'slowestChainIndexingCursor' must be equal to 'omnichainSnapshot.omnichainIndexingCursor'`,\n });\n }\n}\n\n/**\n * Invariant: for cross-chain indexing status snapshot omnichain,\n * snapshotTime is greater than or equal to the \"highest known block\" timestamp.\n */\nexport function invariant_snapshotTimeIsTheHighestKnownBlockTimestamp(\n ctx: ParsePayload<CrossChainIndexingStatusSnapshotOmnichain>,\n) {\n const { snapshotTime, omnichainSnapshot } = ctx.value;\n const chains = Array.from(omnichainSnapshot.chains.values());\n const highestKnownBlockTimestamp = getHighestKnownBlockTimestamp(chains);\n\n if (snapshotTime < highestKnownBlockTimestamp) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'snapshotTime' (${snapshotTime}) must be greater than or equal to the \"highest known block timestamp\" (${highestKnownBlockTimestamp})`,\n });\n }\n}\n\n/**\n * Makes Zod schema for {@link CrossChainIndexingStatusSnapshotOmnichain}\n */\nconst makeCrossChainIndexingStatusSnapshotOmnichainSchema = (\n valueLabel: string = \"Cross-chain Indexing Status Snapshot Omnichain\",\n) =>\n z\n .object({\n strategy: z.literal(CrossChainIndexingStrategyIds.Omnichain),\n slowestChainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n snapshotTime: makeUnixTimestampSchema(valueLabel),\n omnichainSnapshot: makeOmnichainIndexingStatusSnapshotSchema(valueLabel),\n })\n .check(invariant_slowestChainEqualsToOmnichainSnapshotTime)\n .check(invariant_snapshotTimeIsTheHighestKnownBlockTimestamp);\n\n/**\n * Makes Zod schema for {@link CrossChainIndexingStatusSnapshot}\n */\nexport const makeCrossChainIndexingStatusSnapshotSchema = (\n valueLabel: string = \"Cross-chain Indexing Status Snapshot\",\n) =>\n z.discriminatedUnion(\"strategy\", [\n makeCrossChainIndexingStatusSnapshotOmnichainSchema(valueLabel),\n ]);\n\n/**\n * Makes Zod schema for {@link SerializedCrossChainIndexingStatusSnapshot}\n */\nexport const makeSerializedCrossChainIndexingStatusSnapshotSchema = (\n valueLabel: string = \"Serialized Cross-chain Indexing Status Snapshot\",\n) =>\n z.object({\n strategy: z.enum(CrossChainIndexingStrategyIds),\n slowestChainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n snapshotTime: makeUnixTimestampSchema(valueLabel),\n omnichainSnapshot: makeSerializedOmnichainIndexingStatusSnapshotSchema(valueLabel),\n });\n","import type { BlockRef } from \"./types\";\n\n/**\n * Compare two {@link BlockRef} objects to check\n * if blockA is before blockB.\n *\n * Ordering is determined by block number, which is the canonical\n * ordering on a single chain. Timestamp is not used because EVM\n * chains allow consecutive blocks to share the same timestamp.\n */\nexport function isBefore(blockA: BlockRef, blockB: BlockRef) {\n return blockA.number < blockB.number;\n}\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is equal to blockB.\n */\nexport function isEqualTo(blockA: BlockRef, blockB: BlockRef) {\n return blockA.number === blockB.number && blockA.timestamp === blockB.timestamp;\n}\n\n/**\n * Compare two {@link BlockRef} object to check\n * if blockA is before or equal to blockB.\n */\nexport function isBeforeOrEqualTo(blockA: BlockRef, blockB: BlockRef) {\n return isBefore(blockA, blockB) || isEqualTo(blockA, blockB);\n}\n","import { isBeforeOrEqualTo as isBlockRefBeforeOrEqualTo } from \"./block-ref\";\nimport type { BlockNumber, BlockRef } from \"./types\";\n\nexport const RangeTypeIds = {\n Unbounded: \"unbounded\",\n LeftBounded: \"left-bounded\",\n RightBounded: \"right-bounded\",\n Bounded: \"bounded\",\n} as const;\n\nexport type RangeType = (typeof RangeTypeIds)[keyof typeof RangeTypeIds];\n\n/************************\n * Block number range\n ***********************/\n\n/**\n * Block number range unbounded\n */\nexport interface BlockNumberRangeUnbounded {\n rangeType: typeof RangeTypeIds.Unbounded;\n startBlock?: undefined;\n endBlock?: undefined;\n}\n\n/**\n * Block number range left bounded\n *\n * Range is inclusive of its left bound.\n */\nexport interface BlockNumberRangeLeftBounded {\n rangeType: typeof RangeTypeIds.LeftBounded;\n startBlock: BlockNumber;\n endBlock?: undefined;\n}\n\n/**\n * Block number range right bounded\n *\n * Range is inclusive of its right bound.\n */\nexport interface BlockNumberRangeRightBounded {\n rangeType: typeof RangeTypeIds.RightBounded;\n startBlock?: undefined;\n endBlock: BlockNumber;\n}\n\n/**\n * Block number range bounded\n *\n * Range is inclusive of its bounds.\n *\n * Invariants:\n * - `startBlock` is lower than or equal to `endBlock`\n */\nexport interface BlockNumberRangeBounded {\n rangeType: typeof RangeTypeIds.Bounded;\n startBlock: BlockNumber;\n endBlock: BlockNumber;\n}\n\n/**\n * Block number range with start block defined.\n *\n * This is a useful type for representing block ranges for indexed chains.\n */\nexport type BlockNumberRangeWithStartBlock = BlockNumberRangeLeftBounded | BlockNumberRangeBounded;\n\n/**\n * Block number range\n *\n * Use the `rangeType` field to determine the specific type interpretation\n * at runtime.\n */\nexport type BlockNumberRange =\n | BlockNumberRangeUnbounded\n | BlockNumberRangeLeftBounded\n | BlockNumberRangeRightBounded\n | BlockNumberRangeBounded;\n\n/**\n * Build a block number range object.\n */\nexport function buildBlockNumberRange(\n startBlock: undefined,\n endBlock: undefined,\n): BlockNumberRangeUnbounded;\nexport function buildBlockNumberRange(\n startBlock: BlockNumber,\n endBlock: undefined,\n): BlockNumberRangeLeftBounded;\nexport function buildBlockNumberRange(\n startBlock: undefined,\n endBlock: BlockNumber,\n): BlockNumberRangeRightBounded;\nexport function buildBlockNumberRange(\n startBlock: BlockNumber,\n endBlock: BlockNumber,\n): BlockNumberRangeBounded;\nexport function buildBlockNumberRange(\n startBlock?: BlockNumber,\n endBlock?: BlockNumber,\n): BlockNumberRange;\nexport function buildBlockNumberRange(\n startBlock?: BlockNumber,\n endBlock?: BlockNumber,\n): BlockNumberRange {\n if (startBlock === undefined && endBlock === undefined) {\n return {\n rangeType: RangeTypeIds.Unbounded,\n } satisfies BlockNumberRangeUnbounded;\n }\n\n if (startBlock !== undefined && endBlock === undefined) {\n return {\n rangeType: RangeTypeIds.LeftBounded,\n startBlock,\n } satisfies BlockNumberRangeLeftBounded;\n }\n\n if (startBlock === undefined && endBlock !== undefined) {\n return {\n rangeType: RangeTypeIds.RightBounded,\n endBlock,\n } satisfies BlockNumberRangeRightBounded;\n }\n\n if (startBlock !== undefined && endBlock !== undefined) {\n // Invariant: `startBlock` is lower than or equal to `endBlock`\n if (startBlock > endBlock) {\n throw new Error(\n `For a block number range startBlock must be lower than or equal to endBlock.`,\n );\n }\n\n return {\n rangeType: RangeTypeIds.Bounded,\n startBlock,\n endBlock,\n } satisfies BlockNumberRangeBounded;\n }\n\n // This should be unreachable, but TypeScript needs the exhaustive check\n throw new Error(\"Invalid block number range. This should be unreachable.\");\n}\n\n/**\n * Merge multiple block number ranges into a single range.\n *\n * The resulting range is a union that covers all input ranges:\n * - Uses the minimum start block when every input range has a start block\n * - Uses the maximum end block when every input range has an end block\n * - Leaves a side unbounded when any input range is unbounded on that side\n *\n * Returns an unbounded range if no ranges are provided.\n *\n * @param ranges - The block number ranges to merge\n * @returns A single merged block number range covering all inputs\n */\nexport function mergeBlockNumberRanges(...ranges: BlockNumberRange[]): BlockNumberRange {\n if (ranges.length === 0) {\n return buildBlockNumberRange(undefined, undefined);\n }\n\n let minStartBlock: BlockNumber | undefined;\n let maxEndBlock: BlockNumber | undefined;\n let hasUnboundedStart = false;\n let hasUnboundedEnd = false;\n\n for (const range of ranges) {\n if (range.startBlock === undefined) {\n hasUnboundedStart = true;\n } else if (minStartBlock === undefined || range.startBlock < minStartBlock) {\n minStartBlock = range.startBlock;\n }\n\n if (range.endBlock === undefined) {\n hasUnboundedEnd = true;\n } else if (maxEndBlock === undefined || range.endBlock > maxEndBlock) {\n maxEndBlock = range.endBlock;\n }\n\n // Early return if the merged range is already unbounded\n if (hasUnboundedStart && hasUnboundedEnd) {\n return buildBlockNumberRange(undefined, undefined);\n }\n }\n\n // The merged range has an unbounded start if any input range has\n // an unbounded start\n if (hasUnboundedStart) {\n minStartBlock = undefined;\n }\n\n // The merged range has an unbounded end if any input range has\n // an unbounded end\n if (hasUnboundedEnd) {\n maxEndBlock = undefined;\n }\n\n return buildBlockNumberRange(minStartBlock, maxEndBlock);\n}\n\n/************************\n * Block ref range\n ***********************/\n\n/**\n * Block ref range unbounded\n */\nexport interface BlockRefRangeUnbounded {\n rangeType: typeof RangeTypeIds.Unbounded;\n startBlock?: undefined;\n endBlock?: undefined;\n}\n\n/**\n * Block ref range left bounded\n *\n * Range is inclusive of its left bound.\n */\nexport interface BlockRefRangeLeftBounded {\n rangeType: typeof RangeTypeIds.LeftBounded;\n startBlock: BlockRef;\n endBlock?: undefined;\n}\n\n/**\n * Block ref range right bounded\n *\n * Range is inclusive of its right bound.\n */\nexport interface BlockRefRangeRightBounded {\n rangeType: typeof RangeTypeIds.RightBounded;\n startBlock?: undefined;\n endBlock: BlockRef;\n}\n\n/**\n * Block ref range bounded\n *\n * Range is inclusive of its bounds.\n *\n * Invariants:\n * - `startBlock` is before or equal to `endBlock`\n */\nexport interface BlockRefRangeBounded {\n rangeType: typeof RangeTypeIds.Bounded;\n startBlock: BlockRef;\n endBlock: BlockRef;\n}\n\n/**\n * Block ref range\n *\n * Use the `rangeType` field to determine the specific type interpretation\n * at runtime.\n */\nexport type BlockRefRange =\n | BlockRefRangeUnbounded\n | BlockRefRangeLeftBounded\n | BlockRefRangeRightBounded\n | BlockRefRangeBounded;\n\n/**\n * Block ref range with start block defined.\n *\n * This is a useful type for representing block ranges for indexed chains.\n */\nexport type BlockRefRangeWithStartBlock = BlockRefRangeLeftBounded | BlockRefRangeBounded;\n\n/**\n * Build a block ref range object.\n */\nexport function buildBlockRefRange(\n startBlock: undefined,\n endBlock: undefined,\n): BlockRefRangeUnbounded;\nexport function buildBlockRefRange(\n startBlock: BlockRef,\n endBlock: undefined,\n): BlockRefRangeLeftBounded;\nexport function buildBlockRefRange(\n startBlock: undefined,\n endBlock: BlockRef,\n): BlockRefRangeRightBounded;\nexport function buildBlockRefRange(startBlock: BlockRef, endBlock: BlockRef): BlockRefRangeBounded;\nexport function buildBlockRefRange(startBlock?: BlockRef, endBlock?: BlockRef): BlockRefRange;\nexport function buildBlockRefRange(startBlock?: BlockRef, endBlock?: BlockRef): BlockRefRange {\n if (startBlock === undefined && endBlock === undefined) {\n return {\n rangeType: RangeTypeIds.Unbounded,\n } satisfies BlockRefRangeUnbounded;\n }\n\n if (startBlock !== undefined && endBlock === undefined) {\n return {\n rangeType: RangeTypeIds.LeftBounded,\n startBlock,\n } satisfies BlockRefRangeLeftBounded;\n }\n\n if (startBlock === undefined && endBlock !== undefined) {\n return {\n rangeType: RangeTypeIds.RightBounded,\n endBlock,\n } satisfies BlockRefRangeRightBounded;\n }\n\n if (startBlock !== undefined && endBlock !== undefined) {\n // Invariant: `startBlock` is before or equal to `endBlock`\n if (isBlockRefBeforeOrEqualTo(startBlock, endBlock) === false) {\n throw new Error(`For a block ref range startBlock must be before or equal to endBlock.`);\n }\n\n return {\n rangeType: RangeTypeIds.Bounded,\n startBlock,\n endBlock,\n } satisfies BlockRefRangeBounded;\n }\n\n // This should be unreachable, but TypeScript needs the exhaustive check\n throw new Error(\"Invalid block ref range. This should be unreachable.\");\n}\n","import type { ChainId, UnixTimestamp } from \"enssdk\";\n\nimport {\n type BlockRefRangeBounded,\n type BlockRefRangeLeftBounded,\n type BlockRefRangeWithStartBlock,\n RangeTypeIds,\n} from \"../shared/blockrange\";\nimport type { BlockRef } from \"../shared/types\";\n\n/**\n * The status of indexing a chain at the time an indexing status snapshot\n * is captured.\n */\nexport const ChainIndexingStatusIds = {\n /**\n * Represents that indexing of the chain is not ready to begin yet because:\n * - ENSIndexer is in its initialization phase and the data to build a\n * \"true\" {@link ChainIndexingStatusSnapshot} for the chain is still being loaded; or\n * - ENSIndexer is using an omnichain indexing strategy and the\n * `omnichainIndexingCursor` is <= `config.startBlock.timestamp` for the chain's\n * {@link ChainIndexingStatusSnapshot}.\n */\n Queued: \"chain-queued\",\n\n /**\n * Represents that indexing of the chain is in progress and under a special\n * \"backfill\" phase that optimizes for accelerated indexing until reaching the\n * \"fixed target\" `backfillEndBlock`.\n */\n Backfill: \"chain-backfill\",\n\n /**\n * Represents that the \"backfill\" phase of indexing the chain is completed\n * and that the chain is configured to be indexed for an indefinite range.\n * Therefore, indexing of the chain remains indefinitely in progress where\n * ENSIndexer will continuously work to discover and index new blocks as they\n * are added to the chain across time.\n */\n Following: \"chain-following\",\n\n /**\n * Represents that indexing of the chain is completed as the chain is configured\n * to be indexed for a definite range and the indexing of all blocks through\n * that definite range is completed.\n */\n Completed: \"chain-completed\",\n} as const;\n\n/**\n * The derived string union of possible {@link ChainIndexingStatusIds}.\n */\nexport type ChainIndexingStatusId =\n (typeof ChainIndexingStatusIds)[keyof typeof ChainIndexingStatusIds];\n\n/**\n * Chain indexing status snapshot for a chain whose `chainStatus` is\n * {@link ChainIndexingStatusIds.Queued}.\n *\n * Invariants:\n * - `chainStatus` is always {@link ChainIndexingStatusIds.Queued}.\n */\nexport interface ChainIndexingStatusSnapshotQueued {\n /**\n * The status of indexing the chain at the time the indexing status snapshot\n * was captured.\n */\n chainStatus: typeof ChainIndexingStatusIds.Queued;\n\n /**\n * The indexing configuration of the chain.\n */\n config: BlockRefRangeWithStartBlock;\n}\n\n/**\n * Chain indexing status snapshot for a chain whose `chainStatus` is\n * {@link ChainIndexingStatusIds.Backfill}.\n *\n * During a backfill, special performance optimizations are applied to\n * index all blocks between `config.startBlock` and `backfillEndBlock`\n * as fast as possible.\n *\n * Note how `backfillEndBlock` is a \"fixed target\" that does not change during\n * the lifetime of an ENSIndexer process instance:\n * - If the `config` is {@link BlockRefRangeBounded}:\n * `backfillEndBlock` is always the same as `config.endBlock`.\n * - If the `config` is {@link BlockRefRangeLeftBounded}:\n * `backfillEndBlock` is a {@link BlockRef} to what was the latest block on the\n * chain when the ENSIndexer process was performing its initialization. Note how\n * this means that if the backfill process takes X hours to complete, because the\n * `backfillEndBlock` is a \"fixed target\", when `chainStatus` transitions to\n * {@link ChainIndexingStatusIds.Following} the chain will be X hours behind\n * \"realtime\" indexing.\n *\n * When `latestIndexedBlock` reaches `backfillEndBlock` the backfill is complete.\n * The moment backfill is complete the `chainStatus` may not immediately transition.\n * Instead, internal processing is completed for a period of time while\n * `chainStatus` remains {@link ChainIndexingStatusIds.Backfill}. After this internal\n * processing is completed `chainStatus` will transition:\n * - to {@link ChainIndexingStatusIds.Following} if the `config` is\n * {@link BlockRefRangeLeftBounded}.\n * - to {@link ChainIndexingStatusIds.Completed} if the `config` is\n * {@link BlockRefRangeBounded}.\n *\n * Invariants:\n * - `chainStatus` is always {@link ChainIndexingStatusIds.Backfill}.\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `config.endBlock` is always the same as `backfillEndBlock` if and only if\n * the config is {@link BlockRefRangeBounded}.\n * - `latestIndexedBlock` is always before or the same as `backfillEndBlock`\n */\nexport interface ChainIndexingStatusSnapshotBackfill {\n /**\n * The status of indexing the chain at the time the indexing status snapshot\n * was captured.\n */\n chainStatus: typeof ChainIndexingStatusIds.Backfill;\n\n /**\n * The indexing configuration of the chain.\n */\n config: BlockRefRangeWithStartBlock;\n\n /**\n * A {@link BlockRef} to the block that was most recently indexed as of the time the\n * indexing status snapshot was captured.\n */\n latestIndexedBlock: BlockRef;\n\n /**\n * A {@link BlockRef} to the block where the backfill will end.\n */\n backfillEndBlock: BlockRef;\n}\n\n/**\n * Chain indexing status snapshot for a chain whose `chainStatus` is\n * {@link ChainIndexingStatusIds.Following}.\n *\n * Invariants:\n * - `chainStatus` is always {@link ChainIndexingStatusIds.Following}.\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always before or the same as `latestKnownBlock`\n */\nexport interface ChainIndexingStatusSnapshotFollowing {\n /**\n * The status of indexing the chain at the time the indexing status snapshot\n * was captured.\n */\n chainStatus: typeof ChainIndexingStatusIds.Following;\n\n /**\n * The indexing configuration of the chain.\n */\n config: BlockRefRangeLeftBounded;\n\n /**\n * A {@link BlockRef} to the block that was most recently indexed as of the time the\n * indexing status snapshot was captured.\n */\n latestIndexedBlock: BlockRef;\n\n /**\n * A {@link BlockRef} to the \"highest\" block that has been discovered by RPCs\n * and stored in the RPC cache as of the time the indexing status snapshot was\n * captured.\n */\n latestKnownBlock: BlockRef;\n}\n\n/**\n * Chain indexing status snapshot for a chain whose `chainStatus` is\n * {@link ChainIndexingStatusIds.Completed}.\n *\n * After the backfill of a chain is completed, if the chain was configured\n * to be indexed for a definite range, the chain indexing status will transition to\n * {@link ChainIndexingStatusIds.Completed}.\n *\n * Invariants:\n * - `chainStatus` is always {@link ChainIndexingStatusIds.Completed}.\n * - `config.startBlock` is always before or the same as `latestIndexedBlock`\n * - `latestIndexedBlock` is always the same as `config.endBlock`.\n */\nexport interface ChainIndexingStatusSnapshotCompleted {\n /**\n * The status of indexing the chain at the time the indexing status snapshot\n * was captured.\n */\n chainStatus: typeof ChainIndexingStatusIds.Completed;\n\n /**\n * The indexing configuration of the chain.\n */\n config: BlockRefRangeBounded;\n\n /**\n * A {@link BlockRef} to the block that was most recently indexed as of the time the\n * indexing status snapshot was captured.\n */\n latestIndexedBlock: BlockRef;\n}\n\n/**\n * Indexing status snapshot for a single chain.\n *\n * Use the `chainStatus` field to determine the specific type interpretation\n * at runtime.\n */\nexport type ChainIndexingStatusSnapshot =\n | ChainIndexingStatusSnapshotQueued\n | ChainIndexingStatusSnapshotBackfill\n | ChainIndexingStatusSnapshotFollowing\n | ChainIndexingStatusSnapshotCompleted;\n\n/**\n * Get the timestamp of the lowest `config.startBlock` across all chains\n * in the provided array of {@link ChainIndexingStatusSnapshot}.\n *\n * Such timestamp is useful when presenting the \"lowest\" block\n * to be indexed across all chains.\n */\nexport function getTimestampForLowestOmnichainStartBlock(\n chains: ChainIndexingStatusSnapshot[],\n): UnixTimestamp {\n const earliestKnownBlockTimestamps: UnixTimestamp[] = chains.map(\n (chain) => chain.config.startBlock.timestamp,\n );\n\n // Invariant: earliestKnownBlockTimestamps is guaranteed to have at least one element\n if (earliestKnownBlockTimestamps.length === 0) {\n throw new Error(\n \"Invariant violation: at least one chain is required to determine the lowest omnichain start block timestamp\",\n );\n }\n\n return Math.min(...earliestKnownBlockTimestamps);\n}\n\n/**\n * Get the timestamp of the \"highest known block\" across all chains\n * in the provided array of {@link ChainIndexingStatusSnapshot}.\n *\n * Such timestamp is useful when presenting the \"highest known block\"\n * to be indexed across all chains.\n *\n * The \"highest known block\" for a chain depends on its status:\n * - `config.endBlock` for a \"queued\" chain (only if the config range type is `Bounded`),\n * - `backfillEndBlock` for a \"backfill\" chain,\n * - `latestIndexedBlock` for a \"completed\" chain,\n * - `latestKnownBlock` for a \"following\" chain.\n */\nexport function getTimestampForHighestOmnichainKnownBlock(\n chains: ChainIndexingStatusSnapshot[],\n): UnixTimestamp {\n const latestKnownBlockTimestamps: UnixTimestamp[] = [];\n\n for (const chain of chains) {\n switch (chain.chainStatus) {\n case ChainIndexingStatusIds.Queued:\n if (chain.config.rangeType === RangeTypeIds.Bounded) {\n latestKnownBlockTimestamps.push(chain.config.endBlock.timestamp);\n }\n break;\n\n case ChainIndexingStatusIds.Backfill:\n latestKnownBlockTimestamps.push(chain.backfillEndBlock.timestamp);\n\n break;\n\n case ChainIndexingStatusIds.Completed:\n latestKnownBlockTimestamps.push(chain.latestIndexedBlock.timestamp);\n break;\n\n case ChainIndexingStatusIds.Following:\n latestKnownBlockTimestamps.push(chain.latestKnownBlock.timestamp);\n break;\n }\n }\n\n // Invariant: at least one chain must contribute a known block timestamp\n // (e.g., Queued chains with Indefinite config do not contribute)\n if (latestKnownBlockTimestamps.length === 0) {\n throw new Error(\n \"Invariant: at least one chain must contribute a known block timestamp to determine the highest omnichain known block timestamp\",\n );\n }\n\n return Math.max(...latestKnownBlockTimestamps);\n}\n\n/**\n * Sort a list of [{@link ChainId}, {@link ChainIndexingStatusSnapshot}] tuples\n * by the omnichain start block timestamp in ascending order.\n */\nexport function sortChainStatusesByStartBlockAsc<\n ChainStatusType extends ChainIndexingStatusSnapshot,\n>(chains: [ChainId, ChainStatusType][]): [ChainId, ChainStatusType][] {\n // Sort the chain statuses by the omnichain first block to index timestamp\n return [...chains].sort(\n ([, chainA], [, chainB]) =>\n chainA.config.startBlock.timestamp - chainB.config.startBlock.timestamp,\n );\n}\n","import type { ChainId, UnixTimestamp } from \"enssdk\";\n\nimport { RangeTypeIds } from \"../shared/blockrange\";\nimport type { BlockRef } from \"../shared/types\";\nimport {\n ChainIndexingStatusIds,\n type ChainIndexingStatusSnapshot,\n} from \"./chain-indexing-status-snapshot\";\nimport type { OmnichainIndexingStatusSnapshot } from \"./omnichain-indexing-status-snapshot\";\nimport { validateCrossChainIndexingStatusSnapshot } from \"./validate/cross-chain-indexing-status-snapshot\";\n\n/**\n * The strategy used for indexing one or more chains.\n *\n * @see https://ponder.sh/docs/api-reference/ponder/config#parameters\n */\nexport const CrossChainIndexingStrategyIds = {\n /**\n * Represents that the indexing of events across all indexed chains will\n * proceed in a deterministic \"omnichain\" ordering by block timestamp, chain ID,\n * and block number.\n *\n * This strategy is \"deterministic\" in that the order of processing cross-chain indexed\n * events and each resulting indexed data state transition recorded in ENSDb is always\n * the same for each ENSIndexer instance operating with an equivalent\n * `ENSIndexerConfig` and ENSIndexer version. However it also has the drawbacks of:\n * - increased indexing latency that must wait for the slowest indexed chain to\n * add new blocks or to discover new blocks through the configured RPCs.\n * - if any indexed chain gets \"stuck\" due to chain or RPC failures, all indexed chains\n * will be affected.\n */\n Omnichain: \"omnichain\",\n} as const;\n\n/**\n * The derived string union of possible {@link CrossChainIndexingStrategyIds}.\n */\nexport type CrossChainIndexingStrategyId =\n (typeof CrossChainIndexingStrategyIds)[keyof typeof CrossChainIndexingStrategyIds];\n\n/**\n * Cross-chain indexing status snapshot when the `strategy` is\n * {@link CrossChainIndexingStrategyId.Omnichain}.\n *\n * Invariants:\n * - `strategy` is always {@link CrossChainIndexingStrategyId.Omnichain}.\n * - `slowestChainIndexingCursor` is always equal to\n * `omnichainSnapshot.omnichainIndexingCursor`.\n * - `snapshotTime` is always >= the \"highest known block timestamp\", defined as the max of:\n * - the `slowestChainIndexingCursor`.\n * - the `config.startBlock.timestamp` for all indexed chains.\n * - the `config.endBlock.timestamp` for all indexed chains with a `config.rangeType` of\n * {@link RangeTypeIds.Bounded}.\n * - the `backfillEndBlock.timestamp` for all chains with `chainStatus` of\n * {@link ChainIndexingStatusIds.Backfill}.\n * - the `latestKnownBlock.timestamp` for all chains with `chainStatus` of\n * {@link ChainIndexingStatusIds.Following}.\n */\nexport interface CrossChainIndexingStatusSnapshotOmnichain {\n /**\n * The strategy used for indexing one or more chains.\n */\n strategy: typeof CrossChainIndexingStrategyIds.Omnichain;\n\n /**\n * The timestamp of the \"slowest\" latest indexed block timestamp\n * across all indexed chains.\n */\n slowestChainIndexingCursor: UnixTimestamp;\n\n /**\n * The timestamp when the cross-chain indexing status snapshot was generated.\n *\n * Due to possible clock skew between different systems this value must be set\n * to the max of each of the following values to ensure all invariants are followed:\n * - the current system time of the system generating this cross-chain indexing\n * status snapshot.\n * - the \"highest known block timestamp\" (see invariants above for full definition).\n */\n snapshotTime: UnixTimestamp;\n\n /**\n * The omnichain indexing status snapshot for one or more chains.\n */\n omnichainSnapshot: OmnichainIndexingStatusSnapshot;\n}\n\n/**\n * Cross-chain indexing status snapshot for one or more chains.\n *\n * Use the `strategy` field to determine the specific type interpretation\n * at runtime.\n *\n * Currently, only omnichain indexing is supported. This type could theoretically\n * be extended to support other cross-chain indexing strategies in the future,\n * such as Ponder's \"multichain\" indexing strategy that indexes each chain\n * independently without deterministic ordering.\n */\nexport type CrossChainIndexingStatusSnapshot = CrossChainIndexingStatusSnapshotOmnichain;\n\n/**\n * Gets the latest indexed {@link BlockRef} for the given {@link ChainId}.\n *\n * @returns the latest indexed {@link BlockRef} for the given {@link ChainId}, or null if the chain\n * isn't being indexed at all or is queued and therefore hasn't started indexing yet.\n */\nexport function getLatestIndexedBlockRef(\n indexingStatus: CrossChainIndexingStatusSnapshot,\n chainId: ChainId,\n): BlockRef | null {\n const chainIndexingStatus = indexingStatus.omnichainSnapshot.chains.get(chainId);\n\n if (chainIndexingStatus === undefined) {\n // chain isn't being indexed at all\n return null;\n }\n\n if (chainIndexingStatus.chainStatus === ChainIndexingStatusIds.Queued) {\n // chain is queued, so no data for the chain has been indexed yet\n return null;\n }\n\n return chainIndexingStatus.latestIndexedBlock;\n}\n\n/**\n * Get the \"highest known block timestamp\" from chain indexing status snapshots.\n *\n * Returns the maximum timestamp referenced anywhere in the provided chain snapshots,\n * across all of:\n * - `config.startBlock` timestamps for all chains\n * - `config.endBlock` timestamps for bounded chains\n * - `backfillEndBlock` timestamps for chains in backfill status\n * - `latestKnownBlock` timestamps for chains in following status\n *\n * This is used to enforce the invariant that `snapshotTime` must be >= all\n * referenced block timestamps. It differs from {@link getTimestampForHighestOmnichainKnownBlock},\n * which computes the highest \"target\" block timestamp for progress display and\n * does not include `startBlock` timestamps.\n *\n * @throws Error if `chains` is empty.\n */\nexport function getHighestKnownBlockTimestamp(\n chains: ChainIndexingStatusSnapshot[],\n): UnixTimestamp {\n if (chains.length === 0) {\n throw new Error(\n \"Invariant violation: at least one chain is required to determine the highest known block timestamp\",\n );\n }\n\n const startBlockTimestamps = chains.map((chain) => chain.config.startBlock.timestamp);\n\n const endBlockTimestamps = chains\n .map((chain) => chain.config)\n .filter((chainConfig) => chainConfig.rangeType === RangeTypeIds.Bounded)\n .map((chainConfig) => chainConfig.endBlock.timestamp);\n\n const backfillEndBlockTimestamps = chains\n .filter((chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill)\n .map((chain) => chain.backfillEndBlock.timestamp);\n\n const latestKnownBlockTimestamps = chains\n .filter((chain) => chain.chainStatus === ChainIndexingStatusIds.Following)\n .map((chain) => chain.latestKnownBlock.timestamp);\n\n return Math.max(\n ...startBlockTimestamps,\n ...endBlockTimestamps,\n ...backfillEndBlockTimestamps,\n ...latestKnownBlockTimestamps,\n );\n}\n\n/**\n * Build a Cross-Chain Indexing Status Snapshot based on the omnichain indexing status snapshot.\n *\n * @param omnichainSnapshot - The omnichain indexing status snapshot.\n * @param snapshotTime - The timestamp when the cross-chain indexing status snapshot was generated.\n * Will be adjusted upward if necessary to satisfy the invariant that snapshotTime must\n * be >= the highest known block timestamp (handles clock skew and future block timestamps).\n * @returns The cross-chain indexing status snapshot.\n * @throws if the generated snapshot does not satisfy the invariants defined\n * in {@link CrossChainIndexingStatusSnapshotOmnichain}\n */\nexport function buildCrossChainIndexingStatusSnapshotOmnichain(\n omnichainSnapshot: OmnichainIndexingStatusSnapshot,\n snapshotTime: UnixTimestamp,\n): CrossChainIndexingStatusSnapshotOmnichain {\n const chains = Array.from(omnichainSnapshot.chains.values());\n const adjustedSnapshotTime = Math.max(snapshotTime, getHighestKnownBlockTimestamp(chains));\n\n return validateCrossChainIndexingStatusSnapshot({\n strategy: CrossChainIndexingStrategyIds.Omnichain,\n slowestChainIndexingCursor: omnichainSnapshot.omnichainIndexingCursor,\n omnichainSnapshot,\n snapshotTime: adjustedSnapshotTime,\n });\n}\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport {\n makeChainIdSchema,\n makeChainIdStringSchema,\n makeUnixTimestampSchema,\n} from \"../../shared/zod-schemas\";\nimport { ChainIndexingStatusIds } from \"../chain-indexing-status-snapshot\";\nimport {\n checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill,\n checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted,\n checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing,\n checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted,\n getOmnichainIndexingStatus,\n OmnichainIndexingStatusIds,\n type OmnichainIndexingStatusSnapshot,\n type OmnichainIndexingStatusSnapshotBackfill,\n type OmnichainIndexingStatusSnapshotCompleted,\n type OmnichainIndexingStatusSnapshotFollowing,\n type OmnichainIndexingStatusSnapshotUnstarted,\n} from \"../omnichain-indexing-status-snapshot\";\nimport {\n SerializedOmnichainIndexingStatusSnapshot,\n SerializedOmnichainIndexingStatusSnapshotBackfill,\n SerializedOmnichainIndexingStatusSnapshotCompleted,\n SerializedOmnichainIndexingStatusSnapshotFollowing,\n SerializedOmnichainIndexingStatusSnapshotUnstarted,\n} from \"../serialize/omnichain-indexing-status-snapshot\";\nimport {\n makeChainIndexingStatusSnapshotBackfillSchema,\n makeChainIndexingStatusSnapshotCompletedSchema,\n makeChainIndexingStatusSnapshotFollowingSchema,\n makeChainIndexingStatusSnapshotQueuedSchema,\n} from \"./chain-indexing-status-snapshot\";\n\n/**\n * Invariant: For omnichain snapshot,\n * `omnichainStatus` is set based on the snapshots of individual chains.\n */\nexport function invariant_omnichainSnapshotStatusIsConsistentWithChainSnapshot(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshot>,\n) {\n const snapshot = ctx.value;\n const chains = Array.from(snapshot.chains.values());\n const expectedOmnichainStatus = getOmnichainIndexingStatus(chains);\n const actualOmnichainStatus = snapshot.omnichainStatus;\n\n if (expectedOmnichainStatus !== actualOmnichainStatus) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: `'${actualOmnichainStatus}' is an invalid omnichainStatus. Expected '${expectedOmnichainStatus}' based on the statuses of individual chains.`,\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot,\n * `omnichainIndexingCursor` is lower than the earliest start block\n * across all queued chains.\n *\n * Note: if there are no queued chains, the invariant holds.\n */\nexport function invariant_omnichainIndexingCursorLowerThanEarliestStartBlockAcrossQueuedChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshot>,\n) {\n const snapshot = ctx.value;\n const queuedChains = Array.from(snapshot.chains.values()).filter(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Queued,\n );\n\n // there are no queued chains\n if (queuedChains.length === 0) {\n // the invariant holds\n return;\n }\n\n const queuedChainStartBlocks = queuedChains.map((chain) => chain.config.startBlock.timestamp);\n const queuedChainEarliestStartBlock = Math.min(...queuedChainStartBlocks);\n\n // there are queued chains\n // the invariant holds if the omnichain indexing cursor is lower than\n // the earliest start block across all queued chains\n if (snapshot.omnichainIndexingCursor >= queuedChainEarliestStartBlock) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message:\n \"`omnichainIndexingCursor` must be lower than the earliest start block across all queued chains.\",\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot,\n * `omnichainIndexingCursor` is lower than or equal to\n * the highest `backfillEndBlock` across all backfill chains.\n *\n * Note: if there are no backfill chains, the invariant holds.\n */\nexport function invariant_omnichainIndexingCursorLowerThanOrEqualToLatestBackfillEndBlockAcrossBackfillChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshot>,\n) {\n const snapshot = ctx.value;\n const backfillChains = Array.from(snapshot.chains.values()).filter(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill,\n );\n\n // there are no backfill chains\n if (backfillChains.length === 0) {\n // the invariant holds\n return;\n }\n\n const backfillEndBlocks = backfillChains.map((chain) => chain.backfillEndBlock.timestamp);\n const highestBackfillEndBlock = Math.max(...backfillEndBlocks);\n\n // there are backfill chains\n // the invariant holds if the omnichainIndexingCursor is lower than or\n // equal to the highest backfillEndBlock across all backfill chains.\n if (snapshot.omnichainIndexingCursor > highestBackfillEndBlock) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message:\n \"`omnichainIndexingCursor` must be lower than or equal to the highest `backfillEndBlock` across all backfill chains.\",\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot,\n * `omnichainIndexingCursor` is same as the highest latestIndexedBlock\n * across all indexed chains.\n *\n * Note: if there are no indexed chains, the invariant holds.\n */\nexport function invariant_omnichainIndexingCursorIsEqualToHighestLatestIndexedBlockAcrossIndexedChain(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshot>,\n) {\n const snapshot = ctx.value;\n const indexedChains = Array.from(snapshot.chains.values()).filter(\n (chain) =>\n chain.chainStatus === ChainIndexingStatusIds.Backfill ||\n chain.chainStatus === ChainIndexingStatusIds.Completed ||\n chain.chainStatus === ChainIndexingStatusIds.Following,\n );\n\n // there are no indexed chains\n if (indexedChains.length === 0) {\n // the invariant holds\n return;\n }\n\n const indexedChainLatestIndexedBlocks = indexedChains.map(\n (chain) => chain.latestIndexedBlock.timestamp,\n );\n const indexedChainHighestLatestIndexedBlock = Math.max(...indexedChainLatestIndexedBlocks);\n\n // there are indexed chains\n // the invariant holds if the omnichain indexing cursor is same as\n // the highest latestIndexedBlock across all indexed chains\n if (snapshot.omnichainIndexingCursor !== indexedChainHighestLatestIndexedBlock) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message:\n \"`omnichainIndexingCursor` must be same as the highest `latestIndexedBlock` across all indexed chains.\",\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot 'unstarted',\n * all chains must have \"queued\" status.\n */\nexport function invariant_omnichainSnapshotUnstartedHasValidChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshotUnstarted>,\n) {\n const snapshot = ctx.value;\n const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(\n Array.from(snapshot.chains.values()),\n );\n\n if (hasValidChains === false) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: `For omnichain status snapshot 'unstarted', all chains must have \"queued\" status.`,\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot 'backfill',\n * at least one chain must be in \"backfill\" status and\n * each chain has to have a status of either \"queued\", \"backfill\"\n * or \"completed\".\n */\nexport function invariant_omnichainStatusSnapshotBackfillHasValidChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshotBackfill>,\n) {\n const snapshot = ctx.value;\n const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(\n Array.from(snapshot.chains.values()),\n );\n\n if (hasValidChains === false) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: `For omnichain status snapshot 'backfill', at least one chain must be in \"backfill\" status and each chain has to have a status of either \"queued\", \"backfill\" or \"completed\".`,\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot 'completed',\n * all chains must have \"completed\" status.\n */\nexport function invariant_omnichainStatusSnapshotCompletedHasValidChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshotCompleted>,\n) {\n const snapshot = ctx.value;\n const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(\n Array.from(snapshot.chains.values()),\n );\n\n if (hasValidChains === false) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: `For omnichain status snapshot 'completed', all chains must have \"completed\" status.`,\n });\n }\n}\n\n/**\n * Invariant: For omnichain status snapshot 'following',\n * at least one chain must be in 'following' status.\n */\nexport function invariant_omnichainStatusSnapshotFollowingHasValidChains(\n ctx: ParsePayload<OmnichainIndexingStatusSnapshotFollowing>,\n) {\n const snapshot = ctx.value;\n const hasValidChains = checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(\n Array.from(snapshot.chains.values()),\n );\n\n if (hasValidChains === false) {\n ctx.issues.push({\n code: \"custom\",\n input: snapshot,\n message: \"For omnichainStatus 'following', at least one chain must be in 'following' status.\",\n });\n }\n}\n\n/**\n * Makes Zod schema for {@link OmnichainIndexingStatusSnapshotUnstarted}\n */\nconst makeOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel?: string) =>\n z\n .object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Unstarted),\n chains: z.map(\n makeChainIdSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n ]),\n {\n error:\n \"Chains indexing statuses must be a Map with ChainId as keys and ChainIndexingStatusSnapshot as values.\",\n },\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .check(invariant_omnichainSnapshotUnstartedHasValidChains);\n\n/**\n * Makes Zod schema for {@link OmnichainIndexingStatusSnapshotBackfill}\n */\nconst makeOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel?: string) =>\n z\n .object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Backfill),\n chains: z.map(\n makeChainIdSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n {\n error:\n \"Chains indexing statuses must be a Map with ChainId as keys and ChainIndexingStatusSnapshot as values.\",\n },\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .check(invariant_omnichainStatusSnapshotBackfillHasValidChains);\n\n/**\n * Makes Zod schema for {@link OmnichainIndexingStatusSnapshotCompleted}\n */\nconst makeOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel?: string) =>\n z\n .object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Completed),\n chains: z.map(\n makeChainIdSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n {\n error:\n \"Chains indexing statuses must be a Map with ChainId as keys and ChainIndexingStatusSnapshot as values.\",\n },\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .check(invariant_omnichainStatusSnapshotCompletedHasValidChains);\n\n/**\n * Makes Zod schema for {@link OmnichainIndexingStatusSnapshotFollowing}\n */\nconst makeOmnichainIndexingStatusSnapshotFollowingSchema = (valueLabel?: string) =>\n z\n .object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Following),\n chains: z.map(\n makeChainIdSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotFollowingSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n {\n error:\n \"Chains indexing statuses must be a Map with ChainId as keys and ChainIndexingStatusSnapshot as values.\",\n },\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n })\n .check(invariant_omnichainStatusSnapshotFollowingHasValidChains);\n\n/**\n * Omnichain Indexing Snapshot Schema\n *\n * Makes a Zod schema definition for validating indexing snapshot\n * across all chains indexed by ENSIndexer instance.\n */\nexport const makeOmnichainIndexingStatusSnapshotSchema = (\n valueLabel: string = \"Omnichain Indexing Snapshot\",\n) =>\n z\n .discriminatedUnion(\"omnichainStatus\", [\n makeOmnichainIndexingStatusSnapshotUnstartedSchema(valueLabel),\n makeOmnichainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeOmnichainIndexingStatusSnapshotCompletedSchema(valueLabel),\n makeOmnichainIndexingStatusSnapshotFollowingSchema(valueLabel),\n ])\n .check(invariant_omnichainSnapshotStatusIsConsistentWithChainSnapshot)\n .check(invariant_omnichainIndexingCursorLowerThanEarliestStartBlockAcrossQueuedChains)\n .check(\n invariant_omnichainIndexingCursorLowerThanOrEqualToLatestBackfillEndBlockAcrossBackfillChains,\n )\n .check(invariant_omnichainIndexingCursorIsEqualToHighestLatestIndexedBlockAcrossIndexedChain);\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshotUnstarted}\n */\nconst makeSerializedOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel?: string) =>\n z.object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Unstarted),\n chains: z.record(\n makeChainIdStringSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n ]),\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n });\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshotBackfill}\n */\nconst makeSerializedOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel?: string) =>\n z.object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Backfill),\n chains: z.record(\n makeChainIdStringSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n });\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshotCompleted}\n */\nconst makeSerializedOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel?: string) =>\n z.object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Completed),\n chains: z.record(\n makeChainIdStringSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n });\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshotFollowing}\n */\nconst makeSerializedOmnichainIndexingStatusSnapshotFollowingSchema = (valueLabel?: string) =>\n z.object({\n omnichainStatus: z.literal(OmnichainIndexingStatusIds.Following),\n chains: z.record(\n makeChainIdStringSchema(),\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotFollowingSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n ]),\n ),\n omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel),\n });\n\n/**\n * Makes Zod schema for {@link SerializedOmnichainIndexingStatusSnapshot}.\n */\nexport const makeSerializedOmnichainIndexingStatusSnapshotSchema = (valueLabel: string = \"Value\") =>\n z.discriminatedUnion(\"omnichainStatus\", [\n makeSerializedOmnichainIndexingStatusSnapshotUnstartedSchema(valueLabel),\n makeSerializedOmnichainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeSerializedOmnichainIndexingStatusSnapshotCompletedSchema(valueLabel),\n makeSerializedOmnichainIndexingStatusSnapshotFollowingSchema(valueLabel),\n ]);\n","import type { ChainId, UnixTimestamp } from \"enssdk\";\n\nimport type { Unvalidated } from \"../shared/types\";\nimport {\n ChainIndexingStatusIds,\n type ChainIndexingStatusSnapshot,\n type ChainIndexingStatusSnapshotBackfill,\n type ChainIndexingStatusSnapshotCompleted,\n type ChainIndexingStatusSnapshotQueued,\n} from \"./chain-indexing-status-snapshot\";\nimport { validateOmnichainIndexingStatusSnapshot } from \"./validate/omnichain-indexing-status-snapshot\";\n\n/**\n * The status of omnichain indexing at the time an omnichain indexing status\n * snapshot is captured.\n */\nexport const OmnichainIndexingStatusIds = {\n /**\n * Represents that omnichain indexing is not ready to begin yet because\n * ENSIndexer is in its initialization phase and the data to build a \"true\"\n * {@link OmnichainIndexingStatusSnapshot} is still being loaded.\n */\n Unstarted: \"omnichain-unstarted\",\n\n /**\n * Represents that omnichain indexing is in an overall \"backfill\" status because\n * - At least one indexed chain has a `chainStatus` of\n * {@link ChainIndexingStatusIds.Backfill}; and\n * - No indexed chain has a `chainStatus` of {@link ChainIndexingStatusIds.Following}.\n */\n Backfill: \"omnichain-backfill\",\n\n /**\n * Represents that omnichain indexing is in an overall \"following\" status because\n * at least one indexed chain has a `chainStatus` of\n * {@link ChainIndexingStatusIds.Following}.\n */\n Following: \"omnichain-following\",\n\n /**\n * Represents that omnichain indexing has completed because all indexed chains have\n * a `chainStatus` of {@link ChainIndexingStatusIds.Completed}.\n */\n Completed: \"omnichain-completed\",\n} as const;\n\n/**\n * The derived string union of possible {@link OmnichainIndexingStatusIds}.\n */\nexport type OmnichainIndexingStatusId =\n (typeof OmnichainIndexingStatusIds)[keyof typeof OmnichainIndexingStatusIds];\n\n/**\n * Omnichain indexing status snapshot when the overall `omnichainStatus` is\n * {@link OmnichainIndexingStatusIds.Unstarted}.\n *\n * Invariants:\n * - `omnichainStatus` is always {@link OmnichainIndexingStatusIds.Unstarted}.\n * - `chains` is always a map to {@link ChainIndexingStatusSnapshotQueued} values exclusively.\n * - `omnichainIndexingCursor` is always < the `config.startBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Queued}.\n */\nexport interface OmnichainIndexingStatusSnapshotUnstarted {\n /**\n * The status of omnichain indexing.\n */\n omnichainStatus: typeof OmnichainIndexingStatusIds.Unstarted;\n\n /**\n * The indexing status snapshot for each indexed chain.\n */\n chains: Map<ChainId, ChainIndexingStatusSnapshotQueued>;\n\n /**\n * The timestamp of omnichain indexing progress across all indexed chains.\n */\n omnichainIndexingCursor: UnixTimestamp;\n}\n\n/**\n * The range of {@link ChainIndexingSnapshot} types allowed when the\n * overall omnichain indexing status is {@link OmnichainIndexingStatusIds.Backfill}.\n *\n * Note that this is all of the {@link ChainIndexingSnapshot} types with the exception\n * of {@link ChainIndexingStatusSnapshotFollowing}.\n */\nexport type ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill =\n | ChainIndexingStatusSnapshotQueued\n | ChainIndexingStatusSnapshotBackfill\n | ChainIndexingStatusSnapshotCompleted;\n\n/**\n * Omnichain indexing status snapshot when the `omnichainStatus` is\n * {@link OmnichainIndexingStatusIds.Backfill}.\n *\n * Invariants:\n * - `omnichainStatus` is always {@link OmnichainIndexingStatusIds.Backfill}.\n * - `chains` is guaranteed to contain at least one chain with a `chainStatus` of\n * {@link ChainIndexingStatusIds.Backfill}.\n * - `chains` is guaranteed to not to contain any chain with a `chainStatus` of\n * {@link ChainIndexingStatusIds.Following}\n * - `omnichainIndexingCursor` is always < the `config.startBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Queued}.\n * - `omnichainIndexingCursor` is always <= the `backfillEndBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Backfill}.\n * - `omnichainIndexingCursor` is always >= the `latestIndexedBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Completed}.\n * - `omnichainIndexingCursor` is always equal to the timestamp of the highest\n * `latestIndexedBlock` across all chains that have started indexing\n * (`chainStatus` is not {@link ChainIndexingStatusIds.Queued}).\n */\nexport interface OmnichainIndexingStatusSnapshotBackfill {\n /**\n * The status of omnichain indexing.\n */\n omnichainStatus: typeof OmnichainIndexingStatusIds.Backfill;\n\n /**\n * The indexing status snapshot for each indexed chain.\n */\n chains: Map<ChainId, ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill>;\n\n /**\n * The timestamp of omnichain indexing progress across all indexed chains.\n */\n omnichainIndexingCursor: UnixTimestamp;\n}\n\n/**\n * Omnichain indexing status snapshot when the overall `omnichainStatus` is\n * {@link OmnichainIndexingStatusIds.Following}.\n *\n * Invariants:\n * - `omnichainStatus` is always {@link OmnichainIndexingStatusIds.Following}.\n * - `chains` is guaranteed to contain at least one chain with a `status` of\n * {@link ChainIndexingStatusIds.Following}.\n * - `omnichainIndexingCursor` is always < the `config.startBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Queued}.\n * - `omnichainIndexingCursor` is always <= the `backfillEndBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Backfill}.\n * - `omnichainIndexingCursor` is always >= the `latestIndexedBlock.timestamp` for all\n * chains with `chainStatus` of {@link ChainIndexingStatusIds.Completed}.\n * - `omnichainIndexingCursor` is always equal to the timestamp of the highest\n * `latestIndexedBlock` across all chains that have started indexing\n * (`chainStatus` is not {@link ChainIndexingStatusIds.Queued}).\n */\nexport interface OmnichainIndexingStatusSnapshotFollowing {\n /**\n * The status of omnichain indexing.\n */\n omnichainStatus: typeof OmnichainIndexingStatusIds.Following;\n\n /**\n * The indexing status snapshot for each indexed chain.\n */\n chains: Map<ChainId, ChainIndexingStatusSnapshot>;\n\n /**\n * The timestamp of omnichain indexing progress across all indexed chains.\n */\n omnichainIndexingCursor: UnixTimestamp;\n}\n\n/**\n * Omnichain indexing status snapshot when the overall `omnichainStatus` is\n * {@link OmnichainIndexingStatusIds.Completed}.\n *\n * Invariants:\n * - `omnichainStatus` is always {@link OmnichainIndexingStatusIds.Completed}.\n * - `chains` is always a map to {@link ChainIndexingStatusSnapshotCompleted} values exclusively.\n * - `omnichainIndexingCursor` is always equal to the highest\n * `latestIndexedBlock.timestamp` for all chains.\n */\nexport interface OmnichainIndexingStatusSnapshotCompleted {\n /**\n * The status of omnichain indexing.\n */\n omnichainStatus: typeof OmnichainIndexingStatusIds.Completed;\n\n /**\n * The indexing status snapshot for each indexed chain.\n */\n chains: Map<ChainId, ChainIndexingStatusSnapshotCompleted>;\n\n /**\n * The timestamp of omnichain indexing progress across all indexed chains.\n */\n omnichainIndexingCursor: UnixTimestamp;\n}\n\n/**\n * Omnichain indexing status snapshot for one or more chains.\n *\n * Use the `omnichainStatus` field to determine the specific type interpretation\n * at runtime.\n */\nexport type OmnichainIndexingStatusSnapshot =\n | OmnichainIndexingStatusSnapshotUnstarted\n | OmnichainIndexingStatusSnapshotBackfill\n | OmnichainIndexingStatusSnapshotCompleted\n | OmnichainIndexingStatusSnapshotFollowing;\n\n/**\n * Check if Chain Indexing Status Snapshots fit the 'unstarted' overall status\n * snapshot requirements:\n * - All chains are guaranteed to have a status of \"queued\".\n *\n * Note: This function narrows the {@link ChainIndexingStatusSnapshot} type to\n * {@link ChainIndexingStatusSnapshotQueued}.\n */\nexport function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(\n chains: ChainIndexingStatusSnapshot[],\n): chains is ChainIndexingStatusSnapshotQueued[] {\n return chains.every((chain) => chain.chainStatus === ChainIndexingStatusIds.Queued);\n}\n\n/**\n * Check if Chain Indexing Status Snapshots fit the 'backfill' overall status\n * snapshot requirements:\n * - At least one chain is guaranteed to be in the \"backfill\" status.\n * - Each chain is guaranteed to have a status of either \"queued\",\n * \"backfill\" or \"completed\".\n *\n * Note: This function narrows the {@link ChainIndexingStatusSnapshot} type to\n * {@link ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill}.\n */\nexport function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(\n chains: ChainIndexingStatusSnapshot[],\n): chains is ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill[] {\n const atLeastOneChainInTargetStatus = chains.some(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Backfill,\n );\n const otherChainsHaveValidStatuses = chains.every(\n (chain) =>\n chain.chainStatus === ChainIndexingStatusIds.Queued ||\n chain.chainStatus === ChainIndexingStatusIds.Backfill ||\n chain.chainStatus === ChainIndexingStatusIds.Completed,\n );\n\n return atLeastOneChainInTargetStatus && otherChainsHaveValidStatuses;\n}\n\n/**\n * Checks if Chain Indexing Status Snapshots fit the 'completed' overall status\n * snapshot requirements:\n * - All chains are guaranteed to have a status of \"completed\".\n *\n * Note: This function narrows the {@link ChainIndexingStatusSnapshot} type to\n * {@link ChainIndexingStatusSnapshotCompleted}.\n */\nexport function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(\n chains: ChainIndexingStatusSnapshot[],\n): chains is ChainIndexingStatusSnapshotCompleted[] {\n const allChainsHaveValidStatuses = chains.every(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Completed,\n );\n\n return allChainsHaveValidStatuses;\n}\n\n/**\n * Checks Chain Indexing Status Snapshots fit the 'following' overall status\n * snapshot requirements:\n * - At least one chain is guaranteed to be in the \"following\" status.\n * - Any other chain can have any status.\n */\nexport function checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(\n chains: ChainIndexingStatusSnapshot[],\n): boolean {\n const allChainsHaveValidStatuses = chains.some(\n (chain) => chain.chainStatus === ChainIndexingStatusIds.Following,\n );\n\n return allChainsHaveValidStatuses;\n}\n\n/**\n * Get {@link OmnichainIndexingStatusId} based on indexed chains' statuses.\n *\n * This function decides what is the `OmnichainIndexingStatusId` is,\n * based on provided chain indexing statuses.\n *\n * @throws an error if unable to determine overall indexing status\n */\nexport function getOmnichainIndexingStatus(\n chains: ChainIndexingStatusSnapshot[],\n): OmnichainIndexingStatusId {\n if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotFollowing(chains)) {\n return OmnichainIndexingStatusIds.Following;\n }\n\n if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill(chains)) {\n return OmnichainIndexingStatusIds.Backfill;\n }\n\n if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotUnstarted(chains)) {\n return OmnichainIndexingStatusIds.Unstarted;\n }\n\n if (checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotCompleted(chains)) {\n return OmnichainIndexingStatusIds.Completed;\n }\n\n // if none of the chain statuses matched, throw an error\n throw new Error(`Unable to determine omnichain indexing status for provided chains.`);\n}\n\n/**\n * Get Omnichain Indexing Cursor\n *\n * The cursor tracks the \"highest\" latest indexed block timestamp across\n * all indexed chains. If all chains are queued, the cursor tracks the moment\n * just before the earliest start block timestamp across those chains.\n *\n * @throws an error if no chains are provided\n */\nexport function getOmnichainIndexingCursor(chains: ChainIndexingStatusSnapshot[]): UnixTimestamp {\n if (chains.length === 0) {\n throw new Error(`Unable to determine omnichain indexing cursor when no chains were provided.`);\n }\n\n // for omnichain indexing status snapshot 'unstarted', the cursor tracks\n // the moment just before the indexing would start from.\n if (getOmnichainIndexingStatus(chains) === OmnichainIndexingStatusIds.Unstarted) {\n const earliestStartBlockTimestamps = chains.map((chain) => chain.config.startBlock.timestamp);\n\n return Math.min(...earliestStartBlockTimestamps) - 1;\n }\n\n // otherwise, the cursor tracks the \"highest\" latest indexed block timestamp\n // across all indexed chains\n const latestIndexedBlockTimestamps = chains\n .filter((chain) => chain.chainStatus !== ChainIndexingStatusIds.Queued)\n .map((chain) => chain.latestIndexedBlock.timestamp);\n\n // Invariant: there's at least one element in `latestIndexedBlockTimestamps` array\n // This is theoretically impossible based on the 2 checks above,\n // but the invariant is explicitly added here as a formality.\n if (latestIndexedBlockTimestamps.length < 1) {\n throw new Error(\"latestIndexedBlockTimestamps array must include at least one element\");\n }\n\n return Math.max(...latestIndexedBlockTimestamps);\n}\n\n/**\n * Build an Omnichain Indexing Status Snapshot based on the indexing status snapshots of all indexed chains.\n *\n * @param chainStatusSnapshots - A map of chain IDs to their chain indexing status snapshots.\n * @returns The omnichain indexing status snapshot.\n */\nexport function buildOmnichainIndexingStatusSnapshot(\n chainStatusSnapshots: Map<ChainId, ChainIndexingStatusSnapshot>,\n): OmnichainIndexingStatusSnapshot {\n if (chainStatusSnapshots.size === 0) {\n throw new Error(\n \"At least one chain indexing status snapshot is required to build an OmnichainIndexingStatusSnapshot\",\n );\n }\n\n const chains = Array.from(chainStatusSnapshots.values());\n const omnichainStatus = getOmnichainIndexingStatus(chains);\n const omnichainIndexingCursor = getOmnichainIndexingCursor(chains);\n\n switch (omnichainStatus) {\n case OmnichainIndexingStatusIds.Unstarted: {\n return validateOmnichainIndexingStatusSnapshot({\n omnichainStatus: OmnichainIndexingStatusIds.Unstarted,\n chains: chainStatusSnapshots as Map<\n ChainId,\n Unvalidated<ChainIndexingStatusSnapshotQueued>\n >, // narrowing the type here, will be validated in the following 'check' step\n omnichainIndexingCursor,\n } satisfies Unvalidated<OmnichainIndexingStatusSnapshotUnstarted>);\n }\n\n case OmnichainIndexingStatusIds.Backfill: {\n return validateOmnichainIndexingStatusSnapshot({\n omnichainStatus: OmnichainIndexingStatusIds.Backfill,\n chains: chainStatusSnapshots as Map<\n ChainId,\n Unvalidated<ChainIndexingStatusSnapshotForOmnichainIndexingStatusSnapshotBackfill>\n >, // narrowing the type here, will be validated in the following 'check' step\n omnichainIndexingCursor,\n } satisfies Unvalidated<OmnichainIndexingStatusSnapshotBackfill>);\n }\n\n case OmnichainIndexingStatusIds.Completed: {\n return validateOmnichainIndexingStatusSnapshot({\n omnichainStatus: OmnichainIndexingStatusIds.Completed,\n chains: chainStatusSnapshots as Map<\n ChainId,\n Unvalidated<ChainIndexingStatusSnapshotCompleted>\n >, // narrowing the type here, will be validated in the following 'check' step\n omnichainIndexingCursor,\n } satisfies Unvalidated<OmnichainIndexingStatusSnapshotCompleted>);\n }\n\n case OmnichainIndexingStatusIds.Following:\n return validateOmnichainIndexingStatusSnapshot({\n omnichainStatus: OmnichainIndexingStatusIds.Following,\n chains: chainStatusSnapshots,\n omnichainIndexingCursor,\n } satisfies Unvalidated<OmnichainIndexingStatusSnapshotFollowing>);\n }\n}\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport * as blockRef from \"../../shared/block-ref\";\nimport { RangeTypeIds } from \"../../shared/blockrange\";\nimport { makeBlockRefSchema } from \"../../shared/zod-schemas\";\nimport {\n ChainIndexingStatusIds,\n type ChainIndexingStatusSnapshot,\n type ChainIndexingStatusSnapshotBackfill,\n type ChainIndexingStatusSnapshotCompleted,\n type ChainIndexingStatusSnapshotFollowing,\n type ChainIndexingStatusSnapshotQueued,\n} from \"../chain-indexing-status-snapshot\";\n\n/**\n * Invariants for chain snapshot in 'queued' status:\n * - `config.endBlock` (if set) is after `config.startBlock`.\n */\nexport function invariant_chainSnapshotQueuedBlocks(\n ctx: ParsePayload<ChainIndexingStatusSnapshotQueued>,\n) {\n const { config } = ctx.value;\n\n // The `config.endBlock` does not exist for `left-bounded` config range type\n if (config.rangeType === RangeTypeIds.LeftBounded) {\n // invariant holds\n return;\n }\n\n if (blockRef.isBeforeOrEqualTo(config.startBlock, config.endBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`config.startBlock` must be before or same as `config.endBlock`.\",\n });\n }\n}\n\n/**\n * Invariants for chain snapshot in 'backfill' status:\n * - `config.startBlock` is before or same as `latestIndexedBlock`.\n * - `latestIndexedBlock` is before or same as `backfillEndBlock`.\n * - `backfillEndBlock` is the same as `config.endBlock` (if set).\n */\nexport function invariant_chainSnapshotBackfillBlocks(\n ctx: ParsePayload<ChainIndexingStatusSnapshotBackfill>,\n) {\n const { config, latestIndexedBlock, backfillEndBlock } = ctx.value;\n\n if (blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`config.startBlock` must be before or same as `latestIndexedBlock`.\",\n });\n }\n\n if (blockRef.isBeforeOrEqualTo(latestIndexedBlock, backfillEndBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`latestIndexedBlock` must be before or same as `backfillEndBlock`.\",\n });\n }\n\n // The `config.endBlock` does not exist for `left-bounded` config range type\n if (config.rangeType === RangeTypeIds.LeftBounded) {\n // invariant holds\n return;\n }\n\n if (blockRef.isEqualTo(backfillEndBlock, config.endBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`backfillEndBlock` must be the same as `config.endBlock`.\",\n });\n }\n}\n\n/**\n * Invariants for chain snapshot in 'completed' status:\n * - `config.startBlock` is before or same as `latestIndexedBlock`.\n * - `latestIndexedBlock` is before or same as `config.endBlock`.\n */\nexport function invariant_chainSnapshotCompletedBlocks(\n ctx: ParsePayload<ChainIndexingStatusSnapshotCompleted>,\n) {\n const { config, latestIndexedBlock } = ctx.value;\n\n if (blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`config.startBlock` must be before or same as `latestIndexedBlock`.\",\n });\n }\n\n if (blockRef.isBeforeOrEqualTo(latestIndexedBlock, config.endBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`latestIndexedBlock` must be before or same as `config.endBlock`.\",\n });\n }\n}\n\n/**\n * Invariants for chain snapshot in 'following' status:\n * - `config.startBlock` is before or same as `latestIndexedBlock`.\n * - `latestIndexedBlock` is before or same as `latestKnownBlock`.\n */\nexport function invariant_chainSnapshotFollowingBlocks(\n ctx: ParsePayload<ChainIndexingStatusSnapshotFollowing>,\n) {\n const { config, latestIndexedBlock, latestKnownBlock } = ctx.value;\n\n if (blockRef.isBeforeOrEqualTo(config.startBlock, latestIndexedBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`config.startBlock` must be before or same as `latestIndexedBlock`.\",\n });\n }\n\n if (blockRef.isBeforeOrEqualTo(latestIndexedBlock, latestKnownBlock) === false) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"`latestIndexedBlock` must be before or same as `latestKnownBlock`.\",\n });\n }\n}\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshotQueued} type.\n */\nexport const makeChainIndexingStatusSnapshotQueuedSchema = (valueLabel: string = \"Value\") =>\n z\n .object({\n chainStatus: z.literal(ChainIndexingStatusIds.Queued),\n config: z.discriminatedUnion(\"rangeType\", [\n z.object({\n rangeType: z.literal(RangeTypeIds.LeftBounded),\n startBlock: makeBlockRefSchema(valueLabel),\n }),\n z.object({\n rangeType: z.literal(RangeTypeIds.Bounded),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n ]),\n })\n .check(invariant_chainSnapshotQueuedBlocks);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshotBackfill} type.\n */\nexport const makeChainIndexingStatusSnapshotBackfillSchema = (valueLabel: string = \"Value\") =>\n z\n .object({\n chainStatus: z.literal(ChainIndexingStatusIds.Backfill),\n config: z.discriminatedUnion(\"rangeType\", [\n z.object({\n rangeType: z.literal(RangeTypeIds.LeftBounded),\n startBlock: makeBlockRefSchema(valueLabel),\n }),\n z.object({\n rangeType: z.literal(RangeTypeIds.Bounded),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n ]),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n backfillEndBlock: makeBlockRefSchema(valueLabel),\n })\n .check(invariant_chainSnapshotBackfillBlocks);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshotCompleted} type.\n */\nexport const makeChainIndexingStatusSnapshotCompletedSchema = (valueLabel: string = \"Value\") =>\n z\n .object({\n chainStatus: z.literal(ChainIndexingStatusIds.Completed),\n config: z.object({\n rangeType: z.literal(RangeTypeIds.Bounded),\n startBlock: makeBlockRefSchema(valueLabel),\n endBlock: makeBlockRefSchema(valueLabel),\n }),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n })\n .check(invariant_chainSnapshotCompletedBlocks);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshotFollowing} type.\n */\nexport const makeChainIndexingStatusSnapshotFollowingSchema = (valueLabel: string = \"Value\") =>\n z\n .object({\n chainStatus: z.literal(ChainIndexingStatusIds.Following),\n config: z.object({\n rangeType: z.literal(RangeTypeIds.LeftBounded),\n startBlock: makeBlockRefSchema(valueLabel),\n }),\n latestIndexedBlock: makeBlockRefSchema(valueLabel),\n latestKnownBlock: makeBlockRefSchema(valueLabel),\n })\n .check(invariant_chainSnapshotFollowingBlocks);\n\n/**\n * Makes Zod schema for {@link ChainIndexingStatusSnapshot}\n */\nexport const makeChainIndexingStatusSnapshotSchema = (valueLabel: string = \"Value\") =>\n z.discriminatedUnion(\"chainStatus\", [\n makeChainIndexingStatusSnapshotQueuedSchema(valueLabel),\n makeChainIndexingStatusSnapshotBackfillSchema(valueLabel),\n makeChainIndexingStatusSnapshotCompletedSchema(valueLabel),\n makeChainIndexingStatusSnapshotFollowingSchema(valueLabel),\n ]);\n","import { z } from \"zod/v4\";\n\nimport { makeEnsDbPublicConfigSchema } from \"../../ensdb/zod-schemas/config\";\nimport {\n makeEnsIndexerPublicConfigSchema,\n makeSerializedEnsIndexerPublicConfigSchema,\n} from \"../../ensindexer/config/zod-schemas\";\nimport { makeEnsRainbowPublicConfigSchema } from \"../../ensrainbow/zod-schemas/config\";\nimport type { ZodCheckFnInput } from \"../../shared/zod-types\";\nimport type { EnsIndexerStackInfo } from \"../ensindexer-stack-info\";\n\nexport function makeSerializedEnsIndexerStackInfoSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSIndexerStackInfo\";\n\n return z.object({\n ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`),\n ensIndexer: makeSerializedEnsIndexerPublicConfigSchema(`${label}.ensIndexer`),\n ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`),\n });\n}\n\nexport function invariant_ensRainbowCompatibilityWithEnsIndexer(\n ctx: ZodCheckFnInput<EnsIndexerStackInfo>,\n) {\n const { ensIndexer, ensRainbow } = ctx.value;\n const { clientLabelSet } = ensIndexer;\n const { serverLabelSet } = ensRainbow;\n\n if (clientLabelSet.labelSetId !== serverLabelSet.labelSetId) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `ENSRainbow's label set (id: ${serverLabelSet.labelSetId}) must be the same as ENSIndexer's label set (id: ${clientLabelSet.labelSetId}).`,\n });\n }\n\n if (clientLabelSet.labelSetVersion > serverLabelSet.highestLabelSetVersion) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `ENSRainbow's server label set version (highest: ${serverLabelSet.highestLabelSetVersion}) must be greater than or equal to ENSIndexer's client label set version (current: ${clientLabelSet.labelSetVersion}).`,\n });\n }\n}\n\nexport function makeEnsIndexerStackInfoSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSIndexerStackInfo\";\n\n return z\n .object({\n ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`),\n ensIndexer: makeEnsIndexerPublicConfigSchema(`${label}.ensIndexer`),\n ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`),\n })\n .check(invariant_ensRainbowCompatibilityWithEnsIndexer);\n}\n","import { z } from \"zod/v4\";\n\nconst makeEnsDbVersionInfoSchema = (valueLabel?: string) => {\n const label = valueLabel ?? \"EnsDbVersionInfo\";\n\n return z.object({\n postgresql: z\n .string()\n .nonempty(`${label}.postgresql must be a non-empty string`)\n .describe(\"Version of the PostgreSQL server hosting the ENSDb instance.\"),\n });\n};\n\nexport const makeEnsDbPublicConfigSchema = (valueLabel?: string) => {\n const label = valueLabel ?? \"EnsDbPublicConfig\";\n\n return z.object({\n versionInfo: makeEnsDbVersionInfoSchema(`${label}.versionInfo`),\n });\n};\n","import {\n makeEnsApiPublicConfigSchema,\n makeSerializedEnsApiPublicConfigSchema,\n} from \"../../ensapi/config/zod-schemas\";\nimport type { ZodCheckFnInput } from \"../../shared/zod-types\";\nimport type { EnsNodeStackInfo } from \"../ensnode-stack-info\";\nimport {\n invariant_ensRainbowCompatibilityWithEnsIndexer,\n makeEnsIndexerStackInfoSchema,\n makeSerializedEnsIndexerStackInfoSchema,\n} from \"./ensindexer-stack-info\";\n\nfunction invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow(\n ctx: ZodCheckFnInput<EnsNodeStackInfo>,\n) {\n const { ensApi, ensIndexer, ensRainbow } = ctx.value;\n\n // Invariant: ENSApi & ENSDB must match version numbers\n if (ensIndexer.versionInfo.ensDb !== ensApi.versionInfo.ensApi) {\n ctx.issues.push({\n code: \"custom\",\n path: [\"ensIndexer\", \"versionInfo\", \"ensDb\"],\n input: ensIndexer.versionInfo.ensDb,\n message: `Version Mismatch: ENSDB@${ensIndexer.versionInfo.ensDb} !== ENSApi@${ensApi.versionInfo.ensApi}`,\n });\n }\n\n // Invariant: ENSApi & ENSIndexer must match version numbers\n if (ensIndexer.versionInfo.ensIndexer !== ensApi.versionInfo.ensApi) {\n ctx.issues.push({\n code: \"custom\",\n path: [\"ensIndexer\", \"versionInfo\", \"ensIndexer\"],\n input: ensIndexer.versionInfo.ensIndexer,\n message: `Version Mismatch: ENSIndexer@${ensIndexer.versionInfo.ensIndexer} !== ENSApi@${ensApi.versionInfo.ensApi}`,\n });\n }\n\n // Invariant: ENSApi & ENSRainbow must match version numbers\n if (ensRainbow.versionInfo.ensRainbow !== ensApi.versionInfo.ensApi) {\n ctx.issues.push({\n code: \"custom\",\n path: [\"ensRainbow\", \"versionInfo\", \"ensRainbow\"],\n input: ensRainbow.versionInfo.ensRainbow,\n message: `Version Mismatch: ENSRainbow@${ensRainbow.versionInfo.ensRainbow} !== ENSApi@${ensApi.versionInfo.ensApi}`,\n });\n }\n\n // Invariant: `@adraffy/ens-normalize` package version must match between ENSApi & ENSIndexer\n if (ensIndexer.versionInfo.ensNormalize !== ensApi.versionInfo.ensNormalize) {\n ctx.issues.push({\n code: \"custom\",\n path: [\"ensIndexer\", \"versionInfo\", \"ensNormalize\"],\n input: ensIndexer.versionInfo.ensNormalize,\n message: `Dependency Version Mismatch: '@adraffy/ens-normalize' version must be the same between ENSIndexer and ENSApi. Found ENSApi@${ensApi.versionInfo.ensNormalize} and ENSIndexer@${ensIndexer.versionInfo.ensNormalize}`,\n });\n }\n}\n\nexport function makeSerializedEnsNodeStackInfoSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSNodeStackInfo\";\n\n return makeSerializedEnsIndexerStackInfoSchema(label).extend({\n ensApi: makeSerializedEnsApiPublicConfigSchema(`${label}.ensApi`),\n });\n}\n\nexport function makeEnsNodeStackInfoSchema(valueLabel?: string) {\n const label = valueLabel ?? \"ENSNodeStackInfo\";\n\n return makeEnsIndexerStackInfoSchema(label)\n .extend({\n ensApi: makeEnsApiPublicConfigSchema(`${label}.ensApi`),\n })\n .check(invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow)\n .check(invariant_ensRainbowCompatibilityWithEnsIndexer);\n}\n","import type { RealtimeIndexingStatusProjection } from \"../../../indexing-status/realtime-indexing-status-projection\";\nimport type { EnsNodeStackInfo } from \"../../../stack-info/ensnode-stack-info\";\n\n/**\n * A status code for indexing status responses.\n */\nexport const EnsApiIndexingStatusResponseCodes = {\n /**\n * Represents that the indexing status is available.\n */\n Ok: \"ok\",\n\n /**\n * Represents that the indexing status is unavailable.\n */\n Error: \"error\",\n} as const;\n\n/**\n * A status code for indexing status responses.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponseCodes} instead.\n */\nexport const IndexingStatusResponseCodes = EnsApiIndexingStatusResponseCodes;\n\n/**\n * The derived string union of possible {@link EnsApiIndexingStatusResponseCodes}.\n */\nexport type EnsApiIndexingStatusResponseCode =\n (typeof EnsApiIndexingStatusResponseCodes)[keyof typeof EnsApiIndexingStatusResponseCodes];\n\n/**\n * The derived string union of possible {@link EnsApiIndexingStatusResponseCodes}.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponseCode} instead.\n */\nexport type IndexingStatusResponseCode = EnsApiIndexingStatusResponseCode;\n\n/**\n * An indexing status response when the indexing status is available.\n */\nexport type EnsApiIndexingStatusResponseOk = {\n responseCode: typeof EnsApiIndexingStatusResponseCodes.Ok;\n realtimeProjection: RealtimeIndexingStatusProjection;\n stackInfo: EnsNodeStackInfo;\n};\n\n/**\n * An indexing status response when the indexing status is available.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponseOk} instead.\n */\nexport type IndexingStatusResponseOk = EnsApiIndexingStatusResponseOk;\n\n/**\n * An indexing status response when the indexing status is unavailable.\n */\nexport type EnsApiIndexingStatusResponseError = {\n responseCode: typeof EnsApiIndexingStatusResponseCodes.Error;\n};\n\n/**\n * An indexing status response when the indexing status is unavailable.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponseError} instead.\n */\nexport type IndexingStatusResponseError = EnsApiIndexingStatusResponseError;\n\n/**\n * Indexing status response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type EnsApiIndexingStatusResponse =\n | EnsApiIndexingStatusResponseOk\n | EnsApiIndexingStatusResponseError;\n\n/**\n * Indexing status response.\n *\n * @deprecated Use {@link EnsApiIndexingStatusResponse} instead.\n */\nexport type IndexingStatusResponse = EnsApiIndexingStatusResponse;\n","import type { InterpretedName } from \"enssdk\";\n\nimport type {\n SerializedNameTokensResponseError,\n SerializedNameTokensResponseOk,\n} from \"./serialized-response\";\n\n/**\n * Example value for {@link SerializedNameTokensResponseOk}, for use in OpenAPI documentation.\n *\n * - domainId and tokenId correspond to \"vitalik.eth\"\n * - contract is the ENS BaseRegistrar (ERC-721) on Ethereum mainnet\n */\nexport const nameTokensResponseOkExample = {\n responseCode: \"ok\",\n registeredNameTokens: {\n domainId: \"0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835\",\n name: \"vitalik.eth\" as InterpretedName,\n tokens: [\n {\n token: {\n assetNamespace: \"erc721\",\n contract: {\n chainId: 1,\n address: \"0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85\",\n },\n tokenId: \"0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc\",\n },\n ownership: {\n ownershipType: \"fully-onchain\",\n owner: {\n chainId: 1,\n address: \"0x220866b1a2219f40e72f5c628b65d54268ca3a9d\",\n },\n },\n mintStatus: \"minted\",\n },\n ],\n expiresAt: 2461152330,\n accurateAsOf: 1700000000,\n },\n} satisfies SerializedNameTokensResponseOk;\n\n/**\n * Example value for {@link SerializedNameTokensResponseError} representing a 503 Service Unavailable\n * when the Name Tokens API prerequisites are not met, for use in OpenAPI documentation.\n */\nexport const nameTokensServiceUnavailableExample = {\n responseCode: \"error\",\n errorCode: \"unsupported-ensindexer-config\",\n error: {\n message: \"Name Tokens API is not available\",\n details: \"Connected ENSIndexer must have all following plugins active: registrars, tokenscope\",\n },\n} satisfies SerializedNameTokensResponseError;\n\n/**\n * Example value for {@link NameTokensResponseErrorNameTokensNotIndexed} representing a 404 Not Found\n * when no name tokens are indexed for the requested name or domainId, for use in OpenAPI documentation.\n */\nexport const nameTokensNotIndexedExample = {\n responseCode: \"error\",\n errorCode: \"name-tokens-not-indexed\",\n error: {\n message: \"No indexed Name Tokens found\",\n details:\n \"This ENSNode instance has not been configured to index tokens for the requested name: 'vitalik.eth'\",\n },\n} satisfies SerializedNameTokensResponseError;\n","import { namehashInterpretedName } from \"enssdk\";\nimport { z } from \"zod/v4\";\n\nimport {\n makeNodeSchema,\n makeReinterpretedNameSchema,\n makeUnixTimestampSchema,\n} from \"../../../shared/zod-schemas\";\nimport { NameTokenOwnershipTypes } from \"../../../tokenscope/name-token\";\nimport { makeNameTokenSchema } from \"../../../tokenscope/zod-schemas\";\nimport { makeErrorResponseSchema } from \"../shared/errors/zod-schemas\";\nimport {\n NameTokensResponse,\n NameTokensResponseCodes,\n NameTokensResponseError,\n NameTokensResponseErrorCodes,\n NameTokensResponseErrorEnsIndexerConfigUnsupported,\n NameTokensResponseErrorIndexingStatusUnsupported,\n NameTokensResponseErrorNameTokensNotIndexed,\n NameTokensResponseOk,\n type RegisteredNameTokens,\n} from \"./response\";\n\n/**\n * Schema for {@link RegisteredNameTokens}.\n */\nexport const makeRegisteredNameTokenSchema = <const SerializableType extends boolean>(\n valueLabel: string = \"Registered Name Token\",\n serializable?: SerializableType,\n) =>\n z\n .object({\n domainId: makeNodeSchema(`${valueLabel}.domainId`),\n name: makeReinterpretedNameSchema(valueLabel),\n tokens: z.array(makeNameTokenSchema(`${valueLabel}.tokens`, serializable)).nonempty(),\n expiresAt: makeUnixTimestampSchema(`${valueLabel}.expiresAt`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n })\n .check(function invariant_nameIsAssociatedWithDomainId(ctx) {\n const { name, domainId } = ctx.value;\n\n if (namehashInterpretedName(name) !== domainId) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'name' must be associated with 'domainId': ${domainId}`,\n });\n }\n })\n .check(\n function invariant_nameTokensOwnershipTypeNameWrapperRequiresOwnershipTypeFullyOnchainOrUnknown(\n ctx,\n ) {\n const { tokens } = ctx.value;\n const containsOwnershipNameWrapper = tokens.some(\n (t) => t.ownership.ownershipType === NameTokenOwnershipTypes.NameWrapper,\n );\n const containsOwnershipFullyOnchainOrUnknown = tokens.some(\n (t) =>\n t.ownership.ownershipType === NameTokenOwnershipTypes.FullyOnchain ||\n t.ownership.ownershipType === NameTokenOwnershipTypes.Unknown,\n );\n if (containsOwnershipNameWrapper && !containsOwnershipFullyOnchainOrUnknown) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'tokens' must contain name token with ownership type 'fully-onchain' or 'unknown' when name token with ownership type 'namewrapper' in listed`,\n });\n }\n },\n )\n .check(function invariant_nameTokensContainAtMostOneWithOwnershipTypeEffective(ctx) {\n const { tokens } = ctx.value;\n const tokensCountWithOwnershipFullyOnchain = tokens.filter(\n (t) => t.ownership.ownershipType === NameTokenOwnershipTypes.FullyOnchain,\n ).length;\n if (tokensCountWithOwnershipFullyOnchain > 1) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'tokens' must contain at most one name token with ownership type 'fully-onchain', current count: ${tokensCountWithOwnershipFullyOnchain}`,\n });\n }\n });\n\n/**\n * Schema for {@link NameTokensResponseOk}\n */\nexport const makeNameTokensResponseOkSchema = <const SerializableType extends boolean>(\n valueLabel: string = \"Name Tokens Response OK\",\n serializable?: SerializableType,\n) =>\n z.strictObject({\n responseCode: z.literal(NameTokensResponseCodes.Ok),\n registeredNameTokens: makeRegisteredNameTokenSchema(`${valueLabel}.nameTokens`, serializable),\n });\n\n/**\n * Schema for {@link NameTokensResponseErrorNameTokensNotIndexed}\n */\nexport const makeNameTokensResponseErrorNameTokensNotIndexedSchema = (\n _valueLabel: string = \"Name Tokens Response Error Name Not Indexed\",\n) =>\n z.strictObject({\n responseCode: z.literal(NameTokensResponseCodes.Error),\n errorCode: z.literal(NameTokensResponseErrorCodes.NameTokensNotIndexed),\n error: makeErrorResponseSchema(),\n });\n\n/**\n * Schema for {@link NameTokensResponseErrorEnsIndexerConfigUnsupported}\n */\nexport const makeNameTokensResponseErrorEnsIndexerConfigUnsupported = (\n _valueLabel: string = \"Name Tokens Response Error ENSIndexer Config Unsupported\",\n) =>\n z.strictObject({\n responseCode: z.literal(NameTokensResponseCodes.Error),\n errorCode: z.literal(NameTokensResponseErrorCodes.EnsIndexerConfigUnsupported),\n error: makeErrorResponseSchema(),\n });\n/**\n * Schema for {@link NameTokensResponseErrorIndexingStatusUnsupported}\n */\nexport const makeNameTokensResponseErrorNameIndexingStatusUnsupported = (\n _valueLabel: string = \"Name Tokens Response Error Indexing Status Unsupported\",\n) =>\n z.strictObject({\n responseCode: z.literal(NameTokensResponseCodes.Error),\n errorCode: z.literal(NameTokensResponseErrorCodes.IndexingStatusUnsupported),\n error: makeErrorResponseSchema(),\n });\n/**\n * Schema for {@link NameTokensResponseError}\n */\nexport const makeNameTokensResponseErrorSchema = (\n valueLabel: string = \"Name Tokens Response Error\",\n) =>\n z.discriminatedUnion(\"errorCode\", [\n makeNameTokensResponseErrorNameTokensNotIndexedSchema(valueLabel),\n makeNameTokensResponseErrorEnsIndexerConfigUnsupported(valueLabel),\n makeNameTokensResponseErrorNameIndexingStatusUnsupported(valueLabel),\n ]);\n\n/**\n * Schema for {@link NameTokensResponse}\n */\nexport const makeNameTokensResponseSchema = <const SerializableType extends boolean = false>(\n valueLabel: string = \"Name Tokens Response\",\n serializable?: SerializableType,\n) => {\n return z.discriminatedUnion(\"responseCode\", [\n makeNameTokensResponseOkSchema(valueLabel, serializable ?? false),\n makeNameTokensResponseErrorSchema(valueLabel),\n ]);\n};\n","import type { AccountId, AssetId, InterpretedName } from \"enssdk\";\nimport { getParentInterpretedName } from \"enssdk\";\nimport { isAddressEqual, zeroAddress } from \"viem\";\n\nimport { DatasourceNames, type ENSNamespaceId } from \"@ensnode/datasources\";\n\nimport { accountIdEqual } from \"../shared/account-id\";\nimport { getDatasourceContract, maybeGetDatasourceContract } from \"../shared/datasource-contract\";\nimport { type NFTMintStatus, type SerializedAssetId, serializeAssetId } from \"./assets\";\n\n/**\n * An enum representing the possible Name Token Ownership types.\n */\nexport const NameTokenOwnershipTypes = {\n /**\n * Name Token is owned by NameWrapper account.\n */\n NameWrapper: \"namewrapper\",\n\n /**\n * Name Token is owned fully onchain.\n *\n * This ownership type can only apply to direct subnames of `.eth`\n */\n FullyOnchain: \"fully-onchain\",\n\n /**\n * Name Token ownership has been transferred to the null address.\n */\n Burned: \"burned\",\n\n /**\n * Name Token ownership is unknown.\n */\n Unknown: \"unknown\",\n} as const;\n\nexport type NameTokenOwnershipType =\n (typeof NameTokenOwnershipTypes)[keyof typeof NameTokenOwnershipTypes];\n\nexport interface NameTokenOwnershipNameWrapper {\n ownershipType: typeof NameTokenOwnershipTypes.NameWrapper;\n\n /**\n * Owner\n *\n * Guarantees:\n * - `owner.address` is not the zero address.\n * - `owner.chainId` is same as the chainId of the associated NFT,\n * even if that NFT has been burned.\n */\n owner: AccountId;\n}\n\nexport interface NameTokenOwnershipFullyOnchain {\n ownershipType: typeof NameTokenOwnershipTypes.FullyOnchain;\n\n /**\n * Owner\n *\n * Guarantees:\n * - `owner.address` is not the zero address.\n * - `owner.chainId` is same as the chainId of the associated NFT,\n * even if that NFT has been burned.\n */\n owner: AccountId;\n}\n\nexport interface NameTokenOwnershipBurned {\n ownershipType: typeof NameTokenOwnershipTypes.Burned;\n\n /**\n * Owner\n *\n * Guarantees:\n * - `owner.address` is the zero address.\n * - `owner.chainId` is same as the chainId of the associated NFT,\n * even if that NFT has been burned.\n */\n owner: AccountId;\n}\n\nexport interface NameTokenOwnershipUnknown {\n ownershipType: typeof NameTokenOwnershipTypes.Unknown;\n\n /**\n * Owner\n *\n * Guarantees:\n * - `owner.address` is the zero address.\n * - `owner.chainId` is same as the chainId of the associated NFT,\n * even if that NFT has been burned.\n */\n owner: AccountId;\n}\n\nexport type NameTokenOwnership =\n | NameTokenOwnershipNameWrapper\n | NameTokenOwnershipFullyOnchain\n | NameTokenOwnershipBurned\n | NameTokenOwnershipUnknown;\n\nexport interface NameToken {\n /**\n * Token\n *\n * References the NFT that currently or previously tokenized ownership of\n * `name`.\n */\n token: AssetId;\n\n /**\n * Owner\n *\n * Identifies the ownership state of the token.\n *\n * Guarantees:\n * - The `ownership.owner.chainId` of this address is the same as is referenced\n * in `domainAsset.contract.chainId`.\n */\n ownership: NameTokenOwnership;\n\n /**\n * The mint status of the token.\n *\n * After ENSNode indexes the token for a name, even if that token is burned,\n * ENSNode will never forget how the token once represented the name.\n * When the token for a name is burned, ENSNode remembers this token but\n * updates its `mintStatus` to `burned`. If this token becomes minted again\n * after it was burned, its `mintStatus` is updated to `minted` again.\n *\n * NOTE: Tokens managed by the .eth BaseRegistrar for\n * direct subnames of .eth can only be burned when undergoing\n * a state transition of `minted` -> `burned` -> `minted` all within\n * the same registrar action for the case that a direct subname of .eth\n * has expired and has been fully released and is now being registered again.\n * Since all of those mint status state transitions are processed within\n * a single block, once the token managed by the .eth BaseRegistrar for\n * a direct subname of .eth has been minted, our state model will forever\n * represent it as `minted`.\n *\n * Guarantees:\n * - The `mintStatus` will be burned if and only\n * if `ownership.ownershipType` is `NameTokenOwnershipTypes.Burned`.\n */\n mintStatus: NFTMintStatus;\n}\n\n/**\n * Serialized representation of {@link NameToken}.\n */\nexport interface SerializedNameToken extends Omit<NameToken, \"token\"> {\n token: SerializedAssetId;\n}\n\nexport function serializeNameToken(nameToken: NameToken): SerializedNameToken {\n return {\n token: serializeAssetId(nameToken.token),\n ownership: nameToken.ownership,\n mintStatus: nameToken.mintStatus,\n };\n}\n\n/**\n * Get all NameWrapper accounts within provided ENS Namespace.\n *\n * Guaranteed to return at least one account for ENSRoot Datasource.\n */\nexport function getNameWrapperAccounts(namespaceId: ENSNamespaceId): [AccountId, ...AccountId[]] {\n const ethnamesNameWrapperAccount = getDatasourceContract(\n namespaceId,\n DatasourceNames.ENSRoot,\n \"NameWrapper\",\n );\n\n const lineanamesNameWrapperAccount = maybeGetDatasourceContract(\n namespaceId,\n DatasourceNames.Lineanames,\n \"NameWrapper\",\n );\n\n const nameWrapperAccounts: [AccountId, ...AccountId[]] = [\n // NameWrapper for direct subnames of .eth is defined for all ENS namespaces\n ethnamesNameWrapperAccount,\n ];\n\n if (lineanamesNameWrapperAccount) {\n // NameWrapper for Lineanames is only defined for some ENS namespaces\n nameWrapperAccounts.push(lineanamesNameWrapperAccount);\n }\n\n return nameWrapperAccounts;\n}\n\n/**\n * Get name token ownership for provided owner account within selected ENS Namespace.\n */\nexport function getNameTokenOwnership(\n namespaceId: ENSNamespaceId,\n name: InterpretedName,\n owner: AccountId,\n): NameTokenOwnership {\n const nameWrapperAccounts = getNameWrapperAccounts(namespaceId);\n const hasNameWrapperOwnership = nameWrapperAccounts.some((nameWrapperAccount) =>\n accountIdEqual(owner, nameWrapperAccount),\n );\n\n if (hasNameWrapperOwnership) {\n return {\n ownershipType: NameTokenOwnershipTypes.NameWrapper,\n owner,\n } satisfies NameTokenOwnershipNameWrapper;\n }\n\n if (isAddressEqual(owner.address, zeroAddress)) {\n return {\n ownershipType: NameTokenOwnershipTypes.Burned,\n owner,\n } satisfies NameTokenOwnershipBurned;\n }\n\n const parentName = getParentInterpretedName(name);\n if (parentName === null) throw new Error(`Invariant: '${name}' has no parent Name.`);\n\n // set ownershipType as 'fully-onchain' if `name` is a direct subname of .eth\n if (parentName === \"eth\") {\n return {\n ownershipType: NameTokenOwnershipTypes.FullyOnchain,\n owner,\n } satisfies NameTokenOwnershipFullyOnchain;\n }\n\n return {\n ownershipType: NameTokenOwnershipTypes.Unknown,\n owner,\n } satisfies NameTokenOwnershipUnknown;\n}\n","import type { AccountId } from \"enssdk\";\nimport { isAddressEqual } from \"viem\";\n\n/**\n * Determines where the provided AccountId values represent the same address on the same chain.\n */\nexport const accountIdEqual = (a: AccountId, b: AccountId): boolean => {\n return a.chainId === b.chainId && isAddressEqual(a.address, b.address);\n};\n","import type { AccountId } from \"enssdk\";\n\nimport {\n type Datasource,\n type DatasourceName,\n type ENSNamespaceId,\n maybeGetDatasource,\n} from \"@ensnode/datasources\";\n\nimport { accountIdEqual } from \"./account-id\";\n\n/**\n * Gets the AccountId for the contract in the specified namespace, datasource, and\n * contract name, or undefined if it is not defined or is not a single AccountId.\n *\n * This is useful when you want to retrieve the AccountId for a contract by its name\n * where it may or may not actually be defined for the given namespace and datasource.\n *\n * @param namespaceId - The ENSNamespace identifier (e.g. 'mainnet', 'sepolia', 'ens-test-env')\n * @param datasourceName - The name of the Datasource to search for contractName in\n * @param contractName - The name of the contract to retrieve\n * @returns The AccountId of the contract with the given namespace, datasource,\n * and contract name, or undefined if it is not found or is not a single AccountId\n */\nexport const maybeGetDatasourceContract = <\n N extends ENSNamespaceId,\n D extends DatasourceName,\n C extends string,\n>(\n namespaceId: N,\n datasourceName: D,\n contractName: C,\n): AccountId | undefined => {\n const datasource = maybeGetDatasource(namespaceId, datasourceName) as Datasource | undefined;\n if (!datasource) return undefined;\n\n const address = datasource.contracts[contractName]?.address;\n if (address === undefined || Array.isArray(address)) return undefined;\n\n return {\n chainId: datasource.chain.id,\n address,\n };\n};\n\n/**\n * Gets the AccountId for the contract in the specified namespace, datasource, and\n * contract name, or throws an error if it is not defined or is not a single AccountId.\n *\n * @param namespaceId - The ENSNamespace identifier (e.g. 'mainnet', 'sepolia', 'ens-test-env')\n * @param datasourceName - The name of the Datasource to search for contractName in\n * @param contractName - The name of the contract to retrieve\n * @returns The AccountId of the contract with the given namespace, datasource,\n * and contract name\n * @throws Error if the contract is not found or is not a single AccountId\n */\nexport const getDatasourceContract = (\n namespaceId: ENSNamespaceId,\n datasourceName: DatasourceName,\n contractName: string,\n): AccountId => {\n const contract = maybeGetDatasourceContract(namespaceId, datasourceName, contractName);\n if (!contract) {\n throw new Error(\n `Expected contract not found for ${namespaceId} ${datasourceName} ${contractName}`,\n );\n }\n return contract;\n};\n\n/**\n * Makes a comparator fn for `b` against the contract described by `namespace`, `datasourceName`, and `contractName`.\n */\nexport const makeContractMatcher =\n (namespace: ENSNamespaceId, b: AccountId) =>\n (datasourceName: DatasourceName, contractName: string) => {\n const a = maybeGetDatasourceContract(namespace, datasourceName, contractName);\n return a && accountIdEqual(a, b);\n };\n","import type { Address, Hex } from \"enssdk\";\nimport {\n type AccountId,\n type AssetId,\n type AssetIdString,\n type AssetNamespace,\n type ChainId,\n type Node,\n stringifyAssetId,\n type TokenId,\n} from \"enssdk\";\nimport { isAddressEqual, zeroAddress } from \"viem\";\nimport { prettifyError } from \"zod/v4\";\n\nimport { makeAssetIdSchema, makeAssetIdStringSchema } from \"./zod-schemas\";\n\n/**\n * Serialized representation of {@link TokenId}.\n */\nexport type SerializedTokenId = string;\n\n/**\n * Serialized representation of {@link AssetId}.\n */\nexport interface SerializedAssetId extends Omit<AssetId, \"tokenId\"> {\n tokenId: SerializedTokenId;\n}\n\n/**\n * Serializes {@link AssetId} object to a structured form.\n */\nexport function serializeAssetId(assetId: AssetId): SerializedAssetId {\n return {\n assetNamespace: assetId.assetNamespace,\n contract: assetId.contract,\n tokenId: assetId.tokenId.toString(),\n };\n}\n\n/**\n * Deserialize a {@link AssetId} object.\n */\nexport function deserializeAssetId(maybeAssetId: unknown, valueLabel?: string): AssetId {\n const schema = makeAssetIdSchema(valueLabel);\n const parsed = schema.safeParse(maybeAssetId);\n\n if (parsed.error) {\n throw new RangeError(`Cannot deserialize AssetId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\n/**\n * Parse a stringified representation of {@link AssetId} object.\n */\nexport function parseAssetId(maybeAssetId: AssetIdString, valueLabel?: string): AssetId {\n const schema = makeAssetIdStringSchema(valueLabel);\n const parsed = schema.safeParse(maybeAssetId);\n\n if (parsed.error) {\n throw new RangeError(`Cannot parse AssetId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\n/**\n * Builds an AssetId for the NFT represented by the given contract,\n * tokenId, and assetNamespace.\n *\n * @param contract - The contract that manages the NFT\n * @param tokenId - The tokenId of the NFT\n * @param assetNamespace - The assetNamespace of the NFT\n * @returns The AssetId for the NFT represented by the given contract,\n * tokenId, and assetNamespace\n */\nexport const buildAssetId = (\n contract: AccountId,\n tokenId: TokenId,\n assetNamespace: AssetNamespace,\n): AssetId => {\n return {\n assetNamespace,\n contract,\n tokenId,\n };\n};\n\n/**\n * A globally unique reference to an NFT tokenizing the ownership of a domain.\n */\nexport interface DomainAssetId extends AssetId {\n /**\n * The namehash (node) of the domain who's ownership is tokenized by\n * this `AssetId`.\n */\n domainId: Node;\n}\n\n/**\n * Serialized representation of {@link DomainAssetId}.\n */\nexport interface SerializedDomainAssetId extends SerializedAssetId {\n domainId: Node;\n}\n\nexport function serializeDomainAssetId(domainAsset: DomainAssetId): SerializedDomainAssetId {\n return {\n ...serializeAssetId(domainAsset),\n domainId: domainAsset.domainId,\n };\n}\n\n/**\n * An enum representing the mint status of a DomainAssetId.\n *\n * After we index a NFT we never delete it from our index. Instead, when an\n * indexed NFT is burned onchain we retain its record and update its mint\n * status as `burned`. If a NFT is minted again after it is burned its mint\n * status is updated to `minted`.\n */\nexport const NFTMintStatuses = {\n Minted: \"minted\",\n Burned: \"burned\",\n} as const;\n\nexport type NFTMintStatus = (typeof NFTMintStatuses)[keyof typeof NFTMintStatuses];\n\n/**\n * Metadata about a NFT transfer event.\n *\n * This metadata can be used for building more helpful messages when processing\n * NFT transfer events.\n */\nexport interface NFTTransferEventMetadata {\n chainId: ChainId;\n blockNumber: bigint;\n transactionHash: Hex;\n eventHandlerName: string;\n nft: DomainAssetId;\n}\n\nexport const formatNFTTransferEventMetadata = (metadata: NFTTransferEventMetadata): string => {\n const assetIdString = stringifyAssetId(metadata.nft);\n\n return [\n `Event: ${metadata.eventHandlerName}`,\n `Chain ID: ${metadata.chainId}`,\n `Block Number: ${metadata.blockNumber}`,\n `Transaction Hash: ${metadata.transactionHash}`,\n `NFT: ${assetIdString}`,\n ]\n .map((line) => ` - ${line}`)\n .join(\"\\n\");\n};\n\n/**\n * An enum representing the type of transfer that has occurred to a DomainAssetId.\n */\nexport const NFTTransferTypes = {\n /**\n * Initial transfer from zeroAddress to a non-zeroAddress\n * Can happen at most once to a NFT AssetId\n *\n * Invariants:\n * - NFT is not indexed and therefore has no previous mint status or owner\n * - new NFT mint status is `minted`\n * - new NFT owner is a non-zeroAddress\n */\n Mint: \"mint\",\n\n /**\n * Subsequent transfer from zeroAddress to a non-zeroAddress\n * Can happen any number of times to a NFT AssetId as it passes in a cycle from\n * mint -> burn -> remint -> burn -> remint -> ...\n *\n * Invariants:\n * - NFT is indexed\n * - previous NFT mint status was `burned`\n * - previous NFT owner is the zeroAddress\n * - new NFT mint status is `minted`\n * - new NFT owner is a non-zeroAddress\n */\n Remint: \"remint\",\n\n /**\n * Special transfer type for improperly implemented NFT contracts that allow a NFT\n * that is currently minted to be reminted before an intermediate burn.\n *\n * Transfer from zeroAddress to non-zeroAddress for an indexed NFT where the\n * previously indexed nft had status `minted` with a non-zeroAddress owner.\n *\n * Invariants:\n * - NFT is indexed\n * - previous NFT mint status was `minted`\n * - previous NFT owner was a non-zeroAddress\n * - new NFT mint status is `minted`\n * - new NFT owner is a non-zeroAddress\n */\n MintedRemint: \"minted-remint\",\n\n /**\n * Transfer from a non-zeroAddress to zeroAddress\n *\n * Invariants:\n * - NFT is indexed\n * - previous NFT mint status was `minted`\n * - previous NFT owner is a non-zeroAddress\n * - new NFT mint status is `burned`\n * - new NFT owner is the zeroAddress\n */\n Burn: \"burn\",\n\n /**\n * Transfer from a non-zeroAddress to a distinct non-zeroAddress\n *\n * Invariants:\n * - NFT is indexed\n * - previous and new NFT mint status is `minted`\n * - previous and new NFT owner are distinct non-zeroAddress\n */\n Transfer: \"transfer\",\n\n /**\n * Transfer from a non-zeroAddress to the same non-zeroAddress\n *\n * Invariants:\n * - NFT is indexed\n * - previous and new NFT mint status is `minted`\n * - previous and new NFT owner are equivalent non-zeroAddress\n */\n SelfTransfer: \"self-transfer\",\n\n /**\n * Transfer from zeroAddress to zeroAddress for an indexed NFT\n *\n * Invariants:\n * - NFT is indexed\n * - previous and new NFT mint status is `burned`\n * - previous and new NFT owner are zeroAddress\n */\n RemintBurn: \"remint-burn\",\n\n /**\n * Special transfer type for improperly implemented NFT contracts that allow a NFT\n * that is currently minted to be reminted again before an intermediate burn.\n *\n * Transfer from zeroAddress to zeroAddress for an indexed NFT where the\n * previously indexed nft had status `minted` with a non-zeroAddress owner.\n *\n * Invariants:\n * - NFT is indexed\n * - previous NFT mint status was `minted`\n * - previous NFT owner was a non-zeroAddress\n * - new NFT mint status is `burned`\n * - new NFT owner is the zeroAddress\n */\n MintedRemintBurn: \"minted-remint-burn\",\n\n /**\n * Transfer from zeroAddress to zeroAddress for an unindexed NFT\n *\n * Invariants:\n * - NFT is not indexed and therefore has no previous mint status or owner\n * - NFT should remain unindexed and without any mint status or owner\n */\n MintBurn: \"mint-burn\",\n} as const;\n\nexport type NFTTransferType = (typeof NFTTransferTypes)[keyof typeof NFTTransferTypes];\n\nexport const getNFTTransferType = (\n from: Address,\n to: Address,\n allowMintedRemint: boolean,\n metadata: NFTTransferEventMetadata,\n currentlyIndexedOwner?: Address,\n): NFTTransferType => {\n const isIndexed = currentlyIndexedOwner !== undefined;\n const isIndexedAsMinted = isIndexed && !isAddressEqual(currentlyIndexedOwner, zeroAddress);\n\n // a transfer from the zeroAddress to a non-zeroAddress represents minting\n const isMint = isAddressEqual(from, zeroAddress);\n\n // a transfer from a non-zeroAddress to the zeroAddress represents burning\n const isBurn = isAddressEqual(to, zeroAddress);\n\n // it's possible to transfer to and from the same address\n const isSelfTransfer = isAddressEqual(from, to);\n\n if (isIndexed && !isAddressEqual(currentlyIndexedOwner, from)) {\n if (isMint && allowMintedRemint) {\n // special case to allow minted remint from improperly implemented NFT contracts\n } else {\n throw new Error(\n `Error: Sending from ${from} conflicts with currently indexed owner ${currentlyIndexedOwner}.\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n }\n }\n\n if (isSelfTransfer) {\n if (isMint) {\n // a self-transfer to and from the zeroAddress represents either mint-burn, remint-burn,\n // or minted-remint-burn\n if (!isIndexed) {\n // mint-burn with !isIndexed && !isIndexedAsMinted\n return NFTTransferTypes.MintBurn;\n } else if (!isIndexedAsMinted) {\n // remint-burn with isIndexed && !isIndexedAsMinted\n return NFTTransferTypes.RemintBurn;\n } else if (allowMintedRemint) {\n // minted-remint-burn with isIndexed && isIndexedAsMinted && allowMintedRemint\n //\n // this is a non-standard special case for improperly implemented NFT contracts\n // that allow a NFT that is currently minted to be reminted again before an\n // intermediate burn.\n //\n // this is a self-transfer from zeroAddress to zeroAddress for an indexed NFT\n // where the previously indexed nft had status `minted` with a non-zeroAddress owner.\n return NFTTransferTypes.MintedRemintBurn;\n } else {\n // remint-burn with isIndexed && isIndexedAsMinted && !allowMintedRemint\n // invalid state transition to be minted and then remint again\n throw new Error(\n `Error: Invalid state transition from minted -> remint-burn\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n }\n } else {\n // a self-transfer to and from the same non-zero address\n if (!isIndexed) {\n // self-transfer with !isIndexed && !isIndexedAsMinted\n // this branch is unreachable because:\n // - from !== zeroAddress; and\n // - !isIndexedAsMinted requires that from === zeroAddress\n // throw an error to validate above assertions\n throw new Error(\n `Error: Invalid state transition from unindexed -> self-transfer\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else if (!isIndexedAsMinted) {\n // self-transfer with isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: invalid state transition from burned -> self-transfer\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else {\n // self-transfer with isIndexed && isIndexedAsMinted\n return NFTTransferTypes.SelfTransfer;\n }\n }\n } else if (isMint) {\n if (!isIndexed) {\n // mint with !isIndexed && !isIndexedAsMinted\n return NFTTransferTypes.Mint;\n } else if (!isIndexedAsMinted) {\n // mint with isIndexed && !isIndexedAsMinted\n return NFTTransferTypes.Remint;\n } else if (allowMintedRemint) {\n // mint with isIndexed && isIndexedAsMinted && allowMintedRemint\n //\n // this is a non-standard special case for improperly implemented NFT contracts\n // that allow a NFT that is currently minted to be reminted again before an\n // intermediate burn.\n //\n // this is a transfer from zeroAddress to non-zeroAddress for an indexed NFT\n // where the previously indexed nft had status `minted` with a non-zeroAddress owner.\n return NFTTransferTypes.MintedRemint;\n } else {\n // mint with isIndexed && isIndexedAsMinted && !allowMintedRemint\n throw new Error(\n `Error: Invalid state transition from minted -> mint\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n }\n } else if (isBurn) {\n if (!isIndexed) {\n // burn with !isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: Invalid state transition from unindexed -> burn\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else if (!isIndexedAsMinted) {\n // burn with isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: Invalid state transition from burned -> burn\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else {\n // burn with isIndexed && isIndexedAsMinted\n return NFTTransferTypes.Burn;\n }\n } else {\n // a transfer from a non-zeroAddress to a non-zeroAddress represents a transfer\n if (!isIndexed) {\n // transfer with !isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: Invalid state transition from unindexed -> transfer\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else if (!isIndexedAsMinted) {\n // transfer with isIndexed && !isIndexedAsMinted\n throw new Error(\n `Error: Invalid state transition from burned -> transfer\\n${formatNFTTransferEventMetadata(metadata)}`,\n );\n } else {\n // transfer with isIndexed && isIndexedAsMinted\n return NFTTransferTypes.Transfer;\n }\n }\n};\n","import { AssetId as CaipAssetId } from \"caip\";\nimport { type AssetId, AssetNamespaces } from \"enssdk\";\nimport { zeroAddress } from \"viem\";\nimport { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport { makeAccountIdSchema, makeNodeSchema } from \"../shared/zod-schemas\";\nimport { type DomainAssetId, NFTMintStatuses, type SerializedAssetId } from \"./assets\";\nimport {\n type NameToken,\n type NameTokenOwnershipBurned,\n type NameTokenOwnershipFullyOnchain,\n type NameTokenOwnershipNameWrapper,\n NameTokenOwnershipTypes,\n type NameTokenOwnershipUnknown,\n} from \"./name-token\";\n\nconst tokenIdSchemaSerializable = z.string();\nconst tokenIdSchemaNative = z.preprocess(\n (v) => (typeof v === \"string\" ? BigInt(v) : v),\n z.bigint().positive(),\n);\n\nexport function makeTokenIdSchema<const SerializableType extends boolean>(\n _valueLabel: string,\n serializable: SerializableType,\n): SerializableType extends true ? typeof tokenIdSchemaSerializable : typeof tokenIdSchemaNative;\nexport function makeTokenIdSchema(\n _valueLabel: string = \"Token ID Schema\",\n serializable: true | false = false,\n): typeof tokenIdSchemaSerializable | typeof tokenIdSchemaNative {\n if (serializable) {\n return tokenIdSchemaSerializable;\n } else {\n return tokenIdSchemaNative;\n }\n}\n\n/**\n * Make schema for {@link AssetId}.\n *\n */\nexport const makeAssetIdSchema = <const SerializableType extends boolean = false>(\n valueLabel: string = \"Asset ID Schema\",\n serializable?: SerializableType,\n) => {\n return z.object({\n assetNamespace: z.enum(AssetNamespaces),\n contract: makeAccountIdSchema(valueLabel),\n tokenId: makeTokenIdSchema(valueLabel, serializable ?? false),\n });\n};\n\n/**\n * Make schema for {@link AssetIdString}.\n */\nexport const makeAssetIdStringSchema = (valueLabel: string = \"Asset ID String Schema\") =>\n z.preprocess((v) => {\n if (typeof v === \"string\") {\n const result = new CaipAssetId(v);\n return {\n assetNamespace: result.assetName.namespace,\n contract: {\n chainId: Number(result.chainId.reference),\n address: result.assetName.reference,\n },\n tokenId: result.tokenId,\n } as SerializedAssetId;\n }\n\n return v;\n }, makeAssetIdSchema(valueLabel));\n\n/**\n * Make schema for {@link DomainAssetId}.\n */\nexport const makeDomainAssetSchema = (valueLabel: string = \"Domain Asset Schema\") =>\n makeAssetIdSchema(valueLabel).extend({\n domainId: makeNodeSchema(`${valueLabel}.domainId`),\n });\n\nfunction invariant_nameTokenOwnershipHasNonZeroAddressOwner(\n ctx: ParsePayload<\n NameTokenOwnershipNameWrapper | NameTokenOwnershipFullyOnchain | NameTokenOwnershipUnknown\n >,\n) {\n const ownership = ctx.value;\n if (ctx.value.owner.address === zeroAddress) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `Name Token Ownership with '${ownership.ownershipType}' must have 'address' other than the zero address.`,\n });\n }\n}\n\nexport const makeNameTokenOwnershipNameWrapperSchema = (\n valueLabel: string = \"Name Token Ownership NameWrapper\",\n) =>\n z\n .object({\n ownershipType: z.literal(NameTokenOwnershipTypes.NameWrapper),\n owner: makeAccountIdSchema(`${valueLabel}.owner`),\n })\n .check(invariant_nameTokenOwnershipHasNonZeroAddressOwner);\n\nexport const makeNameTokenOwnershipFullyOnchainSchema = (\n valueLabel: string = \"Name Token Ownership Fully Onchain\",\n) =>\n z\n .object({\n ownershipType: z.literal(NameTokenOwnershipTypes.FullyOnchain),\n owner: makeAccountIdSchema(`${valueLabel}.owner`),\n })\n .check(invariant_nameTokenOwnershipHasNonZeroAddressOwner);\n\nexport const makeNameTokenOwnershipBurnedSchema = (\n valueLabel: string = \"Name Token Ownership Burned\",\n) =>\n z\n .object({\n ownershipType: z.literal(NameTokenOwnershipTypes.Burned),\n owner: makeAccountIdSchema(`${valueLabel}.owner`),\n })\n .check(invariant_nameTokenOwnershipHasZeroAddressOwner);\n\nexport const makeNameTokenOwnershipUnknownSchema = (\n valueLabel: string = \"Name Token Ownership Unknown\",\n) =>\n z\n .object({\n ownershipType: z.literal(NameTokenOwnershipTypes.Unknown),\n owner: makeAccountIdSchema(`${valueLabel}.owner`),\n })\n .check(invariant_nameTokenOwnershipHasNonZeroAddressOwner);\n\nfunction invariant_nameTokenOwnershipHasZeroAddressOwner(\n ctx: ParsePayload<NameTokenOwnershipBurned>,\n) {\n const ownership = ctx.value;\n if (ctx.value.owner.address !== zeroAddress) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `Name Token Ownership with '${ownership.ownershipType}' must have 'address' set to the zero address.`,\n });\n }\n}\n\nexport const makeNameTokenOwnershipSchema = (valueLabel: string = \"Name Token Ownership\") =>\n z.discriminatedUnion(\"ownershipType\", [\n makeNameTokenOwnershipNameWrapperSchema(valueLabel),\n makeNameTokenOwnershipFullyOnchainSchema(valueLabel),\n makeNameTokenOwnershipBurnedSchema(valueLabel),\n makeNameTokenOwnershipUnknownSchema(valueLabel),\n ]);\n\n/**\n * Make schema for {@link NameToken}.\n */\nexport const makeNameTokenSchema = <const SerializableType extends boolean>(\n valueLabel: string = \"Name Token Schema\",\n serializable?: SerializableType,\n) =>\n z.object({\n token: makeAssetIdSchema(`${valueLabel}.token`, serializable),\n\n ownership: makeNameTokenOwnershipSchema(`${valueLabel}.ownership`),\n\n mintStatus: z.enum(NFTMintStatuses),\n });\n","import { z } from \"zod/v4\";\n\nimport type { ErrorResponse } from \"./response\";\n\n/**\n * Schema for {@link ErrorResponse}.\n */\nexport const makeErrorResponseSchema = () =>\n z.object({\n message: z.string().describe(\"A description of the error that occurred.\"),\n details: z.optional(z.unknown()).describe(\"Additional details about the error.\"),\n });\n","import type { InterpretedName, Node, UnixTimestamp } from \"enssdk\";\n\nimport type { NameToken, NameTokenOwnershipTypes } from \"../../../tokenscope/name-token\";\nimport type { ErrorResponse } from \"../shared/errors\";\n\n/**\n * A status code for Name Tokens API responses.\n */\nexport const NameTokensResponseCodes = {\n /**\n * Represents a response when Name Tokens API can respond with requested data.\n */\n Ok: \"ok\",\n\n /**\n * Represents a response when Name Tokens API could not respond with requested data.\n */\n Error: \"error\",\n} as const;\n\n/**\n * The derived string union of possible {@link NameTokensResponseCodes}.\n */\nexport type NameTokensResponseCode =\n (typeof NameTokensResponseCodes)[keyof typeof NameTokensResponseCodes];\n\n/**\n * Error codes for Name Tokens API responses with 'error' response code.\n */\nexport const NameTokensResponseErrorCodes = {\n /**\n * Name tokens not indexed\n *\n * Represents an error when tokens for the requested name are not indexed by\n * the ENSNode instance's configuration.\n */\n NameTokensNotIndexed: \"name-tokens-not-indexed\",\n\n /**\n * Unsupported ENSIndexer Config\n *\n * Represents a prerequisites error when connected ENSIndexer config lacks\n * params required to enable Name Tokens API.\n */\n EnsIndexerConfigUnsupported: \"unsupported-ensindexer-config\",\n\n /**\n * Unsupported Indexing Status\n *\n * Represents a prerequisites error when Indexing Status has not yet reached\n * status required to enable Name Tokens API.\n */\n IndexingStatusUnsupported: \"unsupported-indexing-status\",\n} as const;\n\n/**\n * The derived string union of possible {@link NameTokensResponseErrorCodes}.\n */\nexport type NameTokensResponseErrorCode =\n (typeof NameTokensResponseErrorCodes)[keyof typeof NameTokensResponseErrorCodes];\n\n/**\n * Name Tokens for a name who's tokens are configured to\n * be indexed by the ENSNode instance's configuration.\n */\nexport interface RegisteredNameTokens {\n /**\n * Domain ID\n */\n domainId: Node;\n\n /**\n * Name\n *\n * FQDN of the name associated with `domainId`.\n *\n * Guarantees:\n * - `namehash(name)` is always `domainId`.\n */\n name: InterpretedName;\n\n /**\n * Name Tokens associated with the `domainId`.\n *\n * It contains every tokenized representation of `name` that\n * has ever been indexed for the given name as of `accurateAsOf`,\n * even if the given token has been burned or expired.\n *\n * Guarantees:\n * - Always includes at least one name token.\n * - When it includes more than one name token, it means that:\n * 1) More than 1 distinct tokenized representation of the ownership of\n * the `name` has been indexed as of `accurateAsOf`.\n * 2) All possible permutations of mint statuses of these tokens are\n * possible:\n * a) Multiple could be actively minted.\n * b) Multiple could be burned.\n * c) Some could be burned, others could be minted.\n * - Order of name tokens follows the order of onchain events that were\n * indexed when a token was minted, or burned.\n * - Each name token has a distinct `token` value which references\n * the NFT that currently or previously tokenized ownership of `name`.\n * - Each name token has ownership type (`ownership.ownershipType`) assigned:\n * - If there's a name token with ownership type\n * {@link NameTokenOwnershipTypes.NameWrapper}, it means that there must be also\n * another name token with ownership type either\n * {@link NameTokenOwnershipTypes.FullyOnchain}, or\n * {@link NameTokenOwnershipTypes.Unknown}.\n * - There can be at most one name token with ownership type\n * {@link NameTokenOwnershipTypes.FullyOnchain}.\n * - There can be any number of name tokens with ownership type\n * {@link NameTokenOwnershipTypes.Burned}.\n *\n * NOTE: It can be useful to get tokenized representations of the name that\n * are now burned: This can be helpful for looking up historical activity for\n * the name, including past buy orders, sell orders, and sales.\n *\n * How will the direct subnames of .eth that are wrapped by the NameWrapper\n * be represented?\n * 1) A direct subname of .eth that has been registered but\n * has never been wrapped by the NameWrapper, and:\n * a) Is still actively minted (independent of its expiry state).\n * b) Has been burned by sending it to the null address.\n * 2) A direct subname of .eth that has been registered and\n * has been wrapped by the NameWrapper, and:\n * a) Is still actively wrapped by the NameWrapper (independent of its\n * expiry state).\n * b) Is no longer wrapped by the NameWrapper, but is still actively\n * minted by the BaseRegistrar (independent of its expiry state).\n * c) Is no longer wrapped by the NameWrapper, and is also no longer\n * minted by the BaseRegistrar (both tokens now burned by sending to\n * the null address).\n */\n tokens: NameToken[];\n\n /**\n * Expiry date for the Registration Lifecycle\n *\n * The latest Registration Lifecycle for a node referenced in `domainId`.\n */\n expiresAt: UnixTimestamp;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link NameTokensResponseOk.nameTokens} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\n/**\n * A response when Name Tokens API can respond with requested data.\n */\nexport type NameTokensResponseOk = {\n responseCode: typeof NameTokensResponseCodes.Ok;\n\n /**\n * Name Tokens for the requested name.\n */\n registeredNameTokens: RegisteredNameTokens;\n};\n\n/**\n * Represents an error response when requested name was not indexed by ENSNode.\n */\nexport interface NameTokensResponseErrorNameTokensNotIndexed {\n responseCode: typeof NameTokensResponseCodes.Error;\n errorCode: typeof NameTokensResponseErrorCodes.NameTokensNotIndexed;\n error: ErrorResponse;\n}\n\n/**\n * Represents an error response when connected ENSIndexer config lacks\n * params required to enable Name Tokens API.\n */\nexport interface NameTokensResponseErrorEnsIndexerConfigUnsupported {\n responseCode: typeof NameTokensResponseCodes.Error;\n errorCode: typeof NameTokensResponseErrorCodes.EnsIndexerConfigUnsupported;\n error: ErrorResponse;\n}\n\n/**\n * Represents an error response when Indexing Status has not yet reached\n * status required to enable Name Tokens API.\n */\nexport interface NameTokensResponseErrorIndexingStatusUnsupported {\n responseCode: typeof NameTokensResponseCodes.Error;\n errorCode: typeof NameTokensResponseErrorCodes.IndexingStatusUnsupported;\n error: ErrorResponse;\n}\n\nexport type NameTokensResponseError =\n | NameTokensResponseErrorNameTokensNotIndexed\n | NameTokensResponseErrorEnsIndexerConfigUnsupported\n | NameTokensResponseErrorIndexingStatusUnsupported;\n\n/**\n * Name Tokens response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type NameTokensResponse = NameTokensResponseOk | NameTokensResponseError;\n","import { z } from \"zod/v4\";\n\nimport { makeDurationSchema, makeUnixTimestampSchema } from \"../../../shared/zod-schemas\";\nimport { makeErrorResponseSchema } from \"../shared/errors/zod-schemas\";\n\nexport const realtimeResponseSchemaOk = z.object({\n maxWorstCaseDistance: makeDurationSchema().describe(\n \"The requested maximum acceptable worst-case indexing distance in seconds.\",\n ),\n slowestChainIndexingCursor: makeUnixTimestampSchema().describe(\n \"The timestamp of the slowest chain's latest indexed block.\",\n ),\n worstCaseDistance: makeDurationSchema().describe(\n \"The actual worst-case distance in seconds between 'now' and the slowest chain's indexing cursor. \" +\n \"This allows your client to programmatically determine whether the ENSNode instance is sufficiently synchronized for your use case.\",\n ),\n});\n\nexport const realtimeResponseSchemaError = makeErrorResponseSchema();\n","import type { InterpretedName } from \"enssdk\";\n\nimport type { SerializedRegistrarActionsResponseOk } from \"./serialized-response\";\n\n/**\n * Example value for {@link SerializedRegistrarActionsResponseOk}, for use in OpenAPI documentation.\n *\n * - registrationLifecycle.node is namehash(\"vitalik.eth\")\n * - subregistry.node is namehash(\"eth\")\n * - subregistry.subregistryId is the ETH Registrar Controller on Ethereum mainnet\n */\nexport const registrarActionsResponseOkExample = {\n responseCode: \"ok\",\n registrarActions: [\n {\n action: {\n type: \"registration\",\n id: \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n incrementalDuration: 31536000,\n registrant: \"0xd8da6bf26964af9d7eed9e03e53415d37aa96045\",\n registrationLifecycle: {\n subregistry: {\n subregistryId: {\n chainId: 1,\n address: \"0x253553366da8546fc250f225fe3d25d0c782303b\",\n },\n node: \"0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae\",\n },\n node: \"0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835\",\n expiresAt: 1893456000,\n },\n pricing: {\n baseCost: { amount: \"1000000000000000\", currency: \"ETH\" },\n premium: { amount: \"0\", currency: \"ETH\" },\n total: { amount: \"1000000000000000\", currency: \"ETH\" },\n },\n referral: { encodedReferrer: null, decodedReferrer: null },\n block: { timestamp: 1700000000, number: 18500000 },\n transactionHash: \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n eventIds: [\"0x0000000000000000000000000000000000000000000000000000000000000001\"],\n },\n name: \"vitalik.eth\" as InterpretedName,\n },\n ],\n pageContext: {\n page: 1,\n recordsPerPage: 25,\n totalRecords: 1,\n totalPages: 1,\n hasNext: false,\n hasPrev: false,\n startIndex: 0,\n endIndex: 0,\n },\n accurateAsOf: 1700000000,\n} satisfies SerializedRegistrarActionsResponseOk;\n","import { namehashInterpretedName } from \"enssdk\";\nimport { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport {\n makeRegistrarActionSchema,\n makeSerializedRegistrarActionSchema,\n} from \"../../../registrars/zod-schemas\";\nimport { makeReinterpretedNameSchema, makeUnixTimestampSchema } from \"../../../shared/zod-schemas\";\nimport { makeErrorResponseSchema } from \"../shared/errors/zod-schemas\";\nimport { makeResponsePageContextSchema } from \"../shared/pagination/zod-schemas\";\nimport { type NamedRegistrarAction, RegistrarActionsResponseCodes } from \"./response\";\nimport {\n SerializedNamedRegistrarAction,\n SerializedRegistrarActionsResponseOk,\n} from \"./serialized-response\";\n\nfunction invariant_registrationLifecycleNodeMatchesName(ctx: ParsePayload<NamedRegistrarAction>) {\n const { name, action } = ctx.value;\n const expectedNode = action.registrationLifecycle.node;\n const actualNode = namehashInterpretedName(name);\n\n if (actualNode !== expectedNode) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `The 'action.registrationLifecycle.node' must match namehash of 'name'`,\n });\n }\n}\n\n/**\n * Schema for {@link NamedRegistrarAction}.\n */\nexport const makeNamedRegistrarActionSchema = (valueLabel: string = \"Named Registrar Action\") =>\n z\n .object({\n action: makeRegistrarActionSchema(valueLabel),\n name: makeReinterpretedNameSchema(valueLabel),\n })\n .check(invariant_registrationLifecycleNodeMatchesName);\n\n/**\n * Schema for {@link SerializedNamedRegistrarAction}.\n */\nconst makeSerializedNamedRegistrarActionSchema = (\n valueLabel: string = \"Serialized Named Registrar Action\",\n) =>\n z.object({\n action: makeSerializedRegistrarActionSchema(valueLabel),\n name: makeReinterpretedNameSchema(valueLabel),\n });\n\n/**\n * Schema for {@link RegistrarActionsResponseOk}\n */\nexport const makeRegistrarActionsResponseOkSchema = (\n valueLabel: string = \"Registrar Actions Response OK\",\n) =>\n z.object({\n responseCode: z.literal(RegistrarActionsResponseCodes.Ok),\n registrarActions: z.array(makeNamedRegistrarActionSchema(valueLabel)),\n pageContext: makeResponsePageContextSchema(`${valueLabel}.pageContext`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n\n/**\n * Schema for {@link RegistrarActionsResponseError}\n */\nexport const makeRegistrarActionsResponseErrorSchema = (\n _valueLabel: string = \"Registrar Actions Response Error\",\n) =>\n z.strictObject({\n responseCode: z.literal(RegistrarActionsResponseCodes.Error),\n error: makeErrorResponseSchema(),\n });\n\n/**\n * Schema for {@link RegistrarActionsResponse}\n */\nexport const makeRegistrarActionsResponseSchema = (\n valueLabel: string = \"Registrar Actions Response\",\n) =>\n z.discriminatedUnion(\"responseCode\", [\n makeRegistrarActionsResponseOkSchema(valueLabel),\n makeRegistrarActionsResponseErrorSchema(valueLabel),\n ]);\n\n/**\n * Schema for {@link SerializedRegistrarActionsResponseOk}\n */\nexport const makeSerializedRegistrarActionsResponseOkSchema = (\n valueLabel: string = \"Serialized Registrar Actions Response OK\",\n) =>\n z.object({\n responseCode: z.literal(RegistrarActionsResponseCodes.Ok),\n registrarActions: z.array(makeSerializedNamedRegistrarActionSchema(valueLabel)),\n pageContext: makeResponsePageContextSchema(`${valueLabel}.pageContext`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport { addPrices, isPriceEqual } from \"../shared/currencies\";\nimport {\n makeAccountIdSchema,\n makeBlockRefSchema,\n makeDurationSchema,\n makeHexStringSchema,\n makeNodeSchema,\n makeNormalizedAddressSchema,\n makePriceEthSchema,\n makeSerializedPriceEthSchema,\n makeTransactionHashSchema,\n makeUnixTimestampSchema,\n} from \"../shared/zod-schemas\";\nimport { decodeEncodedReferrer, ENCODED_REFERRER_BYTE_LENGTH } from \"./encoded-referrer\";\nimport {\n type RegistrarAction,\n type RegistrarActionEventId,\n RegistrarActionPricing,\n type RegistrarActionPricingAvailable,\n type RegistrarActionPricingUnknown,\n type RegistrarActionReferralAvailable,\n RegistrarActionTypes,\n SerializedRegistrarAction,\n SerializedRegistrarActionPricing,\n} from \"./registrar-action\";\nimport type { RegistrationLifecycle } from \"./registration-lifecycle\";\nimport { Subregistry } from \"./subregistry\";\n\n/**\n * Schema for parsing objects into {@link Subregistry}.\n */\nconst makeSubregistrySchema = (valueLabel: string = \"Subregistry\") =>\n z.object({\n subregistryId: makeAccountIdSchema(`${valueLabel} Subregistry ID`),\n node: makeNodeSchema(`${valueLabel} Node`),\n });\n\n/**\n * Schema for parsing objects into {@link RegistrationLifecycle}.\n */\nexport const makeRegistrationLifecycleSchema = (valueLabel: string = \"Registration Lifecycle\") =>\n z.object({\n subregistry: makeSubregistrySchema(`${valueLabel} Subregistry`),\n node: makeNodeSchema(`${valueLabel} Node`),\n expiresAt: makeUnixTimestampSchema(`${valueLabel} Expires at`),\n });\n\n/** Invariant: total is sum of baseCost and premium */\nfunction invariant_registrarActionPricingTotalIsSumOfBaseCostAndPremium(\n ctx: ParsePayload<RegistrarActionPricingAvailable>,\n) {\n const { baseCost, premium, total } = ctx.value;\n const actualTotal = addPrices(baseCost, premium);\n\n if (!isPriceEqual(actualTotal, total)) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'total' must be equal to the sum of 'baseCost' and 'premium'`,\n });\n }\n}\n\n/**\n * Schema for parsing objects into {@link RegistrarActionPricing}.\n */\nconst makeRegistrarActionPricingSchema = (valueLabel: string = \"Registrar Action Pricing\") =>\n z.union([\n // pricing available\n z\n .object({\n baseCost: makePriceEthSchema(`${valueLabel} Base Cost`),\n premium: makePriceEthSchema(`${valueLabel} Premium`),\n total: makePriceEthSchema(`${valueLabel} Total`),\n })\n .check(invariant_registrarActionPricingTotalIsSumOfBaseCostAndPremium)\n .transform((v) => v as RegistrarActionPricingAvailable),\n\n // pricing unknown\n z\n .object({\n baseCost: z.null(),\n premium: z.null(),\n total: z.null(),\n })\n .transform((v) => v as RegistrarActionPricingUnknown),\n ]);\n\n/**\n * Schema for parsing objects into {@link SerializedRegistrarActionPricing}.\n */\nexport const makeSerializedRegistrarActionPricingSchema = (\n valueLabel: string = \"Serialized Registrar Action Pricing\",\n) =>\n z.union([\n // pricing available\n z.object({\n baseCost: makeSerializedPriceEthSchema(`${valueLabel} Base Cost`),\n premium: makeSerializedPriceEthSchema(`${valueLabel} Premium`),\n total: makeSerializedPriceEthSchema(`${valueLabel} Total`),\n }),\n // pricing unknown\n z.object({\n baseCost: z.null(),\n premium: z.null(),\n total: z.null(),\n }),\n ]);\n\n/** Invariant: decodedReferrer is based on encodedReferrer */\nfunction invariant_registrarActionDecodedReferrerBasedOnRawReferrer(\n ctx: ParsePayload<RegistrarActionReferralAvailable>,\n) {\n const { encodedReferrer, decodedReferrer } = ctx.value;\n\n try {\n const expectedDecodedReferrer = decodeEncodedReferrer(encodedReferrer);\n\n if (decodedReferrer !== expectedDecodedReferrer) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `'decodedReferrer' must be based on 'encodedReferrer'`,\n });\n }\n } catch (error) {\n // in case decoding the encodedReferrer value could not succeed\n // pass the decoding error message\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: errorMessage,\n });\n }\n}\n\nconst makeRegistrarActionReferralSchema = (valueLabel: string = \"Registrar Action Referral\") =>\n z.union([\n // referral available\n z\n .object({\n encodedReferrer: makeHexStringSchema(\n { bytesCount: ENCODED_REFERRER_BYTE_LENGTH },\n `${valueLabel} Encoded Referrer`,\n ),\n decodedReferrer: makeNormalizedAddressSchema(`${valueLabel} Decoded Referrer`),\n })\n .check(invariant_registrarActionDecodedReferrerBasedOnRawReferrer),\n\n // referral not applicable\n z.object({\n encodedReferrer: z.null(),\n decodedReferrer: z.null(),\n }),\n ]);\n\nfunction invariant_eventIdsInitialElementIsTheActionId(\n ctx: ParsePayload<Pick<RegistrarAction, \"id\" | \"eventIds\">>,\n) {\n const { id, eventIds } = ctx.value;\n\n if (eventIds[0] !== id) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: \"The initial element of `eventIds` must be the `id` value\",\n });\n }\n}\n\nconst EventIdSchema = z.string().nonempty();\n\nconst EventIdsSchema = z\n .array(EventIdSchema)\n .min(1)\n .transform((v) => v as [RegistrarActionEventId, ...RegistrarActionEventId[]]);\n\n// Base schema without refinements - can be extended\nconst makeBaseRegistrarActionSchemaWithoutCheck = (valueLabel: string = \"Base Registrar Action\") =>\n z.object({\n id: EventIdSchema,\n incrementalDuration: makeDurationSchema(`${valueLabel} Incremental Duration`),\n registrant: makeNormalizedAddressSchema(`${valueLabel} Registrant`),\n registrationLifecycle: makeRegistrationLifecycleSchema(`${valueLabel} Registration Lifecycle`),\n pricing: makeRegistrarActionPricingSchema(`${valueLabel} Pricing`),\n referral: makeRegistrarActionReferralSchema(`${valueLabel} Referral`),\n block: makeBlockRefSchema(`${valueLabel} Block`),\n transactionHash: makeTransactionHashSchema(`${valueLabel} Transaction Hash`),\n eventIds: EventIdsSchema,\n });\n\n// Base schema with refinements - used for parsing/validation\nexport const makeBaseRegistrarActionSchema = (valueLabel: string = \"Base Registrar Action\") =>\n makeBaseRegistrarActionSchemaWithoutCheck(valueLabel).check(\n invariant_eventIdsInitialElementIsTheActionId,\n );\n\nexport const makeRegistrarActionRegistrationSchema = (valueLabel: string = \"Registration \") =>\n makeBaseRegistrarActionSchema(valueLabel).extend({\n type: z.literal(RegistrarActionTypes.Registration),\n });\n\nexport const makeRegistrarActionRenewalSchema = (valueLabel: string = \"Renewal\") =>\n makeBaseRegistrarActionSchema(valueLabel).extend({\n type: z.literal(RegistrarActionTypes.Renewal),\n });\n\n/**\n * Schema for {@link RegistrarAction}.\n */\nexport const makeRegistrarActionSchema = (valueLabel: string = \"Registrar Action\") =>\n z.discriminatedUnion(\"type\", [\n makeRegistrarActionRegistrationSchema(`${valueLabel} Registration`),\n makeRegistrarActionRenewalSchema(`${valueLabel} Renewal`),\n ]);\n\nconst makeSerializedBaseRegistrarActionSchema = (\n valueLabel: string = \"Serialized Base Registrar Action\",\n) =>\n makeBaseRegistrarActionSchemaWithoutCheck(valueLabel).extend({\n pricing: makeSerializedRegistrarActionPricingSchema(`${valueLabel} Pricing`),\n });\n\nconst makeSerializedRegistrarActionRegistrationSchema = (\n valueLabel: string = \"Serialized Registration\",\n) =>\n makeSerializedBaseRegistrarActionSchema(valueLabel).extend({\n type: z.literal(RegistrarActionTypes.Registration),\n });\n\nconst makeSerializedRegistrarActionRenewalSchema = (valueLabel: string = \"Serialized Renewal\") =>\n makeSerializedBaseRegistrarActionSchema(valueLabel).extend({\n type: z.literal(RegistrarActionTypes.Renewal),\n });\n\n/**\n * Schema for {@link SerializedRegistrarAction}\n */\nexport const makeSerializedRegistrarActionSchema = (\n valueLabel: string = \"Serialized Registrar Action\",\n) =>\n z.discriminatedUnion(\"type\", [\n makeSerializedRegistrarActionRegistrationSchema(`${valueLabel} Registration`),\n makeSerializedRegistrarActionRenewalSchema(`${valueLabel} Renewal`),\n ]);\n","import { type Hex, isNormalizedAddress, type NormalizedAddress, toNormalizedAddress } from \"enssdk\";\nimport { pad, size, slice, zeroAddress } from \"viem\";\n\n/**\n * Encoded Referrer\n *\n * Represents a \"raw\" ENS referrer value.\n *\n * Registrar controllers emit referrer data as bytes32 values. This type represents\n * that raw 32-byte hex string.\n *\n * @invariant Guaranteed to be a hex string representation of a 32-byte value.\n */\nexport type EncodedReferrer = Hex;\n\n/**\n * Encoded Referrer byte offset\n *\n * The count of left-padded bytes in an {@link EncodedReferrer} value.\n */\nexport const ENCODED_REFERRER_BYTE_OFFSET = 12;\n\n/**\n * Encoded Referrer byte length\n *\n * The count of bytes the {@link EncodedReferrer} value consists of.\n */\nexport const ENCODED_REFERRER_BYTE_LENGTH = 32;\n\n/**\n * Expected padding for a valid encoded referrer\n *\n * Properly encoded referrers must have exactly 12 zero bytes of left padding\n * before the 20-byte Ethereum address.\n */\nexport const EXPECTED_ENCODED_REFERRER_PADDING: Hex = pad(\"0x\", {\n size: ENCODED_REFERRER_BYTE_OFFSET,\n dir: \"left\",\n});\n\n/**\n * Zero Encoded Referrer\n *\n * Guaranteed to be a hex string representation of a 32-byte zero value.\n */\nexport const ZERO_ENCODED_REFERRER: EncodedReferrer = pad(\"0x\", {\n size: ENCODED_REFERRER_BYTE_LENGTH,\n dir: \"left\",\n});\n\n/**\n * Build an {@link EncodedReferrer} value for the given {@link NormalizedAddress}\n * according to the referrer encoding with left-zero-padding.\n */\nexport function buildEncodedReferrer(address: NormalizedAddress): EncodedReferrer {\n if (!isNormalizedAddress(address)) throw new Error(`Address '${address}' is not normalized.`);\n\n return pad(address, { size: ENCODED_REFERRER_BYTE_LENGTH, dir: \"left\" });\n}\n\n/**\n * Decode an {@link EncodedReferrer} value into a {@link NormalizedAddress}\n * according to the referrer encoding with left-zero-padding.\n *\n * @param encodedReferrer - The \"raw\" {@link EncodedReferrer} value to decode.\n * @returns The decoded referrer address.\n * @throws when encodedReferrer value is not represented by\n * {@link ENCODED_REFERRER_BYTE_LENGTH} bytes.\n * @throws when decodedReferrer is not a valid EVM address.\n */\nexport function decodeEncodedReferrer(encodedReferrer: EncodedReferrer): NormalizedAddress {\n // Invariant: encoded referrer must be of expected size\n if (size(encodedReferrer) !== ENCODED_REFERRER_BYTE_LENGTH) {\n throw new Error(\n `Encoded referrer value must be represented by ${ENCODED_REFERRER_BYTE_LENGTH} bytes.`,\n );\n }\n\n const padding = slice(encodedReferrer, 0, ENCODED_REFERRER_BYTE_OFFSET);\n\n // strict validation: padding must be all zeros\n // if any byte in the padding is non-zero, treat as Zero Encoded Referrer\n if (padding !== EXPECTED_ENCODED_REFERRER_PADDING) return zeroAddress;\n\n const decodedReferrer = slice(encodedReferrer, ENCODED_REFERRER_BYTE_OFFSET);\n\n try {\n // return normalized address\n return toNormalizedAddress(decodedReferrer);\n } catch {\n throw new Error(`Decoded referrer value must be a valid EVM address.`);\n }\n}\n","import type { ChainId, ChainIdString, DatetimeISO8601, UrlString } from \"enssdk\";\n\nimport type {\n Price,\n PriceDai,\n PriceEnsTokens,\n PriceEth,\n PriceUsdc,\n SerializedPrice,\n SerializedPriceDai,\n SerializedPriceEnsTokens,\n SerializedPriceEth,\n SerializedPriceUsdc,\n} from \"./currencies\";\nimport type { Datetime } from \"./types\";\n\n/**\n * Serializes a {@link ChainId} value into its string representation.\n */\nexport function serializeChainId(chainId: ChainId): ChainIdString {\n return chainId.toString();\n}\n\n/**\n * Serializes a {@link Datetime} value into its string representation.\n */\nexport function serializeDatetime(datetime: Datetime): DatetimeISO8601 {\n return datetime.toISOString();\n}\n\n/**\n * Serializes a {@link URL} value into its string representation.\n */\nexport function serializeUrl(url: URL): UrlString {\n return url.toString();\n}\n\n/**\n * Serializes a {@link Price} object.\n */\nexport function serializePrice(price: Price): SerializedPrice {\n return {\n currency: price.currency,\n amount: price.amount.toString(),\n };\n}\n\n/**\n * Serializes a {@link PriceEth} object.\n */\nexport function serializePriceEth(price: PriceEth): SerializedPriceEth {\n return serializePrice(price) as SerializedPriceEth;\n}\n\n/**\n * Serializes a {@link PriceUsdc} object.\n */\nexport function serializePriceUsdc(price: PriceUsdc): SerializedPriceUsdc {\n return serializePrice(price) as SerializedPriceUsdc;\n}\n\n/**\n * Serializes a {@link PriceDai} object.\n */\nexport function serializePriceDai(price: PriceDai): SerializedPriceDai {\n return serializePrice(price) as SerializedPriceDai;\n}\n\n/**\n * Serializes a {@link PriceEnsTokens} object.\n */\nexport function serializePriceEnsTokens(price: PriceEnsTokens): SerializedPriceEnsTokens {\n return serializePrice(price) as SerializedPriceEnsTokens;\n}\n","import type { Address, Duration } from \"enssdk\";\nimport type { Hash } from \"viem\";\n\nimport type { EncodedReferrer } from \"./encoded-referrer\";\n\nexport type { EncodedReferrer } from \"./encoded-referrer\";\nexport { decodeEncodedReferrer, ZERO_ENCODED_REFERRER } from \"./encoded-referrer\";\n\nimport type { PriceEth, SerializedPriceEth } from \"../shared/currencies\";\nimport { serializePriceEth } from \"../shared/serialize\";\nimport type { BlockRef } from \"../shared/types\";\nimport type { RegistrationLifecycle } from \"./registration-lifecycle\";\n\n/**\n * Globally unique, deterministic ID of an indexed onchain event\n * associated with the \"logical registrar action\".\n */\nexport type RegistrarActionEventId = string;\n\n/**\n * Types of \"logical registrar action\".\n */\nexport const RegistrarActionTypes = {\n Registration: \"registration\",\n Renewal: \"renewal\",\n} as const;\n\nexport type RegistrarActionType = (typeof RegistrarActionTypes)[keyof typeof RegistrarActionTypes];\n\n/**\n * Pricing information for a \"logical registrar action\".\n */\nexport interface RegistrarActionPricingAvailable {\n /**\n * Base cost\n *\n * Base cost (before any `premium`) of Ether measured in units of Wei\n * paid to execute the \"logical registrar action\".\n *\n * May be 0.\n */\n baseCost: PriceEth;\n\n /**\n * Premium\n *\n * \"premium\" cost (in excesses of the `baseCost`) of Ether measured in\n * units of Wei paid to execute the \"logical registrar action\".\n *\n * May be 0.\n */\n premium: PriceEth;\n\n /**\n * Total\n *\n * Total cost of Ether measured in units of Wei paid to execute\n * the \"logical registrar action\".\n *\n * May be 0.\n */\n total: PriceEth;\n}\n\n/**\n * Pricing information for a \"logical registrar action\" when\n * there is no known pricing data.\n */\nexport interface RegistrarActionPricingUnknown {\n /**\n * Base cost\n *\n * Base cost (before any `premium`) of Ether measured in units of Wei\n * paid to execute the \"logical registrar action\".\n */\n baseCost: null;\n\n /**\n * Premium\n *\n * \"premium\" cost (in excesses of the `baseCost`) of Ether measured in\n * units of Wei paid to execute the \"logical registrar action\".\n */\n premium: null;\n\n /**\n * Total\n *\n * Total cost of Ether measured in units of Wei paid to execute\n * the \"logical registrar action\".\n */\n total: null;\n}\n\nexport type RegistrarActionPricing =\n | RegistrarActionPricingAvailable\n | RegistrarActionPricingUnknown;\n\nexport function isRegistrarActionPricingAvailable(\n registrarActionPricing: RegistrarActionPricing,\n): registrarActionPricing is RegistrarActionPricingAvailable {\n const { baseCost, premium, total } = registrarActionPricing;\n\n return baseCost !== null && premium !== null && total !== null;\n}\n\n/**\n * * Referral information for performing a \"logical registrar action\".\n */\nexport interface RegistrarActionReferralAvailable {\n /**\n * Encoded Referrer\n *\n * Represents the \"raw\" 32-byte \"referrer\" value emitted onchain in\n * association with the registrar action.\n */\n encodedReferrer: EncodedReferrer;\n\n /**\n * Decoded Referrer\n *\n * The referrer address decoded from {@link encodedReferrer} using strict\n * left-zero-padding validation.\n *\n * Identifies the interpreted address of the referrer.\n * The \"chainId\" of this address is the same as is referenced in\n * `subregistryId`.\n *\n * May be the \"zero address\" to represent that an `encodedReferrer` is\n * defined but that it is interpreted as no referrer.\n */\n decodedReferrer: Address;\n}\n\n/**\n * Referral information for performing a \"logical registrar action\" when\n * registrar controller does not implement referrals.\n */\nexport interface RegistrarActionReferralNotApplicable {\n /**\n * Encoded Referrer\n *\n * Represents the \"raw\" 32-byte \"referrer\" value emitted onchain in\n * association with the registrar action.\n */\n encodedReferrer: null;\n\n /**\n * Decoded Referrer\n *\n * The referrer address decoded from {@link encodedReferrer} using strict\n * left-zero-padding validation. Null when the registrar controller does not implement referrals.\n */\n decodedReferrer: null;\n}\n\nexport type RegistrarActionReferral =\n | RegistrarActionReferralAvailable\n | RegistrarActionReferralNotApplicable;\n\nexport function isRegistrarActionReferralAvailable(\n registrarActionReferral: RegistrarActionReferral,\n): registrarActionReferral is RegistrarActionReferralAvailable {\n const { encodedReferrer, decodedReferrer } = registrarActionReferral;\n\n return encodedReferrer !== null && decodedReferrer !== null;\n}\n\n/**\n * \"Logical registrar action\"\n *\n * Represents a state of \"logical registrar action\". May be built using data\n * from multiple events within the same \"logical\" registration / renewal action.\n */\nexport interface RegistrarAction {\n /**\n * \"Logical registrar action\" ID\n *\n * The `id` value is a deterministic and globally unique identifier for\n * the \"logical registrar action\".\n *\n * The `id` value represents the *initial* onchain event associated with\n * the \"logical registrar action\", but the full state of\n * the \"logical registrar action\" is an aggregate across each of\n * the onchain events referenced in the `eventIds` field.\n *\n * Guaranteed to be the very first element in `eventIds` array.\n */\n id: RegistrarActionEventId;\n\n /**\n * The type of the \"logical registrar action\".\n */\n type: RegistrarActionType;\n\n /**\n *\n * Incremental Duration\n *\n * If `type` is \"registration\":\n * - Represents the duration between `block.timestamp` and\n * the initial `registrationLifecycle.expiresAt` value that the associated\n * \"registration lifecycle\" will be initialized with.\n * If `type` is \"renewal\":\n * - Represents the incremental increase in duration made to\n * the `registrationLifecycle.expiresAt` value in the associated\n * \"registration lifecycle\".\n *\n * A \"registration lifecycle\" may be extended via renewal even after it\n * expires if it is still within its grace period.\n *\n * Consider the following scenario:\n *\n * The \"registration lifecycle\" of a direct subname of .eth is scheduled to\n * expire on Jan 1, midnight UTC. It is currently 30 days after this\n * expiration time. Therefore, there are currently another 60 days of grace\n * period remaining for this name. Anyone can still make a renewal to\n * extend the \"registration lifecycle\" of this name.\n *\n * Given this scenario, consider the following examples:\n *\n * 1. If a renewal is made with 10 days incremental duration,\n * the \"registration lifecycle\" for this name will remain in\n * an \"expired\" state, but it will now have another 70 days of\n * grace period remaining.\n *\n * 2. If a renewal is made with 50 days incremental duration,\n * the \"registration lifecycle\" for this name will no longer be\n * \"expired\" and will become \"active\", but the \"registration lifecycle\"\n * will now be scheduled to expire again in 20 days.\n *\n * After the \"registration lifecycle\" for a name becomes expired by more\n * than its grace period, it can no longer be renewed by anyone and is\n * considered \"released\". The name must first be registered again, starting\n * a new \"registration lifecycle\" of\n * active / expired / grace period / released.\n *\n * May be 0.\n *\n * Guaranteed to be a non-negative bigint value.\n */\n incrementalDuration: Duration;\n\n /**\n * Registrant\n *\n * Identifies the address that initiated the \"logical registrar action\" and\n * is paying the `pricing.total` cost (if applicable).\n *\n * It may not be the owner of the name:\n * 1. When a name is registered, the initial owner of the name may be\n * distinct from the registrant.\n * 2. There are no restrictions on who may renew a name.\n * Therefore the owner of the name may be distinct from the registrant.\n *\n * The \"chainId\" of this address is the same as is referenced in\n * `registrationLifecycle.subregistry.subregistryId`.\n */\n registrant: Address;\n\n /**\n * Registration Lifecycle associated with this \"logical registrar action\".\n */\n registrationLifecycle: RegistrationLifecycle;\n\n /**\n * Pricing information associated with this \"logical registrar action\".\n */\n pricing: RegistrarActionPricing;\n\n /**\n * Referral information associated with this \"logical registrar action\".\n */\n referral: RegistrarActionReferral;\n\n /**\n * Block ref\n *\n * References the block where the \"logical registrar action\" was executed.\n *\n * The \"chainId\" of this block is the same as is referenced in\n * `registrationLifecycle.subregistry.subregistryId`.\n */\n block: BlockRef;\n\n /**\n * Transaction hash\n *\n * Transaction hash of the transaction associated with\n * the \"logical registrar action\".\n *\n * The \"chainId\" of this transaction is the same as is referenced in\n * `registrationLifecycle.subregistry.subregistryId`.\n *\n * Note that a single transaction may be associated with any number of\n * \"logical registrar actions\".\n */\n transactionHash: Hash;\n\n /**\n * Event IDs\n *\n * Array of the eventIds that have contributed to the state of\n * the \"logical registrar action\" record.\n *\n * Each eventId is a deterministic and globally unique onchain event\n * identifier.\n *\n * Guarantees:\n * - Each eventId is of events that occurred within the block\n * referenced by `block.number`.\n * - At least 1 eventId.\n * - Ordered chronologically (ascending) by logIndex within `block.number`.\n * - The first element in the array is equal to the `id` of\n * the overall \"logical registrar action\" record.\n *\n * The following ideas are not generalized for ENS overall but happen to\n * be a characteristic of the scope of our current indexing logic:\n * 1. These id's always reference events emitted by\n * a related \"BaseRegistrar\" contract.\n * 2. These id's optionally reference events emitted by\n * a related \"Registrar Controller\" contract. This is because our\n * current indexing logic doesn't guarantee to index\n * all \"Registrar Controller\" contracts.\n */\n eventIds: [RegistrarActionEventId, ...RegistrarActionEventId[]];\n}\n\n/**\n * Serialized representation of {@link RegistrarActionPricingUnknown}.\n */\nexport type SerializedRegistrarActionPricingUnknown = RegistrarActionPricingUnknown;\n\n/**\n * Serialized representation of {@link RegistrarActionPricingAvailable}.\n */\nexport interface SerializedRegistrarActionPricingAvailable {\n baseCost: SerializedPriceEth;\n\n premium: SerializedPriceEth;\n\n total: SerializedPriceEth;\n}\n\n/**\n * Serialized representation of {@link RegistrarActionPricing}.\n */\nexport type SerializedRegistrarActionPricing =\n | SerializedRegistrarActionPricingAvailable\n | SerializedRegistrarActionPricingUnknown;\n\n/**\n * Serialized representation of {@link RegistrarAction}.\n */\nexport interface SerializedRegistrarAction extends Omit<RegistrarAction, \"pricing\"> {\n pricing: SerializedRegistrarActionPricing;\n}\n\nexport function serializeRegistrarActionPricing(\n pricing: RegistrarActionPricing,\n): SerializedRegistrarActionPricing {\n if (isRegistrarActionPricingAvailable(pricing)) {\n return {\n baseCost: serializePriceEth(pricing.baseCost),\n premium: serializePriceEth(pricing.premium),\n total: serializePriceEth(pricing.total),\n } satisfies SerializedRegistrarActionPricingAvailable;\n }\n\n return pricing satisfies SerializedRegistrarActionPricingUnknown;\n}\n\nexport function serializeRegistrarAction(\n registrarAction: RegistrarAction,\n): SerializedRegistrarAction {\n return {\n id: registrarAction.id,\n type: registrarAction.type,\n incrementalDuration: registrarAction.incrementalDuration,\n registrant: registrarAction.registrant,\n registrationLifecycle: registrarAction.registrationLifecycle,\n pricing: serializeRegistrarActionPricing(registrarAction.pricing),\n referral: registrarAction.referral,\n block: registrarAction.block,\n transactionHash: registrarAction.transactionHash,\n eventIds: registrarAction.eventIds,\n };\n}\n","import { z } from \"zod/v4\";\nimport type { ParsePayload } from \"zod/v4/core\";\n\nimport {\n makeNonNegativeIntegerSchema,\n makePositiveIntegerSchema,\n} from \"../../../../shared/zod-schemas\";\nimport { RECORDS_PER_PAGE_MAX, RequestPageParams } from \"./request\";\nimport {\n ResponsePageContext,\n ResponsePageContextWithNoRecords,\n type ResponsePageContextWithRecords,\n} from \"./response\";\n\n/**\n * Schema for {@link RequestPageParams}\n */\nexport const makeRequestPageParamsSchema = (valueLabel: string = \"RequestPageParams\") =>\n z.object({\n page: makePositiveIntegerSchema(`${valueLabel}.page`),\n recordsPerPage: makePositiveIntegerSchema(`${valueLabel}.recordsPerPage`).max(\n RECORDS_PER_PAGE_MAX,\n `${valueLabel}.recordsPerPage must not exceed ${RECORDS_PER_PAGE_MAX}`,\n ),\n });\n\n/**\n * Schema for {@link ResponsePageContextWithNoRecords}\n */\nexport const makeResponsePageContextSchemaWithNoRecords = (\n valueLabel: string = \"ResponsePageContextWithNoRecords\",\n) =>\n z\n .object({\n totalRecords: z.literal(0),\n totalPages: z.literal(1),\n hasNext: z.literal(false),\n hasPrev: z.literal(false),\n })\n .extend(makeRequestPageParamsSchema(valueLabel).shape);\n\nfunction invariant_responsePageWithRecordsIsCorrect(\n ctx: ParsePayload<ResponsePageContextWithRecords>,\n) {\n const { hasNext, hasPrev, recordsPerPage, page, totalRecords, startIndex, endIndex } = ctx.value;\n\n const expectedHasNext = page * recordsPerPage < totalRecords;\n if (hasNext !== expectedHasNext) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `hasNext must be equal to '${expectedHasNext ? \"true\" : \"false\"}'`,\n });\n }\n\n const expectedHasPrev = page > 1;\n if (hasPrev !== expectedHasPrev) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `hasPrev must be equal to '${expectedHasPrev ? \"true\" : \"false\"}'`,\n });\n }\n\n if (endIndex < startIndex) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `endIndex must be greater than or equal to startIndex`,\n });\n }\n\n if (endIndex >= totalRecords) {\n ctx.issues.push({\n code: \"custom\",\n input: ctx.value,\n message: `endIndex must be lower than totalRecords`,\n });\n }\n}\n\n/**\n * Schema for {@link ResponsePageContextWithRecords}\n */\nexport const makeResponsePageContextSchemaWithRecords = (\n valueLabel: string = \"ResponsePageContextWithRecords\",\n) =>\n z\n .object({\n totalRecords: makePositiveIntegerSchema(`${valueLabel}.totalRecords`),\n totalPages: makePositiveIntegerSchema(`${valueLabel}.totalPages`),\n hasNext: z.boolean(),\n hasPrev: z.boolean(),\n startIndex: makeNonNegativeIntegerSchema(`${valueLabel}.startIndex`),\n endIndex: makeNonNegativeIntegerSchema(`${valueLabel}.endIndex`),\n })\n .extend(makeRequestPageParamsSchema(valueLabel).shape)\n .check(invariant_responsePageWithRecordsIsCorrect);\n\n/**\n * Schema for {@link ResponsePageContext}\n */\nexport const makeResponsePageContextSchema = (valueLabel: string = \"ResponsePageContext\") =>\n z.union([\n makeResponsePageContextSchemaWithNoRecords(valueLabel),\n makeResponsePageContextSchemaWithRecords(valueLabel),\n ]);\n","export const RECORDS_PER_PAGE_DEFAULT = 10;\n\nexport const RECORDS_PER_PAGE_MAX = 100;\n\n/**\n * Request page params.\n */\nexport interface RequestPageParams {\n /**\n * Requested page number (1-indexed)\n * @invariant Must be a positive integer (>= 1)\n * @default 1\n */\n page?: number;\n\n /**\n * Maximum number of records to return per page\n * @invariant Must be a positive integer (>= 1) and less than or equal to {@link RECORDS_PER_PAGE_MAX}\n * @default {@link RECORDS_PER_PAGE_DEFAULT}\n */\n recordsPerPage?: number;\n}\n","import type { InterpretedName, UnixTimestamp } from \"enssdk\";\n\nimport type { RegistrarAction } from \"../../../registrars/registrar-action\";\nimport type { IndexingStatusResponseCodes } from \"../indexing-status/response\";\nimport type { ErrorResponse } from \"../shared/errors\";\nimport type { ResponsePageContext } from \"../shared/pagination\";\n\n/**\n * A status code for Registrar Actions API responses.\n */\nexport const RegistrarActionsResponseCodes = {\n /**\n * Represents that Registrar Actions are available.\n */\n Ok: \"ok\",\n\n /**\n * Represents that Registrar Actions are unavailable.\n */\n Error: \"error\",\n} as const;\n\n/**\n * The derived string union of possible {@link RegistrarActionsResponseCodes}.\n */\nexport type RegistrarActionsResponseCode =\n (typeof RegistrarActionsResponseCodes)[keyof typeof RegistrarActionsResponseCodes];\n\n/**\n * \"Logical registrar action\" with its associated name.\n */\nexport interface NamedRegistrarAction {\n action: RegistrarAction;\n\n /**\n * Name\n *\n * FQDN of the name associated with `action`.\n *\n * Guarantees:\n * - `namehash(name)` is always `action.registrationLifecycle.node`.\n */\n name: InterpretedName;\n}\n\n/**\n * A response when Registrar Actions are available.\n */\nexport type RegistrarActionsResponseOk = {\n responseCode: typeof RegistrarActionsResponseCodes.Ok;\n registrarActions: NamedRegistrarAction[];\n pageContext: ResponsePageContext;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the list of {@link NamedRegistrarAction} was accurate as of.\n *\n * @remarks\n * **Note:** This value represents the `omnichainIndexingCursor` from the latest omnichain indexing status\n * snapshot captured by ENSApi. The state returned in the response is guaranteed to be accurate as of this\n * timestamp but may be from a timestamp higher than this value.\n */\n accurateAsOf: UnixTimestamp;\n};\n\n/**\n * A response when Registrar Actions are unavailable.\n */\nexport interface RegistrarActionsResponseError {\n responseCode: typeof IndexingStatusResponseCodes.Error;\n error: ErrorResponse;\n}\n\n/**\n * Registrar Actions response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type RegistrarActionsResponse = RegistrarActionsResponseOk | RegistrarActionsResponseError;\n","import type { ResolverRecordsSelection } from \"../../../resolution\";\nimport type {\n ResolvePrimaryNameResponse,\n ResolvePrimaryNamesResponse,\n ResolveRecordsResponse,\n} from \"./types\";\n\n/**\n * Example values for {@link ResolveRecordsResponse}, for use in OpenAPI documentation.\n */\nexport const resolveRecordsResponseExample = {\n records: {\n addresses: { \"60\": \"0xd8da6bf26964af9d7eed9e03e53415d37aa96045\" },\n texts: {\n description: \"mi pinxe lo crino tcati\",\n },\n },\n accelerationRequested: false,\n accelerationAttempted: false,\n} satisfies ResolveRecordsResponse<ResolverRecordsSelection>;\n\n/**\n * Example values for {@link ResolvePrimaryNameResponse}, for use in OpenAPI documentation.\n */\nexport const resolvePrimaryNameResponseExample = {\n name: \"jesse.base.eth\",\n accelerationRequested: false,\n accelerationAttempted: false,\n} satisfies ResolvePrimaryNameResponse;\n\n/**\n * Example values for {@link ResolvePrimaryNamesResponse}, for use in OpenAPI documentation.\n */\nexport const resolvePrimaryNamesResponseExample = {\n names: {\n \"1\": \"jesse.base.eth\",\n \"10\": null,\n \"8453\": \"jesse.base.eth\",\n \"42161\": null,\n \"59144\": null,\n \"534352\": null,\n },\n accelerationRequested: false,\n accelerationAttempted: false,\n} satisfies ResolvePrimaryNamesResponse;\n","import { z } from \"zod/v4\";\n\n/**\n * Schema for resolver records response.\n *\n * NOTE: `version` and `abi.contentType` arrive over the wire as strings (server serializes\n * bigints via `replaceBigInts(response, String)` to avoid `JSON.stringify` throwing on bigint).\n * Callers that need these as `bigint` should `BigInt(...)` them.\n */\nconst makeResolverRecordsResponseSchema = () =>\n z.object({\n name: z.string().nullable().optional(),\n addresses: z.record(z.string(), z.string().nullable()).optional(),\n texts: z.record(z.string(), z.string().nullable()).optional(),\n contenthash: z.string().nullable().optional(),\n pubkey: z.object({ x: z.string(), y: z.string() }).nullable().optional(),\n dnszonehash: z.string().nullable().optional(),\n version: z.string().nullable().optional(),\n abi: z.object({ contentType: z.string(), data: z.string() }).nullable().optional(),\n interfaces: z.record(z.string(), z.string().nullable()).optional(),\n });\n\n/**\n * Schema for {@link ResolveRecordsResponse}\n */\nexport const makeResolveRecordsResponseSchema = () =>\n z.object({\n records: makeResolverRecordsResponseSchema(),\n accelerationRequested: z.boolean(),\n accelerationAttempted: z.boolean(),\n // TODO: Find a better way to handle recursive types, patch solution is .unknown()\n trace: z.array(z.unknown()).optional(),\n });\n\n/**\n * Schema for {@link ResolvePrimaryNameResponse}\n */\nexport const makeResolvePrimaryNameResponseSchema = () =>\n z.object({\n name: z.string().nullable(),\n accelerationRequested: z.boolean(),\n accelerationAttempted: z.boolean(),\n trace: z.array(z.unknown()).optional(),\n });\n\n/**\n * Schema for {@link ResolvePrimaryNamesResponse}\n */\nexport const makeResolvePrimaryNamesResponseSchema = () =>\n z.object({\n names: z.record(z.number(), z.string().nullable()),\n accelerationRequested: z.boolean(),\n accelerationAttempted: z.boolean(),\n trace: z.array(z.unknown()).optional(),\n });\n","import type { ErrorResponse } from \"./response\";\n\n/**\n * Example value for {@link ErrorResponse} representing a 400 Bad Request, for use in OpenAPI documentation.\n */\nexport const errorResponseBadRequestExample = {\n message: \"Invalid Input\",\n} satisfies ErrorResponse;\n\n/**\n * Example value for {@link ErrorResponse} representing a 400 Bad Request for an invalid ENS name,\n * for use in OpenAPI documentation.\n */\nexport const errorResponseInvalidNameExample = {\n message: \"Invalid Input\",\n details: {\n errors: [],\n properties: {\n name: { errors: [\"Must be normalized, see https://docs.ens.domains/resolution/names/\"] },\n },\n },\n} satisfies ErrorResponse;\n\n/**\n * Example value for {@link ErrorResponse} representing a 400 Bad Request for an invalid address,\n * for use in OpenAPI documentation.\n */\nexport const errorResponseInvalidAddressExample = {\n message: \"Invalid Input\",\n details: {\n errors: [],\n properties: { address: { errors: [\"EVM address must be a valid EVM address\"] } },\n },\n} satisfies ErrorResponse;\n\n/**\n * Example value for {@link ErrorResponse} representing a 500 Internal Server Error, for use in OpenAPI documentation.\n */\nexport const errorResponseInternalServerErrorExample = {\n message: \"Internal Server Error\",\n} satisfies ErrorResponse;\n","import { asInterpretedName, toNormalizedAddress } from \"enssdk\";\n\nimport { DatasourceNames, ENSNamespaceIds } from \"@ensnode/datasources\";\nimport { accounts } from \"@ensnode/datasources/devnet\";\n\nimport { maybeGetDatasourceContract } from \"../shared/datasource-contract\";\nimport type { NamespaceSpecificValue } from \"../shared/namespace-specific-value\";\n\nconst SEPOLIA_V2_V2_ETH_REGISTRY = maybeGetDatasourceContract(\n ENSNamespaceIds.SepoliaV2,\n DatasourceNames.ENSv2Root,\n \"ETHRegistry\",\n);\n\nconst SEPOLIA_V2_V2_ETH_REGISTRAR = maybeGetDatasourceContract(\n ENSNamespaceIds.SepoliaV2,\n DatasourceNames.ENSv2Root,\n \"ETHRegistrar\",\n);\n\nconst ENS_TEST_ENV_V2_ETH_REGISTRY = maybeGetDatasourceContract(\n ENSNamespaceIds.EnsTestEnv,\n DatasourceNames.ENSv2Root,\n \"ETHRegistry\",\n);\n\nconst ENS_TEST_ENV_V2_ETH_REGISTRAR = maybeGetDatasourceContract(\n ENSNamespaceIds.EnsTestEnv,\n DatasourceNames.ENSv2Root,\n \"ETHRegistrar\",\n);\n\nconst VITALIK_ADDRESS = toNormalizedAddress(\"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\");\n\n// owns sfmonicdeb*.eth (mix of v1 + v2) on sepolia-v2 and holds v2 ETHRegistry permissions\nconst _SEPOLIA_V2_USER_ADDRESS = toNormalizedAddress(\"0x2f8e8b1126e75fde0b7f731e7cb5847eba2d2574\");\n\nconst SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES = toNormalizedAddress(\n \"0x205d2686da3bf33f64c17f21462c51b5ead462cf\",\n);\n\nconst DEVNET_NAME_WITH_OWNED_RESOLVER = asInterpretedName(\"example.eth\");\n\nconst SEPOLIA_V2_NAME_WITH_OWNED_RESOLVER = asInterpretedName(\"sfmonicdebmig.eth\");\n\nconst SEPOLIA_V2_TEST_NAME = asInterpretedName(\"test-name.eth\");\n\nexport type GraphqlApiExampleQuery = {\n id: string;\n query: string;\n variables: NamespaceSpecificValue<Record<string, unknown>>;\n};\n\nexport function getGraphqlApiExampleQueryById(id: string): GraphqlApiExampleQuery {\n const found = graphqlApiExampleQueryById.get(id);\n if (!found) {\n throw new Error(`Unknown GraphQL API example query id: ${id}`);\n }\n return found;\n}\n\nexport const GRAPHQL_API_EXAMPLE_QUERIES: GraphqlApiExampleQuery[] = [\n ////////////////\n // Hello World\n ////////////////\n {\n id: \"hello-world\",\n query: `#\n# Welcome to this interactive playground for\n# ENSNode's GraphQL API!\n#\n# You can get started by typing your query here or by using\n# the Explorer on the left to select the data you want to query.\n#\n# There are also example queries in the tabs above ☝️\nquery HelloWorld {\n domain(by: { name: \"eth\" }) { canonical { name { interpreted } } owner { address } }\n}`,\n variables: { default: {} },\n },\n\n /////////////////\n // Find Domains\n /////////////////\n {\n id: \"find-domains\",\n query: `\nquery FindDomains(\n $name: DomainsNameFilter!\n $order: DomainsOrderInput\n) {\n domains(\n where: { name: $name }\n order: $order\n first: 20\n ) {\n edges {\n node {\n __typename\n id\n label { interpreted hash }\n canonical { name { interpreted } }\n\n registration { expiry event { timestamp } }\n }\n }\n }\n}`,\n variables: {\n default: { name: { starts_with: \"vitalik\" }, order: { by: \"NAME\", dir: \"DESC\" } },\n [ENSNamespaceIds.EnsTestEnv]: {\n name: { starts_with: \"c\" },\n order: { by: \"NAME\", dir: \"DESC\" },\n },\n [ENSNamespaceIds.SepoliaV2]: {\n name: { starts_with: \"test-na\" },\n order: { by: \"NAME\", dir: \"DESC\" },\n },\n },\n },\n\n ///////////////////\n // Domain By Name\n ///////////////////\n {\n id: \"domain-by-name\",\n query: `\nquery DomainByName($name: InterpretedName!) {\n domain(by: {name: $name}) {\n __typename\n id\n label { interpreted hash }\n canonical { name { interpreted } node path { id } }\n owner { address }\n subregistry { contract { chainId address } }\n\n ... on ENSv1Domain {\n rootRegistryOwner { address }\n }\n }\n}`,\n variables: {\n default: { name: \"eth\" },\n [ENSNamespaceIds.SepoliaV2]: { name: SEPOLIA_V2_TEST_NAME },\n },\n },\n\n //////////////////////\n // Domain Subdomains\n //////////////////////\n {\n id: \"domain-subdomains\",\n query: `\nquery DomainSubdomains($name: InterpretedName!) {\n domain(by: {name: $name}) {\n canonical { name { interpreted } }\n subdomains(first: 10) {\n edges {\n node {\n canonical { name { interpreted } }\n }\n }\n }\n }\n}`,\n variables: { default: { name: \"eth\" } },\n },\n\n /////////////////\n // Domain Events\n /////////////////\n {\n id: \"domain-events\",\n query: `\nquery DomainEvents($name: InterpretedName!) {\n domain(by: {name: $name}) {\n events {\n totalCount\n edges {\n node {\n from\n to\n topics\n data\n timestamp\n transactionHash\n }\n }\n }\n }\n}`,\n variables: {\n default: { name: \"newowner.eth\" },\n [ENSNamespaceIds.SepoliaV2]: { name: \"sfmonicdebmig.eth\" },\n },\n },\n\n ////////////////////\n // Account Domains\n ////////////////////\n {\n id: \"domains-by-address\",\n query: `\nquery AccountDomains(\n $address: Address!\n) {\n account(by: { address: $address }) {\n domains {\n edges {\n node {\n label { interpreted }\n canonical { name { interpreted } }\n }\n }\n }\n }\n}`,\n variables: {\n default: { address: VITALIK_ADDRESS },\n [ENSNamespaceIds.EnsTestEnv]: { address: accounts.owner.address },\n [ENSNamespaceIds.SepoliaV2]: { address: SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES },\n },\n },\n\n ////////////////////\n // Account Events\n ////////////////////\n {\n id: \"account-events\",\n query: `\nquery AccountEvents(\n $address: Address!\n) {\n account(by: { address: $address }) {\n events { totalCount edges { node { topics data timestamp } } }\n }\n}`,\n variables: {\n default: { address: VITALIK_ADDRESS },\n [ENSNamespaceIds.EnsTestEnv]: { address: accounts.deployer.address },\n [ENSNamespaceIds.SepoliaV2]: { address: SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES },\n },\n },\n\n /////////////////////\n // Registry Domains\n /////////////////////\n {\n id: \"registry-domains\",\n query: `\nquery RegistryDomains(\n $registry: AccountIdInput!\n) {\n registry(by: { contract: $registry }) {\n domains {\n edges {\n node {\n label { interpreted }\n canonical { name { interpreted } }\n }\n }\n }\n }\n}`,\n variables: {\n // TODO: this only accesses v2 registries, so we default to ens-test-env for now\n default: { registry: ENS_TEST_ENV_V2_ETH_REGISTRY },\n [ENSNamespaceIds.SepoliaV2]: { registry: SEPOLIA_V2_V2_ETH_REGISTRY },\n },\n },\n\n ////////////////////////////\n // Permissions By Contract\n ////////////////////////////\n {\n id: \"permissions-by-contract\",\n query: `\nquery PermissionsByContract(\n $contract: AccountIdInput!\n) {\n permissions(by: { contract: $contract }) {\n resources {\n edges {\n node {\n resource\n users {\n edges {\n node {\n id\n user { address }\n roles\n }\n }\n }\n }\n }\n }\n events { totalCount edges { node { topics data timestamp } } }\n }\n}`,\n variables: {\n // TODO: same as above\n default: { contract: ENS_TEST_ENV_V2_ETH_REGISTRAR },\n // TODO: example response is empty for this address on Sepolia V2\n [ENSNamespaceIds.SepoliaV2]: { contract: SEPOLIA_V2_V2_ETH_REGISTRAR },\n },\n },\n\n ////////////////////////\n // Permissions By User\n ////////////////////////\n {\n id: \"permissions-by-user\",\n query: `\nquery PermissionsByUser($address: Address!) {\n account(by: { address: $address }) {\n permissions {\n edges {\n node {\n resource\n roles\n }\n }\n }\n }\n}`,\n variables: {\n default: { address: accounts.deployer.address },\n // TODO: example response is empty for this address on Sepolia V2\n [ENSNamespaceIds.SepoliaV2]: { address: SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES },\n },\n },\n\n //////////////////////////////////\n // Account Resolver Permissions\n //////////////////////////////////\n {\n id: \"account-resolver-permissions\",\n query: `\nquery AccountResolverPermissions($address: Address!) {\n account(by: { address: $address }) {\n resolverPermissions {\n edges {\n node {\n resolver {\n contract {\n address\n }\n }\n }\n }\n }\n }\n}`,\n variables: {\n default: { address: accounts.deployer.address },\n [ENSNamespaceIds.SepoliaV2]: { address: SEPOLIA_V2_ADDRESS_WITH_LOT_OF_NAMES },\n },\n },\n\n //////////////////////////////\n // Domain's Assigned Resolver\n //////////////////////////////\n {\n id: \"domain-resolver\",\n query: `\nquery DomainResolver($name: InterpretedName!) {\n domain(by: { name: $name }) {\n resolver {\n assigned {\n records { edges { node { node keys coinTypes } } }\n permissions { resources { edges { node { resource users { edges { node { user { address } roles } } } } } } }\n events { totalCount edges { node { topics data timestamp } } }\n }\n }\n }\n}`,\n variables: {\n default: { name: \"vitalik.eth\" },\n [ENSNamespaceIds.EnsTestEnv]: { name: DEVNET_NAME_WITH_OWNED_RESOLVER },\n [ENSNamespaceIds.SepoliaV2]: { name: SEPOLIA_V2_NAME_WITH_OWNED_RESOLVER },\n },\n },\n\n //////////////\n // Namegraph\n //////////////\n {\n id: \"namegraph\",\n query: `\nquery Namegraph {\n root {\n id\n domains {\n edges {\n node {\n canonical { name { interpreted } }\n\n subdomains {\n edges {\n node {\n canonical { name { interpreted } }\n\n subdomains {\n edges {\n node {\n canonical { name { interpreted } }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n}`,\n variables: { default: {} },\n },\n];\n\nconst graphqlApiExampleQueryById = new Map(\n GRAPHQL_API_EXAMPLE_QUERIES.map((entry) => [entry.id, entry]),\n);\n","import type { Address, InterfaceId } from \"enssdk\";\n\n/**\n * EIP-165 ABI\n * @see https://eips.ethereum.org/EIPS/eip-165\n */\nconst EIP_165_ABI = [\n {\n inputs: [\n {\n internalType: \"bytes4\",\n name: \"interfaceID\",\n type: \"bytes4\",\n },\n ],\n name: \"supportsInterface\",\n outputs: [\n {\n internalType: \"bool\",\n name: \"\",\n type: \"bool\",\n },\n ],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/**\n * Determines whether a Contract at `address` supports a specific EIP-165 `interfaceId`.\n *\n * Accepts both viem PublicClient and Ponder Context client types.\n */\nasync function supportsInterface<\n TClient extends {\n readContract: (params: {\n abi: typeof EIP_165_ABI;\n functionName: \"supportsInterface\";\n address: Address;\n args: readonly [InterfaceId];\n }) => Promise<boolean>;\n },\n>({\n publicClient,\n interfaceId: selector,\n address,\n}: {\n address: Address;\n interfaceId: InterfaceId;\n publicClient: TClient;\n}) {\n try {\n return await publicClient.readContract({\n abi: EIP_165_ABI,\n functionName: \"supportsInterface\",\n address,\n args: [selector],\n });\n } catch {\n // this call reverted for whatever reason — this contract does not support the interface\n return false;\n }\n}\n\nexport const makeSupportsInterfaceReader =\n (interfaceId: InterfaceId) =>\n (args: Omit<Parameters<typeof supportsInterface>[0], \"interfaceId\">) =>\n supportsInterface({\n ...args,\n interfaceId,\n });\n","import { makeSupportsInterfaceReader } from \"./eip-165\";\n\n/**\n * ENSIP-10 Wildcard Resolution Interface Id\n * @see https://docs.ens.domains/ensip/10\n */\nconst IExtendedResolverInterfaceId = \"0x9061b923\";\n\n/**\n * Determines whether a Resolver contract supports ENSIP-10.\n */\nexport const isExtendedResolver = makeSupportsInterfaceReader(IExtendedResolverInterfaceId);\n","import type { ChainId } from \"enssdk\";\nimport {\n arbitrum,\n arbitrumSepolia,\n base,\n baseSepolia,\n linea,\n lineaSepolia,\n mainnet,\n optimism,\n optimismSepolia,\n scroll,\n scrollSepolia,\n sepolia,\n} from \"viem/chains\";\n\n/**\n * Builds a Alchemy RPC base URL for the specified chain ID.\n *\n * @param chainId - The chain ID to build the RPC base URL for\n * @param key - The Alchemy API key\n * @returns The Alchemy RPC base URL, or undefined if the chain is not supported\n *\n * @example\n * ```typescript\n * const url = buildAlchemyUrl(1, \"your-api-key\");\n * // Returns: \"eth-mainnet.g.alchemy.com/v2/your-api-key\"\n * ```\n */\nexport function buildAlchemyBaseUrl(chainId: ChainId, key: string): string | undefined {\n switch (chainId) {\n case mainnet.id:\n return `eth-mainnet.g.alchemy.com/v2/${key}`;\n case sepolia.id:\n return `eth-sepolia.g.alchemy.com/v2/${key}`;\n case arbitrum.id:\n return `arb-mainnet.g.alchemy.com/v2/${key}`;\n case arbitrumSepolia.id:\n return `arb-sepolia.g.alchemy.com/v2/${key}`;\n case base.id:\n return `base-mainnet.g.alchemy.com/v2/${key}`;\n case baseSepolia.id:\n return `base-sepolia.g.alchemy.com/v2/${key}`;\n case optimism.id:\n return `opt-mainnet.g.alchemy.com/v2/${key}`;\n case optimismSepolia.id:\n return `opt-sepolia.g.alchemy.com/v2/${key}`;\n case linea.id:\n return `linea-mainnet.g.alchemy.com/v2/${key}`;\n case lineaSepolia.id:\n return `linea-sepolia.g.alchemy.com/v2/${key}`;\n case scroll.id:\n return `scroll-mainnet.g.alchemy.com/v2/${key}`;\n case scrollSepolia.id:\n return `scroll-sepolia.g.alchemy.com/v2/${key}`;\n default:\n return undefined;\n }\n}\n\n/**\n * Builds a dRPC RPC URL for the specified chain ID.\n *\n * @param chainId - The chain ID to build the RPC URL for\n * @param key - The dRPC API key\n * @returns The complete dRPC RPC URL, or undefined if the chain is not supported\n *\n * @example\n * ```typescript\n * const url = buildDRPCUrl(1, \"your-api-key\");\n * // Returns: \"https://lb.drpc.live/ethereum/your-api-key\"\n * ```\n */\nexport function buildDRPCUrl(chainId: ChainId, key: string): string | undefined {\n switch (chainId) {\n case mainnet.id:\n return `https://lb.drpc.live/ethereum/${key}`;\n case sepolia.id:\n return `https://lb.drpc.live/ethereum-sepolia/${key}`;\n case arbitrum.id:\n return `https://lb.drpc.live/arbitrum/${key}`;\n case arbitrumSepolia.id:\n return `https://lb.drpc.live/arbitrum-sepolia/${key}`;\n case base.id:\n return `https://lb.drpc.live/base/${key}`;\n case baseSepolia.id:\n return `https://lb.drpc.live/base-sepolia/${key}`;\n case optimism.id:\n return `https://lb.drpc.live/optimism/${key}`;\n case optimismSepolia.id:\n return `https://lb.drpc.live/optimism-sepolia/${key}`;\n case linea.id:\n return `https://lb.drpc.live/linea/${key}`;\n case lineaSepolia.id:\n return `https://lb.drpc.live/linea-sepolia/${key}`;\n case scroll.id:\n return `https://lb.drpc.live/scroll/${key}`;\n case scrollSepolia.id:\n return `https://lb.drpc.live/scroll-sepolia/${key}`;\n default:\n return undefined;\n }\n}\n\n/**\n * Builds a QuickNode RPC base URL for the specified chain ID.\n *\n * @param chainId - The chain ID to build the RPC base URL for\n * @param apiKey - The QuickNode API key\n * @param endpointName - The QuickNode Endpoint name\n * @returns The QuickNode RPC base URL, or undefined if the chain is not supported\n *\n * NOTE:\n * - Only multi-chain QuickNode endpoints are supported.\n * https://www.quicknode.com/guides/quicknode-products/how-to-use-multichain-endpoint\n * - QuickNode platform does not support Linea Sepolia RPC (as of 2025-12-03).\n * https://www.quicknode.com/docs/linea\n *\n * @example\n * ```typescript\n * const url = buildQuickNodeURL(1, \"your-api-key\", \"your-endpoint-name\");\n * // Returns: \"your-endpoint-name.quiknode.pro/your-api-key\"\n * ```\n */\nexport function buildQuickNodeURL(\n chainId: ChainId,\n apiKey: string,\n endpointName: string,\n): string | undefined {\n switch (chainId) {\n case mainnet.id:\n return `${endpointName}.quiknode.pro/${apiKey}`;\n case sepolia.id:\n return `${endpointName}.ethereum-sepolia.quiknode.pro/${apiKey}`;\n case arbitrum.id:\n return `${endpointName}.arbitrum-mainnet.quiknode.pro/${apiKey}`;\n case arbitrumSepolia.id:\n return `${endpointName}.arbitrum-sepolia.quiknode.pro/${apiKey}`;\n case base.id:\n return `${endpointName}.base-mainnet.quiknode.pro/${apiKey}`;\n case baseSepolia.id:\n return `${endpointName}.base-sepolia.quiknode.pro/${apiKey}`;\n case optimism.id:\n return `${endpointName}.optimism.quiknode.pro/${apiKey}`;\n case optimismSepolia.id:\n return `${endpointName}.optimism-sepolia.quiknode.pro/${apiKey}`;\n case linea.id:\n return `${endpointName}.linea-mainnet.quiknode.pro/${apiKey}`;\n case lineaSepolia.id:\n return undefined;\n case scroll.id:\n return `${endpointName}.scroll-mainnet.quiknode.pro/${apiKey}`;\n case scrollSepolia.id:\n return `${endpointName}.scroll-testnet.quiknode.pro/${apiKey}`;\n default:\n return undefined;\n }\n}\n\nexport function alchemySupportsChain(chainId: ChainId) {\n return buildAlchemyBaseUrl(chainId, \"\") !== undefined;\n}\n\nexport function dRPCSupportsChain(chainId: ChainId) {\n return buildDRPCUrl(chainId, \"\") !== undefined;\n}\n\nexport function quickNodeSupportsChain(chainId: ChainId) {\n return buildQuickNodeURL(chainId, \"\", \"\") !== undefined;\n}\n","/**\n * A replacer function to be used with `JSON.stringify` for configuration objects.\n *\n * It handles common patterns like:\n * - Stringifying URL objects\n * - Truncating large ABI objects\n * - Converting Map objects to plain objects for serialization\n */\nfunction configJSONReplacer(key: string, value: unknown): unknown {\n // stringify a URL object\n if (value instanceof URL) return value.href;\n\n // truncate ABI value\n if (key === \"abi\") return \"(truncated ABI output)\";\n\n // convert Map to plain object for serialization\n if (value instanceof Map) return Object.fromEntries(value);\n\n // convert Set to array for serialization\n if (value instanceof Set) return Array.from(value);\n\n // pass-through value\n return value;\n}\n\n/**\n * Stringify a config object.\n *\n * @param json The config object to print\n * @param options.pretty Whether to pretty print the JSON output. Defaults to false (minified).\n * @returns The JSON string representation of the config object\n */\nexport const stringifyConfig = (json: any, options: { pretty: boolean } = { pretty: false }) =>\n JSON.stringify(json, configJSONReplacer, options.pretty ? 2 : undefined);\n","/**\n * Generic utilities for redacting sensitive information from configuration objects.\n */\n\nimport type { RpcConfig, RpcConfigs } from \"./types\";\n\n/**\n * Default redacted value placeholder.\n */\nconst REDACTED = \"*****\";\n\n/**\n * Generic function to redact URL objects by replacing the path with a redacted placeholder.\n */\nexport function redactUrl(url: URL): URL {\n return new URL(`/${REDACTED}`, url.origin);\n}\n\n/**\n * Generic function to redact strings by replacing them with a redacted placeholder.\n */\nexport function redactString(_: string): string {\n return REDACTED;\n}\n\n/**\n * Redact RPC configs by replacing URLs with redacted values.\n */\nexport function redactRpcConfigs(rpcConfigs: RpcConfigs): RpcConfigs {\n const redactedRpcConfigs = new Map<number, RpcConfig>();\n\n for (const [chainId, rpcConfig] of rpcConfigs.entries()) {\n const redactedHttpRPCs = rpcConfig.httpRPCs.map(redactUrl) as [URL, ...URL[]];\n const redactedWebsocketRPC = rpcConfig.websocketRPC\n ? redactUrl(rpcConfig.websocketRPC)\n : undefined;\n\n redactedRpcConfigs.set(chainId, {\n httpRPCs: redactedHttpRPCs,\n websocketRPC: redactedWebsocketRPC,\n });\n }\n\n return redactedRpcConfigs;\n}\n","import type { ChainIdString } from \"enssdk\";\n\nimport {\n type Datasource,\n type ENSNamespaceId,\n ensTestEnvChain,\n getENSNamespace,\n} from \"@ensnode/datasources\";\n\nimport { serializeChainId } from \"../serialize\";\nimport type { Unvalidated } from \"../types\";\nimport {\n alchemySupportsChain,\n buildAlchemyBaseUrl,\n buildDRPCUrl,\n buildQuickNodeURL,\n dRPCSupportsChain,\n quickNodeSupportsChain,\n} from \"./build-rpc-urls\";\nimport type { ChainIdSpecificRpcEnvironmentVariable, RpcEnvironment } from \"./environments\";\n\n/**\n * Mode for auto-generating RPCs across indexed chains.\n */\nconst RpcAutoGenModes = {\n /**\n * Auto-generates only HTTP RPCs for supported chains.\n */\n HttpOnly: \"http-only\",\n\n /**\n * Auto-generates both HTTP and WebSocket RPCs for supported chains.\n */\n HttpAndWs: \"http-and-ws\",\n} as const;\n\n/**\n * The derived string union of possible {@link RpcAutoGenModes}.\n */\ntype RpcAutoGenMode = (typeof RpcAutoGenModes)[keyof typeof RpcAutoGenModes];\n\n/**\n * Default mode for auto-generating RPCs across indexed chains.\n */\nconst DEFAULT_RPC_AUTO_GEN_MODE: RpcAutoGenMode = RpcAutoGenModes.HttpOnly;\n\n/**\n * Build the RPCs auto-generation mode based on environment variables, with validation.\n *\n * Note: if env.RPC_AUTO_GEN_MODE is not set,\n * {@link DEFAULT_RPC_AUTO_GEN_MODE} will be used as the default.\n *\n * @param env The RPC environment variables to determine the auto-generation mode.\n * @returns The RPCs auto-generation mode to use for building RPC configurations.\n * @throws Error if the provided RPC_AUTO_GEN_MODE env var is invalid.\n */\nexport function buildRpcAutoGenMode(env: RpcEnvironment): RpcAutoGenMode {\n const mode = env.RPC_AUTO_GEN_MODE as Unvalidated<RpcAutoGenMode>;\n\n if (!mode) {\n return DEFAULT_RPC_AUTO_GEN_MODE;\n }\n\n if (!Object.values(RpcAutoGenModes).includes(mode)) {\n throw new Error(\n `Invalid RPC_AUTO_GEN_MODE env var: ${mode}. Valid values are: ${Object.values(RpcAutoGenModes).join(\", \")}`,\n );\n }\n\n return mode;\n}\n\n/**\n * Constructs dynamic chain configuration from environment variables, scoped to chain IDs that appear\n * in the specified `namespace`.\n *\n * This function auto-generates RPCs, depending on\n * the configured {@link RpcAutoGenMode}, in the following order:\n * 1. RPC_URL_*, if available in the env\n * 2. Alchemy, if ALCHEMY_API_KEY is available in the env\n * 3. QuickNode, if both, QUICKNODE_API_KEY and QUICKNODE_ENDPOINT_NAME are specified,\n * a QuickNode RPC URL will be provided for each of the chains it supports.\n * 4. DRPC, if DRPC_API_KEY is available in the env\n *\n * It also provides a single Alchemy wss:// url if ALCHEMY_API_KEY is available in the env.\n *\n * NOTE: This function returns raw RpcConfigEnvironment values which are not yet parsed or validated.\n *\n * @throws when only one but not both of the following environment variables are defined:\n * {@link RpcEnvironment.QUICKNODE_API_KEY} or\n * {@link RpcEnvironment.QUICKNODE_ENDPOINT_NAME}.\n */\nexport function buildRpcConfigsFromEnv(\n env: RpcEnvironment,\n namespace: ENSNamespaceId,\n): Record<ChainIdString, ChainIdSpecificRpcEnvironmentVariable> {\n const alchemyApiKey = env.ALCHEMY_API_KEY;\n const quickNodeApiKey = env.QUICKNODE_API_KEY;\n const quickNodeEndpointName = env.QUICKNODE_ENDPOINT_NAME;\n const dRPCKey = env.DRPC_API_KEY;\n\n // Invariant: QuickNode: using API key requires using endpoint name as well.\n if (quickNodeApiKey && !quickNodeEndpointName) {\n throw new Error(\n \"Use of the QUICKNODE_API_KEY environment variable requires use of the QUICKNODE_ENDPOINT_NAME environment variable as well.\",\n );\n }\n\n // Invariant: QuickNode: using endpoint name requires using API key as well.\n if (quickNodeEndpointName && !quickNodeApiKey) {\n throw new Error(\n \"Use of the QUICKNODE_ENDPOINT_NAME environment variable requires use of the QUICKNODE_API_KEY environment variable as well.\",\n );\n }\n\n const chainsInNamespace = Object.entries(getENSNamespace(namespace)).map(\n ([, datasource]) => (datasource as Datasource).chain,\n );\n\n const rpcAutoGenMode = buildRpcAutoGenMode(env);\n const rpcConfigs: Record<ChainIdString, ChainIdSpecificRpcEnvironmentVariable> = {};\n\n for (const chain of chainsInNamespace) {\n // RPC_URL_* takes precedence over convenience generation\n const specificValue = env[`RPC_URL_${chain.id}`];\n if (specificValue) {\n rpcConfigs[serializeChainId(chain.id)] = specificValue;\n continue;\n }\n\n // ens-test-env Chain\n if (chain.id === ensTestEnvChain.id) {\n rpcConfigs[serializeChainId(ensTestEnvChain.id)] = ensTestEnvChain.rpcUrls.default.http[0];\n continue;\n }\n\n const httpUrls = [\n // alchemy, if specified and available\n alchemyApiKey &&\n alchemySupportsChain(chain.id) &&\n `https://${buildAlchemyBaseUrl(chain.id, alchemyApiKey)}`,\n\n // QuickNode, if specified and available\n quickNodeApiKey &&\n quickNodeEndpointName &&\n quickNodeSupportsChain(chain.id) &&\n `https://${buildQuickNodeURL(chain.id, quickNodeApiKey, quickNodeEndpointName)}`,\n\n // dRPC, if specified and available\n dRPCKey && dRPCSupportsChain(chain.id) && buildDRPCUrl(chain.id, dRPCKey),\n ];\n\n const wsUrl =\n rpcAutoGenMode === RpcAutoGenModes.HttpAndWs &&\n alchemyApiKey &&\n alchemySupportsChain(chain.id) && //\n `wss://${buildAlchemyBaseUrl(chain.id, alchemyApiKey)}`;\n\n const urls = [...httpUrls, wsUrl]\n // filter out false/undefined values from the set of urls\n .filter(Boolean);\n\n // add if any urls were constructed\n if (urls.length > 0) {\n rpcConfigs[serializeChainId(chain.id)] = urls.join(\n \",\",\n ) as ChainIdSpecificRpcEnvironmentVariable;\n }\n }\n\n return rpcConfigs;\n}\n","import type { z } from \"zod/v4\";\n\nimport { getENSRootChainId } from \"@ensnode/datasources\";\n\nimport { isHttpProtocol, isWebSocketProtocol } from \"../url\";\nimport type { ZodCheckFnInput } from \"../zod-types\";\nimport type { ENSNamespaceSchema, RpcConfigsSchema } from \"./zod-schemas\";\n\n/**\n * Invariant: RPC endpoint configuration for a chain must include at least one http/https protocol URL.\n */\nexport function invariant_rpcEndpointConfigIncludesAtLeastOneHTTPProtocolURL(\n ctx: ZodCheckFnInput<URL[]>,\n) {\n const endpoints = ctx.value;\n const httpEndpoints = endpoints.filter(isHttpProtocol);\n\n if (httpEndpoints.length < 1) {\n ctx.issues.push({\n code: \"custom\",\n input: endpoints,\n message: `RPC endpoint configuration for a chain must include at least one http/https protocol URL.`,\n });\n }\n}\n\n/**\n * Invariant: RPC configuration for a chain must include at most one WS/WSS protocol URL.\n */\nexport function invariant_rpcEndpointConfigIncludesAtMostOneWebSocketsProtocolURL(\n ctx: ZodCheckFnInput<URL[]>,\n) {\n const endpoints = ctx.value;\n const wsEndpoints = endpoints.filter(isWebSocketProtocol);\n\n if (wsEndpoints.length > 1) {\n ctx.issues.push({\n code: \"custom\",\n input: endpoints,\n message: `RPC endpoint configuration for a chain must include at most one websocket (ws/wss) protocol URL.`,\n });\n }\n}\n\n// Invariant: rpcConfig is specified for the ENS Root Chain of the configured namespace\nexport function invariant_rpcConfigsSpecifiedForRootChain(\n ctx: ZodCheckFnInput<{\n namespace: z.infer<typeof ENSNamespaceSchema>;\n rpcConfigs: z.infer<typeof RpcConfigsSchema>;\n }>,\n) {\n const { value: config } = ctx;\n\n const ensRootChainId = getENSRootChainId(config.namespace);\n\n if (!config.rpcConfigs.has(ensRootChainId)) {\n ctx.issues.push({\n code: \"custom\",\n input: config,\n message: `An RPC Config for the ENS Root Chain ('${ensRootChainId}') is required, but none was specified.`,\n });\n }\n}\n","export function isHttpProtocol(url: URL): boolean {\n return [\"http:\", \"https:\"].includes(url.protocol);\n}\n\nexport function isWebSocketProtocol(url: URL): boolean {\n return [\"ws:\", \"wss:\"].includes(url.protocol);\n}\n","import type { ChainId } from \"enssdk\";\nimport { z } from \"zod/v4\";\n\nimport { ENSNamespaceIds } from \"@ensnode/datasources\";\n\nimport { deserializeChainId } from \"../deserialize\";\nimport { isHttpProtocol, isWebSocketProtocol } from \"../url\";\nimport { makeChainIdStringSchema, makeUrlSchema } from \"../zod-schemas\";\nimport type { RpcConfig } from \"./types\";\nimport {\n invariant_rpcEndpointConfigIncludesAtLeastOneHTTPProtocolURL,\n invariant_rpcEndpointConfigIncludesAtMostOneWebSocketsProtocolURL,\n} from \"./validatons\";\n\nconst RpcConfigSchema = z\n .string()\n .transform((val) => val.split(\",\"))\n .pipe(z.array(makeUrlSchema(\"RPC URL\")))\n .check(invariant_rpcEndpointConfigIncludesAtLeastOneHTTPProtocolURL)\n .check(invariant_rpcEndpointConfigIncludesAtMostOneWebSocketsProtocolURL);\n\nexport const RpcConfigsSchema = z\n .record(makeChainIdStringSchema(\"RPC URL\"), RpcConfigSchema, {\n error: \"Chains configuration must be an object mapping valid chain IDs to their configs.\",\n })\n .transform((records) => {\n const rpcConfigs = new Map<ChainId, RpcConfig>();\n\n for (const [chainIdString, rpcConfig] of Object.entries(records)) {\n // rpcConfig is guaranteed to include at least one HTTP protocol URL\n const httpRPCs = rpcConfig.filter(isHttpProtocol) as [URL, ...URL[]];\n\n // rpcConfig is guaranteed to include at most one WebSocket protocol URL\n const websocketRPC = rpcConfig.find(isWebSocketProtocol);\n\n rpcConfigs.set(deserializeChainId(chainIdString), {\n httpRPCs,\n websocketRPC,\n });\n }\n\n return rpcConfigs;\n });\n\nexport const ENSNamespaceSchema = z.enum(ENSNamespaceIds, {\n error: ({ input }) =>\n `Invalid NAMESPACE. Got '${input}', but supported ENS namespaces are: ${Object.keys(ENSNamespaceIds).join(\", \")}`,\n});\n\nexport const PortNumberSchema = z.coerce\n .number({ error: \"PORT must be a number.\" })\n .int({ error: \"PORT must be an integer.\" })\n .min(1, { error: \"PORT must be greater than or equal to 1.\" })\n .max(65535, { error: \"PORT must be less than or equal to 65535.\" });\n\nexport const OptionalPortNumberSchema = PortNumberSchema.optional();\n\nexport const TheGraphApiKeySchema = z.string().optional();\n","import type { AccountId, ChainId, ChainIdString, Duration, UrlString } from \"enssdk\";\nimport z, { prettifyError } from \"zod/v4\";\n\nimport type { PriceDai, PriceEnsTokens, PriceEth, PriceUsdc } from \"./currencies\";\nimport type { BlockNumber, BlockRef, Datetime } from \"./types\";\nimport {\n makeAccountIdStringSchema,\n makeBlockNumberSchema,\n makeBlockRefSchema,\n makeChainIdStringSchema,\n makeDatetimeSchema,\n makeDurationSchema,\n makePriceDaiSchema,\n makePriceEnsTokensSchema,\n makePriceEthSchema,\n makePriceUsdcSchema,\n makeUnixTimestampSchema,\n makeUrlSchema,\n} from \"./zod-schemas\";\n\nexport function deserializeChainId(maybeChainId: ChainIdString, valueLabel?: string): ChainId {\n const schema = makeChainIdStringSchema(valueLabel);\n const parsed = schema.safeParse(maybeChainId);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ChainId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeDatetime(maybeDatetime: string, valueLabel?: string): Datetime {\n const schema = makeDatetimeSchema(valueLabel);\n const parsed = schema.safeParse(maybeDatetime);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Datetime:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeUnixTimestamp(maybeTimestamp: number, valueLabel?: string) {\n const schema = makeUnixTimestampSchema(valueLabel);\n const parsed = schema.safeParse(maybeTimestamp);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize Unix Timestamp:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeUrl(maybeUrl: UrlString, valueLabel?: string): URL {\n const schema = makeUrlSchema(valueLabel);\n const parsed = schema.safeParse(maybeUrl);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize URL:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockNumber(maybeBlockNumber: number, valueLabel?: string): BlockNumber {\n const schema = makeBlockNumberSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockNumber);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize BlockNumber:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeBlockRef(\n maybeBlockRef: Partial<BlockRef>,\n valueLabel?: string,\n): BlockRef {\n const schema = makeBlockRefSchema(valueLabel);\n const parsed = schema.safeParse(maybeBlockRef);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize BlockRef:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializeDuration(maybeDuration: unknown, valueLabel?: string): Duration {\n const schema = z.coerce.number().pipe(makeDurationSchema(valueLabel));\n const parsed = schema.safeParse(maybeDuration);\n\n if (parsed.error) {\n throw new RangeError(`Cannot deserialize Duration:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function parseAccountId(maybeAccountId: unknown, valueLabel?: string): AccountId {\n const schema = makeAccountIdStringSchema(valueLabel);\n const parsed = schema.safeParse(maybeAccountId);\n\n if (parsed.error) {\n throw new RangeError(`Cannot deserialize AccountId:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializePriceEth(maybePrice: unknown, valueLabel?: string): PriceEth {\n const schema = makePriceEthSchema(valueLabel);\n const parsed = schema.safeParse(maybePrice);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize PriceEth:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializePriceUsdc(maybePrice: unknown, valueLabel?: string): PriceUsdc {\n const schema = makePriceUsdcSchema(valueLabel);\n const parsed = schema.safeParse(maybePrice);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize PriceUsdc:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializePriceDai(maybePrice: unknown, valueLabel?: string): PriceDai {\n const schema = makePriceDaiSchema(valueLabel);\n const parsed = schema.safeParse(maybePrice);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize PriceDai:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n\nexport function deserializePriceEnsTokens(\n maybePrice: unknown,\n valueLabel?: string,\n): PriceEnsTokens {\n const schema = makePriceEnsTokensSchema(valueLabel);\n const parsed = schema.safeParse(maybePrice);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize PriceEnsTokens:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\n}\n","import { ENSNamespaceIds } from \"@ensnode/datasources\";\n\n/**\n * Represents the well-known ENSNode configuration templates deployed to the cloud. The value of each\n * key matches the domain segment that identifies this configuration template.\n *\n * @see https://ensnode.io/docs/usage/hosted-ensnode-instances\n */\nexport const ConfigTemplateIds = {\n Mainnet: \"mainnet\",\n Sepolia: \"sepolia\",\n Alpha: \"alpha\",\n AlphaSepolia: \"alpha-sepolia\",\n};\n\nexport type ConfigTemplateId = (typeof ConfigTemplateIds)[keyof typeof ConfigTemplateIds];\n\n/**\n * Determines whether the provided `configTemplateId` is Subgraph Compatible.\n *\n * See packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.ts for additional info.\n *\n * @see https://ensnode.io/docs/concepts/what-is-the-ens-subgraph\n */\nexport function isConfigTemplateSubgraphCompatible(configTemplateId: ConfigTemplateId) {\n switch (configTemplateId) {\n // these ConfigTemplates are run with SUBGRAPH_COMPAT, meaning they are Subgraph Compatible\n case ConfigTemplateIds.Mainnet:\n case ConfigTemplateIds.Sepolia:\n return true;\n\n // these instances are NOT run with SUBGRAPH_COMPAT, meaning they are NOT Subgraph Compatible\n case ConfigTemplateIds.Alpha:\n case ConfigTemplateIds.AlphaSepolia:\n return false;\n default:\n throw new Error(\"never\");\n }\n}\n\n/**\n * Determines the ENSNamespaceId for the provided `configTemplateId`.\n *\n * @see https://ensnode.io/docs/usage/hosted-ensnode-instances\n */\nexport function namespaceForConfigTemplateId(configTemplateId: ConfigTemplateId) {\n switch (configTemplateId) {\n case ConfigTemplateIds.Alpha:\n case ConfigTemplateIds.Mainnet:\n return ENSNamespaceIds.Mainnet;\n case ConfigTemplateIds.AlphaSepolia:\n case ConfigTemplateIds.Sepolia:\n return ENSNamespaceIds.Sepolia;\n default:\n throw new Error(\"never\");\n }\n}\n","import {\n type ContractConfig,\n type Datasource,\n type DatasourceName,\n DatasourceNames,\n type ENSNamespaceId,\n maybeGetDatasource,\n} from \"@ensnode/datasources\";\n\nexport const DATASOURCE_NAMES_WITH_ENSv2_CONTRACTS = [\n DatasourceNames.ENSv2Root,\n] as const satisfies DatasourceName[];\n\n// avoids 'The inferred type of this node exceeds the maximum length the compiler will serialize'\ntype DatasourceWithENSv2Contracts = Datasource & {\n contracts: { Registry: ContractConfig; EnhancedAccessControl: ContractConfig };\n};\n\n/**\n * The set of DatasourceNames that describe ENSv2 contracts that are indexed by the\n * Protocol Acceleration plugin.\n */\nexport const getDatasourcesWithENSv2Contracts = (\n namespace: ENSNamespaceId,\n): DatasourceWithENSv2Contracts[] =>\n DATASOURCE_NAMES_WITH_ENSv2_CONTRACTS.map((datasourceName) =>\n maybeGetDatasource(namespace, datasourceName),\n )\n .filter((datasource) => !!datasource)\n .map((datasource) => {\n // all of the relevant datasources provide a Registry and EnhancedAccessControl ContractConfig\n if (!datasource.contracts.Registry || !datasource.contracts.EnhancedAccessControl) {\n throw new Error(\n `Invariant: Datasource does not define 'Registry' and 'EnhancedAccessControl' contracts. Defined contracts: ${JSON.stringify(Object.keys(datasource.contracts))}`,\n );\n }\n\n return datasource;\n });\n","import {\n type ContractConfig,\n type Datasource,\n type DatasourceName,\n DatasourceNames,\n type ENSNamespaceId,\n maybeGetDatasource,\n} from \"@ensnode/datasources\";\n\nimport { DATASOURCE_NAMES_WITH_ENSv2_CONTRACTS } from \"./datasources-with-ensv2-contracts\";\n\n// avoids 'The inferred type of this node exceeds the maximum length the compiler will serialize'\ntype DatasourceWithResolverContract = Datasource & { contracts: { Resolver: ContractConfig } };\n\nexport const DATASOURCE_NAMES_WITH_RESOLVERS = [\n DatasourceNames.ENSRoot,\n DatasourceNames.Basenames,\n DatasourceNames.Lineanames,\n DatasourceNames.ThreeDNSOptimism,\n DatasourceNames.ThreeDNSBase,\n\n // all datasources that define ENSv2 contracts also define Resolver\n ...DATASOURCE_NAMES_WITH_ENSv2_CONTRACTS,\n] as const satisfies DatasourceName[];\n\n/**\n * The set of DatasourceNames that describe Resolver contracts that are indexed by the\n * Protocol Acceleration plugin.\n */\nexport const getDatasourcesWithResolvers = (\n namespace: ENSNamespaceId,\n): DatasourceWithResolverContract[] =>\n DATASOURCE_NAMES_WITH_RESOLVERS.map((datasourceName) =>\n maybeGetDatasource(namespace, datasourceName),\n )\n .filter((datasource) => !!datasource)\n .map((datasource) => {\n // all of the relevant datasources provide a Resolver ContractConfig with a `startBlock`\n if (!datasource.contracts.Resolver) {\n throw new Error(\n `Invariant: Datasource does not define a 'Resolver' contract. Defined contracts: ${JSON.stringify(Object.keys(datasource.contracts))}`,\n );\n }\n\n return datasource;\n });\n","import type { NormalizedAddress } from \"enssdk\";\nimport { isAddressEqual, zeroAddress } from \"viem\";\n\n/**\n * Interprets a NormalizedAddress. zeroAddress is interpreted as null, otherwise as-is.\n */\nexport const interpretAddress = (owner: NormalizedAddress): NormalizedAddress | null =>\n isAddressEqual(zeroAddress, owner) ? null : owner;\n","import type { InterpretedName, LiteralName } from \"enssdk\";\nimport { isInterpretedName, toNormalizedAddress } from \"enssdk\";\nimport { isAddress, isAddressEqual, zeroAddress } from \"viem\";\n\nimport { hasNullByte } from \"../null-bytes\";\n\n/**\n * Interprets a name record value string and returns null if the value is interpreted as a deletion.\n *\n * The interpreted record value is either:\n * a) null, representing a non-existent or deletion of the record, or\n * b) an {@link InterpretedName}.\n *\n * @param value - The name record value string to interpret.\n * @returns The interpreted name string, or null if deleted.\n */\nexport function interpretNameRecordValue(value: LiteralName): InterpretedName | null {\n // empty string is technically an InterpretedName, representing the ens root node, but in the\n // context of a name record value, empty string is emitted when the user un-sets the record (this\n // is because the abi of this event is only capable of expressing string values, so empty string\n // canonically represents the non-existence or deletion of the record value)\n if (value === \"\") return null;\n\n // if not normalized, is not valid `name` record value\n if (!isInterpretedName(value)) return null;\n\n // otherwise, this is a non-empty-string normalized Name that can be used as a name() record value\n return value;\n}\n\n/**\n * Interprets an address record value string and returns null if the value is interpreted as a deletion.\n *\n * The interpreted record value is either:\n * a) null, representing a non-existent or deletion of the record, or\n * i. contains null bytes\n * ii. empty string\n * iii. empty hex (0x)\n * iv. zeroAddress\n * b) an address record value that\n * i. does not contain null bytes\n * ii. (if is an EVM address) is lowercase\n *\n * @param value - The address record value to interpret.\n * @returns The interpreted address string or null if deleted.\n */\nexport function interpretAddressRecordValue(value: string): string | null {\n // TODO(null-bytes): store null bytes correctly — for now, interpret as deletion\n if (hasNullByte(value)) return null;\n\n // interpret empty string as deletion of address record\n if (value === \"\") return null;\n\n // interpret empty bytes as deletion of address record\n if (value === \"0x\") return null;\n\n // if it's not an EVM address, return as-is\n if (!isAddress(value, { strict: false })) return value;\n\n // interpret zeroAddress as deletion\n if (isAddressEqual(value, zeroAddress)) return null;\n\n // otherwise normalize and return\n return toNormalizedAddress(value);\n}\n\n/**\n * Interprets a text record key string and returns null if the key should be ignored.\n *\n * The interpreted text record key is either:\n * a) null, representing a text record key that should be ignored, or\n * i. contains null bytes\n * ii. empty string\n * b) a text record key that\n * i. does not contain null bytes\n *\n * @param value - The text record key to interpret.\n * @returns The interpreted text string or null if ignored.\n */\nexport function interpretTextRecordKey(key: string): string | null {\n // TODO(null-bytes): store null bytes correctly — for now, ignore\n if (hasNullByte(key)) return null;\n\n // ignore empty-string keys\n if (key === \"\") return null;\n\n // otherwise return the key as-is\n return key;\n}\n\n/**\n * Interprets a text record value string and returns null if the value is interpreted as a deletion.\n *\n * The interpreted record value is either:\n * a) null, representing a non-existent or deletion of the record, or\n * i. contains null bytes\n * ii. empty string\n * b) a text record value that\n * i. does not contain null bytes\n *\n * @param value - The text record value to interpret.\n * @returns The interpreted text string or null if deleted.\n */\nexport function interpretTextRecordValue(value: string): string | null {\n // TODO(null-bytes): store null bytes correctly — for now, interpret as deletion\n if (hasNullByte(value)) return null;\n\n // interpret empty string as deletion of a text record\n if (value === \"\") return null;\n\n // otherwise return the string as-is\n return value;\n}\n","export const hasNullByte = (value: string) => value.indexOf(\"\\u0000\") !== -1;\n\nexport const stripNullBytes = (value: string) => value.replaceAll(\"\\u0000\", \"\");\n","import type { Hex } from \"enssdk\";\nimport { size, zeroHash } from \"viem\";\n\n/**\n * Interprets an ENSIP-7 contenthash value. Empty bytes are interpreted as deletion.\n */\nexport function interpretContenthashValue(value: Hex): Hex | null {\n if (size(value) === 0) return null;\n return value;\n}\n\n/**\n * Interprets a PubkeyResolver (x, y) pair. A (zeroHash, zeroHash) pair is interpreted as deletion.\n *\n * Invariant: both null together, or both set together.\n */\nexport function interpretPubkeyValue(x: Hex, y: Hex): { x: Hex; y: Hex } | null {\n if (x === zeroHash && y === zeroHash) return null;\n return { x, y };\n}\n\n/**\n * Interprets an IDNSZoneResolver zonehash value. Empty bytes are interpreted as deletion.\n */\nexport function interpretDnszonehashValue(value: Hex): Hex | null {\n if (size(value) === 0) return null;\n return value;\n}\n","import { z } from \"zod/v4\";\n\nimport type { LogLevelEnvironment } from \"./config/environments\";\n\n/**\n * Set of valid log levels, mirroring pino#LogLevelWithSilent.\n */\nconst LogLevelSchema = z.enum([\"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\", \"silent\"]);\n\nexport type LogLevel = z.infer<typeof LogLevelSchema>;\n\nexport function getLogLevelFromEnv(env: LogLevelEnvironment, defaultLogLevel: LogLevel): LogLevel {\n try {\n return LogLevelSchema.default(defaultLogLevel).parse(env.LOG_LEVEL);\n } catch {\n console.warn(\n `Invalid LOG_LEVEL '${env.LOG_LEVEL}', expected one of '${Object.values(LogLevelSchema.enum).join(\"' | '\")}' defaulting to '${defaultLogLevel}'`,\n );\n return defaultLogLevel;\n }\n}\n","import {\n type AccountId,\n type DomainId,\n makeENSv1DomainId,\n makeENSv1VirtualRegistryId,\n type RegistryId,\n} from \"enssdk\";\n\nimport { DatasourceNames, maybeGetDatasource } from \"@ensnode/datasources\";\nimport {\n accountIdEqual,\n type ENSNamespaceId,\n getDatasourceContract,\n getENSv1RootRegistry,\n getManagedName,\n} from \"@ensnode/ensnode-sdk\";\n\n// simple cache of BridgedResolverConfig by namespace because it's in an indexing hot-path\nconst cache = new Map<ENSNamespaceId, BridgedResolverConfig[]>();\n\n/**\n * Describes a Bridged Resolver's origin Domain and target Registry.\n */\nexport interface BridgedResolverConfig {\n /**\n * The Bridged Resolver connecting the origin Domain to the target Registry.\n */\n resolver: AccountId;\n\n /**\n * The DomainId of the _legitimate_ originating Domain on the ENS Root chain whose\n * Bridged Resolver attachment canonicalizes the bridged target Registry. Anyone can set a\n * known Bridged Resolver (e.g. `BasenamesL1Resolver`) as their resolver, but only the\n * originating Domain (e.g. mainnet `base.eth`) is the canonical parent of the bridged\n * target Registry.\n */\n originDomainId: DomainId;\n\n /**\n * The RegistryId of the _specific_ (Concrete or Virtual) Registry to which the Bridged Resolver defers.\n */\n targetRegistryId: RegistryId;\n\n /**\n * The AccountId of the Concrete Registry to which the Bridged Resolver defers, necessary for\n * current ENSv1 Protocol Acceleration implementation.\n * TODO: refactor Protocol Acceleration to operate over RegistryId instead of AccountId.\n */\n targetRegistry: AccountId;\n}\n\n/**\n * Constructs the known Bridged Resolver Configurations for the provided `namespace`.\n *\n * These Bridged Resolvers must abide the following pattern:\n * 1. They _always_ emit OffchainLookup for any resolve() call to a well-known CCIP-Read Gateway,\n * 2. That CCIP-Read Gateway exclusively consults a specific (shadow)Registry in order to identify\n * a name's active resolver and resolve records, and\n * 3. Its behavior is unlikely to change (i.e. the contract is not upgradable or is unlikely to be\n * upgraded in a way that violates principles 1. or 2.).\n *\n * The goal is to encode the pattern followed by projects like Basenames and Lineanames where a\n * wildcard resolver is used for subnames of base.eth and that L1Resolver always returns OffchainLookup\n * instructing the caller to consult a well-known CCIP-Read Gateway. This CCIP-Read Gateway then\n * exclusively behaves in the following way: it identifies the name's active resolver via a well-known\n * (shadow)Registry (likely on an L2), and resolves records on that active resolver.\n *\n * In these cases, if the Node-Resolver relationships for the (shadow)Registry in question are indexed,\n * then the CCIP-Read can be short-circuited, in favor of performing an _accelerated_ Forward Resolution\n * against the (shadow)Registry in question.\n *\n * TODO: these relationships could/should be encoded in an ENSIP\n * TODO: once Forward Resolution is updated for ENSv2, this likely just returns RegistryId\n */\nconst getBridgedResolverConfigs = (namespace: ENSNamespaceId): BridgedResolverConfig[] => {\n const cached = cache.get(namespace);\n if (cached) return cached;\n\n const configs: BridgedResolverConfig[] = [];\n\n const basenames = maybeGetDatasource(namespace, DatasourceNames.Basenames);\n if (basenames) {\n const resolver = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"BasenamesL1Resolver\",\n );\n const registry = getDatasourceContract(namespace, DatasourceNames.Basenames, \"Registry\");\n const { node } = getManagedName(namespace, registry);\n configs.push({\n resolver,\n originDomainId: makeENSv1DomainId(getENSv1RootRegistry(namespace), node),\n targetRegistry: registry,\n targetRegistryId: makeENSv1VirtualRegistryId(registry, node),\n });\n }\n\n const lineanames = maybeGetDatasource(namespace, DatasourceNames.Lineanames);\n if (lineanames) {\n const resolver = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"LineanamesL1Resolver\",\n );\n const registry = getDatasourceContract(namespace, DatasourceNames.Lineanames, \"Registry\");\n const { node } = getManagedName(namespace, registry);\n configs.push({\n resolver,\n originDomainId: makeENSv1DomainId(getENSv1RootRegistry(namespace), node),\n targetRegistry: registry,\n targetRegistryId: makeENSv1VirtualRegistryId(registry, node),\n });\n }\n\n cache.set(namespace, configs);\n\n return configs;\n};\n\n/**\n * For a given `resolver`, if it is a known Bridged Resolver, return its Bridged Resolver Config.\n */\nexport function isBridgedResolver(\n namespace: ENSNamespaceId,\n resolver: AccountId,\n): BridgedResolverConfig | null {\n return (\n getBridgedResolverConfigs(namespace).find((config) =>\n accountIdEqual(config.resolver, resolver),\n ) ?? null\n );\n}\n\n/**\n * Returns true iff `domainId` is the origin Domain of a known Bridged Resolver.\n *\n * `Domain.subregistryId` on a bridge origin (e.g. mainnet `base.eth`, `linea.eth`) is owned by\n * `handleBridgedResolverChange` — it must point at the bridged target Registry on the L2 chain\n * so the canonical edge to that target Registry can agree. Chain-local subname events on the\n * origin Domain must not overwrite that pointer.\n */\nexport function isBridgeOriginDomain(namespace: ENSNamespaceId, domainId: DomainId): boolean {\n return getBridgedResolverConfigs(namespace).some((config) => config.originDomainId === domainId);\n}\n\n/**\n * Returns true iff `registryId` is the target Registry of a known Bridged Resolver.\n *\n * `Registry.canonicalDomainId` on a bridged target (e.g. the Basenames/Lineanames L2 Registries)\n * is owned by `handleBridgedResolverChange` — it must point at the mainnet origin Domain so the\n * canonical edge can agree. Chain-local subname events on the target Registry must not overwrite\n * that pointer with the L2-side Domain ID.\n */\nexport function isBridgedTargetRegistry(\n namespace: ENSNamespaceId,\n registryId: RegistryId,\n): boolean {\n return getBridgedResolverConfigs(namespace).some(\n (config) => config.targetRegistryId === registryId,\n );\n}\n","import {\n type AccountId,\n type AccountIdString,\n asInterpretedName,\n ENS_ROOT_NAME,\n type InterpretedName,\n type Name,\n type Node,\n namehashInterpretedName,\n stringifyAccountId,\n} from \"enssdk\";\n\nimport { DatasourceNames, type ENSNamespaceId } from \"@ensnode/datasources\";\n\nimport { accountIdEqual } from \"./account-id\";\nimport { getDatasourceContract, maybeGetDatasourceContract } from \"./datasource-contract\";\nimport { toJson } from \"./to-json\";\n\n/**\n * Many contracts within the ENSv1 Ecosystem are relative to a parent Name. For example,\n * the .eth BaseRegistrar (and RegistrarControllers) manage direct subnames of .eth. As such, they\n * operate on relative Labels, not fully qualified Names. We must know the parent name whose subnames\n * they manage in order to index them correctly.\n *\n * Because we use shared indexing logic for each instance of these contracts (BaseRegistrar,\n * RegistrarControllers, NameWrapper), the concept of \"which name is this contract operating in\n * the context of\" must be generalizable: this is the contract's 'Managed Name'.\n *\n * Concretely, a .eth RegistrarController will emit a _LabelHash_ indicating a new Registration, but\n * correlating that LabelHash with the NameHash of the Name requires knowing the NameHash of the\n * Registrar's Managed Name ('eth' in this case).\n *\n * The NameWrapper contracts are relevant here as well because they include specialized logic for\n * wrapping direct subnames of specific Managed Names.\n */\n\n/**\n * Each Managed Name group is associated with exactly one concrete ENSv1 Registry (the mainnet ENS\n * Registry, the Basenames shadow Registry, or the Lineanames shadow Registry). The Registry is\n * what `handleNewOwner` writes domains into and what every Registrar/Controller/NameWrapper under\n * the same Managed Name contributes to.\n */\ninterface ManagedNameGroup {\n registry: AccountId;\n contracts: AccountId[];\n}\n\n/**\n * Certain Managed Names are different depending on the ENSNamespace — this encodes that relationship.\n */\nconst MANAGED_NAME_BY_NAMESPACE: Partial<Record<ENSNamespaceId, Record<Name, Name>>> = {\n sepolia: {\n \"base.eth\": \"basetest.eth\",\n \"linea.eth\": \"linea-sepolia.eth\",\n },\n};\n\n/**\n * Produces a mapping of a Managed Name to its concrete Registry and the contracts that operate in\n * its (sub)Registry context.\n */\nconst getContractsByManagedName = (namespace: ENSNamespaceId) => {\n const ensRootRegistry = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"ENSv1Registry\",\n );\n const ensRootRegistryOld = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"ENSv1RegistryOld\",\n );\n const ethnamesNameWrapper = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"NameWrapper\",\n );\n\n const basenamesRegistry = maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Basenames,\n \"Registry\",\n );\n const lineanamesRegistry = maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Lineanames,\n \"Registry\",\n );\n const lineanamesNameWrapper = maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Lineanames,\n \"NameWrapper\",\n );\n\n return {\n [ENS_ROOT_NAME]: {\n registry: ensRootRegistry,\n contracts: [ensRootRegistry, ensRootRegistryOld],\n },\n eth: {\n registry: ensRootRegistry,\n contracts: [\n getDatasourceContract(namespace, DatasourceNames.ENSRoot, \"BaseRegistrar\"),\n getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"UnwrappedEthRegistrarController\",\n ),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"LegacyEthRegistrarController\",\n ),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"WrappedEthRegistrarController\",\n ),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"UniversalRegistrarRenewalWithReferrer\",\n ),\n ethnamesNameWrapper,\n ].filter((c): c is AccountId => !!c),\n },\n ...(basenamesRegistry && {\n \"base.eth\": {\n registry: basenamesRegistry,\n contracts: [\n basenamesRegistry,\n maybeGetDatasourceContract(namespace, DatasourceNames.Basenames, \"BaseRegistrar\"),\n maybeGetDatasourceContract(namespace, DatasourceNames.Basenames, \"EARegistrarController\"),\n maybeGetDatasourceContract(namespace, DatasourceNames.Basenames, \"RegistrarController\"),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Basenames,\n \"UpgradeableRegistrarController\",\n ),\n ].filter((c): c is AccountId => !!c),\n },\n }),\n ...(lineanamesRegistry && {\n \"linea.eth\": {\n registry: lineanamesRegistry,\n contracts: [\n lineanamesRegistry,\n maybeGetDatasourceContract(namespace, DatasourceNames.Lineanames, \"BaseRegistrar\"),\n maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Lineanames,\n \"EthRegistrarController\",\n ),\n lineanamesNameWrapper,\n ].filter((c): c is AccountId => !!c),\n },\n }),\n } satisfies Record<Name, ManagedNameGroup>;\n};\n\ninterface ManagedNameResult {\n name: InterpretedName;\n node: Node;\n registry: AccountId;\n}\n\n/**\n * Cache for the memoization of {@link getManagedName} below.\n */\nconst cache = new Map<`${ENSNamespaceId}:${AccountIdString}`, ManagedNameResult>();\n\n/**\n * Given a `contract` in a `namespace`, identify its Managed Name, Node, and the concrete ENSv1\n * Registry in the context of which it operates.\n *\n * @dev memoized by (namespace, contract).\n * @throws if `contract` is not configured under any Managed Name for `namespace`\n */\nexport const getManagedName = (\n namespace: ENSNamespaceId,\n contract: AccountId,\n): ManagedNameResult => {\n const cacheKey = `${namespace}:${stringifyAccountId(contract)}` as const;\n const cached = cache.get(cacheKey);\n if (cached !== undefined) return cached;\n\n for (const [managedName, group] of Object.entries(getContractsByManagedName(namespace))) {\n const isAnyOfTheContracts = group.contracts.some((_contract) =>\n accountIdEqual(_contract, contract),\n );\n if (isAnyOfTheContracts) {\n const namespaceSpecific = MANAGED_NAME_BY_NAMESPACE[namespace]?.[managedName];\n\n // use the namespace-specific Managed Name if specified, otherwise the default\n const name = asInterpretedName(namespaceSpecific ?? managedName);\n const node = namehashInterpretedName(name);\n\n const result: ManagedNameResult = { name, node, registry: group.registry };\n cache.set(cacheKey, result);\n return result;\n }\n }\n\n throw new Error(\n `The following contract ${toJson(contract, { pretty: true })} does not have a configured Managed Name in namespace '${namespace}'.`,\n );\n};\n\n/**\n * Determines whether `contract` is a NameWrapper in the given `namespace`.\n */\nexport const isNameWrapper = (namespace: ENSNamespaceId, contract: AccountId): boolean => {\n const ethnamesNameWrapper = getDatasourceContract(\n namespace,\n DatasourceNames.ENSRoot,\n \"NameWrapper\",\n );\n if (accountIdEqual(ethnamesNameWrapper, contract)) return true;\n\n const lineanamesNameWrapper = maybeGetDatasourceContract(\n namespace,\n DatasourceNames.Lineanames,\n \"NameWrapper\",\n );\n if (lineanamesNameWrapper && accountIdEqual(lineanamesNameWrapper, contract)) return true;\n\n return false;\n};\n","/**\n * `JSON.stringify` with bigints replaced by their string representation.\n *\n * Defaults to compact output. Pass `{ pretty: true }` for 2-space indent\n * (useful for human-readable error messages and console logs).\n *\n * Uses `JSON.stringify`'s replacer callback so native `toJSON` behavior is\n * preserved (e.g. `Date` serializes to its ISO string).\n */\nexport const toJson = (value: unknown, options?: { pretty?: boolean }) =>\n JSON.stringify(\n value,\n (_key, val) => (typeof val === \"bigint\" ? String(val) : val),\n options?.pretty ? 2 : undefined,\n );\n","import { type AccountId, makeENSv1RegistryId, makeENSv2RegistryId, type RegistryId } from \"enssdk\";\n\nimport { DatasourceNames, type ENSNamespaceId } from \"@ensnode/datasources\";\n\nimport { accountIdEqual } from \"./account-id\";\nimport { getDatasourceContract, maybeGetDatasourceContract } from \"./datasource-contract\";\n\n//////////////\n// ENSv1\n//////////////\n\n/**\n * Gets the AccountId representing the ENSv1 Registry in the selected `namespace`.\n */\nexport const getENSv1RootRegistry = (namespace: ENSNamespaceId) =>\n getDatasourceContract(namespace, DatasourceNames.ENSRoot, \"ENSv1Registry\");\n\n/**\n * Gets the ENSv1RegistryId representing the ENSv1 Root Registry in the selected `namespace`.\n */\nexport const getENSv1RootRegistryId = (namespace: ENSNamespaceId) =>\n makeENSv1RegistryId(getENSv1RootRegistry(namespace));\n\n/**\n * Determines whether `contract` is the ENSv1 Registry in `namespace`.\n */\nexport const isENSv1Registry = (namespace: ENSNamespaceId, contract: AccountId) =>\n accountIdEqual(getENSv1RootRegistry(namespace), contract);\n\n//////////////\n// ENSv2\n//////////////\n\n/**\n * Gets the AccountId representing the ENSv2 Root Registry in the selected `namespace`.\n *\n * @throws if the ENSv2Root Datasource or the RootRegistry contract are not defined\n */\nexport const getENSv2RootRegistry = (namespace: ENSNamespaceId) =>\n getDatasourceContract(namespace, DatasourceNames.ENSv2Root, \"RootRegistry\");\n\n/**\n * Gets the RegistryId representing the ENSv2 Root Registry in the selected `namespace`.\n *\n * @throws if the ENSv2Root Datasource or the RootRegistry contract are not defined\n */\nexport const getENSv2RootRegistryId = (namespace: ENSNamespaceId) =>\n makeENSv2RegistryId(getENSv2RootRegistry(namespace));\n\n/**\n * Determines whether `contract` is the ENSv2 Root Registry in `namespace`.\n *\n * @throws if the ENSv2Root Datasource or the RootRegistry contract are not defined\n */\nexport const isENSv2RootRegistry = (namespace: ENSNamespaceId, contract: AccountId) =>\n accountIdEqual(getENSv2RootRegistry(namespace), contract);\n\n/**\n * Gets the AccountId representing the ENSv2 Root Registry in the selected `namespace` if defined,\n * otherwise `undefined`.\n *\n * TODO: remove this function and its usage after all namespaces define ENSv2Root\n */\nexport const maybeGetENSv2RootRegistry = (namespace: ENSNamespaceId) =>\n maybeGetDatasourceContract(namespace, DatasourceNames.ENSv2Root, \"RootRegistry\");\n\n/**\n * Gets the RegistryId representing the ENSv2 Root Registry in the selected `namespace` if defined,\n * otherwise `undefined`.\n *\n * TODO: remove this function and its usage after all namespaces define ENSv2Root\n */\nexport const maybeGetENSv2RootRegistryId = (namespace: ENSNamespaceId) => {\n const root = maybeGetENSv2RootRegistry(namespace);\n if (!root) return undefined;\n return makeENSv2RegistryId(root);\n};\n\n//////////////\n// Root\n//////////////\n\n/**\n * Gets the RegistryId representing the preferred Root Registry for the selected `namespace` —\n * the ENSv2 Root Registry when defined, otherwise the ENSv1 Root Registry. Used as the entry\n * point for resolution-time namegraph traversal.\n */\nexport const getRootRegistryId = (namespace: ENSNamespaceId) =>\n maybeGetENSv2RootRegistryId(namespace) ?? getENSv1RootRegistryId(namespace);\n\n/**\n * Determines whether `registryId` is a Root Registry (ENSv1 Root or, when defined, ENSv2 Root)\n * for the selected `namespace`.\n */\nexport const isRootRegistryId = (namespace: ENSNamespaceId, registryId: RegistryId): boolean =>\n registryId === getENSv1RootRegistryId(namespace) ||\n registryId === maybeGetENSv2RootRegistryId(namespace);\n","import type { AccountId } from \"enssdk\";\n\nimport { DatasourceNames } from \"@ensnode/datasources\";\nimport { type ENSNamespaceId, makeContractMatcher } from \"@ensnode/ensnode-sdk\";\n\n/**\n * ENSIP-19 Reverse Resolvers (i.e. DefaultReverseResolver or ChainReverseResolver) simply:\n * a. read the Name for their specific coinType from their connected StandaloneReverseRegistry, or\n * b. return the default coinType's Name.\n *\n * We encode this behavior here, for the purposes of Protocol Acceleration.\n */\nexport function isKnownENSIP19ReverseResolver(\n namespace: ENSNamespaceId,\n resolver: AccountId,\n): boolean {\n const resolverEq = makeContractMatcher(namespace, resolver);\n\n return [\n // DefaultReverseResolver (default.reverse)\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultReverseResolver3\"),\n\n // the following are each ChainReverseResolver ([coinType].reverse)\n resolverEq(DatasourceNames.ReverseResolverRoot, \"BaseReverseResolver\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"LineaReverseResolver\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"OptimismReverseResolver\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"ArbitrumReverseResolver\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"ScrollReverseResolver\"),\n ].some(Boolean);\n}\n","import type { AccountId } from \"enssdk\";\n\nimport { DatasourceNames } from \"@ensnode/datasources\";\nimport { type ENSNamespaceId, makeContractMatcher } from \"@ensnode/ensnode-sdk\";\n\n/**\n * Returns whether `resolver` is an Static Resolver.\n *\n * Static Resolvers must abide the following pattern:\n * 1. All information necessary for resolution is stored on-chain, and\n * 2. All resolve() calls resolve to the exact value previously emitted by the Resolver in\n * its events (i.e. no post-processing or other logic, a simple return of the on-chain data).\n * 2.a the Resolver MAY implement address record defaulting and still be considered Static (see below).\n * 3. Its behavior is unlikely to change (i.e. the contract is not upgradable or is unlikely to be\n * upgraded in a way that violates principles 1. or 2.).\n *\n * TODO: these relationships could be encoded in an ENSIP\n */\nexport function isStaticResolver(namespace: ENSNamespaceId, resolver: AccountId): boolean {\n const resolverEq = makeContractMatcher(namespace, resolver);\n\n return [\n // ENS Root Chain\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver0\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver1\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver2\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver3\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver4\"),\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver5\"),\n resolverEq(DatasourceNames.ENSRoot, \"ArgentResolver\"),\n resolverEq(DatasourceNames.ENSRoot, \"LoopringResolver\"),\n\n // Basenames\n resolverEq(DatasourceNames.Basenames, \"L2Resolver1\"),\n resolverEq(DatasourceNames.Basenames, \"L2Resolver2\"),\n\n // Lineanames\n resolverEq(DatasourceNames.Lineanames, \"DefaultPublicResolver\"),\n\n // ThreeDNS\n resolverEq(DatasourceNames.ThreeDNSBase, \"Resolver\"),\n resolverEq(DatasourceNames.ThreeDNSOptimism, \"Resolver\"),\n ].some(Boolean);\n}\n\n/**\n * Returns whether `resolver` implements address record defaulting.\n *\n * @see https://docs.ens.domains/ensip/19/#default-address\n */\nexport function staticResolverImplementsAddressRecordDefaulting(\n namespace: ENSNamespaceId,\n resolver: AccountId,\n): boolean {\n const resolverEq = makeContractMatcher(namespace, resolver);\n\n return [\n // ENS Root Chain\n resolverEq(DatasourceNames.ReverseResolverRoot, \"DefaultPublicResolver5\"),\n\n // Base Chain\n resolverEq(DatasourceNames.Basenames, \"L2Resolver2\"),\n ].some(Boolean);\n}\n","import { type ENSNamespaceId, ENSNamespaceIds } from \"@ensnode/datasources\";\n\nimport type { TheGraphFallback } from \"./config/thegraph\";\n\n/**\n * Determines whether, given the provided context, a Subgraph GraphQL API request can be handled by\n * a TheGraph-hosted Subgraph.\n *\n * @see https://ensnode.io/docs/concepts/what-is-the-ens-subgraph\n */\nexport const canFallbackToTheGraph = ({\n namespace,\n theGraphApiKey,\n isSubgraphCompatible,\n}: {\n namespace: ENSNamespaceId;\n theGraphApiKey: string | undefined;\n isSubgraphCompatible: boolean;\n}): TheGraphFallback => {\n // must be subgraph-compatible\n // NOTE: that Subgraph Compatibility requires that 'subgraph' is the only plugin, excluding\n // alpha-style deployments, which are unable to fall back to thegraph due to data inconsistency\n if (!isSubgraphCompatible) return { canFallback: false, reason: \"not-subgraph-compatible\" };\n\n // must have api key for The Graph\n const hasApiKey = theGraphApiKey !== undefined;\n if (!hasApiKey) return { canFallback: false, reason: \"no-api-key\" };\n\n // and namespace must be supported by The Graph\n const url = makeTheGraphSubgraphUrl(namespace, theGraphApiKey);\n if (url === null) return { canFallback: false, reason: \"no-subgraph-url\" };\n\n // otherwise able to fallback\n return { canFallback: true, url };\n};\n\n/**\n * Retrieves the URL of a TheGraph-hosted Subgraph given the provided `namespace`, authenticating\n * with the provided `apiKey`.\n */\nconst makeTheGraphSubgraphUrl = (namespace: ENSNamespaceId, apiKey: string) => {\n switch (namespace) {\n case ENSNamespaceIds.Mainnet:\n return `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH`;\n case ENSNamespaceIds.Sepolia:\n return `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/G1SxZs317YUb9nQX3CC98hDyvxfMJNZH5pPRGpNrtvwN`;\n case ENSNamespaceIds.SepoliaV2:\n case ENSNamespaceIds.EnsTestEnv:\n return null;\n default:\n throw new Error(\"never\");\n }\n};\n"],"mappings":"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","names":["z","z","z","z","ENSNamespaceIds","ENSNamespaceIds","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","isAddressEqual","zeroAddress","isAddressEqual","zeroAddress","z","z","z","z","z","z","namehashInterpretedName","z","z","toNormalizedAddress","size","zeroAddress","size","zeroAddress","toNormalizedAddress","z","z","z","namehashInterpretedName","z","z","toNormalizedAddress","DatasourceNames","ENSNamespaceIds","ENSNamespaceIds","DatasourceNames","toNormalizedAddress","getENSRootChainId","getENSRootChainId","z","ENSNamespaceIds","z","prettifyError","prettifyError","z","ENSNamespaceIds","ENSNamespaceIds","DatasourceNames","maybeGetDatasource","DatasourceNames","maybeGetDatasource","DatasourceNames","maybeGetDatasource","isAddressEqual","zeroAddress","toNormalizedAddress","isAddress","isAddressEqual","zeroAddress","isAddress","isAddressEqual","zeroAddress","toNormalizedAddress","size","z","DatasourceNames","maybeGetDatasource","asInterpretedName","namehashInterpretedName","DatasourceNames","DatasourceNames","asInterpretedName","namehashInterpretedName","DatasourceNames","DatasourceNames","cache","maybeGetDatasource","DatasourceNames","DatasourceNames","DatasourceNames","DatasourceNames","DatasourceNames","ENSNamespaceIds","isSubgraphCompatible"]}
|