@namehash/ens-referrals 1.0.1 → 1.1.0

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.cjs CHANGED
@@ -23,55 +23,530 @@ __export(index_exports, {
23
23
  ENCODED_REFERRER_BYTE_LENGTH: () => ENCODED_REFERRER_BYTE_LENGTH,
24
24
  ENCODED_REFERRER_BYTE_OFFSET: () => ENCODED_REFERRER_BYTE_OFFSET,
25
25
  ENS_HOLIDAY_AWARDS_END_DATE: () => ENS_HOLIDAY_AWARDS_END_DATE,
26
+ ENS_HOLIDAY_AWARDS_MAX_QUALIFIED_REFERRERS: () => ENS_HOLIDAY_AWARDS_MAX_QUALIFIED_REFERRERS,
26
27
  ENS_HOLIDAY_AWARDS_START_DATE: () => ENS_HOLIDAY_AWARDS_START_DATE,
28
+ ENS_HOLIDAY_AWARDS_TOTAL_AWARD_POOL_VALUE: () => ENS_HOLIDAY_AWARDS_TOTAL_AWARD_POOL_VALUE,
29
+ EXPECTED_ENCODED_REFERRER_PADDING: () => EXPECTED_ENCODED_REFERRER_PADDING,
30
+ REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT: () => REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT,
31
+ REFERRERS_PER_LEADERBOARD_PAGE_MAX: () => REFERRERS_PER_LEADERBOARD_PAGE_MAX,
32
+ SECONDS_PER_YEAR: () => SECONDS_PER_YEAR,
33
+ ZERO_ENCODED_REFERRER: () => ZERO_ENCODED_REFERRER,
34
+ buildAggregatedReferrerMetrics: () => buildAggregatedReferrerMetrics,
35
+ buildAwardedReferrerMetrics: () => buildAwardedReferrerMetrics,
27
36
  buildEncodedReferrer: () => buildEncodedReferrer,
28
37
  buildEnsReferralUrl: () => buildEnsReferralUrl,
38
+ buildRankedReferrerMetrics: () => buildRankedReferrerMetrics,
39
+ buildReferralProgramRules: () => buildReferralProgramRules,
40
+ buildReferrerLeaderboard: () => buildReferrerLeaderboard,
41
+ buildReferrerLeaderboardPaginationContext: () => buildReferrerLeaderboardPaginationContext,
42
+ buildReferrerLeaderboardPaginationParams: () => buildReferrerLeaderboardPaginationParams,
43
+ buildReferrerMetrics: () => buildReferrerMetrics,
44
+ buildScoredReferrerMetrics: () => buildScoredReferrerMetrics,
45
+ calcReferrerAwardPoolShare: () => calcReferrerAwardPoolShare,
46
+ calcReferrerFinalScore: () => calcReferrerFinalScore,
47
+ calcReferrerFinalScoreBoost: () => calcReferrerFinalScoreBoost,
48
+ calcReferrerFinalScoreMultiplier: () => calcReferrerFinalScoreMultiplier,
49
+ calcReferrerScore: () => calcReferrerScore,
50
+ compareReferrerMetrics: () => compareReferrerMetrics,
29
51
  decodeEncodedReferrer: () => decodeEncodedReferrer,
30
- encodedReferrerPadding: () => encodedReferrerPadding,
31
- zeroEncodedReferrer: () => zeroEncodedReferrer
52
+ getReferrerLeaderboardPage: () => getReferrerLeaderboardPage,
53
+ isFiniteNonNegativeNumber: () => isFiniteNonNegativeNumber,
54
+ isInteger: () => isInteger,
55
+ isNonNegativeInteger: () => isNonNegativeInteger,
56
+ isPositiveInteger: () => isPositiveInteger,
57
+ isReferrerQualified: () => isReferrerQualified,
58
+ isValidDuration: () => isValidDuration,
59
+ isValidReferrerScore: () => isValidReferrerScore,
60
+ isValidUSDQuantity: () => isValidUSDQuantity,
61
+ normalizeAddress: () => normalizeAddress,
62
+ sortReferrerMetrics: () => sortReferrerMetrics,
63
+ validateAggregatedReferrerMetrics: () => validateAggregatedReferrerMetrics,
64
+ validateAwardedReferrerMetrics: () => validateAwardedReferrerMetrics,
65
+ validateDuration: () => validateDuration,
66
+ validateLowercaseAddress: () => validateLowercaseAddress,
67
+ validateNonNegativeInteger: () => validateNonNegativeInteger,
68
+ validateRankedReferrerMetrics: () => validateRankedReferrerMetrics,
69
+ validateReferralProgramRules: () => validateReferralProgramRules,
70
+ validateReferrerLeaderboardPaginationContext: () => validateReferrerLeaderboardPaginationContext,
71
+ validateReferrerMetrics: () => validateReferrerMetrics,
72
+ validateReferrerRank: () => validateReferrerRank,
73
+ validateReferrerScore: () => validateReferrerScore,
74
+ validateScoredReferrerMetrics: () => validateScoredReferrerMetrics,
75
+ validateUSDQuantity: () => validateUSDQuantity,
76
+ validateUnixTimestamp: () => validateUnixTimestamp
32
77
  });
