-
Notifications
You must be signed in to change notification settings - Fork 15
Referral Program Statuses #1621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0e75e14
0e76212
23a61a1
f6f6ae2
915eef2
fb7779a
bbf57b6
f590bdc
d281d2c
d2beb23
5e85c3d
549b11d
41b8056
013be95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| "@namehash/ens-referrals": minor | ||
| "ensapi": minor | ||
| --- | ||
|
|
||
| Added `status` field to referral program API responses (`ReferrerLeaderboardPage`, `ReferrerEditionMetricsRanked`, `ReferrerEditionMetricsUnranked`) indicating whether a program is "Scheduled", "Active", or "Closed" based on the program's timing relative to `accurateAsOf`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@ensnode/ensnode-sdk": minor | ||
| --- | ||
|
|
||
| SWRCache `fn` now optionally receives the currently cached result as a parameter, allowing implementations to inspect cached data before deciding whether to return it or fetch fresh data. Fully backward compatible. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "ensapi": minor | ||
| --- | ||
|
|
||
| Referral program edition leaderboard caches now check for immutability within the cache builder function. Closed editions past the safety window return cached data without re-fetching. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import type { ReferralProgramRules } from "@namehash/ens-referrals/v1"; | ||
| import { minutesToSeconds } from "date-fns"; | ||
|
|
||
| import { addDuration, type Duration, type UnixTimestamp } from "@ensnode/ensnode-sdk"; | ||
|
|
||
| /** | ||
| * Duration after which we assume a closed edition is safe from chain reorganizations. | ||
| * | ||
| * This is a heuristic value (10 minutes) chosen to provide a reasonable safety margin | ||
| * beyond typical Ethereum finality. It is not a guarantee of immutability. | ||
| */ | ||
| export const ASSUMED_CHAIN_REORG_SAFE_DURATION: Duration = minutesToSeconds(10); | ||
|
|
||
| /** | ||
| * Assumes a referral program edition is immutably closed if it ended more than | ||
| * ASSUMED_CHAIN_REORG_SAFE_DURATION ago. | ||
| * | ||
| * This is a practical heuristic for determining when edition data can be cached | ||
| * indefinitely, based on the assumption that chain reorgs become extremely unlikely | ||
| * after the safety window has passed. | ||
| * | ||
| * @param rules - The referral program rules containing endTime | ||
| * @param referenceTime - The timestamp to check against (typically accurateAsOf from cached leaderboard) | ||
| * @returns true if we assume the edition is immutably closed | ||
| */ | ||
| export function assumeReferralProgramEditionImmutablyClosed( | ||
| rules: ReferralProgramRules, | ||
| referenceTime: UnixTimestamp, | ||
| ): boolean { | ||
Goader marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const immutabilityThreshold = addDuration(rules.endTime, ASSUMED_CHAIN_REORG_SAFE_DURATION); | ||
| return referenceTime > immutabilityThreshold; | ||
Goader marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+28
to
+31
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Closeout check off-by-one |
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -28,6 +28,7 @@ import { | |||||||||||||||||||
| ReferrerEditionMetricsTypeIds, | ||||||||||||||||||||
| } from "../edition-metrics"; | ||||||||||||||||||||
| import { REFERRERS_PER_LEADERBOARD_PAGE_MAX } from "../leaderboard-page"; | ||||||||||||||||||||
| import { ReferralProgramStatuses } from "../status"; | ||||||||||||||||||||
| import { | ||||||||||||||||||||
| MAX_EDITIONS_PER_REQUEST, | ||||||||||||||||||||
| ReferralProgramEditionConfigSetResponseCodes, | ||||||||||||||||||||
|
|
@@ -140,6 +141,15 @@ export const makeReferrerLeaderboardPageContextSchema = ( | |||||||||||||||||||
| endIndex: z.optional(makeNonNegativeIntegerSchema(`${valueLabel}.endIndex`)), | ||||||||||||||||||||
| }); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** | ||||||||||||||||||||
| * Schema for referral program status field. | ||||||||||||||||||||
| * Validates that the status is one of: "Scheduled", "Active", or "Closed". | ||||||||||||||||||||
| */ | ||||||||||||||||||||
| export const makeReferralProgramStatusSchema = (valueLabel: string = "status") => | ||||||||||||||||||||
| z.enum(ReferralProgramStatuses, { | ||||||||||||||||||||
| message: `${valueLabel} must be "Scheduled", "Active", or "Closed"`, | ||||||||||||||||||||
|
Comment on lines
+149
to
+150
|
||||||||||||||||||||
| z.enum(ReferralProgramStatuses, { | |
| message: `${valueLabel} must be "Scheduled", "Active", or "Closed"`, | |
| z.nativeEnum(ReferralProgramStatuses, { | |
| errorMap: (issue, ctx) => { | |
| if (issue.code === z.ZodIssueCode.invalid_enum_value) { | |
| return { message: `${valueLabel} must be "Scheduled", "Active", or "Closed"` }; | |
| } | |
| return { message: ctx.defaultError }; | |
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CodeRabbit says it's ok, nativeEnum seems to only work with TypeScript's enums.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest reviewing how we define Zod schemas for other enum values. For example: https://github.com/namehash/ensnode/blob/main/packages/ponder-sdk/src/deserialize/indexing-metrics.ts#L77 and then repeating those patterns here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
z.enum passed object
makeReferralProgramStatusSchema calls z.enum(ReferralProgramStatuses, ...), but z.enum expects a tuple/array of string literals (or you should use z.nativeEnum for an enum-like object). Passing an object here will throw at runtime or fail typing depending on Zod version. Fix by using z.nativeEnum(ReferralProgramStatuses) or z.enum(["Scheduled","Active","Closed"] as const).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment for
ASSUMED_CHAIN_REORG_SAFE_DURATIONreferences "typical Ethereum finality", but this helper is keyed offrules.subregistryId.chainIdand may apply to non-Ethereum chains/L2s as well. Consider making the wording chain-agnostic (e.g., "typical chain finality") or explicitly scoping this heuristic to the supported chains.