@namehash/ens-referrals 0.0.0-next-20260122143405 → 0.0.0-next-20260126125206

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/address.ts","../src/number.ts","../src/revenue-contribution.ts","../src/time.ts","../src/score.ts","../src/aggregations.ts","../src/api/deserialize.ts","../src/api/zod-schemas.ts","../../ensnode-sdk/src/shared/address.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/spec.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/utils.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/chain.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/account.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/assetName.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/assetType.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/assetId.ts","../../ensnode-sdk/src/shared/zod-schemas.ts","../src/leaderboard-page.ts","../src/rank.ts","../src/referrer-metrics.ts","../src/referrer-detail.ts","../src/api/types.ts","../src/api/serialize.ts","../src/client.ts","../src/currency.ts","../src/leaderboard.ts","../src/link.ts","../src/rules.ts","../src/status.ts"],"sourcesContent":["import { type Address, isAddress } from \"viem\";\n\nexport const validateLowercaseAddress = (address: Address): void => {\n if (!isAddress(address, { strict: false })) {\n throw new Error(`Invalid address: ${address}. Address must be a valid EVM address.`);\n }\n\n if (address !== address.toLowerCase()) {\n throw new Error(`Invalid address: ${address}. Address must be in lowercase format.`);\n }\n};\n\nexport const normalizeAddress = (address: Address): Address => {\n return address.toLowerCase() as Address;\n};\n","export const isInteger = (value: number): boolean => {\n return Number.isInteger(value);\n};\n\nexport const isNonNegativeInteger = (value: number): boolean => {\n return value >= 0 && Number.isInteger(value);\n};\n\nexport const isPositiveInteger = (value: number): boolean => {\n return value >= 1 && Number.isInteger(value);\n};\n\nexport const validateNonNegativeInteger = (value: number): void => {\n if (!isNonNegativeInteger(value)) {\n throw new Error(`Invalid non-negative integer: ${value}.`);\n }\n};\n\nexport const isFiniteNonNegativeNumber = (value: number): boolean => {\n return value >= 0 && Number.isFinite(value);\n};\n","/**\n * Revenue Contribution\n *\n * Represents the total revenue contribution (in Wei) made to the ENS DAO.\n *\n * This is the sum of the total cost paid by registrants for registrar actions.\n * From the perspective of the ENS DAO, this represents revenue received.\n *\n * @invariant Guaranteed to be a non-negative bigint value (>= 0n)\n * @invariant Never null (records with null `total` in the database are treated as 0 when summing)\n */\nexport type RevenueContribution = bigint;\n\n/**\n * Check if a value is a valid revenue contribution.\n *\n * @param value - The value to check\n * @returns true if the value is a non-negative bigint, false otherwise\n */\nexport function isValidRevenueContribution(value: unknown): value is RevenueContribution {\n return typeof value === \"bigint\" && value >= 0n;\n}\n\n/**\n * Validate that a value is a valid revenue contribution.\n *\n * @param value - The value to validate\n * @throws {Error} If the value is not a valid revenue contribution\n */\nexport function validateRevenueContribution(value: unknown): void {\n if (typeof value !== \"bigint\") {\n throw new Error(`Invalid revenue contribution: must be a bigint, got: ${typeof value}`);\n }\n\n if (value < 0n) {\n throw new Error(`Invalid revenue contribution: must be non-negative, got: ${value.toString()}`);\n }\n}\n","import type { Duration, UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport { isInteger, isNonNegativeInteger } from \"./number\";\n\nexport const validateUnixTimestamp = (timestamp: UnixTimestamp): void => {\n if (!isInteger(timestamp)) {\n throw new Error(`Invalid Unix timestamp: ${timestamp}. Unix timestamp must be an integer.`);\n }\n};\n\n/**\n * The number of seconds in a year.\n *\n * (60 seconds per minute * 60 minutes per hour *\n * 24 hours per day * 365.2425 days on average per year).\n */\nexport const SECONDS_PER_YEAR: Duration = 31556952;\n\nexport function isValidDuration(duration: Duration): boolean {\n return isNonNegativeInteger(duration);\n}\n\nexport function validateDuration(duration: Duration): void {\n if (!isValidDuration(duration)) {\n throw new Error(`Invalid duration: ${duration}. Duration must be a non-negative integer.`);\n }\n}\n","import type { Duration } from \"@ensnode/ensnode-sdk\";\n\nimport { SECONDS_PER_YEAR } from \"./time\";\n\n/**\n * The score of a referrer.\n *\n * @invariant Guaranteed to be a finite non-negative number (>= 0)\n */\nexport type ReferrerScore = number;\n\nexport const isValidReferrerScore = (score: ReferrerScore): boolean => {\n return score >= 0 && Number.isFinite(score);\n};\n\nexport const validateReferrerScore = (score: ReferrerScore): void => {\n if (!isValidReferrerScore(score)) {\n throw new Error(\n `Invalid referrer score: ${score}. Referrer score must be a finite non-negative number.`,\n );\n }\n};\n\n/**\n * Calculate the score of a referrer based on the total incremental duration\n * (in seconds) of registrations and renewals for direct subnames of .eth\n * referrered by the referrer within the ENS Holiday Awards period.\n *\n * @param totalIncrementalDuration - The total incremental duration (in seconds)\n * of referrals made by a referrer within the {@link ReferralProgramRules}.\n * @returns The score of the referrer.\n */\nexport const calcReferrerScore = (totalIncrementalDuration: Duration): ReferrerScore => {\n return totalIncrementalDuration / SECONDS_PER_YEAR;\n};\n","import type { Duration } from \"@ensnode/ensnode-sdk\";\n\nimport { validateNonNegativeInteger } from \"./number\";\nimport type { RankedReferrerMetrics } from \"./referrer-metrics\";\nimport type { RevenueContribution } from \"./revenue-contribution\";\nimport { validateRevenueContribution } from \"./revenue-contribution\";\nimport type { ReferralProgramRules } from \"./rules\";\nimport { type ReferrerScore, validateReferrerScore } from \"./score\";\nimport { validateDuration } from \"./time\";\n\n/**\n * Represents aggregated metrics for a list of `RankedReferrerMetrics`.\n */\nexport interface AggregatedReferrerMetrics {\n /**\n * @invariant The sum of `totalReferrals` across all `RankedReferrerMetrics` in the list.\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n grandTotalReferrals: number;\n\n /**\n * @invariant The sum of `totalIncrementalDuration` across all `RankedReferrerMetrics` in the list.\n */\n grandTotalIncrementalDuration: Duration;\n\n /**\n * The total revenue contribution (in Wei) to the ENS DAO from all referrals\n * across all referrers on the leaderboard.\n *\n * This is the sum of `totalRevenueContribution` across all `RankedReferrerMetrics` in the list.\n *\n * @invariant Guaranteed to be a non-negative bigint value (>= 0n)\n */\n grandTotalRevenueContribution: RevenueContribution;\n\n /**\n * @invariant The sum of `finalScore` across all `RankedReferrerMetrics` where `isQualified` is `true`.\n */\n grandTotalQualifiedReferrersFinalScore: ReferrerScore;\n\n /**\n * @invariant Identifies the minimum final score required to become a qualified referrer.\n * @invariant If `rules.maxQualifiedReferrers` is 0, then `minFinalScoreToQualify` is guaranteed to\n * be `Number.MAX_SAFE_INTEGER`.\n * @invariant If `rules.maxQualifiedReferrers` is greater than 0, and there are no current referrers\n * matching the `rules`, then `minFinalScoreToQualify` is guaranteed to be `0`.\n */\n minFinalScoreToQualify: ReferrerScore;\n}\n\nexport const validateAggregatedReferrerMetrics = (metrics: AggregatedReferrerMetrics): void => {\n validateNonNegativeInteger(metrics.grandTotalReferrals);\n validateDuration(metrics.grandTotalIncrementalDuration);\n validateRevenueContribution(metrics.grandTotalRevenueContribution);\n validateReferrerScore(metrics.grandTotalQualifiedReferrersFinalScore);\n validateReferrerScore(metrics.minFinalScoreToQualify);\n};\n\nexport const buildAggregatedReferrerMetrics = (\n referrers: RankedReferrerMetrics[],\n rules: ReferralProgramRules,\n): AggregatedReferrerMetrics => {\n let grandTotalReferrals = 0;\n let grandTotalIncrementalDuration = 0;\n let grandTotalRevenueContribution = 0n;\n let grandTotalQualifiedReferrersFinalScore = 0;\n let minFinalScoreToQualify = Number.MAX_SAFE_INTEGER;\n\n for (const referrer of referrers) {\n grandTotalReferrals += referrer.totalReferrals;\n grandTotalIncrementalDuration += referrer.totalIncrementalDuration;\n grandTotalRevenueContribution += referrer.totalRevenueContribution;\n if (referrer.isQualified) {\n grandTotalQualifiedReferrersFinalScore += referrer.finalScore;\n if (referrer.finalScore < minFinalScoreToQualify) {\n minFinalScoreToQualify = referrer.finalScore;\n }\n }\n }\n\n if (minFinalScoreToQualify === Number.MAX_SAFE_INTEGER) {\n if (rules.maxQualifiedReferrers === 0) {\n // ... because it's impossible to qualify based on the rules\n // therefore keep minFinalScoreToQualify as Number.MAX_SAFE_INTEGER\n } else {\n // ... because there are no referrers at all on the leaderboard\n if (referrers.length !== 0) {\n // invariant sanity check\n throw new Error(\n \"AggregatedReferrerMetrics: There are referrers on the leaderboard, and the rules allow for qualified referrers, but no qualified referrers.\",\n );\n }\n\n minFinalScoreToQualify = 0;\n }\n }\n\n const result = {\n grandTotalReferrals,\n grandTotalIncrementalDuration,\n grandTotalRevenueContribution,\n grandTotalQualifiedReferrersFinalScore,\n minFinalScoreToQualify,\n };\n\n validateAggregatedReferrerMetrics(result);\n\n return result;\n};\n","import { prettifyError } from \"zod/v4\";\n\nimport type { AggregatedReferrerMetrics } from \"../aggregations\";\nimport type { ReferrerLeaderboardPage } from \"../leaderboard-page\";\nimport type { ReferrerDetailRanked, ReferrerDetailUnranked } from \"../referrer-detail\";\nimport type { AwardedReferrerMetrics, UnrankedReferrerMetrics } from \"../referrer-metrics\";\nimport type { RevenueContribution } from \"../revenue-contribution\";\nimport type { ReferralProgramRules } from \"../rules\";\nimport type {\n SerializedAggregatedReferrerMetrics,\n SerializedAwardedReferrerMetrics,\n SerializedReferralProgramRules,\n SerializedReferrerDetailRanked,\n SerializedReferrerDetailResponse,\n SerializedReferrerDetailUnranked,\n SerializedReferrerLeaderboardPage,\n SerializedReferrerLeaderboardPageResponse,\n SerializedUnrankedReferrerMetrics,\n} from \"./serialized-types\";\nimport type { ReferrerDetailResponse, ReferrerLeaderboardPageResponse } from \"./types\";\nimport {\n makeReferrerDetailResponseSchema,\n makeReferrerLeaderboardPageResponseSchema,\n} from \"./zod-schemas\";\n\n/**\n * Deserializes a string representation of {@link RevenueContribution} back to bigint.\n */\nfunction deserializeRevenueContribution(value: string): RevenueContribution {\n return BigInt(value);\n}\n\n/**\n * Deserializes a {@link SerializedReferralProgramRules} object.\n */\nfunction deserializeReferralProgramRules(\n rules: SerializedReferralProgramRules,\n): ReferralProgramRules {\n // All fields are already deserializable primitives\n return rules;\n}\n\n/**\n * Deserializes an {@link SerializedAwardedReferrerMetrics} object.\n */\nfunction deserializeAwardedReferrerMetrics(\n metrics: SerializedAwardedReferrerMetrics,\n): AwardedReferrerMetrics {\n return {\n referrer: metrics.referrer,\n totalReferrals: metrics.totalReferrals,\n totalIncrementalDuration: metrics.totalIncrementalDuration,\n totalRevenueContribution: deserializeRevenueContribution(metrics.totalRevenueContribution),\n score: metrics.score,\n rank: metrics.rank,\n isQualified: metrics.isQualified,\n finalScoreBoost: metrics.finalScoreBoost,\n finalScore: metrics.finalScore,\n awardPoolShare: metrics.awardPoolShare,\n awardPoolApproxValue: metrics.awardPoolApproxValue,\n };\n}\n\n/**\n * Deserializes an {@link SerializedUnrankedReferrerMetrics} object.\n */\nfunction deserializeUnrankedReferrerMetrics(\n metrics: SerializedUnrankedReferrerMetrics,\n): UnrankedReferrerMetrics {\n return {\n referrer: metrics.referrer,\n totalReferrals: metrics.totalReferrals,\n totalIncrementalDuration: metrics.totalIncrementalDuration,\n totalRevenueContribution: deserializeRevenueContribution(metrics.totalRevenueContribution),\n score: metrics.score,\n rank: metrics.rank,\n isQualified: metrics.isQualified,\n finalScoreBoost: metrics.finalScoreBoost,\n finalScore: metrics.finalScore,\n awardPoolShare: metrics.awardPoolShare,\n awardPoolApproxValue: metrics.awardPoolApproxValue,\n };\n}\n\n/**\n * Deserializes an {@link SerializedAggregatedReferrerMetrics} object.\n */\nfunction deserializeAggregatedReferrerMetrics(\n metrics: SerializedAggregatedReferrerMetrics,\n): AggregatedReferrerMetrics {\n return {\n grandTotalReferrals: metrics.grandTotalReferrals,\n grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,\n grandTotalRevenueContribution: deserializeRevenueContribution(\n metrics.grandTotalRevenueContribution,\n ),\n grandTotalQualifiedReferrersFinalScore: metrics.grandTotalQualifiedReferrersFinalScore,\n minFinalScoreToQualify: metrics.minFinalScoreToQualify,\n };\n}\n\n/**\n * Deserializes a {@link SerializedReferrerLeaderboardPage} object.\n */\nfunction deserializeReferrerLeaderboardPage(\n page: SerializedReferrerLeaderboardPage,\n): ReferrerLeaderboardPage {\n return {\n rules: deserializeReferralProgramRules(page.rules),\n referrers: page.referrers.map(deserializeAwardedReferrerMetrics),\n aggregatedMetrics: deserializeAggregatedReferrerMetrics(page.aggregatedMetrics),\n pageContext: page.pageContext,\n accurateAsOf: page.accurateAsOf,\n };\n}\n\n/**\n * Deserializes a {@link SerializedReferrerDetailRanked} object.\n */\nfunction deserializeReferrerDetailRanked(\n detail: SerializedReferrerDetailRanked,\n): ReferrerDetailRanked {\n return {\n type: detail.type,\n rules: deserializeReferralProgramRules(detail.rules),\n referrer: deserializeAwardedReferrerMetrics(detail.referrer),\n aggregatedMetrics: deserializeAggregatedReferrerMetrics(detail.aggregatedMetrics),\n accurateAsOf: detail.accurateAsOf,\n };\n}\n\n/**\n * Deserializes a {@link SerializedReferrerDetailUnranked} object.\n */\nfunction deserializeReferrerDetailUnranked(\n detail: SerializedReferrerDetailUnranked,\n): ReferrerDetailUnranked {\n return {\n type: detail.type,\n rules: deserializeReferralProgramRules(detail.rules),\n referrer: deserializeUnrankedReferrerMetrics(detail.referrer),\n aggregatedMetrics: deserializeAggregatedReferrerMetrics(detail.aggregatedMetrics),\n accurateAsOf: detail.accurateAsOf,\n };\n}\n\n/**\n * Deserialize a {@link ReferrerLeaderboardPageResponse} object.\n *\n * Note: This function explicitly deserializes each subobject to convert string\n * RevenueContribution values back to bigint, then validates using Zod schemas\n * to enforce invariants on the data.\n */\nexport function deserializeReferrerLeaderboardPageResponse(\n maybeResponse: SerializedReferrerLeaderboardPageResponse,\n valueLabel?: string,\n): ReferrerLeaderboardPageResponse {\n let deserialized: ReferrerLeaderboardPageResponse;\n switch (maybeResponse.responseCode) {\n case \"ok\": {\n deserialized = {\n responseCode: maybeResponse.responseCode,\n data: deserializeReferrerLeaderboardPage(maybeResponse.data),\n } as ReferrerLeaderboardPageResponse;\n break;\n }\n\n case \"error\":\n deserialized = maybeResponse;\n break;\n }\n\n // Then validate the deserialized structure using zod schemas\n const schema = makeReferrerLeaderboardPageResponseSchema(valueLabel);\n const parsed = schema.safeParse(deserialized);\n\n if (parsed.error) {\n throw new Error(\n `Cannot deserialize SerializedReferrerLeaderboardPageResponse:\\n${prettifyError(parsed.error)}\\n`,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Deserialize a {@link ReferrerDetailResponse} object.\n *\n * Note: This function explicitly deserializes each subobject to convert string\n * RevenueContribution values back to bigint, then validates using Zod schemas\n * to enforce invariants on the data.\n */\nexport function deserializeReferrerDetailResponse(\n maybeResponse: SerializedReferrerDetailResponse,\n valueLabel?: string,\n): ReferrerDetailResponse {\n let deserialized: ReferrerDetailResponse;\n switch (maybeResponse.responseCode) {\n case \"ok\": {\n switch (maybeResponse.data.type) {\n case \"ranked\":\n deserialized = {\n responseCode: maybeResponse.responseCode,\n data: deserializeReferrerDetailRanked(maybeResponse.data),\n } as ReferrerDetailResponse;\n break;\n\n case \"unranked\":\n deserialized = {\n responseCode: maybeResponse.responseCode,\n data: deserializeReferrerDetailUnranked(maybeResponse.data),\n } as ReferrerDetailResponse;\n break;\n }\n break;\n }\n\n case \"error\":\n deserialized = maybeResponse;\n break;\n }\n\n // Then validate the deserialized structure using zod schemas\n const schema = makeReferrerDetailResponseSchema(valueLabel);\n const parsed = schema.safeParse(deserialized);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ReferrerDetailResponse:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\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 */\n\nimport z from \"zod/v4\";\n\nimport {\n makeAccountIdSchema,\n makeDurationSchema,\n makeFiniteNonNegativeNumberSchema,\n makeLowercaseAddressSchema,\n makeNonNegativeIntegerSchema,\n makePositiveIntegerSchema,\n makeUnixTimestampSchema,\n} from \"@ensnode/ensnode-sdk/internal\";\n\nimport { REFERRERS_PER_LEADERBOARD_PAGE_MAX } from \"../leaderboard-page\";\nimport { type ReferrerDetailRanked, ReferrerDetailTypeIds } from \"../referrer-detail\";\nimport type { RevenueContribution } from \"../revenue-contribution\";\nimport { ReferrerDetailResponseCodes, ReferrerLeaderboardPageResponseCodes } from \"./types\";\n\n/**\n * Schema for {@link RevenueContribution}\n */\nconst makeRevenueContributionSchema = (valueLabel: string = \"RevenueContribution\") =>\n z.coerce\n .bigint({\n error: `${valueLabel} must represent a bigint.`,\n })\n .nonnegative({\n error: `${valueLabel} must not be negative.`,\n });\n\n/**\n * Schema for ReferralProgramRules\n */\nexport const makeReferralProgramRulesSchema = (valueLabel: string = \"ReferralProgramRules\") =>\n z.object({\n totalAwardPoolValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.totalAwardPoolValue`),\n maxQualifiedReferrers: makeNonNegativeIntegerSchema(`${valueLabel}.maxQualifiedReferrers`),\n startTime: makeUnixTimestampSchema(`${valueLabel}.startTime`),\n endTime: makeUnixTimestampSchema(`${valueLabel}.endTime`),\n subregistryId: makeAccountIdSchema(`${valueLabel}.subregistryId`),\n });\n\n/**\n * Schema for AwardedReferrerMetrics (with numeric rank)\n */\nexport const makeAwardedReferrerMetricsSchema = (valueLabel: string = \"AwardedReferrerMetrics\") =>\n z.object({\n referrer: makeLowercaseAddressSchema(`${valueLabel}.referrer`),\n totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),\n totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),\n totalRevenueContribution: makeRevenueContributionSchema(\n `${valueLabel}.totalRevenueContribution`,\n ),\n score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),\n rank: makePositiveIntegerSchema(`${valueLabel}.rank`),\n isQualified: z.boolean(),\n finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(\n 1,\n `${valueLabel}.finalScoreBoost must be <= 1`,\n ),\n finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),\n awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(\n 1,\n `${valueLabel}.awardPoolShare must be <= 1`,\n ),\n awardPoolApproxValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolApproxValue`),\n });\n\n/**\n * Schema for UnrankedReferrerMetrics (with null rank)\n */\nexport const makeUnrankedReferrerMetricsSchema = (valueLabel: string = \"UnrankedReferrerMetrics\") =>\n z.object({\n referrer: makeLowercaseAddressSchema(`${valueLabel}.referrer`),\n totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),\n totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),\n totalRevenueContribution: makeRevenueContributionSchema(\n `${valueLabel}.totalRevenueContribution`,\n ),\n score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),\n rank: z.null(),\n isQualified: z.literal(false),\n finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(\n 1,\n `${valueLabel}.finalScoreBoost must be <= 1`,\n ),\n finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),\n awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(\n 1,\n `${valueLabel}.awardPoolShare must be <= 1`,\n ),\n awardPoolApproxValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolApproxValue`),\n });\n\n/**\n * Schema for AggregatedReferrerMetrics\n */\nexport const makeAggregatedReferrerMetricsSchema = (\n valueLabel: string = \"AggregatedReferrerMetrics\",\n) =>\n z.object({\n grandTotalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.grandTotalReferrals`),\n grandTotalIncrementalDuration: makeDurationSchema(\n `${valueLabel}.grandTotalIncrementalDuration`,\n ),\n grandTotalRevenueContribution: makeRevenueContributionSchema(\n `${valueLabel}.grandTotalRevenueContribution`,\n ),\n grandTotalQualifiedReferrersFinalScore: makeFiniteNonNegativeNumberSchema(\n `${valueLabel}.grandTotalQualifiedReferrersFinalScore`,\n ),\n minFinalScoreToQualify: makeFiniteNonNegativeNumberSchema(\n `${valueLabel}.minFinalScoreToQualify`,\n ),\n });\n\nexport const makeReferrerLeaderboardPageContextSchema = (\n valueLabel: string = \"ReferrerLeaderboardPageContext\",\n) =>\n z.object({\n page: makePositiveIntegerSchema(`${valueLabel}.page`),\n recordsPerPage: makePositiveIntegerSchema(`${valueLabel}.recordsPerPage`).max(\n REFERRERS_PER_LEADERBOARD_PAGE_MAX,\n `${valueLabel}.recordsPerPage must not exceed ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}`,\n ),\n totalRecords: makeNonNegativeIntegerSchema(`${valueLabel}.totalRecords`),\n totalPages: makePositiveIntegerSchema(`${valueLabel}.totalPages`),\n hasNext: z.boolean(),\n hasPrev: z.boolean(),\n startIndex: z.optional(makeNonNegativeIntegerSchema(`${valueLabel}.startIndex`)),\n endIndex: z.optional(makeNonNegativeIntegerSchema(`${valueLabel}.endIndex`)),\n });\n\n/**\n * Schema for ReferrerLeaderboardPage\n */\nexport const makeReferrerLeaderboardPageSchema = (valueLabel: string = \"ReferrerLeaderboardPage\") =>\n z.object({\n rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),\n referrers: z.array(makeAwardedReferrerMetricsSchema(`${valueLabel}.referrers[record]`)),\n aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),\n pageContext: makeReferrerLeaderboardPageContextSchema(`${valueLabel}.pageContext`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n\n/**\n * Schema for {@link ReferrerLeaderboardPageResponseOk}\n */\nexport const makeReferrerLeaderboardPageResponseOkSchema = (\n valueLabel: string = \"ReferrerLeaderboardPageResponseOk\",\n) =>\n z.object({\n responseCode: z.literal(ReferrerLeaderboardPageResponseCodes.Ok),\n data: makeReferrerLeaderboardPageSchema(`${valueLabel}.data`),\n });\n\n/**\n * Schema for {@link ReferrerLeaderboardPageResponseError}\n */\nexport const makeReferrerLeaderboardPageResponseErrorSchema = (\n _valueLabel: string = \"ReferrerLeaderboardPageResponseError\",\n) =>\n z.object({\n responseCode: z.literal(ReferrerLeaderboardPageResponseCodes.Error),\n error: z.string(),\n errorMessage: z.string(),\n });\n\n/**\n * Schema for {@link ReferrerLeaderboardPageResponse}\n */\nexport const makeReferrerLeaderboardPageResponseSchema = (\n valueLabel: string = \"ReferrerLeaderboardPageResponse\",\n) =>\n z.union([\n makeReferrerLeaderboardPageResponseOkSchema(valueLabel),\n makeReferrerLeaderboardPageResponseErrorSchema(valueLabel),\n ]);\n\n/**\n * Schema for {@link ReferrerDetailRanked} (with ranked metrics)\n */\nexport const makeReferrerDetailRankedSchema = (valueLabel: string = \"ReferrerDetailRanked\") =>\n z.object({\n type: z.literal(ReferrerDetailTypeIds.Ranked),\n rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),\n referrer: makeAwardedReferrerMetricsSchema(`${valueLabel}.referrer`),\n aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n\n/**\n * Schema for {@link ReferrerDetailUnranked} (with unranked metrics)\n */\nexport const makeReferrerDetailUnrankedSchema = (valueLabel: string = \"ReferrerDetailUnranked\") =>\n z.object({\n type: z.literal(ReferrerDetailTypeIds.Unranked),\n rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),\n referrer: makeUnrankedReferrerMetricsSchema(`${valueLabel}.referrer`),\n aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n\n/**\n * Schema for {@link ReferrerDetailResponseOk}\n * Accepts either ranked or unranked referrer detail data\n */\nexport const makeReferrerDetailResponseOkSchema = (valueLabel: string = \"ReferrerDetailResponse\") =>\n z.object({\n responseCode: z.literal(ReferrerDetailResponseCodes.Ok),\n data: z.union([\n makeReferrerDetailRankedSchema(`${valueLabel}.data`),\n makeReferrerDetailUnrankedSchema(`${valueLabel}.data`),\n ]),\n });\n\n/**\n * Schema for {@link ReferrerDetailResponseError}\n */\nexport const makeReferrerDetailResponseErrorSchema = (\n _valueLabel: string = \"ReferrerDetailResponse\",\n) =>\n z.object({\n responseCode: z.literal(ReferrerDetailResponseCodes.Error),\n error: z.string(),\n errorMessage: z.string(),\n });\n\n/**\n * Schema for {@link ReferrerDetailResponse}\n */\nexport const makeReferrerDetailResponseSchema = (valueLabel: string = \"ReferrerDetailResponse\") =>\n z.union([\n makeReferrerDetailResponseOkSchema(valueLabel),\n makeReferrerDetailResponseErrorSchema(valueLabel),\n ]);\n","import type { Address } from \"viem\";\n\n/**\n * Converts an EVM address to its lowercase representation.\n *\n * @param address - EVM address to convert.\n * @returns The lowercase representation of the EVM address.\n */\nexport function asLowerCaseAddress(address: Address): Address {\n return address.toLowerCase() as Address;\n}\n","import { IdentifierSpec } from \"./types\";\n\nconst CAIP2: IdentifierSpec = {\n name: \"chainId\",\n regex: \"[-:a-zA-Z0-9]{5,41}\",\n parameters: {\n delimiter: \":\",\n values: {\n 0: {\n name: \"namespace\",\n regex: \"[-a-z0-9]{3,8}\",\n },\n 1: {\n name: \"reference\",\n regex: \"[-a-zA-Z0-9]{1,32}\",\n },\n },\n },\n};\n\nconst CAIP10: IdentifierSpec = {\n name: \"accountId\",\n regex: \"[-:a-zA-Z0-9]{7,106}\",\n parameters: {\n delimiter: \":\",\n values: {\n 0: {\n name: \"namespace\",\n regex: \"[-a-z0-9]{3,8}\",\n },\n 1: {\n name: \"reference\",\n regex: \"[-a-zA-Z0-9]{1,32}\",\n },\n 2: {\n name: \"address\",\n regex: \"[a-zA-Z0-9]{1,64}\",\n },\n },\n },\n};\n\n// represents namespace:reference in CAIP-19\nconst AssetName: IdentifierSpec = {\n name: \"assetName\",\n regex: \"[-:a-zA-Z0-9]{5,73}\",\n parameters: {\n delimiter: \":\",\n values: {\n 0: {\n name: \"namespace\",\n regex: \"[-a-z0-9]{3,8}\",\n },\n 1: {\n name: \"reference\",\n regex: \"[-a-zA-Z0-9]{1,64}\",\n },\n },\n },\n};\n\nconst CAIP19AssetType: IdentifierSpec = {\n name: \"assetType\",\n regex: \"[-:a-zA-Z0-9]{11,115}\",\n parameters: {\n delimiter: \"/\",\n values: {\n 0: CAIP2,\n 1: AssetName,\n },\n },\n};\n\nconst CAIP19AssetId: IdentifierSpec = {\n name: \"assetId\",\n regex: \"[-:a-zA-Z0-9]{13,148}\",\n parameters: {\n delimiter: \"/\",\n values: {\n 0: CAIP2,\n 1: AssetName,\n 2: {\n name: \"tokenId\",\n regex: \"[-a-zA-Z0-9]{1,32}\",\n },\n },\n },\n};\n\nexport const CAIP = {\n \"2\": CAIP2,\n \"10\": CAIP10,\n \"19\": {\n assetName: AssetName,\n assetType: CAIP19AssetType,\n assetId: CAIP19AssetId,\n },\n};\n","import { IdentifierSpec, Params } from \"./types\";\n\nexport function splitParams(id: string, spec: IdentifierSpec): string[] {\n return id.split(spec.parameters.delimiter);\n}\n\nexport function getParams<T>(id: string, spec: IdentifierSpec): T {\n const arr = splitParams(id, spec);\n const params = {};\n arr.forEach((value, index) => {\n params[spec.parameters.values[index].name] = value;\n });\n return params as T;\n}\n\nexport function joinParams(params: Params, spec: IdentifierSpec): string {\n return Object.values(spec.parameters.values)\n .map(parameter => {\n const param = params[parameter.name];\n return typeof param === \"string\"\n ? param\n : joinParams(param, parameter as IdentifierSpec);\n })\n .join(spec.parameters.delimiter);\n}\n\nexport function isValidId(id: string, spec: IdentifierSpec): boolean {\n // console.log(\"id\", id);\n // console.log(\"spec\", spec);\n // console.log(\"before regex\");\n if (!new RegExp(spec.regex).test(id)) return false;\n // console.log(\"after regex\");\n // console.log(\"before split\");\n const params = splitParams(id, spec);\n // console.log(\"after split\");\n // console.log(\"params\", params);\n // console.log(\"before length\");\n if (params.length !== Object.keys(spec.parameters.values).length)\n return false;\n // console.log(\"after length\");\n // console.log(\"before matches\");\n const matches = params\n .map((param, index) =>\n new RegExp(spec.parameters.values[index].regex).test(param)\n )\n .filter(x => !!x);\n if (matches.length !== params.length) return false;\n // console.log(\"after matches\");\n return true;\n}\n","import { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface ChainIdParams {\n namespace: string;\n reference: string;\n}\n\nexport class ChainId {\n public static spec: IdentifierSpec = CAIP[\"2\"];\n\n public static parse(id: string): ChainIdParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n return new ChainId(getParams<ChainIdParams>(id, this.spec)).toJSON();\n }\n\n public static format(params: ChainIdParams): string {\n return joinParams(params as any, this.spec);\n }\n\n public namespace: string;\n public reference: string;\n\n constructor(params: ChainIdParams | string) {\n if (typeof params === \"string\") {\n params = ChainId.parse(params);\n }\n\n this.namespace = params.namespace;\n this.reference = params.reference;\n }\n\n public toString(): string {\n return ChainId.format(this.toJSON());\n }\n\n public toJSON(): ChainIdParams {\n return {\n namespace: this.namespace,\n reference: this.reference,\n };\n }\n}\n","import { ChainId, ChainIdParams } from \"./chain\";\nimport { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface AccountIdSplitParams extends ChainIdParams {\n address: string;\n}\nexport interface AccountIdParams {\n chainId: string | ChainIdParams;\n address: string;\n}\n\nexport class AccountId {\n public static spec: IdentifierSpec = CAIP[\"10\"];\n\n public static parse(id: string): AccountIdParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n const { namespace, reference, address } = getParams<AccountIdSplitParams>(\n id,\n this.spec\n );\n const chainId = new ChainId({ namespace, reference });\n return new AccountId({ chainId, address }).toJSON();\n }\n\n public static format(params: AccountIdParams): string {\n const chainId = new ChainId(params.chainId);\n const splitParams: AccountIdSplitParams = {\n ...chainId.toJSON(),\n address: params.address,\n };\n return joinParams(splitParams as any, this.spec);\n }\n\n public chainId: ChainId;\n public address: string;\n\n constructor(params: AccountIdParams | string) {\n if (typeof params === \"string\") {\n params = AccountId.parse(params);\n }\n\n this.chainId = new ChainId(params.chainId);\n this.address = params.address;\n }\n\n public toString(): string {\n return AccountId.format(this.toJSON());\n }\n\n public toJSON(): AccountIdParams {\n return {\n chainId: this.chainId.toJSON(),\n address: this.address,\n };\n }\n}\n","import { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface AssetNameParams {\n namespace: string;\n reference: string;\n}\n\nexport class AssetName {\n public static spec: IdentifierSpec = CAIP[\"19\"].assetName;\n\n public static parse(id: string): AssetNameParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n return new AssetName(getParams<AssetNameParams>(id, this.spec)).toJSON();\n }\n\n public static format(params: AssetNameParams): string {\n return joinParams(params as any, this.spec);\n }\n\n public namespace: string;\n public reference: string;\n\n constructor(params: AssetNameParams | string) {\n if (typeof params === \"string\") {\n params = AssetName.parse(params);\n }\n\n this.namespace = params.namespace;\n this.reference = params.reference;\n }\n\n public toString(): string {\n return AssetName.format(this.toJSON());\n }\n\n public toJSON(): AssetNameParams {\n return {\n namespace: this.namespace,\n reference: this.reference,\n };\n }\n}\n","import { AssetName, AssetNameParams } from \"./assetName\";\nimport { ChainId, ChainIdParams } from \"./chain\";\nimport { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface AssetTypeParams {\n chainId: string | ChainIdParams;\n assetName: string | AssetNameParams;\n}\n\nexport class AssetType {\n public static spec: IdentifierSpec = CAIP[\"19\"].assetType;\n\n public static parse(id: string): AssetTypeParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n return new AssetType(getParams<AssetTypeParams>(id, this.spec)).toJSON();\n }\n\n public static format(params: AssetTypeParams): string {\n return joinParams(params as any, this.spec);\n }\n\n public chainId: ChainId;\n public assetName: AssetName;\n\n constructor(params: AssetTypeParams | string) {\n if (typeof params === \"string\") {\n params = AssetType.parse(params);\n }\n\n this.chainId = new ChainId(params.chainId);\n this.assetName = new AssetName(params.assetName);\n }\n\n public toString(): string {\n return AssetType.format(this.toJSON());\n }\n\n public toJSON(): AssetTypeParams {\n return {\n chainId: this.chainId.toJSON(),\n assetName: this.assetName,\n };\n }\n}\n","import { AssetName, AssetNameParams } from \"./assetName\";\nimport { ChainId, ChainIdParams } from \"./chain\";\nimport { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface AssetIdParams {\n chainId: string | ChainIdParams;\n assetName: string | AssetNameParams;\n tokenId: string;\n}\n\nexport class AssetId {\n public static spec: IdentifierSpec = CAIP[\"19\"].assetId;\n\n public static parse(id: string): AssetIdParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n return new AssetId(getParams<AssetIdParams>(id, this.spec)).toJSON();\n }\n\n public static format(params: AssetIdParams): string {\n return joinParams(params as any, this.spec);\n }\n\n public chainId: ChainId;\n public assetName: AssetName;\n public tokenId: string;\n\n constructor(params: AssetIdParams | string) {\n if (typeof params === \"string\") {\n params = AssetId.parse(params);\n }\n\n this.chainId = new ChainId(params.chainId);\n this.assetName = new AssetName(params.assetName);\n this.tokenId = params.tokenId;\n }\n\n public toString(): string {\n return AssetId.format(this.toJSON());\n }\n\n public toJSON(): AssetIdParams {\n return {\n chainId: this.chainId.toJSON(),\n assetName: this.assetName.toJSON(),\n tokenId: this.tokenId,\n };\n }\n}\n","import type { CoinType } from \"@ensdomains/address-encoder\";\nimport { AccountId as CaipAccountId } from \"caip\";\nimport { type Address, type Hex, 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, type InterpretedName, Node } from \"../ens\";\nimport { asLowerCaseAddress } from \"./address\";\nimport { type CurrencyId, CurrencyIds, Price, type PriceEth } from \"./currencies\";\nimport { reinterpretName } from \"./interpretation/reinterpretation\";\nimport type { AccountIdString } from \"./serialized-types\";\nimport type {\n AccountId,\n BlockRef,\n ChainId,\n Datetime,\n DefaultableChainId,\n Duration,\n UnixTimestamp,\n} 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.coerce\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 lowercase Address.\n */\nexport const makeLowercaseAddressSchema = (valueLabel: string = \"EVM address\") =>\n z\n .string()\n .check((ctx) => {\n if (!isAddress(ctx.value)) {\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) => asLowerCaseAddress(val as Address));\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 Blockrange} object.\n */\nexport const makeBlockrangeSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject(\n {\n startBlock: makeBlockNumberSchema(`${valueLabel}.startBlock`).optional(),\n endBlock: makeBlockNumberSchema(`${valueLabel}.endBlock`).optional(),\n },\n {\n error: `${valueLabel} must be a valid Blockrange object.`,\n },\n )\n .refine(\n (v) => {\n if (v.startBlock && v.endBlock) {\n return v.startBlock <= v.endBlock;\n }\n\n return true;\n },\n { error: `${valueLabel}: startBlock must be before or equal to endBlock` },\n );\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\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\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 ],\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\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: makeLowercaseAddressSchema(`${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","import type { UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport type { AggregatedReferrerMetrics } from \"./aggregations\";\nimport type { ReferrerLeaderboard } from \"./leaderboard\";\nimport { isNonNegativeInteger, isPositiveInteger } from \"./number\";\nimport type { AwardedReferrerMetrics } from \"./referrer-metrics\";\nimport type { ReferralProgramRules } from \"./rules\";\n\n/**\n * The default number of referrers per leaderboard page.\n */\nexport const REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT = 25;\n\n/**\n * The maximum number of referrers per leaderboard page.\n */\n\nexport const REFERRERS_PER_LEADERBOARD_PAGE_MAX = 100;\n\n/**\n * Pagination params for leaderboard queries.\n */\nexport interface ReferrerLeaderboardPageParams {\n /**\n * Requested referrer leaderboard 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 referrers to return per leaderboard page\n * @invariant Must be a positive integer (>= 1) and less than or equal to {@link REFERRERS_PER_LEADERBOARD_PAGE_MAX}\n * @default {@link REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT}\n */\n recordsPerPage?: number;\n}\n\nconst validateReferrerLeaderboardPageParams = (params: ReferrerLeaderboardPageParams): void => {\n if (params.page !== undefined && !isPositiveInteger(params.page)) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageParams: ${params.page}. page must be a positive integer.`,\n );\n }\n if (params.recordsPerPage !== undefined && !isPositiveInteger(params.recordsPerPage)) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageParams: ${params.recordsPerPage}. recordsPerPage must be a positive integer.`,\n );\n }\n if (\n params.recordsPerPage !== undefined &&\n params.recordsPerPage > REFERRERS_PER_LEADERBOARD_PAGE_MAX\n ) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageParams: ${params.recordsPerPage}. recordsPerPage must be less than or equal to ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}.`,\n );\n }\n};\n\nexport const buildReferrerLeaderboardPageParams = (\n params: ReferrerLeaderboardPageParams,\n): Required<ReferrerLeaderboardPageParams> => {\n const result = {\n page: params.page ?? 1,\n recordsPerPage: params.recordsPerPage ?? REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT,\n } satisfies Required<ReferrerLeaderboardPageParams>;\n validateReferrerLeaderboardPageParams(result);\n return result;\n};\n\nexport interface ReferrerLeaderboardPageContext extends Required<ReferrerLeaderboardPageParams> {\n /**\n * Total number of referrers across all leaderboard pages\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n totalRecords: number;\n\n /**\n * Total number of pages in the leaderboard\n * @invariant Guaranteed to be a positive integer (>= 1)\n */\n totalPages: number;\n\n /**\n * Indicates if there is a next page available\n * @invariant true if and only if (`page` * `recordsPerPage` < `total`)\n */\n hasNext: boolean;\n\n /**\n * Indicates if there is a previous page available\n * @invariant true if and only if (`page` > 1)\n */\n hasPrev: boolean;\n\n /**\n * The start index of the referrers on the page (0-indexed)\n *\n * `undefined` if and only if `totalRecords` is 0.\n *\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n startIndex?: number;\n\n /**\n * The end index of the referrers on the page (0-indexed)\n *\n * `undefined` if and only if `totalRecords` is 0.\n *\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n * @invariant If `totalRecords` is > 0:\n * - Guaranteed to be greater than or equal to `startIndex`.\n * - Guaranteed to be less than `totalRecords`.\n */\n endIndex?: number;\n}\n\nexport const validateReferrerLeaderboardPageContext = (\n context: ReferrerLeaderboardPageContext,\n): void => {\n validateReferrerLeaderboardPageParams(context);\n if (!isNonNegativeInteger(context.totalRecords)) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: total must be a non-negative integer but is ${context.totalRecords}.`,\n );\n }\n const startIndex = (context.page - 1) * context.recordsPerPage;\n const endIndex = startIndex + context.recordsPerPage;\n\n if (!context.hasNext && endIndex < context.totalRecords) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: if hasNext is false, endIndex (${endIndex}) must be greater than or equal to total (${context.totalRecords}).`,\n );\n } else if (context.hasNext && context.page * context.recordsPerPage >= context.totalRecords) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: if hasNext is true, endIndex (${endIndex}) must be less than total (${context.totalRecords}).`,\n );\n }\n if (!context.hasPrev && context.page !== 1) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: if hasPrev is false, page must be the first page (1) but is ${context.page}.`,\n );\n } else if (context.hasPrev && context.page === 1) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: if hasPrev is true, page must not be the first page (1) but is ${context.page}.`,\n );\n }\n};\n\nexport const buildReferrerLeaderboardPageContext = (\n optionalParams: ReferrerLeaderboardPageParams,\n leaderboard: ReferrerLeaderboard,\n): ReferrerLeaderboardPageContext => {\n const materializedParams = buildReferrerLeaderboardPageParams(optionalParams);\n\n const totalRecords = leaderboard.referrers.size;\n\n const totalPages = Math.max(1, Math.ceil(totalRecords / materializedParams.recordsPerPage));\n\n if (materializedParams.page > totalPages) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: page ${materializedParams.page} exceeds total pages ${totalPages}.`,\n );\n }\n\n if (totalRecords === 0) {\n return {\n ...materializedParams,\n totalRecords: 0,\n totalPages: 1,\n hasNext: false,\n hasPrev: false,\n startIndex: undefined,\n endIndex: undefined,\n } satisfies ReferrerLeaderboardPageContext;\n }\n\n const startIndex = (materializedParams.page - 1) * materializedParams.recordsPerPage;\n const maxTheoreticalIndexOnPage = startIndex + (materializedParams.recordsPerPage - 1);\n const endIndex = Math.min(maxTheoreticalIndexOnPage, totalRecords - 1);\n const hasNext = maxTheoreticalIndexOnPage < totalRecords - 1;\n const hasPrev = materializedParams.page > 1;\n\n const result = {\n ...materializedParams,\n totalRecords,\n totalPages,\n hasNext,\n hasPrev,\n startIndex,\n endIndex,\n } satisfies ReferrerLeaderboardPageContext;\n validateReferrerLeaderboardPageContext(result);\n return result;\n};\n\n/**\n * A page of referrers from the referrer leaderboard.\n */\nexport interface ReferrerLeaderboardPage {\n /**\n * The {@link ReferralProgramRules} used to generate the {@link ReferrerLeaderboard}\n * that this {@link ReferrerLeaderboardPage} comes from.\n */\n rules: ReferralProgramRules;\n\n /**\n * Ordered list of {@link AwardedReferrerMetrics} for the {@link ReferrerLeaderboardPage}\n * described by `pageContext` within the related {@link ReferrerLeaderboard}.\n *\n * @invariant Array will be empty if `pageContext.totalRecords` is 0.\n * @invariant Array entries are ordered by `rank` (descending).\n */\n referrers: AwardedReferrerMetrics[];\n\n /**\n * Aggregated metrics for all referrers on the leaderboard.\n */\n aggregatedMetrics: AggregatedReferrerMetrics;\n\n /**\n * The {@link ReferrerLeaderboardPageContext} of this {@link ReferrerLeaderboardPage} relative to the overall\n * {@link ReferrerLeaderboard}.\n */\n pageContext: ReferrerLeaderboardPageContext;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link ReferrerLeaderboardPage} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\nexport const getReferrerLeaderboardPage = (\n pageParams: ReferrerLeaderboardPageParams,\n leaderboard: ReferrerLeaderboard,\n): ReferrerLeaderboardPage => {\n const pageContext = buildReferrerLeaderboardPageContext(pageParams, leaderboard);\n\n let referrers: AwardedReferrerMetrics[];\n\n if (\n pageContext.totalRecords > 0 &&\n typeof pageContext.startIndex !== \"undefined\" &&\n typeof pageContext.endIndex !== \"undefined\"\n ) {\n // extract the referrers from the leaderboard in the range specified by `pageContext`.\n referrers = Array.from(leaderboard.referrers.values()).slice(\n pageContext.startIndex,\n pageContext.endIndex + 1, // For `slice`, this is exclusive of the element at the index 'end'. We need it to be inclusive, hence plus one.\n );\n } else {\n referrers = [];\n }\n\n return {\n rules: leaderboard.rules,\n referrers,\n aggregatedMetrics: leaderboard.aggregatedMetrics,\n pageContext,\n accurateAsOf: leaderboard.accurateAsOf,\n };\n};\n","import type { Address } from \"viem\";\n\nimport type { Duration } from \"@ensnode/ensnode-sdk\";\n\nimport { isPositiveInteger } from \"./number\";\nimport type { ReferralProgramRules } from \"./rules\";\nimport { calcReferrerScore, type ReferrerScore } from \"./score\";\n\n/**\n * The rank of a referrer relative to all other referrers, where 1 is the\n * top-ranked referrer.\n *\n * @invariant Guaranteed to be a positive integer (> 0)\n */\nexport type ReferrerRank = number;\n\nexport const validateReferrerRank = (rank: ReferrerRank): void => {\n if (!isPositiveInteger(rank)) {\n throw new Error(`Invalid ReferrerRank: ${rank}. ReferrerRank must be a positive integer.`);\n }\n};\n\n/**\n * Determine if a referrer with the given `rank` is qualified to receive a non-zero `awardPoolShare` according to the given `rules`.\n *\n * @param rank - The rank of the referrer relative to all other referrers on a {@link ReferrerLeaderboard}.\n * @param rules - The rules of the referral program that generated the `rank`.\n */\nexport function isReferrerQualified(rank: ReferrerRank, rules: ReferralProgramRules): boolean {\n return rank <= rules.maxQualifiedReferrers;\n}\n\n/**\n * Calculate the final score boost of a referrer based on their rank.\n *\n * @param rank - The rank of the referrer relative to all other referrers, where 1 is the\n * top-ranked referrer.\n * @returns The final score boost of the referrer as a number between 0 and 1 (inclusive).\n */\nexport function calcReferrerFinalScoreBoost(\n rank: ReferrerRank,\n rules: ReferralProgramRules,\n): number {\n if (!isReferrerQualified(rank, rules)) return 0;\n\n return 1 - (rank - 1) / (rules.maxQualifiedReferrers - 1);\n}\n\n/**\n * Calculate the final score multiplier of a referrer based on their rank.\n *\n * @param rank - The rank of the referrer relative to all other referrers, where 1 is the\n * top-ranked referrer.\n * @returns The final score multiplier of the referrer as a number between 1 and 2 (inclusive).\n */\nexport function calcReferrerFinalScoreMultiplier(\n rank: ReferrerRank,\n rules: ReferralProgramRules,\n): number {\n return 1 + calcReferrerFinalScoreBoost(rank, rules);\n}\n\n/**\n * Calculate the final score of a referrer based on their score and final score boost.\n *\n * @param rank - The rank of the referrer relative to all other referrers.\n * @param totalIncrementalDuration - The total incremental duration (in seconds)\n * of referrals made by the referrer within the `rules`.\n * @param rules - The rules of the referral program that generated the `rank`.\n * @returns The final score of the referrer.\n */\nexport function calcReferrerFinalScore(\n rank: ReferrerRank,\n totalIncrementalDuration: Duration,\n rules: ReferralProgramRules,\n): ReferrerScore {\n return (\n calcReferrerScore(totalIncrementalDuration) * calcReferrerFinalScoreMultiplier(rank, rules)\n );\n}\n\nexport interface ReferrerMetricsForComparison {\n /**\n * The total incremental duration (in seconds) of all referrals made by the referrer within\n * the {@link ReferralProgramRules}.\n */\n totalIncrementalDuration: Duration;\n\n /**\n * The fully lowercase Ethereum address of the referrer.\n *\n * @invariant Guaranteed to be a valid EVM address in lowercase format.\n */\n referrer: Address;\n}\n\nexport const compareReferrerMetrics = (\n a: ReferrerMetricsForComparison,\n b: ReferrerMetricsForComparison,\n): number => {\n // Primary sort: totalIncrementalDuration (descending)\n if (a.totalIncrementalDuration !== b.totalIncrementalDuration) {\n return b.totalIncrementalDuration - a.totalIncrementalDuration;\n }\n\n // Secondary sort: referrer address using lexicographic comparison of ASCII hex strings (descending)\n if (b.referrer > a.referrer) return 1;\n if (b.referrer < a.referrer) return -1;\n return 0;\n};\n","import type { Address } from \"viem\";\n\nimport type { Duration } from \"@ensnode/ensnode-sdk\";\n\nimport { normalizeAddress, validateLowercaseAddress } from \"./address\";\nimport type { AggregatedReferrerMetrics } from \"./aggregations\";\nimport type { USDQuantity } from \"./currency\";\nimport { validateNonNegativeInteger } from \"./number\";\nimport {\n calcReferrerFinalScore,\n calcReferrerFinalScoreBoost,\n compareReferrerMetrics,\n isReferrerQualified,\n type ReferrerRank,\n validateReferrerRank,\n} from \"./rank\";\nimport type { RevenueContribution } from \"./revenue-contribution\";\nimport { validateRevenueContribution } from \"./revenue-contribution\";\nimport type { ReferralProgramRules } from \"./rules\";\nimport { calcReferrerScore, type ReferrerScore, validateReferrerScore } from \"./score\";\nimport { validateDuration } from \"./time\";\n\n/**\n * Represents metrics for a single referrer independent of other referrers.\n */\nexport interface ReferrerMetrics {\n /**\n * The fully lowercase Ethereum address of the referrer.\n *\n * @invariant Guaranteed to be a valid EVM address in lowercase format\n */\n referrer: Address;\n\n /**\n * The total number of referrals made by the referrer within the {@link ReferralProgramRules}.\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n totalReferrals: number;\n\n /**\n * The total incremental duration (in seconds) of all referrals made by the referrer within\n * the {@link ReferralProgramRules}.\n */\n totalIncrementalDuration: Duration;\n\n /**\n * The total revenue contribution (in Wei) made to the ENS DAO by all referrals\n * from this referrer.\n *\n * This is the sum of the total cost paid by registrants for all registrar actions\n * where this address was the referrer.\n *\n * @invariant Guaranteed to be a non-negative bigint value (>= 0n)\n * @invariant Never null (records with null `total` in the database are treated as 0 when summing)\n */\n totalRevenueContribution: RevenueContribution;\n}\n\nexport const buildReferrerMetrics = (\n referrer: Address,\n totalReferrals: number,\n totalIncrementalDuration: Duration,\n totalRevenueContribution: RevenueContribution,\n): ReferrerMetrics => {\n const result = {\n referrer: normalizeAddress(referrer),\n totalReferrals,\n totalIncrementalDuration,\n totalRevenueContribution,\n } satisfies ReferrerMetrics;\n\n validateReferrerMetrics(result);\n return result;\n};\n\nexport const validateReferrerMetrics = (metrics: ReferrerMetrics): void => {\n validateLowercaseAddress(metrics.referrer);\n validateNonNegativeInteger(metrics.totalReferrals);\n validateDuration(metrics.totalIncrementalDuration);\n validateRevenueContribution(metrics.totalRevenueContribution);\n};\n\nexport const sortReferrerMetrics = (referrers: ReferrerMetrics[]): ReferrerMetrics[] => {\n return [...referrers].sort(compareReferrerMetrics);\n};\n\n/**\n * Represents metrics for a single referrer independent of other referrers,\n * including a calculation of the referrer's score.\n */\nexport interface ScoredReferrerMetrics extends ReferrerMetrics {\n /**\n * The referrer's score.\n *\n * @invariant Guaranteed to be `calcReferrerScore(totalIncrementalDuration)`\n */\n score: ReferrerScore;\n}\n\nexport const buildScoredReferrerMetrics = (referrer: ReferrerMetrics): ScoredReferrerMetrics => {\n const result = {\n ...referrer,\n score: calcReferrerScore(referrer.totalIncrementalDuration),\n } satisfies ScoredReferrerMetrics;\n\n validateScoredReferrerMetrics(result);\n return result;\n};\n\nexport const validateScoredReferrerMetrics = (metrics: ScoredReferrerMetrics): void => {\n validateReferrerMetrics(metrics);\n validateReferrerScore(metrics.score);\n\n const expectedScore = calcReferrerScore(metrics.totalIncrementalDuration);\n if (metrics.score !== expectedScore) {\n throw new Error(`Referrer: Invalid score: ${metrics.score}, expected: ${expectedScore}.`);\n }\n};\n\n/**\n * Extends {@link ScoredReferrerMetrics} to include additional metrics\n * relative to all other referrers on a {@link ReferrerLeaderboard} and {@link ReferralProgramRules}.\n */\nexport interface RankedReferrerMetrics extends ScoredReferrerMetrics {\n /**\n * The referrer's rank on the {@link ReferrerLeaderboard} relative to all other referrers.\n */\n rank: ReferrerRank;\n\n /**\n * Identifies if the referrer meets the qualifications of the {@link ReferralProgramRules} to receive a non-zero `awardPoolShare`.\n *\n * @invariant true if and only if `rank` is less than or equal to {@link ReferralProgramRules.maxQualifiedReferrers}\n */\n isQualified: boolean;\n\n /**\n * The referrer's final score boost.\n *\n * @invariant Guaranteed to be a number between 0 and 1 (inclusive)\n * @invariant Calculated as: `1-((rank-1)/({@link ReferralProgramRules.maxQualifiedReferrers}-1))` if `isQualified` is `true`, else `0`\n */\n finalScoreBoost: number;\n\n /**\n * The referrer's final score.\n *\n * @invariant Calculated as: `score * (1 + finalScoreBoost)`\n */\n finalScore: ReferrerScore;\n}\n\nexport const validateRankedReferrerMetrics = (\n metrics: RankedReferrerMetrics,\n rules: ReferralProgramRules,\n): void => {\n validateScoredReferrerMetrics(metrics);\n validateReferrerRank(metrics.rank);\n\n if (metrics.finalScoreBoost < 0 || metrics.finalScoreBoost > 1) {\n throw new Error(\n `Invalid RankedReferrerMetrics: Invalid finalScoreBoost: ${metrics.finalScoreBoost}. finalScoreBoost must be between 0 and 1 (inclusive).`,\n );\n }\n\n validateReferrerScore(metrics.finalScore);\n\n const expectedIsQualified = isReferrerQualified(metrics.rank, rules);\n if (metrics.isQualified !== expectedIsQualified) {\n throw new Error(\n `RankedReferrerMetrics: Invalid isQualified: ${metrics.isQualified}, expected: ${expectedIsQualified}.`,\n );\n }\n\n const expectedFinalScoreBoost = calcReferrerFinalScoreBoost(metrics.rank, rules);\n if (metrics.finalScoreBoost !== expectedFinalScoreBoost) {\n throw new Error(\n `RankedReferrerMetrics: Invalid finalScoreBoost: ${metrics.finalScoreBoost}, expected: ${expectedFinalScoreBoost}.`,\n );\n }\n\n const expectedFinalScore = calcReferrerFinalScore(\n metrics.rank,\n metrics.totalIncrementalDuration,\n rules,\n );\n if (metrics.finalScore !== expectedFinalScore) {\n throw new Error(\n `RankedReferrerMetrics: Invalid finalScore: ${metrics.finalScore}, expected: ${expectedFinalScore}.`,\n );\n }\n};\n\nexport const buildRankedReferrerMetrics = (\n referrer: ScoredReferrerMetrics,\n rank: ReferrerRank,\n rules: ReferralProgramRules,\n): RankedReferrerMetrics => {\n const result = {\n ...referrer,\n rank,\n isQualified: isReferrerQualified(rank, rules),\n finalScoreBoost: calcReferrerFinalScoreBoost(rank, rules),\n finalScore: calcReferrerFinalScore(rank, referrer.totalIncrementalDuration, rules),\n } satisfies RankedReferrerMetrics;\n validateRankedReferrerMetrics(result, rules);\n return result;\n};\n\n/**\n * Calculate the share of the award pool for a referrer.\n * @param referrer - The referrer to calculate the award pool share for.\n * @param aggregatedMetrics - Aggregated metrics for all referrers.\n * @param rules - The rules of the referral program.\n * @returns The referrer's share of the award pool as a number between 0 and 1 (inclusive).\n */\nexport const calcReferrerAwardPoolShare = (\n referrer: RankedReferrerMetrics,\n aggregatedMetrics: AggregatedReferrerMetrics,\n rules: ReferralProgramRules,\n): number => {\n if (!isReferrerQualified(referrer.rank, rules)) return 0;\n if (aggregatedMetrics.grandTotalQualifiedReferrersFinalScore === 0) return 0;\n\n return (\n calcReferrerFinalScore(referrer.rank, referrer.totalIncrementalDuration, rules) /\n aggregatedMetrics.grandTotalQualifiedReferrersFinalScore\n );\n};\n\n/**\n * Extends {@link RankedReferrerMetrics} to include additional metrics\n * relative to {@link AggregatedRankedReferrerMetrics}.\n */\nexport interface AwardedReferrerMetrics extends RankedReferrerMetrics {\n /**\n * The referrer's share of the award pool.\n *\n * @invariant Guaranteed to be a number between 0 and 1 (inclusive)\n * @invariant Calculated as: `finalScore / {@link AggregatedRankedReferrerMetrics.grandTotalQualifiedReferrersFinalScore}` if `isQualified` is `true`, else `0`\n */\n awardPoolShare: number;\n\n /**\n * The approximate {@link USDQuantity} of the referrer's share of the {@link ReferralProgramRules.totalAwardPoolValue}.\n *\n * @invariant Guaranteed to be a number between 0 and {@link ReferralProgramRules.totalAwardPoolValue} (inclusive)\n * @invariant Calculated as: `awardPoolShare` * {@link ReferralProgramRules.totalAwardPoolValue}\n */\n awardPoolApproxValue: USDQuantity;\n}\n\nexport const validateAwardedReferrerMetrics = (\n referrer: AwardedReferrerMetrics,\n rules: ReferralProgramRules,\n): void => {\n validateRankedReferrerMetrics(referrer, rules);\n if (referrer.awardPoolShare < 0 || referrer.awardPoolShare > 1) {\n throw new Error(\n `Invalid AwardedReferrerMetrics: ${referrer.awardPoolShare}. awardPoolShare must be between 0 and 1 (inclusive).`,\n );\n }\n\n if (\n referrer.awardPoolApproxValue < 0 ||\n referrer.awardPoolApproxValue > rules.totalAwardPoolValue\n ) {\n throw new Error(\n `Invalid AwardedReferrerMetrics: ${referrer.awardPoolApproxValue}. awardPoolApproxValue must be between 0 and ${rules.totalAwardPoolValue} (inclusive).`,\n );\n }\n};\n\nexport const buildAwardedReferrerMetrics = (\n referrer: RankedReferrerMetrics,\n aggregatedMetrics: AggregatedReferrerMetrics,\n rules: ReferralProgramRules,\n): AwardedReferrerMetrics => {\n const awardPoolShare = calcReferrerAwardPoolShare(referrer, aggregatedMetrics, rules);\n\n const result = {\n ...referrer,\n awardPoolShare,\n awardPoolApproxValue: awardPoolShare * rules.totalAwardPoolValue,\n };\n validateAwardedReferrerMetrics(result, rules);\n return result;\n};\n\n/**\n * Extends {@link AwardedReferrerMetrics} but with rank set to null to represent\n * a referrer who is not on the leaderboard (has zero referrals within the rules associated with the leaderboard).\n */\nexport interface UnrankedReferrerMetrics\n extends Omit<AwardedReferrerMetrics, \"rank\" | \"isQualified\"> {\n /**\n * The referrer is not on the leaderboard and therefore has no rank.\n */\n rank: null;\n\n /**\n * Always false for unranked referrers.\n */\n isQualified: false;\n}\n\nexport const validateUnrankedReferrerMetrics = (metrics: UnrankedReferrerMetrics): void => {\n validateScoredReferrerMetrics(metrics);\n\n if (metrics.rank !== null) {\n throw new Error(`Invalid UnrankedReferrerMetrics: rank must be null, got: ${metrics.rank}.`);\n }\n\n if (metrics.isQualified !== false) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: isQualified must be false, got: ${metrics.isQualified}.`,\n );\n }\n\n if (metrics.totalReferrals !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: totalReferrals must be 0, got: ${metrics.totalReferrals}.`,\n );\n }\n\n if (metrics.totalIncrementalDuration !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: totalIncrementalDuration must be 0, got: ${metrics.totalIncrementalDuration}.`,\n );\n }\n\n if (metrics.totalRevenueContribution !== 0n) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: totalRevenueContribution must be 0n, got: ${metrics.totalRevenueContribution.toString()}.`,\n );\n }\n\n if (metrics.score !== 0) {\n throw new Error(`Invalid UnrankedReferrerMetrics: score must be 0, got: ${metrics.score}.`);\n }\n\n if (metrics.finalScoreBoost !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: finalScoreBoost must be 0, got: ${metrics.finalScoreBoost}.`,\n );\n }\n\n if (metrics.finalScore !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: finalScore must be 0, got: ${metrics.finalScore}.`,\n );\n }\n\n if (metrics.awardPoolShare !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: awardPoolShare must be 0, got: ${metrics.awardPoolShare}.`,\n );\n }\n\n if (metrics.awardPoolApproxValue !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: awardPoolApproxValue must be 0, got: ${metrics.awardPoolApproxValue}.`,\n );\n }\n};\n\n/**\n * Build an unranked zero-score referrer record for a referrer address that is not in the leaderboard.\n *\n * This is useful when you want to return a referrer record for an address that has no referrals\n * and is not qualified for the leaderboard.\n *\n * @param referrer - The referrer address\n * @returns An {@link UnrankedReferrerMetrics} with zero values for all metrics and null rank\n */\nexport const buildUnrankedReferrerMetrics = (referrer: Address): UnrankedReferrerMetrics => {\n const baseMetrics = buildReferrerMetrics(referrer, 0, 0, 0n);\n const scoredMetrics = buildScoredReferrerMetrics(baseMetrics);\n\n const result = {\n ...scoredMetrics,\n rank: null,\n isQualified: false,\n finalScoreBoost: 0,\n finalScore: 0,\n awardPoolShare: 0,\n awardPoolApproxValue: 0,\n } satisfies UnrankedReferrerMetrics;\n\n validateUnrankedReferrerMetrics(result);\n return result;\n};\n","import type { Address } from \"viem\";\n\nimport type { UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport type { AggregatedReferrerMetrics } from \"./aggregations\";\nimport type { ReferrerLeaderboard } from \"./leaderboard\";\nimport {\n type AwardedReferrerMetrics,\n buildUnrankedReferrerMetrics,\n type UnrankedReferrerMetrics,\n} from \"./referrer-metrics\";\nimport type { ReferralProgramRules } from \"./rules\";\n\n/**\n * The type of referrer detail data.\n */\nexport const ReferrerDetailTypeIds = {\n /**\n * Represents a referrer who is ranked on the leaderboard.\n */\n Ranked: \"ranked\",\n\n /**\n * Represents a referrer who is not ranked on the leaderboard.\n */\n Unranked: \"unranked\",\n} as const;\n\n/**\n * The derived string union of possible {@link ReferrerDetailTypeIds}.\n */\nexport type ReferrerDetailTypeId =\n (typeof ReferrerDetailTypeIds)[keyof typeof ReferrerDetailTypeIds];\n\n/**\n * Referrer detail data for a specific referrer address on the leaderboard.\n *\n * Includes the referrer's awarded metrics from the leaderboard plus timestamp.\n *\n * Invariants:\n * - `type` is always {@link ReferrerDetailTypeIds.Ranked}.\n *\n * @see {@link AwardedReferrerMetrics}\n */\nexport interface ReferrerDetailRanked {\n /**\n * The type of referrer detail data.\n */\n type: typeof ReferrerDetailTypeIds.Ranked;\n\n /**\n * The {@link ReferralProgramRules} used to calculate the {@link AwardedReferrerMetrics}.\n */\n rules: ReferralProgramRules;\n\n /**\n * The awarded referrer metrics from the leaderboard.\n *\n * Contains all calculated metrics including score, rank, qualification status,\n * and award pool share information.\n */\n referrer: AwardedReferrerMetrics;\n\n /**\n * Aggregated metrics for all referrers on the leaderboard.\n */\n aggregatedMetrics: AggregatedReferrerMetrics;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link ReferrerDetailData} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\n/**\n * Referrer detail data for a specific referrer address NOT on the leaderboard.\n *\n * Includes the referrer's unranked metrics (with null rank and isQualified: false) plus timestamp.\n *\n * Invariants:\n * - `type` is always {@link ReferrerDetailTypeIds.Unranked}.\n *\n * @see {@link UnrankedReferrerMetrics}\n */\nexport interface ReferrerDetailUnranked {\n /**\n * The type of referrer detail data.\n */\n type: typeof ReferrerDetailTypeIds.Unranked;\n\n /**\n * The {@link ReferralProgramRules} used to calculate the {@link UnrankedReferrerMetrics}.\n */\n rules: ReferralProgramRules;\n\n /**\n * The unranked referrer metrics (not on the leaderboard).\n *\n * Contains all calculated metrics with rank set to null and isQualified set to false.\n */\n referrer: UnrankedReferrerMetrics;\n\n /**\n * Aggregated metrics for all referrers on the leaderboard.\n */\n aggregatedMetrics: AggregatedReferrerMetrics;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link UnrankedReferrerDetailData} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\n/**\n * Referrer detail data for a specific referrer address.\n *\n * Use the `type` field to determine the specific type interpretation\n * at runtime.\n */\nexport type ReferrerDetail = ReferrerDetailRanked | ReferrerDetailUnranked;\n\n/**\n * Get the detail for a specific referrer from the leaderboard.\n *\n * Returns a {@link ReferrerDetailRanked} if the referrer is on the leaderboard,\n * or a {@link ReferrerDetailUnranked} if the referrer has no referrals.\n *\n * @param referrer - The referrer address to look up\n * @param leaderboard - The referrer leaderboard to query\n * @returns The appropriate {@link ReferrerDetail} (ranked or unranked)\n */\nexport const getReferrerDetail = (\n referrer: Address,\n leaderboard: ReferrerLeaderboard,\n): ReferrerDetail => {\n const awardedReferrerMetrics = leaderboard.referrers.get(referrer);\n\n // If referrer is on the leaderboard, return their ranked metrics\n if (awardedReferrerMetrics) {\n return {\n type: ReferrerDetailTypeIds.Ranked,\n rules: leaderboard.rules,\n referrer: awardedReferrerMetrics,\n aggregatedMetrics: leaderboard.aggregatedMetrics,\n accurateAsOf: leaderboard.accurateAsOf,\n };\n }\n\n // If referrer not found, return an unranked referrer record\n return {\n type: ReferrerDetailTypeIds.Unranked,\n rules: leaderboard.rules,\n referrer: buildUnrankedReferrerMetrics(referrer),\n aggregatedMetrics: leaderboard.aggregatedMetrics,\n accurateAsOf: leaderboard.accurateAsOf,\n };\n};\n","import type { Address } from \"viem\";\n\nimport type { ReferrerLeaderboardPage, ReferrerLeaderboardPageParams } from \"../leaderboard-page\";\nimport type { ReferrerDetail } from \"../referrer-detail\";\n\n/**\n * Request parameters for a referrer leaderboard page query.\n */\nexport interface ReferrerLeaderboardPageRequest extends ReferrerLeaderboardPageParams {}\n\n/**\n * A status code for a referrer leaderboard page API response.\n */\nexport const ReferrerLeaderboardPageResponseCodes = {\n /**\n * Represents that the requested referrer leaderboard page is available.\n */\n Ok: \"ok\",\n\n /**\n * Represents that the referrer leaderboard data is not available.\n */\n Error: \"error\",\n} as const;\n\n/**\n * The derived string union of possible {@link ReferrerLeaderboardPageResponseCodes}.\n */\nexport type ReferrerLeaderboardPageResponseCode =\n (typeof ReferrerLeaderboardPageResponseCodes)[keyof typeof ReferrerLeaderboardPageResponseCodes];\n\n/**\n * A referrer leaderboard page response when the data is available.\n */\nexport type ReferrerLeaderboardPageResponseOk = {\n responseCode: typeof ReferrerLeaderboardPageResponseCodes.Ok;\n data: ReferrerLeaderboardPage;\n};\n\n/**\n * A referrer leaderboard page response when the data is not available.\n */\nexport type ReferrerLeaderboardPageResponseError = {\n responseCode: typeof ReferrerLeaderboardPageResponseCodes.Error;\n error: string;\n errorMessage: string;\n};\n\n/**\n * A referrer leaderboard page API response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type ReferrerLeaderboardPageResponse =\n | ReferrerLeaderboardPageResponseOk\n | ReferrerLeaderboardPageResponseError;\n\n/**\n * Request parameters for referrer detail query.\n */\nexport interface ReferrerDetailRequest {\n /** The Ethereum address of the referrer to query */\n referrer: Address;\n}\n\n/**\n * A status code for referrer detail API responses.\n */\nexport const ReferrerDetailResponseCodes = {\n /**\n * Represents that the referrer detail data is available.\n */\n Ok: \"ok\",\n\n /**\n * Represents that an error occurred while fetching the data.\n */\n Error: \"error\",\n} as const;\n\n/**\n * The derived string union of possible {@link ReferrerDetailResponseCodes}.\n */\nexport type ReferrerDetailResponseCode =\n (typeof ReferrerDetailResponseCodes)[keyof typeof ReferrerDetailResponseCodes];\n\n/**\n * A referrer detail response when the data is available for a referrer on the leaderboard.\n */\nexport type ReferrerDetailResponseOk = {\n responseCode: typeof ReferrerDetailResponseCodes.Ok;\n data: ReferrerDetail;\n};\n\n/**\n * A referrer detail response when an error occurs.\n */\nexport type ReferrerDetailResponseError = {\n responseCode: typeof ReferrerDetailResponseCodes.Error;\n error: string;\n errorMessage: string;\n};\n\n/**\n * A referrer detail API response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type ReferrerDetailResponse = ReferrerDetailResponseOk | ReferrerDetailResponseError;\n","import type { AggregatedReferrerMetrics } from \"../aggregations\";\nimport type { ReferrerLeaderboardPage } from \"../leaderboard-page\";\nimport type { ReferrerDetailRanked, ReferrerDetailUnranked } from \"../referrer-detail\";\nimport type { AwardedReferrerMetrics, UnrankedReferrerMetrics } from \"../referrer-metrics\";\nimport type { RevenueContribution } from \"../revenue-contribution\";\nimport type { ReferralProgramRules } from \"../rules\";\nimport type {\n SerializedAggregatedReferrerMetrics,\n SerializedAwardedReferrerMetrics,\n SerializedReferralProgramRules,\n SerializedReferrerDetailRanked,\n SerializedReferrerDetailResponse,\n SerializedReferrerDetailUnranked,\n SerializedReferrerLeaderboardPage,\n SerializedReferrerLeaderboardPageResponse,\n SerializedUnrankedReferrerMetrics,\n} from \"./serialized-types\";\nimport {\n type ReferrerDetailResponse,\n ReferrerDetailResponseCodes,\n type ReferrerLeaderboardPageResponse,\n ReferrerLeaderboardPageResponseCodes,\n} from \"./types\";\n\n/**\n * Serializes a {@link RevenueContribution} value into its string representation.\n */\nfunction serializeRevenueContribution(revenueContribution: RevenueContribution): string {\n return revenueContribution.toString();\n}\n\n/**\n * Serializes a {@link ReferralProgramRules} object.\n */\nfunction serializeReferralProgramRules(\n rules: ReferralProgramRules,\n): SerializedReferralProgramRules {\n // All fields are already serializable primitives\n return rules;\n}\n\n/**\n * Serializes an {@link AwardedReferrerMetrics} object.\n */\nfunction serializeAwardedReferrerMetrics(\n metrics: AwardedReferrerMetrics,\n): SerializedAwardedReferrerMetrics {\n return {\n referrer: metrics.referrer,\n totalReferrals: metrics.totalReferrals,\n totalIncrementalDuration: metrics.totalIncrementalDuration,\n totalRevenueContribution: serializeRevenueContribution(metrics.totalRevenueContribution),\n score: metrics.score,\n rank: metrics.rank,\n isQualified: metrics.isQualified,\n finalScoreBoost: metrics.finalScoreBoost,\n finalScore: metrics.finalScore,\n awardPoolShare: metrics.awardPoolShare,\n awardPoolApproxValue: metrics.awardPoolApproxValue,\n };\n}\n\n/**\n * Serializes an {@link UnrankedReferrerMetrics} object.\n */\nfunction serializeUnrankedReferrerMetrics(\n metrics: UnrankedReferrerMetrics,\n): SerializedUnrankedReferrerMetrics {\n return {\n referrer: metrics.referrer,\n totalReferrals: metrics.totalReferrals,\n totalIncrementalDuration: metrics.totalIncrementalDuration,\n totalRevenueContribution: serializeRevenueContribution(metrics.totalRevenueContribution),\n score: metrics.score,\n rank: metrics.rank,\n isQualified: metrics.isQualified,\n finalScoreBoost: metrics.finalScoreBoost,\n finalScore: metrics.finalScore,\n awardPoolShare: metrics.awardPoolShare,\n awardPoolApproxValue: metrics.awardPoolApproxValue,\n };\n}\n\n/**\n * Serializes an {@link AggregatedReferrerMetrics} object.\n */\nfunction serializeAggregatedReferrerMetrics(\n metrics: AggregatedReferrerMetrics,\n): SerializedAggregatedReferrerMetrics {\n return {\n grandTotalReferrals: metrics.grandTotalReferrals,\n grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,\n grandTotalRevenueContribution: serializeRevenueContribution(\n metrics.grandTotalRevenueContribution,\n ),\n grandTotalQualifiedReferrersFinalScore: metrics.grandTotalQualifiedReferrersFinalScore,\n minFinalScoreToQualify: metrics.minFinalScoreToQualify,\n };\n}\n\n/**\n * Serializes a {@link ReferrerLeaderboardPage} object.\n */\nfunction serializeReferrerLeaderboardPage(\n page: ReferrerLeaderboardPage,\n): SerializedReferrerLeaderboardPage {\n return {\n rules: serializeReferralProgramRules(page.rules),\n referrers: page.referrers.map(serializeAwardedReferrerMetrics),\n aggregatedMetrics: serializeAggregatedReferrerMetrics(page.aggregatedMetrics),\n pageContext: page.pageContext,\n accurateAsOf: page.accurateAsOf,\n };\n}\n\n/**\n * Serializes a {@link ReferrerDetailRanked} object.\n */\nfunction serializeReferrerDetailRanked(\n detail: ReferrerDetailRanked,\n): SerializedReferrerDetailRanked {\n return {\n type: detail.type,\n rules: serializeReferralProgramRules(detail.rules),\n referrer: serializeAwardedReferrerMetrics(detail.referrer),\n aggregatedMetrics: serializeAggregatedReferrerMetrics(detail.aggregatedMetrics),\n accurateAsOf: detail.accurateAsOf,\n };\n}\n\n/**\n * Serializes a {@link ReferrerDetailUnranked} object.\n */\nfunction serializeReferrerDetailUnranked(\n detail: ReferrerDetailUnranked,\n): SerializedReferrerDetailUnranked {\n return {\n type: detail.type,\n rules: serializeReferralProgramRules(detail.rules),\n referrer: serializeUnrankedReferrerMetrics(detail.referrer),\n aggregatedMetrics: serializeAggregatedReferrerMetrics(detail.aggregatedMetrics),\n accurateAsOf: detail.accurateAsOf,\n };\n}\n\n/**\n * Serialize a {@link ReferrerLeaderboardPageResponse} object.\n */\nexport function serializeReferrerLeaderboardPageResponse(\n response: ReferrerLeaderboardPageResponse,\n): SerializedReferrerLeaderboardPageResponse {\n switch (response.responseCode) {\n case ReferrerLeaderboardPageResponseCodes.Ok:\n return {\n responseCode: response.responseCode,\n data: serializeReferrerLeaderboardPage(response.data),\n };\n\n case ReferrerLeaderboardPageResponseCodes.Error:\n return response;\n }\n}\n\n/**\n * Serialize a {@link ReferrerDetailResponse} object.\n */\nexport function serializeReferrerDetailResponse(\n response: ReferrerDetailResponse,\n): SerializedReferrerDetailResponse {\n switch (response.responseCode) {\n case ReferrerDetailResponseCodes.Ok:\n switch (response.data.type) {\n case \"ranked\":\n return {\n responseCode: response.responseCode,\n data: serializeReferrerDetailRanked(response.data),\n };\n\n case \"unranked\":\n return {\n responseCode: response.responseCode,\n data: serializeReferrerDetailUnranked(response.data),\n };\n }\n break;\n\n case ReferrerDetailResponseCodes.Error:\n return response;\n }\n}\n","import {\n deserializeReferrerDetailResponse,\n deserializeReferrerLeaderboardPageResponse,\n type ReferrerDetailRequest,\n type ReferrerDetailResponse,\n type ReferrerLeaderboardPageRequest,\n type ReferrerLeaderboardPageResponse,\n type SerializedReferrerDetailResponse,\n type SerializedReferrerLeaderboardPageResponse,\n} from \"./api\";\n\n/**\n * Default ENSNode API endpoint URL\n */\nexport const DEFAULT_ENSNODE_API_URL = \"https://api.alpha.ensnode.io\" as const;\n\n/**\n * Configuration options for ENS Referrals API client\n */\nexport interface ClientOptions {\n /** The ENSNode API URL */\n url: URL;\n}\n\n/**\n * ENS Referrals API Client\n *\n * Provides access to ENS Referrals data and leaderboard information.\n *\n * @example\n * ```typescript\n * // Create client with default options\n * const client = new ENSReferralsClient();\n *\n * // Get referrer leaderboard\n * const leaderboardPage = await client.getReferrerLeaderboardPage({\n * page: 1,\n * recordsPerPage: 25\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Custom configuration\n * const client = new ENSReferralsClient({\n * url: new URL(\"https://my-ensnode-instance.com\"),\n * });\n * ```\n */\nexport class ENSReferralsClient {\n private readonly options: ClientOptions;\n\n static defaultOptions(): ClientOptions {\n return {\n url: new URL(DEFAULT_ENSNODE_API_URL),\n };\n }\n\n constructor(options: Partial<ClientOptions> = {}) {\n this.options = {\n ...ENSReferralsClient.defaultOptions(),\n ...options,\n };\n }\n\n getOptions(): Readonly<ClientOptions> {\n return Object.freeze({\n url: new URL(this.options.url.href),\n });\n }\n\n /**\n * Fetch Referrer Leaderboard Page\n *\n * Retrieves a paginated list of referrer leaderboard metrics with contribution percentages.\n * Each referrer's contribution is calculated as a percentage of the grand totals across all referrers.\n *\n * @param request - Pagination parameters\n * @param request.page - The page number to retrieve (1-indexed, default: 1)\n * @param request.recordsPerPage - Number of records per page (default: 25, max: 100)\n * @returns {ReferrerLeaderboardPageResponse}\n *\n * @throws if the ENSNode request fails\n * @throws if the ENSNode API returns an error response\n * @throws if the ENSNode response breaks required invariants\n *\n * @example\n * ```typescript\n * // Get first page with default page size (25 records)\n * const response = await client.getReferrerLeaderboardPage();\n * if (response.responseCode === ReferrerLeaderboardPageResponseCodes.Ok) {\n * const {\n * aggregatedMetrics,\n * referrers,\n * rules,\n * pageContext,\n * updatedAt\n * } = response.data;\n * console.log(aggregatedMetrics);\n * console.log(referrers);\n * console.log(rules);\n * console.log(updatedAt);\n * console.log(`Page ${pageContext.page} of ${pageContext.totalPages}`);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Get second page with 50 records per page\n * const response = await client.getReferrerLeaderboardPage({ page: 2, recordsPerPage: 50 });\n * ```\n *\n * @example\n * ```typescript\n * // Handle error response, ie. when Referrer Leaderboard is not currently available.\n * const response = await client.getReferrerLeaderboardPage();\n *\n * if (response.responseCode === ReferrerLeaderboardPageResponseCodes.Error) {\n * console.error(response.error);\n * console.error(response.errorMessage);\n * }\n * ```\n */\n async getReferrerLeaderboardPage(\n request?: ReferrerLeaderboardPageRequest,\n ): Promise<ReferrerLeaderboardPageResponse> {\n const url = new URL(`/ensanalytics/referrers`, this.options.url);\n\n if (request?.page) url.searchParams.set(\"page\", request.page.toString());\n if (request?.recordsPerPage)\n url.searchParams.set(\"recordsPerPage\", request.recordsPerPage.toString());\n\n const response = await fetch(url);\n\n // ENSNode API should always allow parsing a response as JSON object.\n // If for some reason it's not the case, throw an error.\n let responseData: unknown;\n try {\n responseData = await response.json();\n } catch {\n throw new Error(\"Malformed response data: invalid JSON\");\n }\n\n // The API can return errors with 500 status, but they're still in the\n // PaginatedAggregatedReferrersResponse format with responseCode: 'error'\n // So we don't need to check response.ok here, just deserialize and let\n // the caller handle the responseCode\n\n return deserializeReferrerLeaderboardPageResponse(\n responseData as SerializedReferrerLeaderboardPageResponse,\n );\n }\n\n /**\n * Fetch Referrer Detail\n *\n * Retrieves detailed information about a specific referrer, whether they are on the\n * leaderboard or not.\n *\n * The response data is a discriminated union type with a `type` field:\n *\n * **For referrers on the leaderboard** (`ReferrerDetailRanked`):\n * - `type`: {@link ReferrerDetailTypeIds.Ranked}\n * - `referrer`: The `AwardedReferrerMetrics` from @namehash/ens-referrals\n * - `rules`: The referral program rules\n * - `aggregatedMetrics`: Aggregated metrics for all referrers on the leaderboard\n * - `accurateAsOf`: Unix timestamp indicating when the data was last updated\n *\n * **For referrers NOT on the leaderboard** (`ReferrerDetailUnranked`):\n * - `type`: {@link ReferrerDetailTypeIds.Unranked}\n * - `referrer`: The `UnrankedReferrerMetrics` from @namehash/ens-referrals\n * - `rules`: The referral program rules\n * - `aggregatedMetrics`: Aggregated metrics for all referrers on the leaderboard\n * - `accurateAsOf`: Unix timestamp indicating when the data was last updated\n *\n * @see {@link https://www.npmjs.com/package/@namehash/ens-referrals|@namehash/ens-referrals} for calculation details\n *\n * @param request The referrer address to query\n * @returns {ReferrerDetailResponse} Returns the referrer detail response\n *\n * @throws if the ENSNode request fails\n * @throws if the response data is malformed\n *\n * @example\n * ```typescript\n * // Get referrer detail for a specific address\n * const response = await client.getReferrerDetail({\n * referrer: \"0x1234567890123456789012345678901234567890\"\n * });\n * if (response.responseCode === ReferrerDetailResponseCodes.Ok) {\n * const { type, referrer, rules, aggregatedMetrics, accurateAsOf } = response.data;\n * console.log(type); // ReferrerDetailTypeIds.Ranked or ReferrerDetailTypeIds.Unranked\n * console.log(referrer);\n * console.log(accurateAsOf);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Use discriminated union to check if referrer is ranked\n * const response = await client.getReferrerDetail({\n * referrer: \"0x1234567890123456789012345678901234567890\"\n * });\n * if (response.responseCode === ReferrerDetailResponseCodes.Ok) {\n * if (response.data.type === ReferrerDetailTypeIds.Ranked) {\n * // TypeScript knows this is ReferrerDetailRanked\n * console.log(`Rank: ${response.data.referrer.rank}`);\n * console.log(`Qualified: ${response.data.referrer.isQualified}`);\n * console.log(`Award Pool Share: ${response.data.referrer.awardPoolShare * 100}%`);\n * } else {\n * // TypeScript knows this is ReferrerDetailUnranked\n * console.log(\"Referrer is not on the leaderboard (no referrals yet)\");\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Handle error response, ie. when Referrer Detail is not currently available.\n * const response = await client.getReferrerDetail({\n * referrer: \"0x1234567890123456789012345678901234567890\"\n * });\n *\n * if (response.responseCode === ReferrerDetailResponseCodes.Error) {\n * console.error(response.error);\n * console.error(response.errorMessage);\n * }\n * ```\n */\n async getReferrerDetail(request: ReferrerDetailRequest): Promise<ReferrerDetailResponse> {\n const url = new URL(\n `/api/ensanalytics/referrers/${encodeURIComponent(request.referrer)}`,\n this.options.url,\n );\n\n const response = await fetch(url);\n\n // ENSNode API should always allow parsing a response as JSON object.\n // If for some reason it's not the case, throw an error.\n let responseData: unknown;\n try {\n responseData = await response.json();\n } catch {\n throw new Error(\"Malformed response data: invalid JSON\");\n }\n\n // The API can return errors with 500 status, but they're still in the\n // ReferrerDetailResponse format with responseCode: 'error'\n // So we don't need to check response.ok here, just deserialize and let\n // the caller handle the responseCode\n\n return deserializeReferrerDetailResponse(responseData as SerializedReferrerDetailResponse);\n }\n}\n","import { isFiniteNonNegativeNumber } from \"./number\";\n\n/**\n * Represents a quantity of USD.\n *\n * @invariant Guaranteed to be a finite non-negative number (>= 0)\n */\nexport type USDQuantity = number;\n\nexport function isValidUSDQuantity(value: USDQuantity): boolean {\n return isFiniteNonNegativeNumber(value);\n}\n\nexport function validateUSDQuantity(value: USDQuantity): void {\n if (!isValidUSDQuantity(value)) {\n throw new Error(`Invalid USD quantity: ${value}.`);\n }\n}\n","import type { Address } from \"viem\";\n\nimport type { UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport { type AggregatedReferrerMetrics, buildAggregatedReferrerMetrics } from \"./aggregations\";\nimport {\n type AwardedReferrerMetrics,\n buildAwardedReferrerMetrics,\n buildRankedReferrerMetrics,\n buildScoredReferrerMetrics,\n type ReferrerMetrics,\n sortReferrerMetrics,\n} from \"./referrer-metrics\";\nimport type { ReferralProgramRules } from \"./rules\";\n\n/**\n * Represents a leaderboard for any number of referrers.\n */\nexport interface ReferrerLeaderboard {\n /**\n * The rules of the referral program that generated the {@link ReferrerLeaderboard}.\n */\n rules: ReferralProgramRules;\n\n /**\n * The {@link AggregatedReferrerMetrics} for all `RankedReferrerMetrics` values in `leaderboard`.\n */\n aggregatedMetrics: AggregatedReferrerMetrics;\n\n /**\n * Ordered map containing `AwardedReferrerMetrics` for all referrers with 1 or more\n * `totalReferrals` within the `rules` as of `updatedAt`.\n *\n * @invariant Map entries are ordered by `rank` (ascending).\n * @invariant Map is empty if there are no referrers with 1 or more `totalReferrals`\n * within the `rules` as of `updatedAt`.\n * @invariant If a fully-lowercase `Address` is not a key in this map then that `Address` had\n * 0 `totalReferrals`, `totalIncrementalDuration`, and `score` within the\n * `rules` as of `updatedAt`.\n * @invariant Each value in this map is guaranteed to have a non-zero\n * `totalReferrals`, `totalIncrementalDuration`, and `score`.\n */\n referrers: Map<Address, AwardedReferrerMetrics>;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link ReferrerLeaderboard} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\nexport const buildReferrerLeaderboard = (\n allReferrers: ReferrerMetrics[],\n rules: ReferralProgramRules,\n accurateAsOf: UnixTimestamp,\n): ReferrerLeaderboard => {\n const uniqueReferrers = allReferrers.map((referrer) => referrer.referrer);\n if (uniqueReferrers.length !== allReferrers.length) {\n throw new Error(\n \"ReferrerLeaderboard: Cannot buildReferrerLeaderboard containing duplicate referrers\",\n );\n }\n\n if (accurateAsOf < rules.startTime && allReferrers.length > 0) {\n throw new Error(\n `ReferrerLeaderboard: accurateAsOf (${accurateAsOf}) is before startTime (${rules.startTime}) which indicates allReferrers should be empty, but allReferrers is not empty.`,\n );\n }\n\n const sortedReferrers = sortReferrerMetrics(allReferrers);\n\n const scoredReferrers = sortedReferrers.map((referrer) => buildScoredReferrerMetrics(referrer));\n\n const rankedReferrers = scoredReferrers.map((referrer, index) => {\n return buildRankedReferrerMetrics(referrer, index + 1, rules);\n });\n\n const aggregatedMetrics = buildAggregatedReferrerMetrics(rankedReferrers, rules);\n\n const awardedReferrers = rankedReferrers.map((referrer) => {\n return buildAwardedReferrerMetrics(referrer, aggregatedMetrics, rules);\n });\n\n // Transform ordered list into an ordered map (preserves sort order)\n const referrers = new Map(\n awardedReferrers.map((referrer) => {\n return [referrer.referrer, referrer];\n }),\n );\n\n return {\n rules,\n aggregatedMetrics,\n referrers,\n accurateAsOf,\n };\n};\n","import { type Address, getAddress } from \"viem\";\n\n/**\n * Build a URL to the official ENS manager app\n * where the given {@link Address} is set as the referrer.\n */\nexport function buildEnsReferralUrl(address: Address): URL {\n const ensAppUrl = new URL(\"https://app.ens.domains\");\n\n ensAppUrl.searchParams.set(\"referrer\", getAddress(address));\n\n return ensAppUrl;\n}\n","import type { AccountId, UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport { type USDQuantity, validateUSDQuantity } from \"./currency\";\nimport { validateNonNegativeInteger } from \"./number\";\nimport { validateUnixTimestamp } from \"./time\";\n\n/**\n * Start date for the ENS Holiday Awards referral program.\n * 2025-12-01T00:00:00Z (December 1, 2025 at 00:00:00 UTC)\n */\nexport const ENS_HOLIDAY_AWARDS_START_DATE: UnixTimestamp = 1764547200;\n\n/**\n * End date for the ENS Holiday Awards referral program.\n * 2025-12-31T23:59:59Z (December 31, 2025 at 23:59:59 UTC)\n */\nexport const ENS_HOLIDAY_AWARDS_END_DATE: UnixTimestamp = 1767225599;\n\n/**\n * The maximum number of qualified referrers for ENS Holiday Awards.\n */\nexport const ENS_HOLIDAY_AWARDS_MAX_QUALIFIED_REFERRERS = 10;\n\n/**\n * The total value of the award pool in USD.\n */\nexport const ENS_HOLIDAY_AWARDS_TOTAL_AWARD_POOL_VALUE: USDQuantity = 10_000.0;\n\nexport interface ReferralProgramRules {\n /**\n * The total value of the award pool in USD.\n *\n * NOTE: Awards will actually be distributed in $ENS tokens.\n */\n totalAwardPoolValue: USDQuantity;\n\n /**\n * The maximum number of referrers that will qualify to receive a non-zero `awardPoolShare`.\n *\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n maxQualifiedReferrers: number;\n\n /**\n * The start time of the referral program.\n */\n startTime: UnixTimestamp;\n\n /**\n * The end time of the referral program.\n * @invariant Guaranteed to be greater than or equal to `startTime`\n */\n endTime: UnixTimestamp;\n\n /**\n * The account ID of the subregistry for the referral program.\n */\n subregistryId: AccountId;\n}\n\nexport const validateReferralProgramRules = (rules: ReferralProgramRules): void => {\n validateUSDQuantity(rules.totalAwardPoolValue);\n validateNonNegativeInteger(rules.maxQualifiedReferrers);\n validateUnixTimestamp(rules.startTime);\n validateUnixTimestamp(rules.endTime);\n\n if (rules.endTime < rules.startTime) {\n throw new Error(\n `ReferralProgramRules: startTime: ${rules.startTime} is after endTime: ${rules.endTime}.`,\n );\n }\n};\n\nexport const buildReferralProgramRules = (\n totalAwardPoolValue: USDQuantity,\n maxQualifiedReferrers: number,\n startTime: UnixTimestamp,\n endTime: UnixTimestamp,\n subregistryId: AccountId,\n): ReferralProgramRules => {\n const result = {\n totalAwardPoolValue,\n maxQualifiedReferrers,\n startTime,\n endTime,\n subregistryId,\n } satisfies ReferralProgramRules;\n\n validateReferralProgramRules(result);\n\n return result;\n};\n","import type { UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport type { ReferralProgramRules } from \"./rules.ts\";\n\n/**\n * The type of referral program's status.\n */\nexport const ReferralProgramStatuses = {\n /**\n * Represents a referral program that has been announced, but hasn't started yet.\n */\n Scheduled: \"Scheduled\",\n\n /**\n * Represents a currently ongoing referral program.\n */\n Active: \"Active\",\n\n /**\n * Represents a referral program that has already ended.\n */\n Closed: \"Closed\",\n} as const;\n\n/**\n * The derived string union of possible {@link ReferralProgramStatuses}.\n */\nexport type ReferralProgramStatusId =\n (typeof ReferralProgramStatuses)[keyof typeof ReferralProgramStatuses];\n\n/**\n * Calculate the status of the referral program based on the current date\n * and program's timeframe available in its rules.\n *\n * @param referralProgramRules - Related referral program's rules containing\n * program's start date and end date.\n *\n * @param now - Current date in {@link UnixTimestamp} format.\n */\nexport const calcReferralProgramStatus = (\n referralProgramRules: ReferralProgramRules,\n now: UnixTimestamp,\n): ReferralProgramStatusId => {\n // if the program has not started return \"Scheduled\"\n if (now < referralProgramRules.startTime) return ReferralProgramStatuses.Scheduled;\n\n // if the program has ended return \"Closed\"\n if (now > referralProgramRules.endTime) return ReferralProgramStatuses.Closed;\n\n // otherwise, return \"Active\"\n return ReferralProgramStatuses.Active;\n};\n"],"mappings":"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","names":["z","CAIP2","name","regex","parameters","delimiter","values","CAIP10","AssetName","CAIP19AssetType","CAIP19AssetId","CAIP","assetName","assetType","assetId","splitParams","id","spec","split","getParams","arr","params","forEach","value","index","joinParams","Object","map","parameter","param","join","isValidId","RegExp","test","length","keys","matches","filter","x","ChainId","parse","namespace","reference","Error","toJSON","format","toString","AccountId","chainId","address","AssetType","AssetId","tokenId","isAddress","isAddress","z"]}
1
+ {"version":3,"sources":["../src/address.ts","../src/number.ts","../src/revenue-contribution.ts","../src/time.ts","../src/score.ts","../src/aggregations.ts","../src/api/deserialize.ts","../src/api/zod-schemas.ts","../../ensnode-sdk/src/shared/address.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/spec.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/utils.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/chain.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/account.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/assetName.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/assetType.ts","../../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/src/assetId.ts","../../ensnode-sdk/src/shared/zod-schemas.ts","../src/leaderboard-page.ts","../src/rank.ts","../src/referrer-metrics.ts","../src/referrer-detail.ts","../src/api/types.ts","../src/api/serialize.ts","../src/client.ts","../src/currency.ts","../src/leaderboard.ts","../src/link.ts","../src/rules.ts","../src/status.ts"],"sourcesContent":["import { type Address, isAddress } from \"viem\";\n\nexport const validateLowercaseAddress = (address: Address): void => {\n if (!isAddress(address, { strict: false })) {\n throw new Error(`Invalid address: ${address}. Address must be a valid EVM address.`);\n }\n\n if (address !== address.toLowerCase()) {\n throw new Error(`Invalid address: ${address}. Address must be in lowercase format.`);\n }\n};\n\nexport const normalizeAddress = (address: Address): Address => {\n return address.toLowerCase() as Address;\n};\n","export const isInteger = (value: number): boolean => {\n return Number.isInteger(value);\n};\n\nexport const isNonNegativeInteger = (value: number): boolean => {\n return value >= 0 && Number.isInteger(value);\n};\n\nexport const isPositiveInteger = (value: number): boolean => {\n return value >= 1 && Number.isInteger(value);\n};\n\nexport const validateNonNegativeInteger = (value: number): void => {\n if (!isNonNegativeInteger(value)) {\n throw new Error(`Invalid non-negative integer: ${value}.`);\n }\n};\n\nexport const isFiniteNonNegativeNumber = (value: number): boolean => {\n return value >= 0 && Number.isFinite(value);\n};\n","/**\n * Revenue Contribution\n *\n * Represents the total revenue contribution (in Wei) made to the ENS DAO.\n *\n * This is the sum of the total cost paid by registrants for registrar actions.\n * From the perspective of the ENS DAO, this represents revenue received.\n *\n * @invariant Guaranteed to be a non-negative bigint value (>= 0n)\n * @invariant Never null (records with null `total` in the database are treated as 0 when summing)\n */\nexport type RevenueContribution = bigint;\n\n/**\n * Check if a value is a valid revenue contribution.\n *\n * @param value - The value to check\n * @returns true if the value is a non-negative bigint, false otherwise\n */\nexport function isValidRevenueContribution(value: unknown): value is RevenueContribution {\n return typeof value === \"bigint\" && value >= 0n;\n}\n\n/**\n * Validate that a value is a valid revenue contribution.\n *\n * @param value - The value to validate\n * @throws {Error} If the value is not a valid revenue contribution\n */\nexport function validateRevenueContribution(value: unknown): void {\n if (typeof value !== \"bigint\") {\n throw new Error(`Invalid revenue contribution: must be a bigint, got: ${typeof value}`);\n }\n\n if (value < 0n) {\n throw new Error(`Invalid revenue contribution: must be non-negative, got: ${value.toString()}`);\n }\n}\n","import type { Duration, UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport { isInteger, isNonNegativeInteger } from \"./number\";\n\nexport const validateUnixTimestamp = (timestamp: UnixTimestamp): void => {\n if (!isInteger(timestamp)) {\n throw new Error(`Invalid Unix timestamp: ${timestamp}. Unix timestamp must be an integer.`);\n }\n};\n\n/**\n * The number of seconds in a year.\n *\n * (60 seconds per minute * 60 minutes per hour *\n * 24 hours per day * 365.2425 days on average per year).\n */\nexport const SECONDS_PER_YEAR: Duration = 31556952;\n\nexport function isValidDuration(duration: Duration): boolean {\n return isNonNegativeInteger(duration);\n}\n\nexport function validateDuration(duration: Duration): void {\n if (!isValidDuration(duration)) {\n throw new Error(`Invalid duration: ${duration}. Duration must be a non-negative integer.`);\n }\n}\n","import type { Duration } from \"@ensnode/ensnode-sdk\";\n\nimport { SECONDS_PER_YEAR } from \"./time\";\n\n/**\n * The score of a referrer.\n *\n * @invariant Guaranteed to be a finite non-negative number (>= 0)\n */\nexport type ReferrerScore = number;\n\nexport const isValidReferrerScore = (score: ReferrerScore): boolean => {\n return score >= 0 && Number.isFinite(score);\n};\n\nexport const validateReferrerScore = (score: ReferrerScore): void => {\n if (!isValidReferrerScore(score)) {\n throw new Error(\n `Invalid referrer score: ${score}. Referrer score must be a finite non-negative number.`,\n );\n }\n};\n\n/**\n * Calculate the score of a referrer based on the total incremental duration\n * (in seconds) of registrations and renewals for direct subnames of .eth\n * referrered by the referrer within the ENS Holiday Awards period.\n *\n * @param totalIncrementalDuration - The total incremental duration (in seconds)\n * of referrals made by a referrer within the {@link ReferralProgramRules}.\n * @returns The score of the referrer.\n */\nexport const calcReferrerScore = (totalIncrementalDuration: Duration): ReferrerScore => {\n return totalIncrementalDuration / SECONDS_PER_YEAR;\n};\n","import type { Duration } from \"@ensnode/ensnode-sdk\";\n\nimport { validateNonNegativeInteger } from \"./number\";\nimport type { RankedReferrerMetrics } from \"./referrer-metrics\";\nimport type { RevenueContribution } from \"./revenue-contribution\";\nimport { validateRevenueContribution } from \"./revenue-contribution\";\nimport type { ReferralProgramRules } from \"./rules\";\nimport { type ReferrerScore, validateReferrerScore } from \"./score\";\nimport { validateDuration } from \"./time\";\n\n/**\n * Represents aggregated metrics for a list of `RankedReferrerMetrics`.\n */\nexport interface AggregatedReferrerMetrics {\n /**\n * @invariant The sum of `totalReferrals` across all `RankedReferrerMetrics` in the list.\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n grandTotalReferrals: number;\n\n /**\n * @invariant The sum of `totalIncrementalDuration` across all `RankedReferrerMetrics` in the list.\n */\n grandTotalIncrementalDuration: Duration;\n\n /**\n * The total revenue contribution (in Wei) to the ENS DAO from all referrals\n * across all referrers on the leaderboard.\n *\n * This is the sum of `totalRevenueContribution` across all `RankedReferrerMetrics` in the list.\n *\n * @invariant Guaranteed to be a non-negative bigint value (>= 0n)\n */\n grandTotalRevenueContribution: RevenueContribution;\n\n /**\n * @invariant The sum of `finalScore` across all `RankedReferrerMetrics` where `isQualified` is `true`.\n */\n grandTotalQualifiedReferrersFinalScore: ReferrerScore;\n\n /**\n * @invariant Identifies the minimum final score required to become a qualified referrer.\n * @invariant If `rules.maxQualifiedReferrers` is 0, then `minFinalScoreToQualify` is guaranteed to\n * be `Number.MAX_SAFE_INTEGER`.\n * @invariant If `rules.maxQualifiedReferrers` is greater than 0, and there are no current referrers\n * matching the `rules`, then `minFinalScoreToQualify` is guaranteed to be `0`.\n */\n minFinalScoreToQualify: ReferrerScore;\n}\n\nexport const validateAggregatedReferrerMetrics = (metrics: AggregatedReferrerMetrics): void => {\n validateNonNegativeInteger(metrics.grandTotalReferrals);\n validateDuration(metrics.grandTotalIncrementalDuration);\n validateRevenueContribution(metrics.grandTotalRevenueContribution);\n validateReferrerScore(metrics.grandTotalQualifiedReferrersFinalScore);\n validateReferrerScore(metrics.minFinalScoreToQualify);\n};\n\nexport const buildAggregatedReferrerMetrics = (\n referrers: RankedReferrerMetrics[],\n rules: ReferralProgramRules,\n): AggregatedReferrerMetrics => {\n let grandTotalReferrals = 0;\n let grandTotalIncrementalDuration = 0;\n let grandTotalRevenueContribution = 0n;\n let grandTotalQualifiedReferrersFinalScore = 0;\n let minFinalScoreToQualify = Number.MAX_SAFE_INTEGER;\n\n for (const referrer of referrers) {\n grandTotalReferrals += referrer.totalReferrals;\n grandTotalIncrementalDuration += referrer.totalIncrementalDuration;\n grandTotalRevenueContribution += referrer.totalRevenueContribution;\n if (referrer.isQualified) {\n grandTotalQualifiedReferrersFinalScore += referrer.finalScore;\n if (referrer.finalScore < minFinalScoreToQualify) {\n minFinalScoreToQualify = referrer.finalScore;\n }\n }\n }\n\n if (minFinalScoreToQualify === Number.MAX_SAFE_INTEGER) {\n if (rules.maxQualifiedReferrers === 0) {\n // ... because it's impossible to qualify based on the rules\n // therefore keep minFinalScoreToQualify as Number.MAX_SAFE_INTEGER\n } else {\n // ... because there are no referrers at all on the leaderboard\n if (referrers.length !== 0) {\n // invariant sanity check\n throw new Error(\n \"AggregatedReferrerMetrics: There are referrers on the leaderboard, and the rules allow for qualified referrers, but no qualified referrers.\",\n );\n }\n\n minFinalScoreToQualify = 0;\n }\n }\n\n const result = {\n grandTotalReferrals,\n grandTotalIncrementalDuration,\n grandTotalRevenueContribution,\n grandTotalQualifiedReferrersFinalScore,\n minFinalScoreToQualify,\n };\n\n validateAggregatedReferrerMetrics(result);\n\n return result;\n};\n","import { prettifyError } from \"zod/v4\";\n\nimport type { AggregatedReferrerMetrics } from \"../aggregations\";\nimport type { ReferrerLeaderboardPage } from \"../leaderboard-page\";\nimport type { ReferrerDetailRanked, ReferrerDetailUnranked } from \"../referrer-detail\";\nimport type { AwardedReferrerMetrics, UnrankedReferrerMetrics } from \"../referrer-metrics\";\nimport type { RevenueContribution } from \"../revenue-contribution\";\nimport type { ReferralProgramRules } from \"../rules\";\nimport type {\n SerializedAggregatedReferrerMetrics,\n SerializedAwardedReferrerMetrics,\n SerializedReferralProgramRules,\n SerializedReferrerDetailRanked,\n SerializedReferrerDetailResponse,\n SerializedReferrerDetailUnranked,\n SerializedReferrerLeaderboardPage,\n SerializedReferrerLeaderboardPageResponse,\n SerializedUnrankedReferrerMetrics,\n} from \"./serialized-types\";\nimport type { ReferrerDetailResponse, ReferrerLeaderboardPageResponse } from \"./types\";\nimport {\n makeReferrerDetailResponseSchema,\n makeReferrerLeaderboardPageResponseSchema,\n} from \"./zod-schemas\";\n\n/**\n * Deserializes a string representation of {@link RevenueContribution} back to bigint.\n */\nfunction deserializeRevenueContribution(value: string): RevenueContribution {\n return BigInt(value);\n}\n\n/**\n * Deserializes a {@link SerializedReferralProgramRules} object.\n */\nfunction deserializeReferralProgramRules(\n rules: SerializedReferralProgramRules,\n): ReferralProgramRules {\n // All fields are already deserializable primitives\n return rules;\n}\n\n/**\n * Deserializes an {@link SerializedAwardedReferrerMetrics} object.\n */\nfunction deserializeAwardedReferrerMetrics(\n metrics: SerializedAwardedReferrerMetrics,\n): AwardedReferrerMetrics {\n return {\n referrer: metrics.referrer,\n totalReferrals: metrics.totalReferrals,\n totalIncrementalDuration: metrics.totalIncrementalDuration,\n totalRevenueContribution: deserializeRevenueContribution(metrics.totalRevenueContribution),\n score: metrics.score,\n rank: metrics.rank,\n isQualified: metrics.isQualified,\n finalScoreBoost: metrics.finalScoreBoost,\n finalScore: metrics.finalScore,\n awardPoolShare: metrics.awardPoolShare,\n awardPoolApproxValue: metrics.awardPoolApproxValue,\n };\n}\n\n/**\n * Deserializes an {@link SerializedUnrankedReferrerMetrics} object.\n */\nfunction deserializeUnrankedReferrerMetrics(\n metrics: SerializedUnrankedReferrerMetrics,\n): UnrankedReferrerMetrics {\n return {\n referrer: metrics.referrer,\n totalReferrals: metrics.totalReferrals,\n totalIncrementalDuration: metrics.totalIncrementalDuration,\n totalRevenueContribution: deserializeRevenueContribution(metrics.totalRevenueContribution),\n score: metrics.score,\n rank: metrics.rank,\n isQualified: metrics.isQualified,\n finalScoreBoost: metrics.finalScoreBoost,\n finalScore: metrics.finalScore,\n awardPoolShare: metrics.awardPoolShare,\n awardPoolApproxValue: metrics.awardPoolApproxValue,\n };\n}\n\n/**\n * Deserializes an {@link SerializedAggregatedReferrerMetrics} object.\n */\nfunction deserializeAggregatedReferrerMetrics(\n metrics: SerializedAggregatedReferrerMetrics,\n): AggregatedReferrerMetrics {\n return {\n grandTotalReferrals: metrics.grandTotalReferrals,\n grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,\n grandTotalRevenueContribution: deserializeRevenueContribution(\n metrics.grandTotalRevenueContribution,\n ),\n grandTotalQualifiedReferrersFinalScore: metrics.grandTotalQualifiedReferrersFinalScore,\n minFinalScoreToQualify: metrics.minFinalScoreToQualify,\n };\n}\n\n/**\n * Deserializes a {@link SerializedReferrerLeaderboardPage} object.\n */\nfunction deserializeReferrerLeaderboardPage(\n page: SerializedReferrerLeaderboardPage,\n): ReferrerLeaderboardPage {\n return {\n rules: deserializeReferralProgramRules(page.rules),\n referrers: page.referrers.map(deserializeAwardedReferrerMetrics),\n aggregatedMetrics: deserializeAggregatedReferrerMetrics(page.aggregatedMetrics),\n pageContext: page.pageContext,\n accurateAsOf: page.accurateAsOf,\n };\n}\n\n/**\n * Deserializes a {@link SerializedReferrerDetailRanked} object.\n */\nfunction deserializeReferrerDetailRanked(\n detail: SerializedReferrerDetailRanked,\n): ReferrerDetailRanked {\n return {\n type: detail.type,\n rules: deserializeReferralProgramRules(detail.rules),\n referrer: deserializeAwardedReferrerMetrics(detail.referrer),\n aggregatedMetrics: deserializeAggregatedReferrerMetrics(detail.aggregatedMetrics),\n accurateAsOf: detail.accurateAsOf,\n };\n}\n\n/**\n * Deserializes a {@link SerializedReferrerDetailUnranked} object.\n */\nfunction deserializeReferrerDetailUnranked(\n detail: SerializedReferrerDetailUnranked,\n): ReferrerDetailUnranked {\n return {\n type: detail.type,\n rules: deserializeReferralProgramRules(detail.rules),\n referrer: deserializeUnrankedReferrerMetrics(detail.referrer),\n aggregatedMetrics: deserializeAggregatedReferrerMetrics(detail.aggregatedMetrics),\n accurateAsOf: detail.accurateAsOf,\n };\n}\n\n/**\n * Deserialize a {@link ReferrerLeaderboardPageResponse} object.\n *\n * Note: This function explicitly deserializes each subobject to convert string\n * RevenueContribution values back to bigint, then validates using Zod schemas\n * to enforce invariants on the data.\n */\nexport function deserializeReferrerLeaderboardPageResponse(\n maybeResponse: SerializedReferrerLeaderboardPageResponse,\n valueLabel?: string,\n): ReferrerLeaderboardPageResponse {\n let deserialized: ReferrerLeaderboardPageResponse;\n switch (maybeResponse.responseCode) {\n case \"ok\": {\n deserialized = {\n responseCode: maybeResponse.responseCode,\n data: deserializeReferrerLeaderboardPage(maybeResponse.data),\n } as ReferrerLeaderboardPageResponse;\n break;\n }\n\n case \"error\":\n deserialized = maybeResponse;\n break;\n }\n\n // Then validate the deserialized structure using zod schemas\n const schema = makeReferrerLeaderboardPageResponseSchema(valueLabel);\n const parsed = schema.safeParse(deserialized);\n\n if (parsed.error) {\n throw new Error(\n `Cannot deserialize SerializedReferrerLeaderboardPageResponse:\\n${prettifyError(parsed.error)}\\n`,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Deserialize a {@link ReferrerDetailResponse} object.\n *\n * Note: This function explicitly deserializes each subobject to convert string\n * RevenueContribution values back to bigint, then validates using Zod schemas\n * to enforce invariants on the data.\n */\nexport function deserializeReferrerDetailResponse(\n maybeResponse: SerializedReferrerDetailResponse,\n valueLabel?: string,\n): ReferrerDetailResponse {\n let deserialized: ReferrerDetailResponse;\n switch (maybeResponse.responseCode) {\n case \"ok\": {\n switch (maybeResponse.data.type) {\n case \"ranked\":\n deserialized = {\n responseCode: maybeResponse.responseCode,\n data: deserializeReferrerDetailRanked(maybeResponse.data),\n } as ReferrerDetailResponse;\n break;\n\n case \"unranked\":\n deserialized = {\n responseCode: maybeResponse.responseCode,\n data: deserializeReferrerDetailUnranked(maybeResponse.data),\n } as ReferrerDetailResponse;\n break;\n }\n break;\n }\n\n case \"error\":\n deserialized = maybeResponse;\n break;\n }\n\n // Then validate the deserialized structure using zod schemas\n const schema = makeReferrerDetailResponseSchema(valueLabel);\n const parsed = schema.safeParse(deserialized);\n\n if (parsed.error) {\n throw new Error(`Cannot deserialize ReferrerDetailResponse:\\n${prettifyError(parsed.error)}\\n`);\n }\n\n return parsed.data;\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 */\n\nimport { z } from \"zod/v4\";\n\nimport {\n makeAccountIdSchema,\n makeDurationSchema,\n makeFiniteNonNegativeNumberSchema,\n makeLowercaseAddressSchema,\n makeNonNegativeIntegerSchema,\n makePositiveIntegerSchema,\n makeUnixTimestampSchema,\n} from \"@ensnode/ensnode-sdk/internal\";\n\nimport { REFERRERS_PER_LEADERBOARD_PAGE_MAX } from \"../leaderboard-page\";\nimport { type ReferrerDetailRanked, ReferrerDetailTypeIds } from \"../referrer-detail\";\nimport type { RevenueContribution } from \"../revenue-contribution\";\nimport { ReferrerDetailResponseCodes, ReferrerLeaderboardPageResponseCodes } from \"./types\";\n\n/**\n * Schema for {@link RevenueContribution}\n */\nconst makeRevenueContributionSchema = (valueLabel: string = \"RevenueContribution\") =>\n z.coerce\n .bigint({\n error: `${valueLabel} must represent a bigint.`,\n })\n .nonnegative({\n error: `${valueLabel} must not be negative.`,\n });\n\n/**\n * Schema for ReferralProgramRules\n */\nexport const makeReferralProgramRulesSchema = (valueLabel: string = \"ReferralProgramRules\") =>\n z.object({\n totalAwardPoolValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.totalAwardPoolValue`),\n maxQualifiedReferrers: makeNonNegativeIntegerSchema(`${valueLabel}.maxQualifiedReferrers`),\n startTime: makeUnixTimestampSchema(`${valueLabel}.startTime`),\n endTime: makeUnixTimestampSchema(`${valueLabel}.endTime`),\n subregistryId: makeAccountIdSchema(`${valueLabel}.subregistryId`),\n });\n\n/**\n * Schema for AwardedReferrerMetrics (with numeric rank)\n */\nexport const makeAwardedReferrerMetricsSchema = (valueLabel: string = \"AwardedReferrerMetrics\") =>\n z.object({\n referrer: makeLowercaseAddressSchema(`${valueLabel}.referrer`),\n totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),\n totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),\n totalRevenueContribution: makeRevenueContributionSchema(\n `${valueLabel}.totalRevenueContribution`,\n ),\n score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),\n rank: makePositiveIntegerSchema(`${valueLabel}.rank`),\n isQualified: z.boolean(),\n finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(\n 1,\n `${valueLabel}.finalScoreBoost must be <= 1`,\n ),\n finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),\n awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(\n 1,\n `${valueLabel}.awardPoolShare must be <= 1`,\n ),\n awardPoolApproxValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolApproxValue`),\n });\n\n/**\n * Schema for UnrankedReferrerMetrics (with null rank)\n */\nexport const makeUnrankedReferrerMetricsSchema = (valueLabel: string = \"UnrankedReferrerMetrics\") =>\n z.object({\n referrer: makeLowercaseAddressSchema(`${valueLabel}.referrer`),\n totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),\n totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),\n totalRevenueContribution: makeRevenueContributionSchema(\n `${valueLabel}.totalRevenueContribution`,\n ),\n score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),\n rank: z.null(),\n isQualified: z.literal(false),\n finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(\n 1,\n `${valueLabel}.finalScoreBoost must be <= 1`,\n ),\n finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),\n awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(\n 1,\n `${valueLabel}.awardPoolShare must be <= 1`,\n ),\n awardPoolApproxValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolApproxValue`),\n });\n\n/**\n * Schema for AggregatedReferrerMetrics\n */\nexport const makeAggregatedReferrerMetricsSchema = (\n valueLabel: string = \"AggregatedReferrerMetrics\",\n) =>\n z.object({\n grandTotalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.grandTotalReferrals`),\n grandTotalIncrementalDuration: makeDurationSchema(\n `${valueLabel}.grandTotalIncrementalDuration`,\n ),\n grandTotalRevenueContribution: makeRevenueContributionSchema(\n `${valueLabel}.grandTotalRevenueContribution`,\n ),\n grandTotalQualifiedReferrersFinalScore: makeFiniteNonNegativeNumberSchema(\n `${valueLabel}.grandTotalQualifiedReferrersFinalScore`,\n ),\n minFinalScoreToQualify: makeFiniteNonNegativeNumberSchema(\n `${valueLabel}.minFinalScoreToQualify`,\n ),\n });\n\nexport const makeReferrerLeaderboardPageContextSchema = (\n valueLabel: string = \"ReferrerLeaderboardPageContext\",\n) =>\n z.object({\n page: makePositiveIntegerSchema(`${valueLabel}.page`),\n recordsPerPage: makePositiveIntegerSchema(`${valueLabel}.recordsPerPage`).max(\n REFERRERS_PER_LEADERBOARD_PAGE_MAX,\n `${valueLabel}.recordsPerPage must not exceed ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}`,\n ),\n totalRecords: makeNonNegativeIntegerSchema(`${valueLabel}.totalRecords`),\n totalPages: makePositiveIntegerSchema(`${valueLabel}.totalPages`),\n hasNext: z.boolean(),\n hasPrev: z.boolean(),\n startIndex: z.optional(makeNonNegativeIntegerSchema(`${valueLabel}.startIndex`)),\n endIndex: z.optional(makeNonNegativeIntegerSchema(`${valueLabel}.endIndex`)),\n });\n\n/**\n * Schema for ReferrerLeaderboardPage\n */\nexport const makeReferrerLeaderboardPageSchema = (valueLabel: string = \"ReferrerLeaderboardPage\") =>\n z.object({\n rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),\n referrers: z.array(makeAwardedReferrerMetricsSchema(`${valueLabel}.referrers[record]`)),\n aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),\n pageContext: makeReferrerLeaderboardPageContextSchema(`${valueLabel}.pageContext`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n\n/**\n * Schema for {@link ReferrerLeaderboardPageResponseOk}\n */\nexport const makeReferrerLeaderboardPageResponseOkSchema = (\n valueLabel: string = \"ReferrerLeaderboardPageResponseOk\",\n) =>\n z.object({\n responseCode: z.literal(ReferrerLeaderboardPageResponseCodes.Ok),\n data: makeReferrerLeaderboardPageSchema(`${valueLabel}.data`),\n });\n\n/**\n * Schema for {@link ReferrerLeaderboardPageResponseError}\n */\nexport const makeReferrerLeaderboardPageResponseErrorSchema = (\n _valueLabel: string = \"ReferrerLeaderboardPageResponseError\",\n) =>\n z.object({\n responseCode: z.literal(ReferrerLeaderboardPageResponseCodes.Error),\n error: z.string(),\n errorMessage: z.string(),\n });\n\n/**\n * Schema for {@link ReferrerLeaderboardPageResponse}\n */\nexport const makeReferrerLeaderboardPageResponseSchema = (\n valueLabel: string = \"ReferrerLeaderboardPageResponse\",\n) =>\n z.union([\n makeReferrerLeaderboardPageResponseOkSchema(valueLabel),\n makeReferrerLeaderboardPageResponseErrorSchema(valueLabel),\n ]);\n\n/**\n * Schema for {@link ReferrerDetailRanked} (with ranked metrics)\n */\nexport const makeReferrerDetailRankedSchema = (valueLabel: string = \"ReferrerDetailRanked\") =>\n z.object({\n type: z.literal(ReferrerDetailTypeIds.Ranked),\n rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),\n referrer: makeAwardedReferrerMetricsSchema(`${valueLabel}.referrer`),\n aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n\n/**\n * Schema for {@link ReferrerDetailUnranked} (with unranked metrics)\n */\nexport const makeReferrerDetailUnrankedSchema = (valueLabel: string = \"ReferrerDetailUnranked\") =>\n z.object({\n type: z.literal(ReferrerDetailTypeIds.Unranked),\n rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),\n referrer: makeUnrankedReferrerMetricsSchema(`${valueLabel}.referrer`),\n aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),\n accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`),\n });\n\n/**\n * Schema for {@link ReferrerDetailResponseOk}\n * Accepts either ranked or unranked referrer detail data\n */\nexport const makeReferrerDetailResponseOkSchema = (valueLabel: string = \"ReferrerDetailResponse\") =>\n z.object({\n responseCode: z.literal(ReferrerDetailResponseCodes.Ok),\n data: z.union([\n makeReferrerDetailRankedSchema(`${valueLabel}.data`),\n makeReferrerDetailUnrankedSchema(`${valueLabel}.data`),\n ]),\n });\n\n/**\n * Schema for {@link ReferrerDetailResponseError}\n */\nexport const makeReferrerDetailResponseErrorSchema = (\n _valueLabel: string = \"ReferrerDetailResponse\",\n) =>\n z.object({\n responseCode: z.literal(ReferrerDetailResponseCodes.Error),\n error: z.string(),\n errorMessage: z.string(),\n });\n\n/**\n * Schema for {@link ReferrerDetailResponse}\n */\nexport const makeReferrerDetailResponseSchema = (valueLabel: string = \"ReferrerDetailResponse\") =>\n z.union([\n makeReferrerDetailResponseOkSchema(valueLabel),\n makeReferrerDetailResponseErrorSchema(valueLabel),\n ]);\n","import type { Address } from \"viem\";\n\n/**\n * Converts an EVM address to its lowercase representation.\n *\n * @param address - EVM address to convert.\n * @returns The lowercase representation of the EVM address.\n */\nexport function asLowerCaseAddress(address: Address): Address {\n return address.toLowerCase() as Address;\n}\n","import { IdentifierSpec } from \"./types\";\n\nconst CAIP2: IdentifierSpec = {\n name: \"chainId\",\n regex: \"[-:a-zA-Z0-9]{5,41}\",\n parameters: {\n delimiter: \":\",\n values: {\n 0: {\n name: \"namespace\",\n regex: \"[-a-z0-9]{3,8}\",\n },\n 1: {\n name: \"reference\",\n regex: \"[-a-zA-Z0-9]{1,32}\",\n },\n },\n },\n};\n\nconst CAIP10: IdentifierSpec = {\n name: \"accountId\",\n regex: \"[-:a-zA-Z0-9]{7,106}\",\n parameters: {\n delimiter: \":\",\n values: {\n 0: {\n name: \"namespace\",\n regex: \"[-a-z0-9]{3,8}\",\n },\n 1: {\n name: \"reference\",\n regex: \"[-a-zA-Z0-9]{1,32}\",\n },\n 2: {\n name: \"address\",\n regex: \"[a-zA-Z0-9]{1,64}\",\n },\n },\n },\n};\n\n// represents namespace:reference in CAIP-19\nconst AssetName: IdentifierSpec = {\n name: \"assetName\",\n regex: \"[-:a-zA-Z0-9]{5,73}\",\n parameters: {\n delimiter: \":\",\n values: {\n 0: {\n name: \"namespace\",\n regex: \"[-a-z0-9]{3,8}\",\n },\n 1: {\n name: \"reference\",\n regex: \"[-a-zA-Z0-9]{1,64}\",\n },\n },\n },\n};\n\nconst CAIP19AssetType: IdentifierSpec = {\n name: \"assetType\",\n regex: \"[-:a-zA-Z0-9]{11,115}\",\n parameters: {\n delimiter: \"/\",\n values: {\n 0: CAIP2,\n 1: AssetName,\n },\n },\n};\n\nconst CAIP19AssetId: IdentifierSpec = {\n name: \"assetId\",\n regex: \"[-:a-zA-Z0-9]{13,148}\",\n parameters: {\n delimiter: \"/\",\n values: {\n 0: CAIP2,\n 1: AssetName,\n 2: {\n name: \"tokenId\",\n regex: \"[-a-zA-Z0-9]{1,32}\",\n },\n },\n },\n};\n\nexport const CAIP = {\n \"2\": CAIP2,\n \"10\": CAIP10,\n \"19\": {\n assetName: AssetName,\n assetType: CAIP19AssetType,\n assetId: CAIP19AssetId,\n },\n};\n","import { IdentifierSpec, Params } from \"./types\";\n\nexport function splitParams(id: string, spec: IdentifierSpec): string[] {\n return id.split(spec.parameters.delimiter);\n}\n\nexport function getParams<T>(id: string, spec: IdentifierSpec): T {\n const arr = splitParams(id, spec);\n const params = {};\n arr.forEach((value, index) => {\n params[spec.parameters.values[index].name] = value;\n });\n return params as T;\n}\n\nexport function joinParams(params: Params, spec: IdentifierSpec): string {\n return Object.values(spec.parameters.values)\n .map(parameter => {\n const param = params[parameter.name];\n return typeof param === \"string\"\n ? param\n : joinParams(param, parameter as IdentifierSpec);\n })\n .join(spec.parameters.delimiter);\n}\n\nexport function isValidId(id: string, spec: IdentifierSpec): boolean {\n // console.log(\"id\", id);\n // console.log(\"spec\", spec);\n // console.log(\"before regex\");\n if (!new RegExp(spec.regex).test(id)) return false;\n // console.log(\"after regex\");\n // console.log(\"before split\");\n const params = splitParams(id, spec);\n // console.log(\"after split\");\n // console.log(\"params\", params);\n // console.log(\"before length\");\n if (params.length !== Object.keys(spec.parameters.values).length)\n return false;\n // console.log(\"after length\");\n // console.log(\"before matches\");\n const matches = params\n .map((param, index) =>\n new RegExp(spec.parameters.values[index].regex).test(param)\n )\n .filter(x => !!x);\n if (matches.length !== params.length) return false;\n // console.log(\"after matches\");\n return true;\n}\n","import { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface ChainIdParams {\n namespace: string;\n reference: string;\n}\n\nexport class ChainId {\n public static spec: IdentifierSpec = CAIP[\"2\"];\n\n public static parse(id: string): ChainIdParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n return new ChainId(getParams<ChainIdParams>(id, this.spec)).toJSON();\n }\n\n public static format(params: ChainIdParams): string {\n return joinParams(params as any, this.spec);\n }\n\n public namespace: string;\n public reference: string;\n\n constructor(params: ChainIdParams | string) {\n if (typeof params === \"string\") {\n params = ChainId.parse(params);\n }\n\n this.namespace = params.namespace;\n this.reference = params.reference;\n }\n\n public toString(): string {\n return ChainId.format(this.toJSON());\n }\n\n public toJSON(): ChainIdParams {\n return {\n namespace: this.namespace,\n reference: this.reference,\n };\n }\n}\n","import { ChainId, ChainIdParams } from \"./chain\";\nimport { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface AccountIdSplitParams extends ChainIdParams {\n address: string;\n}\nexport interface AccountIdParams {\n chainId: string | ChainIdParams;\n address: string;\n}\n\nexport class AccountId {\n public static spec: IdentifierSpec = CAIP[\"10\"];\n\n public static parse(id: string): AccountIdParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n const { namespace, reference, address } = getParams<AccountIdSplitParams>(\n id,\n this.spec\n );\n const chainId = new ChainId({ namespace, reference });\n return new AccountId({ chainId, address }).toJSON();\n }\n\n public static format(params: AccountIdParams): string {\n const chainId = new ChainId(params.chainId);\n const splitParams: AccountIdSplitParams = {\n ...chainId.toJSON(),\n address: params.address,\n };\n return joinParams(splitParams as any, this.spec);\n }\n\n public chainId: ChainId;\n public address: string;\n\n constructor(params: AccountIdParams | string) {\n if (typeof params === \"string\") {\n params = AccountId.parse(params);\n }\n\n this.chainId = new ChainId(params.chainId);\n this.address = params.address;\n }\n\n public toString(): string {\n return AccountId.format(this.toJSON());\n }\n\n public toJSON(): AccountIdParams {\n return {\n chainId: this.chainId.toJSON(),\n address: this.address,\n };\n }\n}\n","import { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface AssetNameParams {\n namespace: string;\n reference: string;\n}\n\nexport class AssetName {\n public static spec: IdentifierSpec = CAIP[\"19\"].assetName;\n\n public static parse(id: string): AssetNameParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n return new AssetName(getParams<AssetNameParams>(id, this.spec)).toJSON();\n }\n\n public static format(params: AssetNameParams): string {\n return joinParams(params as any, this.spec);\n }\n\n public namespace: string;\n public reference: string;\n\n constructor(params: AssetNameParams | string) {\n if (typeof params === \"string\") {\n params = AssetName.parse(params);\n }\n\n this.namespace = params.namespace;\n this.reference = params.reference;\n }\n\n public toString(): string {\n return AssetName.format(this.toJSON());\n }\n\n public toJSON(): AssetNameParams {\n return {\n namespace: this.namespace,\n reference: this.reference,\n };\n }\n}\n","import { AssetName, AssetNameParams } from \"./assetName\";\nimport { ChainId, ChainIdParams } from \"./chain\";\nimport { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface AssetTypeParams {\n chainId: string | ChainIdParams;\n assetName: string | AssetNameParams;\n}\n\nexport class AssetType {\n public static spec: IdentifierSpec = CAIP[\"19\"].assetType;\n\n public static parse(id: string): AssetTypeParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n return new AssetType(getParams<AssetTypeParams>(id, this.spec)).toJSON();\n }\n\n public static format(params: AssetTypeParams): string {\n return joinParams(params as any, this.spec);\n }\n\n public chainId: ChainId;\n public assetName: AssetName;\n\n constructor(params: AssetTypeParams | string) {\n if (typeof params === \"string\") {\n params = AssetType.parse(params);\n }\n\n this.chainId = new ChainId(params.chainId);\n this.assetName = new AssetName(params.assetName);\n }\n\n public toString(): string {\n return AssetType.format(this.toJSON());\n }\n\n public toJSON(): AssetTypeParams {\n return {\n chainId: this.chainId.toJSON(),\n assetName: this.assetName,\n };\n }\n}\n","import { AssetName, AssetNameParams } from \"./assetName\";\nimport { ChainId, ChainIdParams } from \"./chain\";\nimport { CAIP } from \"./spec\";\nimport { IdentifierSpec } from \"./types\";\nimport { isValidId, joinParams, getParams } from \"./utils\";\n\nexport interface AssetIdParams {\n chainId: string | ChainIdParams;\n assetName: string | AssetNameParams;\n tokenId: string;\n}\n\nexport class AssetId {\n public static spec: IdentifierSpec = CAIP[\"19\"].assetId;\n\n public static parse(id: string): AssetIdParams {\n if (!isValidId(id, this.spec)) {\n throw new Error(`Invalid ${this.spec.name} provided: ${id}`);\n }\n return new AssetId(getParams<AssetIdParams>(id, this.spec)).toJSON();\n }\n\n public static format(params: AssetIdParams): string {\n return joinParams(params as any, this.spec);\n }\n\n public chainId: ChainId;\n public assetName: AssetName;\n public tokenId: string;\n\n constructor(params: AssetIdParams | string) {\n if (typeof params === \"string\") {\n params = AssetId.parse(params);\n }\n\n this.chainId = new ChainId(params.chainId);\n this.assetName = new AssetName(params.assetName);\n this.tokenId = params.tokenId;\n }\n\n public toString(): string {\n return AssetId.format(this.toJSON());\n }\n\n public toJSON(): AssetIdParams {\n return {\n chainId: this.chainId.toJSON(),\n assetName: this.assetName.toJSON(),\n tokenId: this.tokenId,\n };\n }\n}\n","import type { CoinType } from \"@ensdomains/address-encoder\";\nimport { AccountId as CaipAccountId } from \"caip\";\nimport { type Address, type Hex, 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, type InterpretedName, Node } from \"../ens\";\nimport { asLowerCaseAddress } from \"./address\";\nimport { type CurrencyId, CurrencyIds, Price, type PriceEth } from \"./currencies\";\nimport { reinterpretName } from \"./interpretation/reinterpretation\";\nimport type { AccountIdString } from \"./serialized-types\";\nimport type {\n AccountId,\n BlockRef,\n ChainId,\n Datetime,\n DefaultableChainId,\n Duration,\n UnixTimestamp,\n} 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.coerce\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 lowercase Address.\n */\nexport const makeLowercaseAddressSchema = (valueLabel: string = \"EVM address\") =>\n z\n .string()\n .check((ctx) => {\n if (!isAddress(ctx.value)) {\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) => asLowerCaseAddress(val as Address));\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 Blockrange} object.\n */\nexport const makeBlockrangeSchema = (valueLabel: string = \"Value\") =>\n z\n .strictObject(\n {\n startBlock: makeBlockNumberSchema(`${valueLabel}.startBlock`).optional(),\n endBlock: makeBlockNumberSchema(`${valueLabel}.endBlock`).optional(),\n },\n {\n error: `${valueLabel} must be a valid Blockrange object.`,\n },\n )\n .refine(\n (v) => {\n if (v.startBlock && v.endBlock) {\n return v.startBlock <= v.endBlock;\n }\n\n return true;\n },\n { error: `${valueLabel}: startBlock must be before or equal to endBlock` },\n );\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\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\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 ],\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\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: makeLowercaseAddressSchema(`${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","import type { UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport type { AggregatedReferrerMetrics } from \"./aggregations\";\nimport type { ReferrerLeaderboard } from \"./leaderboard\";\nimport { isNonNegativeInteger, isPositiveInteger } from \"./number\";\nimport type { AwardedReferrerMetrics } from \"./referrer-metrics\";\nimport type { ReferralProgramRules } from \"./rules\";\n\n/**\n * The default number of referrers per leaderboard page.\n */\nexport const REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT = 25;\n\n/**\n * The maximum number of referrers per leaderboard page.\n */\n\nexport const REFERRERS_PER_LEADERBOARD_PAGE_MAX = 100;\n\n/**\n * Pagination params for leaderboard queries.\n */\nexport interface ReferrerLeaderboardPageParams {\n /**\n * Requested referrer leaderboard 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 referrers to return per leaderboard page\n * @invariant Must be a positive integer (>= 1) and less than or equal to {@link REFERRERS_PER_LEADERBOARD_PAGE_MAX}\n * @default {@link REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT}\n */\n recordsPerPage?: number;\n}\n\nconst validateReferrerLeaderboardPageParams = (params: ReferrerLeaderboardPageParams): void => {\n if (params.page !== undefined && !isPositiveInteger(params.page)) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageParams: ${params.page}. page must be a positive integer.`,\n );\n }\n if (params.recordsPerPage !== undefined && !isPositiveInteger(params.recordsPerPage)) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageParams: ${params.recordsPerPage}. recordsPerPage must be a positive integer.`,\n );\n }\n if (\n params.recordsPerPage !== undefined &&\n params.recordsPerPage > REFERRERS_PER_LEADERBOARD_PAGE_MAX\n ) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageParams: ${params.recordsPerPage}. recordsPerPage must be less than or equal to ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}.`,\n );\n }\n};\n\nexport const buildReferrerLeaderboardPageParams = (\n params: ReferrerLeaderboardPageParams,\n): Required<ReferrerLeaderboardPageParams> => {\n const result = {\n page: params.page ?? 1,\n recordsPerPage: params.recordsPerPage ?? REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT,\n } satisfies Required<ReferrerLeaderboardPageParams>;\n validateReferrerLeaderboardPageParams(result);\n return result;\n};\n\nexport interface ReferrerLeaderboardPageContext extends Required<ReferrerLeaderboardPageParams> {\n /**\n * Total number of referrers across all leaderboard pages\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n totalRecords: number;\n\n /**\n * Total number of pages in the leaderboard\n * @invariant Guaranteed to be a positive integer (>= 1)\n */\n totalPages: number;\n\n /**\n * Indicates if there is a next page available\n * @invariant true if and only if (`page` * `recordsPerPage` < `total`)\n */\n hasNext: boolean;\n\n /**\n * Indicates if there is a previous page available\n * @invariant true if and only if (`page` > 1)\n */\n hasPrev: boolean;\n\n /**\n * The start index of the referrers on the page (0-indexed)\n *\n * `undefined` if and only if `totalRecords` is 0.\n *\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n startIndex?: number;\n\n /**\n * The end index of the referrers on the page (0-indexed)\n *\n * `undefined` if and only if `totalRecords` is 0.\n *\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n * @invariant If `totalRecords` is > 0:\n * - Guaranteed to be greater than or equal to `startIndex`.\n * - Guaranteed to be less than `totalRecords`.\n */\n endIndex?: number;\n}\n\nexport const validateReferrerLeaderboardPageContext = (\n context: ReferrerLeaderboardPageContext,\n): void => {\n validateReferrerLeaderboardPageParams(context);\n if (!isNonNegativeInteger(context.totalRecords)) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: total must be a non-negative integer but is ${context.totalRecords}.`,\n );\n }\n const startIndex = (context.page - 1) * context.recordsPerPage;\n const endIndex = startIndex + context.recordsPerPage;\n\n if (!context.hasNext && endIndex < context.totalRecords) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: if hasNext is false, endIndex (${endIndex}) must be greater than or equal to total (${context.totalRecords}).`,\n );\n } else if (context.hasNext && context.page * context.recordsPerPage >= context.totalRecords) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: if hasNext is true, endIndex (${endIndex}) must be less than total (${context.totalRecords}).`,\n );\n }\n if (!context.hasPrev && context.page !== 1) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: if hasPrev is false, page must be the first page (1) but is ${context.page}.`,\n );\n } else if (context.hasPrev && context.page === 1) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: if hasPrev is true, page must not be the first page (1) but is ${context.page}.`,\n );\n }\n};\n\nexport const buildReferrerLeaderboardPageContext = (\n optionalParams: ReferrerLeaderboardPageParams,\n leaderboard: ReferrerLeaderboard,\n): ReferrerLeaderboardPageContext => {\n const materializedParams = buildReferrerLeaderboardPageParams(optionalParams);\n\n const totalRecords = leaderboard.referrers.size;\n\n const totalPages = Math.max(1, Math.ceil(totalRecords / materializedParams.recordsPerPage));\n\n if (materializedParams.page > totalPages) {\n throw new Error(\n `Invalid ReferrerLeaderboardPageContext: page ${materializedParams.page} exceeds total pages ${totalPages}.`,\n );\n }\n\n if (totalRecords === 0) {\n return {\n ...materializedParams,\n totalRecords: 0,\n totalPages: 1,\n hasNext: false,\n hasPrev: false,\n startIndex: undefined,\n endIndex: undefined,\n } satisfies ReferrerLeaderboardPageContext;\n }\n\n const startIndex = (materializedParams.page - 1) * materializedParams.recordsPerPage;\n const maxTheoreticalIndexOnPage = startIndex + (materializedParams.recordsPerPage - 1);\n const endIndex = Math.min(maxTheoreticalIndexOnPage, totalRecords - 1);\n const hasNext = maxTheoreticalIndexOnPage < totalRecords - 1;\n const hasPrev = materializedParams.page > 1;\n\n const result = {\n ...materializedParams,\n totalRecords,\n totalPages,\n hasNext,\n hasPrev,\n startIndex,\n endIndex,\n } satisfies ReferrerLeaderboardPageContext;\n validateReferrerLeaderboardPageContext(result);\n return result;\n};\n\n/**\n * A page of referrers from the referrer leaderboard.\n */\nexport interface ReferrerLeaderboardPage {\n /**\n * The {@link ReferralProgramRules} used to generate the {@link ReferrerLeaderboard}\n * that this {@link ReferrerLeaderboardPage} comes from.\n */\n rules: ReferralProgramRules;\n\n /**\n * Ordered list of {@link AwardedReferrerMetrics} for the {@link ReferrerLeaderboardPage}\n * described by `pageContext` within the related {@link ReferrerLeaderboard}.\n *\n * @invariant Array will be empty if `pageContext.totalRecords` is 0.\n * @invariant Array entries are ordered by `rank` (descending).\n */\n referrers: AwardedReferrerMetrics[];\n\n /**\n * Aggregated metrics for all referrers on the leaderboard.\n */\n aggregatedMetrics: AggregatedReferrerMetrics;\n\n /**\n * The {@link ReferrerLeaderboardPageContext} of this {@link ReferrerLeaderboardPage} relative to the overall\n * {@link ReferrerLeaderboard}.\n */\n pageContext: ReferrerLeaderboardPageContext;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link ReferrerLeaderboardPage} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\nexport const getReferrerLeaderboardPage = (\n pageParams: ReferrerLeaderboardPageParams,\n leaderboard: ReferrerLeaderboard,\n): ReferrerLeaderboardPage => {\n const pageContext = buildReferrerLeaderboardPageContext(pageParams, leaderboard);\n\n let referrers: AwardedReferrerMetrics[];\n\n if (\n pageContext.totalRecords > 0 &&\n typeof pageContext.startIndex !== \"undefined\" &&\n typeof pageContext.endIndex !== \"undefined\"\n ) {\n // extract the referrers from the leaderboard in the range specified by `pageContext`.\n referrers = Array.from(leaderboard.referrers.values()).slice(\n pageContext.startIndex,\n pageContext.endIndex + 1, // For `slice`, this is exclusive of the element at the index 'end'. We need it to be inclusive, hence plus one.\n );\n } else {\n referrers = [];\n }\n\n return {\n rules: leaderboard.rules,\n referrers,\n aggregatedMetrics: leaderboard.aggregatedMetrics,\n pageContext,\n accurateAsOf: leaderboard.accurateAsOf,\n };\n};\n","import type { Address } from \"viem\";\n\nimport type { Duration } from \"@ensnode/ensnode-sdk\";\n\nimport { isPositiveInteger } from \"./number\";\nimport type { ReferralProgramRules } from \"./rules\";\nimport { calcReferrerScore, type ReferrerScore } from \"./score\";\n\n/**\n * The rank of a referrer relative to all other referrers, where 1 is the\n * top-ranked referrer.\n *\n * @invariant Guaranteed to be a positive integer (> 0)\n */\nexport type ReferrerRank = number;\n\nexport const validateReferrerRank = (rank: ReferrerRank): void => {\n if (!isPositiveInteger(rank)) {\n throw new Error(`Invalid ReferrerRank: ${rank}. ReferrerRank must be a positive integer.`);\n }\n};\n\n/**\n * Determine if a referrer with the given `rank` is qualified to receive a non-zero `awardPoolShare` according to the given `rules`.\n *\n * @param rank - The rank of the referrer relative to all other referrers on a {@link ReferrerLeaderboard}.\n * @param rules - The rules of the referral program that generated the `rank`.\n */\nexport function isReferrerQualified(rank: ReferrerRank, rules: ReferralProgramRules): boolean {\n return rank <= rules.maxQualifiedReferrers;\n}\n\n/**\n * Calculate the final score boost of a referrer based on their rank.\n *\n * @param rank - The rank of the referrer relative to all other referrers, where 1 is the\n * top-ranked referrer.\n * @returns The final score boost of the referrer as a number between 0 and 1 (inclusive).\n */\nexport function calcReferrerFinalScoreBoost(\n rank: ReferrerRank,\n rules: ReferralProgramRules,\n): number {\n if (!isReferrerQualified(rank, rules)) return 0;\n\n return 1 - (rank - 1) / (rules.maxQualifiedReferrers - 1);\n}\n\n/**\n * Calculate the final score multiplier of a referrer based on their rank.\n *\n * @param rank - The rank of the referrer relative to all other referrers, where 1 is the\n * top-ranked referrer.\n * @returns The final score multiplier of the referrer as a number between 1 and 2 (inclusive).\n */\nexport function calcReferrerFinalScoreMultiplier(\n rank: ReferrerRank,\n rules: ReferralProgramRules,\n): number {\n return 1 + calcReferrerFinalScoreBoost(rank, rules);\n}\n\n/**\n * Calculate the final score of a referrer based on their score and final score boost.\n *\n * @param rank - The rank of the referrer relative to all other referrers.\n * @param totalIncrementalDuration - The total incremental duration (in seconds)\n * of referrals made by the referrer within the `rules`.\n * @param rules - The rules of the referral program that generated the `rank`.\n * @returns The final score of the referrer.\n */\nexport function calcReferrerFinalScore(\n rank: ReferrerRank,\n totalIncrementalDuration: Duration,\n rules: ReferralProgramRules,\n): ReferrerScore {\n return (\n calcReferrerScore(totalIncrementalDuration) * calcReferrerFinalScoreMultiplier(rank, rules)\n );\n}\n\nexport interface ReferrerMetricsForComparison {\n /**\n * The total incremental duration (in seconds) of all referrals made by the referrer within\n * the {@link ReferralProgramRules}.\n */\n totalIncrementalDuration: Duration;\n\n /**\n * The fully lowercase Ethereum address of the referrer.\n *\n * @invariant Guaranteed to be a valid EVM address in lowercase format.\n */\n referrer: Address;\n}\n\nexport const compareReferrerMetrics = (\n a: ReferrerMetricsForComparison,\n b: ReferrerMetricsForComparison,\n): number => {\n // Primary sort: totalIncrementalDuration (descending)\n if (a.totalIncrementalDuration !== b.totalIncrementalDuration) {\n return b.totalIncrementalDuration - a.totalIncrementalDuration;\n }\n\n // Secondary sort: referrer address using lexicographic comparison of ASCII hex strings (descending)\n if (b.referrer > a.referrer) return 1;\n if (b.referrer < a.referrer) return -1;\n return 0;\n};\n","import type { Address } from \"viem\";\n\nimport type { Duration } from \"@ensnode/ensnode-sdk\";\n\nimport { normalizeAddress, validateLowercaseAddress } from \"./address\";\nimport type { AggregatedReferrerMetrics } from \"./aggregations\";\nimport type { USDQuantity } from \"./currency\";\nimport { validateNonNegativeInteger } from \"./number\";\nimport {\n calcReferrerFinalScore,\n calcReferrerFinalScoreBoost,\n compareReferrerMetrics,\n isReferrerQualified,\n type ReferrerRank,\n validateReferrerRank,\n} from \"./rank\";\nimport type { RevenueContribution } from \"./revenue-contribution\";\nimport { validateRevenueContribution } from \"./revenue-contribution\";\nimport type { ReferralProgramRules } from \"./rules\";\nimport { calcReferrerScore, type ReferrerScore, validateReferrerScore } from \"./score\";\nimport { validateDuration } from \"./time\";\n\n/**\n * Represents metrics for a single referrer independent of other referrers.\n */\nexport interface ReferrerMetrics {\n /**\n * The fully lowercase Ethereum address of the referrer.\n *\n * @invariant Guaranteed to be a valid EVM address in lowercase format\n */\n referrer: Address;\n\n /**\n * The total number of referrals made by the referrer within the {@link ReferralProgramRules}.\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n totalReferrals: number;\n\n /**\n * The total incremental duration (in seconds) of all referrals made by the referrer within\n * the {@link ReferralProgramRules}.\n */\n totalIncrementalDuration: Duration;\n\n /**\n * The total revenue contribution (in Wei) made to the ENS DAO by all referrals\n * from this referrer.\n *\n * This is the sum of the total cost paid by registrants for all registrar actions\n * where this address was the referrer.\n *\n * @invariant Guaranteed to be a non-negative bigint value (>= 0n)\n * @invariant Never null (records with null `total` in the database are treated as 0 when summing)\n */\n totalRevenueContribution: RevenueContribution;\n}\n\nexport const buildReferrerMetrics = (\n referrer: Address,\n totalReferrals: number,\n totalIncrementalDuration: Duration,\n totalRevenueContribution: RevenueContribution,\n): ReferrerMetrics => {\n const result = {\n referrer: normalizeAddress(referrer),\n totalReferrals,\n totalIncrementalDuration,\n totalRevenueContribution,\n } satisfies ReferrerMetrics;\n\n validateReferrerMetrics(result);\n return result;\n};\n\nexport const validateReferrerMetrics = (metrics: ReferrerMetrics): void => {\n validateLowercaseAddress(metrics.referrer);\n validateNonNegativeInteger(metrics.totalReferrals);\n validateDuration(metrics.totalIncrementalDuration);\n validateRevenueContribution(metrics.totalRevenueContribution);\n};\n\nexport const sortReferrerMetrics = (referrers: ReferrerMetrics[]): ReferrerMetrics[] => {\n return [...referrers].sort(compareReferrerMetrics);\n};\n\n/**\n * Represents metrics for a single referrer independent of other referrers,\n * including a calculation of the referrer's score.\n */\nexport interface ScoredReferrerMetrics extends ReferrerMetrics {\n /**\n * The referrer's score.\n *\n * @invariant Guaranteed to be `calcReferrerScore(totalIncrementalDuration)`\n */\n score: ReferrerScore;\n}\n\nexport const buildScoredReferrerMetrics = (referrer: ReferrerMetrics): ScoredReferrerMetrics => {\n const result = {\n ...referrer,\n score: calcReferrerScore(referrer.totalIncrementalDuration),\n } satisfies ScoredReferrerMetrics;\n\n validateScoredReferrerMetrics(result);\n return result;\n};\n\nexport const validateScoredReferrerMetrics = (metrics: ScoredReferrerMetrics): void => {\n validateReferrerMetrics(metrics);\n validateReferrerScore(metrics.score);\n\n const expectedScore = calcReferrerScore(metrics.totalIncrementalDuration);\n if (metrics.score !== expectedScore) {\n throw new Error(`Referrer: Invalid score: ${metrics.score}, expected: ${expectedScore}.`);\n }\n};\n\n/**\n * Extends {@link ScoredReferrerMetrics} to include additional metrics\n * relative to all other referrers on a {@link ReferrerLeaderboard} and {@link ReferralProgramRules}.\n */\nexport interface RankedReferrerMetrics extends ScoredReferrerMetrics {\n /**\n * The referrer's rank on the {@link ReferrerLeaderboard} relative to all other referrers.\n */\n rank: ReferrerRank;\n\n /**\n * Identifies if the referrer meets the qualifications of the {@link ReferralProgramRules} to receive a non-zero `awardPoolShare`.\n *\n * @invariant true if and only if `rank` is less than or equal to {@link ReferralProgramRules.maxQualifiedReferrers}\n */\n isQualified: boolean;\n\n /**\n * The referrer's final score boost.\n *\n * @invariant Guaranteed to be a number between 0 and 1 (inclusive)\n * @invariant Calculated as: `1-((rank-1)/({@link ReferralProgramRules.maxQualifiedReferrers}-1))` if `isQualified` is `true`, else `0`\n */\n finalScoreBoost: number;\n\n /**\n * The referrer's final score.\n *\n * @invariant Calculated as: `score * (1 + finalScoreBoost)`\n */\n finalScore: ReferrerScore;\n}\n\nexport const validateRankedReferrerMetrics = (\n metrics: RankedReferrerMetrics,\n rules: ReferralProgramRules,\n): void => {\n validateScoredReferrerMetrics(metrics);\n validateReferrerRank(metrics.rank);\n\n if (metrics.finalScoreBoost < 0 || metrics.finalScoreBoost > 1) {\n throw new Error(\n `Invalid RankedReferrerMetrics: Invalid finalScoreBoost: ${metrics.finalScoreBoost}. finalScoreBoost must be between 0 and 1 (inclusive).`,\n );\n }\n\n validateReferrerScore(metrics.finalScore);\n\n const expectedIsQualified = isReferrerQualified(metrics.rank, rules);\n if (metrics.isQualified !== expectedIsQualified) {\n throw new Error(\n `RankedReferrerMetrics: Invalid isQualified: ${metrics.isQualified}, expected: ${expectedIsQualified}.`,\n );\n }\n\n const expectedFinalScoreBoost = calcReferrerFinalScoreBoost(metrics.rank, rules);\n if (metrics.finalScoreBoost !== expectedFinalScoreBoost) {\n throw new Error(\n `RankedReferrerMetrics: Invalid finalScoreBoost: ${metrics.finalScoreBoost}, expected: ${expectedFinalScoreBoost}.`,\n );\n }\n\n const expectedFinalScore = calcReferrerFinalScore(\n metrics.rank,\n metrics.totalIncrementalDuration,\n rules,\n );\n if (metrics.finalScore !== expectedFinalScore) {\n throw new Error(\n `RankedReferrerMetrics: Invalid finalScore: ${metrics.finalScore}, expected: ${expectedFinalScore}.`,\n );\n }\n};\n\nexport const buildRankedReferrerMetrics = (\n referrer: ScoredReferrerMetrics,\n rank: ReferrerRank,\n rules: ReferralProgramRules,\n): RankedReferrerMetrics => {\n const result = {\n ...referrer,\n rank,\n isQualified: isReferrerQualified(rank, rules),\n finalScoreBoost: calcReferrerFinalScoreBoost(rank, rules),\n finalScore: calcReferrerFinalScore(rank, referrer.totalIncrementalDuration, rules),\n } satisfies RankedReferrerMetrics;\n validateRankedReferrerMetrics(result, rules);\n return result;\n};\n\n/**\n * Calculate the share of the award pool for a referrer.\n * @param referrer - The referrer to calculate the award pool share for.\n * @param aggregatedMetrics - Aggregated metrics for all referrers.\n * @param rules - The rules of the referral program.\n * @returns The referrer's share of the award pool as a number between 0 and 1 (inclusive).\n */\nexport const calcReferrerAwardPoolShare = (\n referrer: RankedReferrerMetrics,\n aggregatedMetrics: AggregatedReferrerMetrics,\n rules: ReferralProgramRules,\n): number => {\n if (!isReferrerQualified(referrer.rank, rules)) return 0;\n if (aggregatedMetrics.grandTotalQualifiedReferrersFinalScore === 0) return 0;\n\n return (\n calcReferrerFinalScore(referrer.rank, referrer.totalIncrementalDuration, rules) /\n aggregatedMetrics.grandTotalQualifiedReferrersFinalScore\n );\n};\n\n/**\n * Extends {@link RankedReferrerMetrics} to include additional metrics\n * relative to {@link AggregatedRankedReferrerMetrics}.\n */\nexport interface AwardedReferrerMetrics extends RankedReferrerMetrics {\n /**\n * The referrer's share of the award pool.\n *\n * @invariant Guaranteed to be a number between 0 and 1 (inclusive)\n * @invariant Calculated as: `finalScore / {@link AggregatedRankedReferrerMetrics.grandTotalQualifiedReferrersFinalScore}` if `isQualified` is `true`, else `0`\n */\n awardPoolShare: number;\n\n /**\n * The approximate {@link USDQuantity} of the referrer's share of the {@link ReferralProgramRules.totalAwardPoolValue}.\n *\n * @invariant Guaranteed to be a number between 0 and {@link ReferralProgramRules.totalAwardPoolValue} (inclusive)\n * @invariant Calculated as: `awardPoolShare` * {@link ReferralProgramRules.totalAwardPoolValue}\n */\n awardPoolApproxValue: USDQuantity;\n}\n\nexport const validateAwardedReferrerMetrics = (\n referrer: AwardedReferrerMetrics,\n rules: ReferralProgramRules,\n): void => {\n validateRankedReferrerMetrics(referrer, rules);\n if (referrer.awardPoolShare < 0 || referrer.awardPoolShare > 1) {\n throw new Error(\n `Invalid AwardedReferrerMetrics: ${referrer.awardPoolShare}. awardPoolShare must be between 0 and 1 (inclusive).`,\n );\n }\n\n if (\n referrer.awardPoolApproxValue < 0 ||\n referrer.awardPoolApproxValue > rules.totalAwardPoolValue\n ) {\n throw new Error(\n `Invalid AwardedReferrerMetrics: ${referrer.awardPoolApproxValue}. awardPoolApproxValue must be between 0 and ${rules.totalAwardPoolValue} (inclusive).`,\n );\n }\n};\n\nexport const buildAwardedReferrerMetrics = (\n referrer: RankedReferrerMetrics,\n aggregatedMetrics: AggregatedReferrerMetrics,\n rules: ReferralProgramRules,\n): AwardedReferrerMetrics => {\n const awardPoolShare = calcReferrerAwardPoolShare(referrer, aggregatedMetrics, rules);\n\n const result = {\n ...referrer,\n awardPoolShare,\n awardPoolApproxValue: awardPoolShare * rules.totalAwardPoolValue,\n };\n validateAwardedReferrerMetrics(result, rules);\n return result;\n};\n\n/**\n * Extends {@link AwardedReferrerMetrics} but with rank set to null to represent\n * a referrer who is not on the leaderboard (has zero referrals within the rules associated with the leaderboard).\n */\nexport interface UnrankedReferrerMetrics\n extends Omit<AwardedReferrerMetrics, \"rank\" | \"isQualified\"> {\n /**\n * The referrer is not on the leaderboard and therefore has no rank.\n */\n rank: null;\n\n /**\n * Always false for unranked referrers.\n */\n isQualified: false;\n}\n\nexport const validateUnrankedReferrerMetrics = (metrics: UnrankedReferrerMetrics): void => {\n validateScoredReferrerMetrics(metrics);\n\n if (metrics.rank !== null) {\n throw new Error(`Invalid UnrankedReferrerMetrics: rank must be null, got: ${metrics.rank}.`);\n }\n\n if (metrics.isQualified !== false) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: isQualified must be false, got: ${metrics.isQualified}.`,\n );\n }\n\n if (metrics.totalReferrals !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: totalReferrals must be 0, got: ${metrics.totalReferrals}.`,\n );\n }\n\n if (metrics.totalIncrementalDuration !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: totalIncrementalDuration must be 0, got: ${metrics.totalIncrementalDuration}.`,\n );\n }\n\n if (metrics.totalRevenueContribution !== 0n) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: totalRevenueContribution must be 0n, got: ${metrics.totalRevenueContribution.toString()}.`,\n );\n }\n\n if (metrics.score !== 0) {\n throw new Error(`Invalid UnrankedReferrerMetrics: score must be 0, got: ${metrics.score}.`);\n }\n\n if (metrics.finalScoreBoost !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: finalScoreBoost must be 0, got: ${metrics.finalScoreBoost}.`,\n );\n }\n\n if (metrics.finalScore !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: finalScore must be 0, got: ${metrics.finalScore}.`,\n );\n }\n\n if (metrics.awardPoolShare !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: awardPoolShare must be 0, got: ${metrics.awardPoolShare}.`,\n );\n }\n\n if (metrics.awardPoolApproxValue !== 0) {\n throw new Error(\n `Invalid UnrankedReferrerMetrics: awardPoolApproxValue must be 0, got: ${metrics.awardPoolApproxValue}.`,\n );\n }\n};\n\n/**\n * Build an unranked zero-score referrer record for a referrer address that is not in the leaderboard.\n *\n * This is useful when you want to return a referrer record for an address that has no referrals\n * and is not qualified for the leaderboard.\n *\n * @param referrer - The referrer address\n * @returns An {@link UnrankedReferrerMetrics} with zero values for all metrics and null rank\n */\nexport const buildUnrankedReferrerMetrics = (referrer: Address): UnrankedReferrerMetrics => {\n const baseMetrics = buildReferrerMetrics(referrer, 0, 0, 0n);\n const scoredMetrics = buildScoredReferrerMetrics(baseMetrics);\n\n const result = {\n ...scoredMetrics,\n rank: null,\n isQualified: false,\n finalScoreBoost: 0,\n finalScore: 0,\n awardPoolShare: 0,\n awardPoolApproxValue: 0,\n } satisfies UnrankedReferrerMetrics;\n\n validateUnrankedReferrerMetrics(result);\n return result;\n};\n","import type { Address } from \"viem\";\n\nimport type { UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport type { AggregatedReferrerMetrics } from \"./aggregations\";\nimport type { ReferrerLeaderboard } from \"./leaderboard\";\nimport {\n type AwardedReferrerMetrics,\n buildUnrankedReferrerMetrics,\n type UnrankedReferrerMetrics,\n} from \"./referrer-metrics\";\nimport type { ReferralProgramRules } from \"./rules\";\n\n/**\n * The type of referrer detail data.\n */\nexport const ReferrerDetailTypeIds = {\n /**\n * Represents a referrer who is ranked on the leaderboard.\n */\n Ranked: \"ranked\",\n\n /**\n * Represents a referrer who is not ranked on the leaderboard.\n */\n Unranked: \"unranked\",\n} as const;\n\n/**\n * The derived string union of possible {@link ReferrerDetailTypeIds}.\n */\nexport type ReferrerDetailTypeId =\n (typeof ReferrerDetailTypeIds)[keyof typeof ReferrerDetailTypeIds];\n\n/**\n * Referrer detail data for a specific referrer address on the leaderboard.\n *\n * Includes the referrer's awarded metrics from the leaderboard plus timestamp.\n *\n * Invariants:\n * - `type` is always {@link ReferrerDetailTypeIds.Ranked}.\n *\n * @see {@link AwardedReferrerMetrics}\n */\nexport interface ReferrerDetailRanked {\n /**\n * The type of referrer detail data.\n */\n type: typeof ReferrerDetailTypeIds.Ranked;\n\n /**\n * The {@link ReferralProgramRules} used to calculate the {@link AwardedReferrerMetrics}.\n */\n rules: ReferralProgramRules;\n\n /**\n * The awarded referrer metrics from the leaderboard.\n *\n * Contains all calculated metrics including score, rank, qualification status,\n * and award pool share information.\n */\n referrer: AwardedReferrerMetrics;\n\n /**\n * Aggregated metrics for all referrers on the leaderboard.\n */\n aggregatedMetrics: AggregatedReferrerMetrics;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link ReferrerDetailData} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\n/**\n * Referrer detail data for a specific referrer address NOT on the leaderboard.\n *\n * Includes the referrer's unranked metrics (with null rank and isQualified: false) plus timestamp.\n *\n * Invariants:\n * - `type` is always {@link ReferrerDetailTypeIds.Unranked}.\n *\n * @see {@link UnrankedReferrerMetrics}\n */\nexport interface ReferrerDetailUnranked {\n /**\n * The type of referrer detail data.\n */\n type: typeof ReferrerDetailTypeIds.Unranked;\n\n /**\n * The {@link ReferralProgramRules} used to calculate the {@link UnrankedReferrerMetrics}.\n */\n rules: ReferralProgramRules;\n\n /**\n * The unranked referrer metrics (not on the leaderboard).\n *\n * Contains all calculated metrics with rank set to null and isQualified set to false.\n */\n referrer: UnrankedReferrerMetrics;\n\n /**\n * Aggregated metrics for all referrers on the leaderboard.\n */\n aggregatedMetrics: AggregatedReferrerMetrics;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link UnrankedReferrerDetailData} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\n/**\n * Referrer detail data for a specific referrer address.\n *\n * Use the `type` field to determine the specific type interpretation\n * at runtime.\n */\nexport type ReferrerDetail = ReferrerDetailRanked | ReferrerDetailUnranked;\n\n/**\n * Get the detail for a specific referrer from the leaderboard.\n *\n * Returns a {@link ReferrerDetailRanked} if the referrer is on the leaderboard,\n * or a {@link ReferrerDetailUnranked} if the referrer has no referrals.\n *\n * @param referrer - The referrer address to look up\n * @param leaderboard - The referrer leaderboard to query\n * @returns The appropriate {@link ReferrerDetail} (ranked or unranked)\n */\nexport const getReferrerDetail = (\n referrer: Address,\n leaderboard: ReferrerLeaderboard,\n): ReferrerDetail => {\n const awardedReferrerMetrics = leaderboard.referrers.get(referrer);\n\n // If referrer is on the leaderboard, return their ranked metrics\n if (awardedReferrerMetrics) {\n return {\n type: ReferrerDetailTypeIds.Ranked,\n rules: leaderboard.rules,\n referrer: awardedReferrerMetrics,\n aggregatedMetrics: leaderboard.aggregatedMetrics,\n accurateAsOf: leaderboard.accurateAsOf,\n };\n }\n\n // If referrer not found, return an unranked referrer record\n return {\n type: ReferrerDetailTypeIds.Unranked,\n rules: leaderboard.rules,\n referrer: buildUnrankedReferrerMetrics(referrer),\n aggregatedMetrics: leaderboard.aggregatedMetrics,\n accurateAsOf: leaderboard.accurateAsOf,\n };\n};\n","import type { Address } from \"viem\";\n\nimport type { ReferrerLeaderboardPage, ReferrerLeaderboardPageParams } from \"../leaderboard-page\";\nimport type { ReferrerDetail } from \"../referrer-detail\";\n\n/**\n * Request parameters for a referrer leaderboard page query.\n */\nexport interface ReferrerLeaderboardPageRequest extends ReferrerLeaderboardPageParams {}\n\n/**\n * A status code for a referrer leaderboard page API response.\n */\nexport const ReferrerLeaderboardPageResponseCodes = {\n /**\n * Represents that the requested referrer leaderboard page is available.\n */\n Ok: \"ok\",\n\n /**\n * Represents that the referrer leaderboard data is not available.\n */\n Error: \"error\",\n} as const;\n\n/**\n * The derived string union of possible {@link ReferrerLeaderboardPageResponseCodes}.\n */\nexport type ReferrerLeaderboardPageResponseCode =\n (typeof ReferrerLeaderboardPageResponseCodes)[keyof typeof ReferrerLeaderboardPageResponseCodes];\n\n/**\n * A referrer leaderboard page response when the data is available.\n */\nexport type ReferrerLeaderboardPageResponseOk = {\n responseCode: typeof ReferrerLeaderboardPageResponseCodes.Ok;\n data: ReferrerLeaderboardPage;\n};\n\n/**\n * A referrer leaderboard page response when the data is not available.\n */\nexport type ReferrerLeaderboardPageResponseError = {\n responseCode: typeof ReferrerLeaderboardPageResponseCodes.Error;\n error: string;\n errorMessage: string;\n};\n\n/**\n * A referrer leaderboard page API response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type ReferrerLeaderboardPageResponse =\n | ReferrerLeaderboardPageResponseOk\n | ReferrerLeaderboardPageResponseError;\n\n/**\n * Request parameters for referrer detail query.\n */\nexport interface ReferrerDetailRequest {\n /** The Ethereum address of the referrer to query */\n referrer: Address;\n}\n\n/**\n * A status code for referrer detail API responses.\n */\nexport const ReferrerDetailResponseCodes = {\n /**\n * Represents that the referrer detail data is available.\n */\n Ok: \"ok\",\n\n /**\n * Represents that an error occurred while fetching the data.\n */\n Error: \"error\",\n} as const;\n\n/**\n * The derived string union of possible {@link ReferrerDetailResponseCodes}.\n */\nexport type ReferrerDetailResponseCode =\n (typeof ReferrerDetailResponseCodes)[keyof typeof ReferrerDetailResponseCodes];\n\n/**\n * A referrer detail response when the data is available for a referrer on the leaderboard.\n */\nexport type ReferrerDetailResponseOk = {\n responseCode: typeof ReferrerDetailResponseCodes.Ok;\n data: ReferrerDetail;\n};\n\n/**\n * A referrer detail response when an error occurs.\n */\nexport type ReferrerDetailResponseError = {\n responseCode: typeof ReferrerDetailResponseCodes.Error;\n error: string;\n errorMessage: string;\n};\n\n/**\n * A referrer detail API response.\n *\n * Use the `responseCode` field to determine the specific type interpretation\n * at runtime.\n */\nexport type ReferrerDetailResponse = ReferrerDetailResponseOk | ReferrerDetailResponseError;\n","import type { AggregatedReferrerMetrics } from \"../aggregations\";\nimport type { ReferrerLeaderboardPage } from \"../leaderboard-page\";\nimport type { ReferrerDetailRanked, ReferrerDetailUnranked } from \"../referrer-detail\";\nimport type { AwardedReferrerMetrics, UnrankedReferrerMetrics } from \"../referrer-metrics\";\nimport type { RevenueContribution } from \"../revenue-contribution\";\nimport type { ReferralProgramRules } from \"../rules\";\nimport type {\n SerializedAggregatedReferrerMetrics,\n SerializedAwardedReferrerMetrics,\n SerializedReferralProgramRules,\n SerializedReferrerDetailRanked,\n SerializedReferrerDetailResponse,\n SerializedReferrerDetailUnranked,\n SerializedReferrerLeaderboardPage,\n SerializedReferrerLeaderboardPageResponse,\n SerializedUnrankedReferrerMetrics,\n} from \"./serialized-types\";\nimport {\n type ReferrerDetailResponse,\n ReferrerDetailResponseCodes,\n type ReferrerLeaderboardPageResponse,\n ReferrerLeaderboardPageResponseCodes,\n} from \"./types\";\n\n/**\n * Serializes a {@link RevenueContribution} value into its string representation.\n */\nfunction serializeRevenueContribution(revenueContribution: RevenueContribution): string {\n return revenueContribution.toString();\n}\n\n/**\n * Serializes a {@link ReferralProgramRules} object.\n */\nfunction serializeReferralProgramRules(\n rules: ReferralProgramRules,\n): SerializedReferralProgramRules {\n // All fields are already serializable primitives\n return rules;\n}\n\n/**\n * Serializes an {@link AwardedReferrerMetrics} object.\n */\nfunction serializeAwardedReferrerMetrics(\n metrics: AwardedReferrerMetrics,\n): SerializedAwardedReferrerMetrics {\n return {\n referrer: metrics.referrer,\n totalReferrals: metrics.totalReferrals,\n totalIncrementalDuration: metrics.totalIncrementalDuration,\n totalRevenueContribution: serializeRevenueContribution(metrics.totalRevenueContribution),\n score: metrics.score,\n rank: metrics.rank,\n isQualified: metrics.isQualified,\n finalScoreBoost: metrics.finalScoreBoost,\n finalScore: metrics.finalScore,\n awardPoolShare: metrics.awardPoolShare,\n awardPoolApproxValue: metrics.awardPoolApproxValue,\n };\n}\n\n/**\n * Serializes an {@link UnrankedReferrerMetrics} object.\n */\nfunction serializeUnrankedReferrerMetrics(\n metrics: UnrankedReferrerMetrics,\n): SerializedUnrankedReferrerMetrics {\n return {\n referrer: metrics.referrer,\n totalReferrals: metrics.totalReferrals,\n totalIncrementalDuration: metrics.totalIncrementalDuration,\n totalRevenueContribution: serializeRevenueContribution(metrics.totalRevenueContribution),\n score: metrics.score,\n rank: metrics.rank,\n isQualified: metrics.isQualified,\n finalScoreBoost: metrics.finalScoreBoost,\n finalScore: metrics.finalScore,\n awardPoolShare: metrics.awardPoolShare,\n awardPoolApproxValue: metrics.awardPoolApproxValue,\n };\n}\n\n/**\n * Serializes an {@link AggregatedReferrerMetrics} object.\n */\nfunction serializeAggregatedReferrerMetrics(\n metrics: AggregatedReferrerMetrics,\n): SerializedAggregatedReferrerMetrics {\n return {\n grandTotalReferrals: metrics.grandTotalReferrals,\n grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,\n grandTotalRevenueContribution: serializeRevenueContribution(\n metrics.grandTotalRevenueContribution,\n ),\n grandTotalQualifiedReferrersFinalScore: metrics.grandTotalQualifiedReferrersFinalScore,\n minFinalScoreToQualify: metrics.minFinalScoreToQualify,\n };\n}\n\n/**\n * Serializes a {@link ReferrerLeaderboardPage} object.\n */\nfunction serializeReferrerLeaderboardPage(\n page: ReferrerLeaderboardPage,\n): SerializedReferrerLeaderboardPage {\n return {\n rules: serializeReferralProgramRules(page.rules),\n referrers: page.referrers.map(serializeAwardedReferrerMetrics),\n aggregatedMetrics: serializeAggregatedReferrerMetrics(page.aggregatedMetrics),\n pageContext: page.pageContext,\n accurateAsOf: page.accurateAsOf,\n };\n}\n\n/**\n * Serializes a {@link ReferrerDetailRanked} object.\n */\nfunction serializeReferrerDetailRanked(\n detail: ReferrerDetailRanked,\n): SerializedReferrerDetailRanked {\n return {\n type: detail.type,\n rules: serializeReferralProgramRules(detail.rules),\n referrer: serializeAwardedReferrerMetrics(detail.referrer),\n aggregatedMetrics: serializeAggregatedReferrerMetrics(detail.aggregatedMetrics),\n accurateAsOf: detail.accurateAsOf,\n };\n}\n\n/**\n * Serializes a {@link ReferrerDetailUnranked} object.\n */\nfunction serializeReferrerDetailUnranked(\n detail: ReferrerDetailUnranked,\n): SerializedReferrerDetailUnranked {\n return {\n type: detail.type,\n rules: serializeReferralProgramRules(detail.rules),\n referrer: serializeUnrankedReferrerMetrics(detail.referrer),\n aggregatedMetrics: serializeAggregatedReferrerMetrics(detail.aggregatedMetrics),\n accurateAsOf: detail.accurateAsOf,\n };\n}\n\n/**\n * Serialize a {@link ReferrerLeaderboardPageResponse} object.\n */\nexport function serializeReferrerLeaderboardPageResponse(\n response: ReferrerLeaderboardPageResponse,\n): SerializedReferrerLeaderboardPageResponse {\n switch (response.responseCode) {\n case ReferrerLeaderboardPageResponseCodes.Ok:\n return {\n responseCode: response.responseCode,\n data: serializeReferrerLeaderboardPage(response.data),\n };\n\n case ReferrerLeaderboardPageResponseCodes.Error:\n return response;\n }\n}\n\n/**\n * Serialize a {@link ReferrerDetailResponse} object.\n */\nexport function serializeReferrerDetailResponse(\n response: ReferrerDetailResponse,\n): SerializedReferrerDetailResponse {\n switch (response.responseCode) {\n case ReferrerDetailResponseCodes.Ok:\n switch (response.data.type) {\n case \"ranked\":\n return {\n responseCode: response.responseCode,\n data: serializeReferrerDetailRanked(response.data),\n };\n\n case \"unranked\":\n return {\n responseCode: response.responseCode,\n data: serializeReferrerDetailUnranked(response.data),\n };\n }\n break;\n\n case ReferrerDetailResponseCodes.Error:\n return response;\n }\n}\n","import {\n deserializeReferrerDetailResponse,\n deserializeReferrerLeaderboardPageResponse,\n type ReferrerDetailRequest,\n type ReferrerDetailResponse,\n type ReferrerLeaderboardPageRequest,\n type ReferrerLeaderboardPageResponse,\n type SerializedReferrerDetailResponse,\n type SerializedReferrerLeaderboardPageResponse,\n} from \"./api\";\n\n/**\n * Default ENSNode API endpoint URL\n */\nexport const DEFAULT_ENSNODE_API_URL = \"https://api.alpha.ensnode.io\" as const;\n\n/**\n * Configuration options for ENS Referrals API client\n */\nexport interface ClientOptions {\n /** The ENSNode API URL */\n url: URL;\n}\n\n/**\n * ENS Referrals API Client\n *\n * Provides access to ENS Referrals data and leaderboard information.\n *\n * @example\n * ```typescript\n * // Create client with default options\n * const client = new ENSReferralsClient();\n *\n * // Get referrer leaderboard\n * const leaderboardPage = await client.getReferrerLeaderboardPage({\n * page: 1,\n * recordsPerPage: 25\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Custom configuration\n * const client = new ENSReferralsClient({\n * url: new URL(\"https://my-ensnode-instance.com\"),\n * });\n * ```\n */\nexport class ENSReferralsClient {\n private readonly options: ClientOptions;\n\n static defaultOptions(): ClientOptions {\n return {\n url: new URL(DEFAULT_ENSNODE_API_URL),\n };\n }\n\n constructor(options: Partial<ClientOptions> = {}) {\n this.options = {\n ...ENSReferralsClient.defaultOptions(),\n ...options,\n };\n }\n\n getOptions(): Readonly<ClientOptions> {\n return Object.freeze({\n url: new URL(this.options.url.href),\n });\n }\n\n /**\n * Fetch Referrer Leaderboard Page\n *\n * Retrieves a paginated list of referrer leaderboard metrics with contribution percentages.\n * Each referrer's contribution is calculated as a percentage of the grand totals across all referrers.\n *\n * @param request - Pagination parameters\n * @param request.page - The page number to retrieve (1-indexed, default: 1)\n * @param request.recordsPerPage - Number of records per page (default: 25, max: 100)\n * @returns {ReferrerLeaderboardPageResponse}\n *\n * @throws if the ENSNode request fails\n * @throws if the ENSNode API returns an error response\n * @throws if the ENSNode response breaks required invariants\n *\n * @example\n * ```typescript\n * // Get first page with default page size (25 records)\n * const response = await client.getReferrerLeaderboardPage();\n * if (response.responseCode === ReferrerLeaderboardPageResponseCodes.Ok) {\n * const {\n * aggregatedMetrics,\n * referrers,\n * rules,\n * pageContext,\n * updatedAt\n * } = response.data;\n * console.log(aggregatedMetrics);\n * console.log(referrers);\n * console.log(rules);\n * console.log(updatedAt);\n * console.log(`Page ${pageContext.page} of ${pageContext.totalPages}`);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Get second page with 50 records per page\n * const response = await client.getReferrerLeaderboardPage({ page: 2, recordsPerPage: 50 });\n * ```\n *\n * @example\n * ```typescript\n * // Handle error response, ie. when Referrer Leaderboard is not currently available.\n * const response = await client.getReferrerLeaderboardPage();\n *\n * if (response.responseCode === ReferrerLeaderboardPageResponseCodes.Error) {\n * console.error(response.error);\n * console.error(response.errorMessage);\n * }\n * ```\n */\n async getReferrerLeaderboardPage(\n request?: ReferrerLeaderboardPageRequest,\n ): Promise<ReferrerLeaderboardPageResponse> {\n const url = new URL(`/ensanalytics/referrers`, this.options.url);\n\n if (request?.page) url.searchParams.set(\"page\", request.page.toString());\n if (request?.recordsPerPage)\n url.searchParams.set(\"recordsPerPage\", request.recordsPerPage.toString());\n\n const response = await fetch(url);\n\n // ENSNode API should always allow parsing a response as JSON object.\n // If for some reason it's not the case, throw an error.\n let responseData: unknown;\n try {\n responseData = await response.json();\n } catch {\n throw new Error(\"Malformed response data: invalid JSON\");\n }\n\n // The API can return errors with 500 status, but they're still in the\n // PaginatedAggregatedReferrersResponse format with responseCode: 'error'\n // So we don't need to check response.ok here, just deserialize and let\n // the caller handle the responseCode\n\n return deserializeReferrerLeaderboardPageResponse(\n responseData as SerializedReferrerLeaderboardPageResponse,\n );\n }\n\n /**\n * Fetch Referrer Detail\n *\n * Retrieves detailed information about a specific referrer, whether they are on the\n * leaderboard or not.\n *\n * The response data is a discriminated union type with a `type` field:\n *\n * **For referrers on the leaderboard** (`ReferrerDetailRanked`):\n * - `type`: {@link ReferrerDetailTypeIds.Ranked}\n * - `referrer`: The `AwardedReferrerMetrics` from @namehash/ens-referrals\n * - `rules`: The referral program rules\n * - `aggregatedMetrics`: Aggregated metrics for all referrers on the leaderboard\n * - `accurateAsOf`: Unix timestamp indicating when the data was last updated\n *\n * **For referrers NOT on the leaderboard** (`ReferrerDetailUnranked`):\n * - `type`: {@link ReferrerDetailTypeIds.Unranked}\n * - `referrer`: The `UnrankedReferrerMetrics` from @namehash/ens-referrals\n * - `rules`: The referral program rules\n * - `aggregatedMetrics`: Aggregated metrics for all referrers on the leaderboard\n * - `accurateAsOf`: Unix timestamp indicating when the data was last updated\n *\n * @see {@link https://www.npmjs.com/package/@namehash/ens-referrals|@namehash/ens-referrals} for calculation details\n *\n * @param request The referrer address to query\n * @returns {ReferrerDetailResponse} Returns the referrer detail response\n *\n * @throws if the ENSNode request fails\n * @throws if the response data is malformed\n *\n * @example\n * ```typescript\n * // Get referrer detail for a specific address\n * const response = await client.getReferrerDetail({\n * referrer: \"0x1234567890123456789012345678901234567890\"\n * });\n * if (response.responseCode === ReferrerDetailResponseCodes.Ok) {\n * const { type, referrer, rules, aggregatedMetrics, accurateAsOf } = response.data;\n * console.log(type); // ReferrerDetailTypeIds.Ranked or ReferrerDetailTypeIds.Unranked\n * console.log(referrer);\n * console.log(accurateAsOf);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Use discriminated union to check if referrer is ranked\n * const response = await client.getReferrerDetail({\n * referrer: \"0x1234567890123456789012345678901234567890\"\n * });\n * if (response.responseCode === ReferrerDetailResponseCodes.Ok) {\n * if (response.data.type === ReferrerDetailTypeIds.Ranked) {\n * // TypeScript knows this is ReferrerDetailRanked\n * console.log(`Rank: ${response.data.referrer.rank}`);\n * console.log(`Qualified: ${response.data.referrer.isQualified}`);\n * console.log(`Award Pool Share: ${response.data.referrer.awardPoolShare * 100}%`);\n * } else {\n * // TypeScript knows this is ReferrerDetailUnranked\n * console.log(\"Referrer is not on the leaderboard (no referrals yet)\");\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Handle error response, ie. when Referrer Detail is not currently available.\n * const response = await client.getReferrerDetail({\n * referrer: \"0x1234567890123456789012345678901234567890\"\n * });\n *\n * if (response.responseCode === ReferrerDetailResponseCodes.Error) {\n * console.error(response.error);\n * console.error(response.errorMessage);\n * }\n * ```\n */\n async getReferrerDetail(request: ReferrerDetailRequest): Promise<ReferrerDetailResponse> {\n const url = new URL(\n `/api/ensanalytics/referrers/${encodeURIComponent(request.referrer)}`,\n this.options.url,\n );\n\n const response = await fetch(url);\n\n // ENSNode API should always allow parsing a response as JSON object.\n // If for some reason it's not the case, throw an error.\n let responseData: unknown;\n try {\n responseData = await response.json();\n } catch {\n throw new Error(\"Malformed response data: invalid JSON\");\n }\n\n // The API can return errors with 500 status, but they're still in the\n // ReferrerDetailResponse format with responseCode: 'error'\n // So we don't need to check response.ok here, just deserialize and let\n // the caller handle the responseCode\n\n return deserializeReferrerDetailResponse(responseData as SerializedReferrerDetailResponse);\n }\n}\n","import { isFiniteNonNegativeNumber } from \"./number\";\n\n/**\n * Represents a quantity of USD.\n *\n * @invariant Guaranteed to be a finite non-negative number (>= 0)\n */\nexport type USDQuantity = number;\n\nexport function isValidUSDQuantity(value: USDQuantity): boolean {\n return isFiniteNonNegativeNumber(value);\n}\n\nexport function validateUSDQuantity(value: USDQuantity): void {\n if (!isValidUSDQuantity(value)) {\n throw new Error(`Invalid USD quantity: ${value}.`);\n }\n}\n","import type { Address } from \"viem\";\n\nimport type { UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport { type AggregatedReferrerMetrics, buildAggregatedReferrerMetrics } from \"./aggregations\";\nimport {\n type AwardedReferrerMetrics,\n buildAwardedReferrerMetrics,\n buildRankedReferrerMetrics,\n buildScoredReferrerMetrics,\n type ReferrerMetrics,\n sortReferrerMetrics,\n} from \"./referrer-metrics\";\nimport type { ReferralProgramRules } from \"./rules\";\n\n/**\n * Represents a leaderboard for any number of referrers.\n */\nexport interface ReferrerLeaderboard {\n /**\n * The rules of the referral program that generated the {@link ReferrerLeaderboard}.\n */\n rules: ReferralProgramRules;\n\n /**\n * The {@link AggregatedReferrerMetrics} for all `RankedReferrerMetrics` values in `leaderboard`.\n */\n aggregatedMetrics: AggregatedReferrerMetrics;\n\n /**\n * Ordered map containing `AwardedReferrerMetrics` for all referrers with 1 or more\n * `totalReferrals` within the `rules` as of `updatedAt`.\n *\n * @invariant Map entries are ordered by `rank` (ascending).\n * @invariant Map is empty if there are no referrers with 1 or more `totalReferrals`\n * within the `rules` as of `updatedAt`.\n * @invariant If a fully-lowercase `Address` is not a key in this map then that `Address` had\n * 0 `totalReferrals`, `totalIncrementalDuration`, and `score` within the\n * `rules` as of `updatedAt`.\n * @invariant Each value in this map is guaranteed to have a non-zero\n * `totalReferrals`, `totalIncrementalDuration`, and `score`.\n */\n referrers: Map<Address, AwardedReferrerMetrics>;\n\n /**\n * The {@link UnixTimestamp} of when the data used to build the {@link ReferrerLeaderboard} was accurate as of.\n */\n accurateAsOf: UnixTimestamp;\n}\n\nexport const buildReferrerLeaderboard = (\n allReferrers: ReferrerMetrics[],\n rules: ReferralProgramRules,\n accurateAsOf: UnixTimestamp,\n): ReferrerLeaderboard => {\n const uniqueReferrers = allReferrers.map((referrer) => referrer.referrer);\n if (uniqueReferrers.length !== allReferrers.length) {\n throw new Error(\n \"ReferrerLeaderboard: Cannot buildReferrerLeaderboard containing duplicate referrers\",\n );\n }\n\n if (accurateAsOf < rules.startTime && allReferrers.length > 0) {\n throw new Error(\n `ReferrerLeaderboard: accurateAsOf (${accurateAsOf}) is before startTime (${rules.startTime}) which indicates allReferrers should be empty, but allReferrers is not empty.`,\n );\n }\n\n const sortedReferrers = sortReferrerMetrics(allReferrers);\n\n const scoredReferrers = sortedReferrers.map((referrer) => buildScoredReferrerMetrics(referrer));\n\n const rankedReferrers = scoredReferrers.map((referrer, index) => {\n return buildRankedReferrerMetrics(referrer, index + 1, rules);\n });\n\n const aggregatedMetrics = buildAggregatedReferrerMetrics(rankedReferrers, rules);\n\n const awardedReferrers = rankedReferrers.map((referrer) => {\n return buildAwardedReferrerMetrics(referrer, aggregatedMetrics, rules);\n });\n\n // Transform ordered list into an ordered map (preserves sort order)\n const referrers = new Map(\n awardedReferrers.map((referrer) => {\n return [referrer.referrer, referrer];\n }),\n );\n\n return {\n rules,\n aggregatedMetrics,\n referrers,\n accurateAsOf,\n };\n};\n","import { type Address, getAddress } from \"viem\";\n\n/**\n * Build a URL to the official ENS manager app\n * where the given {@link Address} is set as the referrer.\n */\nexport function buildEnsReferralUrl(address: Address): URL {\n const ensAppUrl = new URL(\"https://app.ens.domains\");\n\n ensAppUrl.searchParams.set(\"referrer\", getAddress(address));\n\n return ensAppUrl;\n}\n","import type { AccountId, UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport { type USDQuantity, validateUSDQuantity } from \"./currency\";\nimport { validateNonNegativeInteger } from \"./number\";\nimport { validateUnixTimestamp } from \"./time\";\n\n/**\n * Start date for the ENS Holiday Awards referral program.\n * 2025-12-01T00:00:00Z (December 1, 2025 at 00:00:00 UTC)\n */\nexport const ENS_HOLIDAY_AWARDS_START_DATE: UnixTimestamp = 1764547200;\n\n/**\n * End date for the ENS Holiday Awards referral program.\n * 2025-12-31T23:59:59Z (December 31, 2025 at 23:59:59 UTC)\n */\nexport const ENS_HOLIDAY_AWARDS_END_DATE: UnixTimestamp = 1767225599;\n\n/**\n * The maximum number of qualified referrers for ENS Holiday Awards.\n */\nexport const ENS_HOLIDAY_AWARDS_MAX_QUALIFIED_REFERRERS = 10;\n\n/**\n * The total value of the award pool in USD.\n */\nexport const ENS_HOLIDAY_AWARDS_TOTAL_AWARD_POOL_VALUE: USDQuantity = 10_000.0;\n\nexport interface ReferralProgramRules {\n /**\n * The total value of the award pool in USD.\n *\n * NOTE: Awards will actually be distributed in $ENS tokens.\n */\n totalAwardPoolValue: USDQuantity;\n\n /**\n * The maximum number of referrers that will qualify to receive a non-zero `awardPoolShare`.\n *\n * @invariant Guaranteed to be a non-negative integer (>= 0)\n */\n maxQualifiedReferrers: number;\n\n /**\n * The start time of the referral program.\n */\n startTime: UnixTimestamp;\n\n /**\n * The end time of the referral program.\n * @invariant Guaranteed to be greater than or equal to `startTime`\n */\n endTime: UnixTimestamp;\n\n /**\n * The account ID of the subregistry for the referral program.\n */\n subregistryId: AccountId;\n}\n\nexport const validateReferralProgramRules = (rules: ReferralProgramRules): void => {\n validateUSDQuantity(rules.totalAwardPoolValue);\n validateNonNegativeInteger(rules.maxQualifiedReferrers);\n validateUnixTimestamp(rules.startTime);\n validateUnixTimestamp(rules.endTime);\n\n if (rules.endTime < rules.startTime) {\n throw new Error(\n `ReferralProgramRules: startTime: ${rules.startTime} is after endTime: ${rules.endTime}.`,\n );\n }\n};\n\nexport const buildReferralProgramRules = (\n totalAwardPoolValue: USDQuantity,\n maxQualifiedReferrers: number,\n startTime: UnixTimestamp,\n endTime: UnixTimestamp,\n subregistryId: AccountId,\n): ReferralProgramRules => {\n const result = {\n totalAwardPoolValue,\n maxQualifiedReferrers,\n startTime,\n endTime,\n subregistryId,\n } satisfies ReferralProgramRules;\n\n validateReferralProgramRules(result);\n\n return result;\n};\n","import type { UnixTimestamp } from \"@ensnode/ensnode-sdk\";\n\nimport type { ReferralProgramRules } from \"./rules.ts\";\n\n/**\n * The type of referral program's status.\n */\nexport const ReferralProgramStatuses = {\n /**\n * Represents a referral program that has been announced, but hasn't started yet.\n */\n Scheduled: \"Scheduled\",\n\n /**\n * Represents a currently ongoing referral program.\n */\n Active: \"Active\",\n\n /**\n * Represents a referral program that has already ended.\n */\n Closed: \"Closed\",\n} as const;\n\n/**\n * The derived string union of possible {@link ReferralProgramStatuses}.\n */\nexport type ReferralProgramStatusId =\n (typeof ReferralProgramStatuses)[keyof typeof ReferralProgramStatuses];\n\n/**\n * Calculate the status of the referral program based on the current date\n * and program's timeframe available in its rules.\n *\n * @param referralProgramRules - Related referral program's rules containing\n * program's start date and end date.\n *\n * @param now - Current date in {@link UnixTimestamp} format.\n */\nexport const calcReferralProgramStatus = (\n referralProgramRules: ReferralProgramRules,\n now: UnixTimestamp,\n): ReferralProgramStatusId => {\n // if the program has not started return \"Scheduled\"\n if (now < referralProgramRules.startTime) return ReferralProgramStatuses.Scheduled;\n\n // if the program has ended return \"Closed\"\n if (now > referralProgramRules.endTime) return ReferralProgramStatuses.Closed;\n\n // otherwise, return \"Active\"\n return ReferralProgramStatuses.Active;\n};\n"],"mappings":"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","names":["z","CAIP2","name","regex","parameters","delimiter","values","CAIP10","AssetName","CAIP19AssetType","CAIP19AssetId","CAIP","assetName","assetType","assetId","splitParams","id","spec","split","getParams","arr","params","forEach","value","index","joinParams","Object","map","parameter","param","join","isValidId","RegExp","test","length","keys","matches","filter","x","ChainId","parse","namespace","reference","Error","toJSON","format","toString","AccountId","chainId","address","AssetType","AssetId","tokenId","isAddress","isAddress","z"]}