33
78
  module.exports = __toCommonJS(index_exports);
34
79
 
35
- // src/constants.ts
36
- var ENS_HOLIDAY_AWARDS_START_DATE = 1764547200;
37
- var ENS_HOLIDAY_AWARDS_END_DATE = 1767225599;
38
-
39
- // src/referrer.ts
80
+ // src/address.ts
40
81
  var import_viem = require("viem");
82
+ var validateLowercaseAddress = (address) => {
83
+ if (!(0, import_viem.isAddress)(address, { strict: false })) {
84
+ throw new Error(`Invalid address: ${address}. Address must be a valid EVM address.`);
85
+ }
86
+ if (address !== address.toLowerCase()) {
87
+ throw new Error(`Invalid address: ${address}. Address must be in lowercase format.`);
88
+ }
89
+ };
90
+ var normalizeAddress = (address) => {
91
+ return address.toLowerCase();
92
+ };
93
+
94
+ // src/number.ts
95
+ var isInteger = (value) => {
96
+ return Number.isInteger(value);
97
+ };
98
+ var isNonNegativeInteger = (value) => {
99
+ return value >= 0 && Number.isInteger(value);
100
+ };
101
+ var isPositiveInteger = (value) => {
102
+ return value >= 1 && Number.isInteger(value);
103
+ };
104
+ var validateNonNegativeInteger = (value) => {
105
+ if (!isNonNegativeInteger(value)) {
106
+ throw new Error(`Invalid non-negative integer: ${value}.`);
107
+ }
108
+ };
109
+ var isFiniteNonNegativeNumber = (value) => {
110
+ return value >= 0 && Number.isFinite(value);
111
+ };
112
+
113
+ // src/time.ts
114
+ var validateUnixTimestamp = (timestamp) => {
115
+ if (!isInteger(timestamp)) {
116
+ throw new Error(`Invalid Unix timestamp: ${timestamp}. Unix timestamp must be an integer.`);
117
+ }
118
+ };
119
+ var SECONDS_PER_YEAR = 31556952;
120
+ function isValidDuration(duration) {
121
+ return isNonNegativeInteger(duration);
122
+ }
123
+ function validateDuration(duration) {
124
+ if (!isValidDuration(duration)) {
125
+ throw new Error(`Invalid duration: ${duration}. Duration must be a non-negative integer.`);
126
+ }
127
+ }
128
+
129
+ // src/score.ts
130
+ var isValidReferrerScore = (score) => {
131
+ return score >= 0 && Number.isFinite(score);
132
+ };
133
+ var validateReferrerScore = (score) => {
134
+ if (!isValidReferrerScore(score)) {
135
+ throw new Error(
136
+ `Invalid referrer score: ${score}. Referrer score must be a finite non-negative number.`
137
+ );
138
+ }
139
+ };
140
+ var calcReferrerScore = (totalIncrementalDuration) => {
141
+ return totalIncrementalDuration / SECONDS_PER_YEAR;
142
+ };
143
+
144
+ // src/aggregations.ts
145
+ var validateAggregatedReferrerMetrics = (metrics) => {
146
+ validateNonNegativeInteger(metrics.grandTotalReferrals);
147
+ validateDuration(metrics.grandTotalIncrementalDuration);
148
+ validateReferrerScore(metrics.grandTotalQualifiedReferrersFinalScore);
149
+ validateReferrerScore(metrics.minFinalScoreToQualify);
150
+ };
151
+ var buildAggregatedReferrerMetrics = (referrers, rules) => {
152
+ let grandTotalReferrals = 0;
153
+ let grandTotalIncrementalDuration = 0;
154
+ let grandTotalQualifiedReferrersFinalScore = 0;
155
+ let minFinalScoreToQualify = Number.MAX_SAFE_INTEGER;
156
+ for (const referrer of referrers) {
157
+ grandTotalReferrals += referrer.totalReferrals;
158
+ grandTotalIncrementalDuration += referrer.totalIncrementalDuration;
159
+ if (referrer.isQualified) {
160
+ grandTotalQualifiedReferrersFinalScore += referrer.finalScore;
161
+ if (referrer.finalScore < minFinalScoreToQualify) {
162
+ minFinalScoreToQualify = referrer.finalScore;
163
+ }
164
+ }
165
+ }
166
+ if (minFinalScoreToQualify === Number.MAX_SAFE_INTEGER) {
167
+ if (rules.maxQualifiedReferrers === 0) {
168
+ } else {
169
+ if (referrers.length !== 0) {
170
+ throw new Error(
171
+ "AggregatedReferrerMetrics: There are referrers on the leaderboard, and the rules allow for qualified referrers, but no qualified referrers."
172
+ );
173
+ }
174
+ minFinalScoreToQualify = 0;
175
+ }
176
+ }
177
+ const result = {
178
+ grandTotalReferrals,
179
+ grandTotalIncrementalDuration,
180
+ grandTotalQualifiedReferrersFinalScore,
181
+ minFinalScoreToQualify
182
+ };
183
+ validateAggregatedReferrerMetrics(result);
184
+ return result;
185
+ };
186
+
187
+ // src/currency.ts
188
+ function isValidUSDQuantity(value) {
189
+ return isFiniteNonNegativeNumber(value);
190
+ }
191
+ function validateUSDQuantity(value) {
192
+ if (!isValidUSDQuantity(value)) {
193
+ throw new Error(`Invalid USD quantity: ${value}.`);
194
+ }
195
+ }
196
+
197
+ // src/encoding.ts
198
+ var import_viem2 = require("viem");
41
199
  var ENCODED_REFERRER_BYTE_OFFSET = 12;
42
200
  var ENCODED_REFERRER_BYTE_LENGTH = 32;
43
- var encodedReferrerPadding = (0, import_viem.pad)("0x", {
201
+ var EXPECTED_ENCODED_REFERRER_PADDING = (0, import_viem2.pad)("0x", {
44
202
  size: ENCODED_REFERRER_BYTE_OFFSET,
45
203
  dir: "left"
46
204
  });
47
- var zeroEncodedReferrer = (0, import_viem.pad)("0x", {
205
+ var ZERO_ENCODED_REFERRER = (0, import_viem2.pad)("0x", {
48
206
  size: ENCODED_REFERRER_BYTE_LENGTH,
49
207
  dir: "left"
50
208
  });
51
209
  function buildEncodedReferrer(address) {
52
210
  const lowercaseAddress = address.toLowerCase();
53
- return (0, import_viem.pad)(lowercaseAddress, { size: ENCODED_REFERRER_BYTE_LENGTH, dir: "left" });
211
+ return (0, import_viem2.pad)(lowercaseAddress, { size: ENCODED_REFERRER_BYTE_LENGTH, dir: "left" });
54
212
  }
55
213
  function decodeEncodedReferrer(encodedReferrer) {
56
- if ((0, import_viem.size)(encodedReferrer) !== ENCODED_REFERRER_BYTE_LENGTH) {
214
+ if ((0, import_viem2.size)(encodedReferrer) !== ENCODED_REFERRER_BYTE_LENGTH) {
57
215
  throw new Error(
58
216
  `Encoded referrer value must be represented by ${ENCODED_REFERRER_BYTE_LENGTH} bytes.`
59
217
  );
60
218
  }
61
- const padding = (0, import_viem.slice)(encodedReferrer, 0, ENCODED_REFERRER_BYTE_OFFSET);
62
- if (padding !== encodedReferrerPadding) {
63
- return import_viem.zeroAddress;
219
+ const padding = (0, import_viem2.slice)(encodedReferrer, 0, ENCODED_REFERRER_BYTE_OFFSET);
220
+ if (padding !== EXPECTED_ENCODED_REFERRER_PADDING) {
221
+ return import_viem2.zeroAddress;
64
222
  }
65
- const decodedReferrer = (0, import_viem.slice)(encodedReferrer, ENCODED_REFERRER_BYTE_OFFSET);
223
+ const decodedReferrer = (0, import_viem2.slice)(encodedReferrer, ENCODED_REFERRER_BYTE_OFFSET);
66
224
  try {
67
- return (0, import_viem.getAddress)(decodedReferrer);
225
+ return (0, import_viem2.getAddress)(decodedReferrer);
68
226
  } catch {
69
227
  throw new Error(`Decoded referrer value must be a valid EVM address.`);
70
228
  }
71
229
  }
230
+
231
+ // src/rank.ts
232
+ var validateReferrerRank = (rank) => {
233
+ if (!isPositiveInteger(rank)) {
234
+ throw new Error(`Invalid ReferrerRank: ${rank}. ReferrerRank must be a positive integer.`);
235
+ }
236
+ };
237
+ function isReferrerQualified(rank, rules) {
238
+ return rank <= rules.maxQualifiedReferrers;
239
+ }
240
+ function calcReferrerFinalScoreBoost(rank, rules) {
241
+ if (!isReferrerQualified(rank, rules)) return 0;
242
+ return 1 - (rank - 1) / (rules.maxQualifiedReferrers - 1);
243
+ }
244
+ function calcReferrerFinalScoreMultiplier(rank, rules) {
245
+ return 1 + calcReferrerFinalScoreBoost(rank, rules);
246
+ }
247
+ function calcReferrerFinalScore(rank, totalIncrementalDuration, rules) {
248
+ return calcReferrerScore(totalIncrementalDuration) * calcReferrerFinalScoreMultiplier(rank, rules);
249
+ }
250
+ var compareReferrerMetrics = (a, b) => {
251
+ if (a.totalIncrementalDuration !== b.totalIncrementalDuration) {
252
+ return b.totalIncrementalDuration - a.totalIncrementalDuration;
253
+ }
254
+ if (b.referrer > a.referrer) return 1;
255
+ if (b.referrer < a.referrer) return -1;
256
+ return 0;
257
+ };
258
+
259
+ // src/referrer-metrics.ts
260
+ var buildReferrerMetrics = (referrer, totalReferrals, totalIncrementalDuration) => {
261
+ const result = {
262
+ referrer: normalizeAddress(referrer),
263
+ totalReferrals,
264
+ totalIncrementalDuration
265
+ };
266
+ validateReferrerMetrics(result);
267
+ return result;
268
+ };
269
+ var validateReferrerMetrics = (metrics) => {
270
+ validateLowercaseAddress(metrics.referrer);
271
+ validateNonNegativeInteger(metrics.totalReferrals);
272
+ validateDuration(metrics.totalIncrementalDuration);
273
+ };
274
+ var sortReferrerMetrics = (referrers) => {
275
+ return [...referrers].sort(compareReferrerMetrics);
276
+ };
277
+ var buildScoredReferrerMetrics = (referrer) => {
278
+ const result = {
279
+ ...referrer,
280
+ score: calcReferrerScore(referrer.totalIncrementalDuration)
281
+ };
282
+ validateScoredReferrerMetrics(result);
283
+ return result;
284
+ };
285
+ var validateScoredReferrerMetrics = (metrics) => {
286
+ validateReferrerMetrics(metrics);
287
+ validateReferrerScore(metrics.score);
288
+ const expectedScore = calcReferrerScore(metrics.totalIncrementalDuration);
289
+ if (metrics.score !== expectedScore) {
290
+ throw new Error(`Referrer: Invalid score: ${metrics.score}, expected: ${expectedScore}.`);
291
+ }
292
+ };
293
+ var validateRankedReferrerMetrics = (metrics, rules) => {
294
+ validateScoredReferrerMetrics(metrics);
295
+ validateReferrerRank(metrics.rank);
296
+ if (metrics.finalScoreBoost < 0 || metrics.finalScoreBoost > 1) {
297
+ throw new Error(
298
+ `Invalid RankedReferrerMetrics: Invalid finalScoreBoost: ${metrics.finalScoreBoost}. finalScoreBoost must be between 0 and 1 (inclusive).`
299
+ );
300
+ }
301
+ validateReferrerScore(metrics.finalScore);
302
+ const expectedIsQualified = isReferrerQualified(metrics.rank, rules);
303
+ if (metrics.isQualified !== expectedIsQualified) {
304
+ throw new Error(
305
+ `RankedReferrerMetrics: Invalid isQualified: ${metrics.isQualified}, expected: ${expectedIsQualified}.`
306
+ );
307
+ }
308
+ const expectedFinalScoreBoost = calcReferrerFinalScoreBoost(metrics.rank, rules);
309
+ if (metrics.finalScoreBoost !== expectedFinalScoreBoost) {
310
+ throw new Error(
311
+ `RankedReferrerMetrics: Invalid finalScoreBoost: ${metrics.finalScoreBoost}, expected: ${expectedFinalScoreBoost}.`
312
+ );
313
+ }
314
+ const expectedFinalScore = calcReferrerFinalScore(
315
+ metrics.rank,
316
+ metrics.totalIncrementalDuration,
317
+ rules
318
+ );
319
+ if (metrics.finalScore !== expectedFinalScore) {
320
+ throw new Error(
321
+ `RankedReferrerMetrics: Invalid finalScore: ${metrics.finalScore}, expected: ${expectedFinalScore}.`
322
+ );
323
+ }
324
+ };
325
+ var buildRankedReferrerMetrics = (referrer, rank, rules) => {
326
+ const result = {
327
+ ...referrer,
328
+ rank,
329
+ isQualified: isReferrerQualified(rank, rules),
330
+ finalScoreBoost: calcReferrerFinalScoreBoost(rank, rules),
331
+ finalScore: calcReferrerFinalScore(rank, referrer.totalIncrementalDuration, rules)
332
+ };
333
+ validateRankedReferrerMetrics(result, rules);
334
+ return result;
335
+ };
336
+ var calcReferrerAwardPoolShare = (referrer, aggregatedMetrics, rules) => {
337
+ if (!isReferrerQualified(referrer.rank, rules)) return 0;
338
+ if (aggregatedMetrics.grandTotalQualifiedReferrersFinalScore === 0) return 0;
339
+ return calcReferrerFinalScore(referrer.rank, referrer.totalIncrementalDuration, rules) / aggregatedMetrics.grandTotalQualifiedReferrersFinalScore;
340
+ };
341
+ var validateAwardedReferrerMetrics = (referrer, rules) => {
342
+ validateRankedReferrerMetrics(referrer, rules);
343
+ if (referrer.awardPoolShare < 0 || referrer.awardPoolShare > 1) {
344
+ throw new Error(
345
+ `Invalid AwardedReferrerMetrics: ${referrer.awardPoolShare}. awardPoolShare must be between 0 and 1 (inclusive).`
346
+ );
347
+ }
348
+ if (referrer.awardPoolApproxValue < 0 || referrer.awardPoolApproxValue > rules.totalAwardPoolValue) {
349
+ throw new Error(
350
+ `Invalid AwardedReferrerMetrics: ${referrer.awardPoolApproxValue}. awardPoolApproxValue must be between 0 and ${rules.totalAwardPoolValue} (inclusive).`
351
+ );
352
+ }
353
+ };
354
+ var buildAwardedReferrerMetrics = (referrer, aggregatedMetrics, rules) => {
355
+ const awardPoolShare = calcReferrerAwardPoolShare(referrer, aggregatedMetrics, rules);
356
+ const result = {
357
+ ...referrer,
358
+ awardPoolShare,
359
+ awardPoolApproxValue: awardPoolShare * rules.totalAwardPoolValue
360
+ };
361
+ validateAwardedReferrerMetrics(result, rules);
362
+ return result;
363
+ };
364
+
365
+ // src/leaderboard.ts
366
+ var buildReferrerLeaderboard = (allReferrers, rules, accurateAsOf) => {
367
+ const uniqueReferrers = allReferrers.map((referrer) => referrer.referrer);
368
+ if (uniqueReferrers.length !== allReferrers.length) {
369
+ throw new Error(
370
+ "ReferrerLeaderboard: Cannot buildReferrerLeaderboard containing duplicate referrers"
371
+ );
372
+ }
373
+ if (accurateAsOf < rules.startTime && allReferrers.length > 0) {
374
+ throw new Error(
375
+ `ReferrerLeaderboard: accurateAsOf (${accurateAsOf}) is before startTime (${rules.startTime}) which indicates allReferrers should be empty, but allReferrers is not empty.`
376
+ );
377
+ }
378
+ const sortedReferrers = sortReferrerMetrics(allReferrers);
379
+ const scoredReferrers = sortedReferrers.map((referrer) => buildScoredReferrerMetrics(referrer));
380
+ const rankedReferrers = scoredReferrers.map((referrer, index) => {
381
+ return buildRankedReferrerMetrics(referrer, index + 1, rules);
382
+ });
383
+ const aggregatedMetrics = buildAggregatedReferrerMetrics(rankedReferrers, rules);
384
+ const awardedReferrers = rankedReferrers.map((referrer) => {
385
+ return buildAwardedReferrerMetrics(referrer, aggregatedMetrics, rules);
386
+ });
387
+ const referrers = new Map(
388
+ awardedReferrers.map((referrer) => {
389
+ return [referrer.referrer, referrer];
390
+ })
391
+ );
392
+ return {
393
+ rules,
394
+ aggregatedMetrics,
395
+ referrers,
396
+ accurateAsOf
397
+ };
398
+ };
399
+
400
+ // src/leaderboard-page.ts
401
+ var REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT = 25;
402
+ var REFERRERS_PER_LEADERBOARD_PAGE_MAX = 100;
403
+ var validateReferrerLeaderboardPaginationParams = (params) => {
404
+ if (params.page !== void 0 && !isPositiveInteger(params.page)) {
405
+ throw new Error(
406
+ `Invalid ReferrerLeaderboardPaginationParams: ${params.page}. page must be a positive integer.`
407
+ );
408
+ }
409
+ if (params.itemsPerPage !== void 0 && !isPositiveInteger(params.itemsPerPage)) {
410
+ throw new Error(
411
+ `Invalid ReferrerLeaderboardPaginationParams: ${params.itemsPerPage}. itemsPerPage must be a positive integer.`
412
+ );
413
+ }
414
+ if (params.itemsPerPage !== void 0 && params.itemsPerPage > REFERRERS_PER_LEADERBOARD_PAGE_MAX) {
415
+ throw new Error(
416
+ `Invalid ReferrerLeaderboardPaginationParams: ${params.itemsPerPage}. itemsPerPage must be less than or equal to ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}.`
417
+ );
418
+ }
419
+ };
420
+ var buildReferrerLeaderboardPaginationParams = (params) => {
421
+ const result = {
422
+ page: params.page ?? 1,
423
+ itemsPerPage: params.itemsPerPage ?? REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT
424
+ };
425
+ validateReferrerLeaderboardPaginationParams(result);
426
+ return result;
427
+ };
428
+ var validateReferrerLeaderboardPaginationContext = (context) => {
429
+ validateReferrerLeaderboardPaginationParams(context);
430
+ if (!isNonNegativeInteger(context.totalRecords)) {
431
+ throw new Error(
432
+ `Invalid ReferrerLeaderboardPaginationContext: total must be a non-negative integer but is ${context.totalRecords}.`
433
+ );
434
+ }
435
+ const startIndex = (context.page - 1) * context.itemsPerPage;
436
+ const endIndex = startIndex + context.itemsPerPage;
437
+ if (!context.hasNext && endIndex < context.totalRecords) {
438
+ throw new Error(
439
+ `Invalid ReferrerLeaderboardPaginationContext: if hasNext is false, endIndex (${endIndex}) must be greater than or equal to total (${context.totalRecords}).`
440
+ );
441
+ } else if (context.hasNext && context.page * context.itemsPerPage >= context.totalRecords) {
442
+ throw new Error(
443
+ `Invalid ReferrerLeaderboardPaginationContext: if hasNext is true, endIndex (${endIndex}) must be less than total (${context.totalRecords}).`
444
+ );
445
+ }
446
+ if (!context.hasPrev && context.page !== 1) {
447
+ throw new Error(
448
+ `Invalid ReferrerLeaderboardPaginationContext: if hasPrev is false, page must be the first page (1) but is ${context.page}.`
449
+ );
450
+ } else if (context.hasPrev && context.page === 1) {
451
+ throw new Error(
452
+ `Invalid ReferrerLeaderboardPaginationContext: if hasPrev is true, page must not be the first page (1) but is ${context.page}.`
453
+ );
454
+ }
455
+ };
456
+ var buildReferrerLeaderboardPaginationContext = (optionalParams, leaderboard) => {
457
+ const materializedParams = buildReferrerLeaderboardPaginationParams(optionalParams);
458
+ const totalRecords = leaderboard.referrers.size;
459
+ const totalPages = Math.max(1, Math.ceil(totalRecords / materializedParams.itemsPerPage));
460
+ if (materializedParams.page > totalPages) {
461
+ throw new Error(
462
+ `Invalid ReferrerLeaderboardPaginationContext: page ${materializedParams.page} exceeds total pages ${totalPages}.`
463
+ );
464
+ }
465
+ if (totalRecords === 0) {
466
+ return {
467
+ ...materializedParams,
468
+ totalRecords: 0,
469
+ totalPages: 1,
470
+ hasNext: false,
471
+ hasPrev: false,
472
+ startIndex: void 0,
473
+ endIndex: void 0
474
+ };
475
+ }
476
+ const startIndex = (materializedParams.page - 1) * materializedParams.itemsPerPage;
477
+ const maxTheoreticalIndexOnPage = startIndex + (materializedParams.itemsPerPage - 1);
478
+ const endIndex = Math.min(maxTheoreticalIndexOnPage, totalRecords - 1);
479
+ const hasNext = maxTheoreticalIndexOnPage < totalRecords;
480
+ const hasPrev = materializedParams.page > 1;
481
+ const result = {
482
+ ...materializedParams,
483
+ totalRecords,
484
+ totalPages,
485
+ hasNext,
486
+ hasPrev,
487
+ startIndex,
488
+ endIndex
489
+ };
490
+ validateReferrerLeaderboardPaginationContext(result);
491
+ return result;
492
+ };
493
+ var getReferrerLeaderboardPage = (paginationParams, leaderboard) => {
494
+ const paginationContext = buildReferrerLeaderboardPaginationContext(
495
+ paginationParams,
496
+ leaderboard
497
+ );
498
+ let referrers;
499
+ if (paginationContext.totalRecords > 0 && typeof paginationContext.startIndex !== "undefined" && typeof paginationContext.endIndex !== "undefined") {
500
+ referrers = Array.from(leaderboard.referrers.values()).slice(
501
+ paginationContext.startIndex,
502
+ paginationContext.endIndex + 1
503
+ // For `slice`, this is exclusive of the element at the index 'end'. We need it to be inclusive, hence plus one.
504
+ );
505
+ } else {
506
+ referrers = [];
507
+ }
508
+ return {
509
+ rules: leaderboard.rules,
510
+ referrers,
511
+ aggregatedMetrics: leaderboard.aggregatedMetrics,
512
+ paginationContext,
513
+ accurateAsOf: leaderboard.accurateAsOf
514
+ };
515
+ };
516
+
517
+ // src/link.ts
518
+ var import_viem3 = require("viem");
72
519
  function buildEnsReferralUrl(address) {
73
520
  const ensAppUrl = new URL("https://app.ens.domains");
74
- ensAppUrl.searchParams.set("referrer", (0, import_viem.getAddress)(address));
521
+ ensAppUrl.searchParams.set("referrer", (0, import_viem3.getAddress)(address));
75
522
  return ensAppUrl;
76
523
  }
524
+
525
+ // src/rules.ts
526
+ var ENS_HOLIDAY_AWARDS_START_DATE = 1764547200;
527
+ var ENS_HOLIDAY_AWARDS_END_DATE = 1767225599;
528
+ var ENS_HOLIDAY_AWARDS_MAX_QUALIFIED_REFERRERS = 10;
529
+ var ENS_HOLIDAY_AWARDS_TOTAL_AWARD_POOL_VALUE = 1e4;
530
+ var validateReferralProgramRules = (rules) => {
531
+ validateUSDQuantity(rules.totalAwardPoolValue);
532
+ validateNonNegativeInteger(rules.maxQualifiedReferrers);
533
+ validateUnixTimestamp(rules.startTime);
534
+ validateUnixTimestamp(rules.endTime);
535
+ if (rules.endTime < rules.startTime) {
536
+ throw new Error(
537
+ `ReferralProgramRules: startTime: ${rules.startTime} is after endTime: ${rules.endTime}.`
538
+ );
539
+ }
540
+ };
541
+ var buildReferralProgramRules = (totalAwardPoolValue, maxQualifiedReferrers, startTime, endTime, subregistryId) => {
542
+ const result = {
543
+ totalAwardPoolValue,
544
+ maxQualifiedReferrers,
545
+ startTime,
546
+ endTime,
547
+ subregistryId
548
+ };
549
+ validateReferralProgramRules(result);
550
+ return result;
551
+ };
77
552
  //# sourceMappingURL=index.cjs.map