@namehash/ens-referrals 1.9.0 → 1.10.1

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 CHANGED
@@ -1,132 +1,16 @@
1
1
  // src/address.ts
2
- import { isAddress } from "viem";
3
- var validateLowercaseAddress = (address) => {
4
- if (!isAddress(address, { strict: false })) {
5
- throw new Error(`Invalid address: ${address}. Address must be a valid EVM address.`);
2
+ import { isNormalizedAddress } from "enssdk";
3
+ var validateNormalizedAddress = (address) => {
4
+ if (!isNormalizedAddress(address)) {
5
+ throw new Error(`Invalid address: '${address}'. Address must be a lowercase EVM Address.`);
6
6
  }
7
- if (address !== address.toLowerCase()) {
8
- throw new Error(`Invalid address: ${address}. Address must be in lowercase format.`);
9
- }
10
- };
11
- var normalizeAddress = (address) => {
12
- return address.toLowerCase();
13
- };
14
-
15
- // src/number.ts
16
- var isInteger = (value) => {
17
- return Number.isInteger(value);
18
- };
19
- var isNonNegativeInteger = (value) => {
20
- return value >= 0 && Number.isInteger(value);
21
- };
22
- var isPositiveInteger = (value) => {
23
- return value >= 1 && Number.isInteger(value);
24
- };
25
- var validateNonNegativeInteger = (value) => {
26
- if (!isNonNegativeInteger(value)) {
27
- throw new Error(`Invalid non-negative integer: ${value}.`);
28
- }
29
- };
30
- var isFiniteNonNegativeNumber = (value) => {
31
- return value >= 0 && Number.isFinite(value);
32
- };
33
-
34
- // src/revenue-contribution.ts
35
- function isValidRevenueContribution(value) {
36
- return typeof value === "bigint" && value >= 0n;
37
- }
38
- function validateRevenueContribution(value) {
39
- if (typeof value !== "bigint") {
40
- throw new Error(`Invalid revenue contribution: must be a bigint, got: ${typeof value}`);
41
- }
42
- if (value < 0n) {
43
- throw new Error(`Invalid revenue contribution: must be non-negative, got: ${value.toString()}`);
44
- }
45
- }
46
-
47
- // src/time.ts
48
- var validateUnixTimestamp = (timestamp) => {
49
- if (!isInteger(timestamp)) {
50
- throw new Error(`Invalid Unix timestamp: ${timestamp}. Unix timestamp must be an integer.`);
51
- }
52
- };
53
- var SECONDS_PER_YEAR = 31556952;
54
- function isValidDuration(duration) {
55
- return isNonNegativeInteger(duration);
56
- }
57
- function validateDuration(duration) {
58
- if (!isValidDuration(duration)) {
59
- throw new Error(`Invalid duration: ${duration}. Duration must be a non-negative integer.`);
60
- }
61
- }
62
-
63
- // src/score.ts
64
- var isValidReferrerScore = (score) => {
65
- return score >= 0 && Number.isFinite(score);
66
- };
67
- var validateReferrerScore = (score) => {
68
- if (!isValidReferrerScore(score)) {
69
- throw new Error(
70
- `Invalid referrer score: ${score}. Referrer score must be a finite non-negative number.`
71
- );
72
- }
73
- };
74
- var calcReferrerScore = (totalIncrementalDuration) => {
75
- return totalIncrementalDuration / SECONDS_PER_YEAR;
76
- };
77
-
78
- // src/aggregations.ts
79
- var validateAggregatedReferrerMetrics = (metrics) => {
80
- validateNonNegativeInteger(metrics.grandTotalReferrals);
81
- validateDuration(metrics.grandTotalIncrementalDuration);
82
- validateRevenueContribution(metrics.grandTotalRevenueContribution);
83
- validateReferrerScore(metrics.grandTotalQualifiedReferrersFinalScore);
84
- validateReferrerScore(metrics.minFinalScoreToQualify);
85
- };
86
- var buildAggregatedReferrerMetrics = (referrers, rules) => {
87
- let grandTotalReferrals = 0;
88
- let grandTotalIncrementalDuration = 0;
89
- let grandTotalRevenueContribution = 0n;
90
- let grandTotalQualifiedReferrersFinalScore = 0;
91
- let minFinalScoreToQualify = Number.MAX_SAFE_INTEGER;
92
- for (const referrer of referrers) {
93
- grandTotalReferrals += referrer.totalReferrals;
94
- grandTotalIncrementalDuration += referrer.totalIncrementalDuration;
95
- grandTotalRevenueContribution += referrer.totalRevenueContribution;
96
- if (referrer.isQualified) {
97
- grandTotalQualifiedReferrersFinalScore += referrer.finalScore;
98
- if (referrer.finalScore < minFinalScoreToQualify) {
99
- minFinalScoreToQualify = referrer.finalScore;
100
- }
101
- }
102
- }
103
- if (minFinalScoreToQualify === Number.MAX_SAFE_INTEGER) {
104
- if (rules.maxQualifiedReferrers === 0) {
105
- } else {
106
- if (referrers.length !== 0) {
107
- throw new Error(
108
- "AggregatedReferrerMetrics: There are referrers on the leaderboard, and the rules allow for qualified referrers, but no qualified referrers."
109
- );
110
- }
111
- minFinalScoreToQualify = 0;
112
- }
113
- }
114
- const result = {
115
- grandTotalReferrals,
116
- grandTotalIncrementalDuration,
117
- grandTotalRevenueContribution,
118
- grandTotalQualifiedReferrersFinalScore,
119
- minFinalScoreToQualify
120
- };
121
- validateAggregatedReferrerMetrics(result);
122
- return result;
123
7
  };
124
8
 
125
9
  // src/api/deserialize.ts
126
10
  import { prettifyError } from "zod/v4";
127
11
 
128
12
  // src/api/zod-schemas.ts
129
- import { z as z2 } from "zod/v4";
13
+ import z5 from "zod/v4";
130
14
 
131
15
  // ../../node_modules/.pnpm/caip@1.1.1/node_modules/caip/dist/index.mjs
132
16
  function _extends() {
@@ -428,12 +312,123 @@ var AssetId = /* @__PURE__ */ (function() {
428
312
  AssetId.spec = CAIP["19"].assetId;
429
313
 
430
314
  // ../ensnode-sdk/src/shared/zod-schemas.ts
431
- import { isAddress as isAddress2, isHex, size } from "viem";
315
+ import { reinterpretName, toNormalizedAddress } from "enssdk";
316
+ import { isAddress, isHex, size } from "viem";
432
317
  import { z } from "zod/v4";
433
318
 
434
- // ../ensnode-sdk/src/shared/address.ts
435
- function asLowerCaseAddress(address) {
436
- return address.toLowerCase();
319
+ // ../ensnode-sdk/src/shared/currencies.ts
320
+ import { parseUnits } from "viem";
321
+
322
+ // ../ensnode-sdk/src/shared/numbers.ts
323
+ function scaleBigintByNumber(value, scaleFactor) {
324
+ if (value < 0n) {
325
+ throw new Error(`scaleBigintByNumber: value must be non-negative, got: ${value.toString()}`);
326
+ }
327
+ if (!Number.isFinite(scaleFactor)) {
328
+ throw new Error(
329
+ `scaleBigintByNumber: scaleFactor must be a finite number, got: ${scaleFactor}`
330
+ );
331
+ }
332
+ if (scaleFactor < 0) {
333
+ throw new Error(`scaleBigintByNumber: scaleFactor must be non-negative, got: ${scaleFactor}`);
334
+ }
335
+ if (scaleFactor >= 1e21) {
336
+ throw new Error(`scaleBigintByNumber: scaleFactor must be less than 1e21, got: ${scaleFactor}`);
337
+ }
338
+ if (value === 0n || scaleFactor === 0) {
339
+ return 0n;
340
+ }
341
+ if (scaleFactor === 1) {
342
+ return value;
343
+ }
344
+ const fixedStr = scaleFactor.toFixed(20);
345
+ const [integerPart, decimalPart = ""] = fixedStr.split(".");
346
+ const trimmedDecimal = decimalPart.replace(/0+$/, "") || "0";
347
+ const numerator = BigInt(integerPart + trimmedDecimal);
348
+ const denominator = 10n ** BigInt(trimmedDecimal.length);
349
+ return value * numerator / denominator;
350
+ }
351
+
352
+ // ../ensnode-sdk/src/shared/currencies.ts
353
+ var CurrencyIds = {
354
+ ETH: "ETH",
355
+ USDC: "USDC",
356
+ DAI: "DAI"
357
+ };
358
+ var currencyInfo = {
359
+ [CurrencyIds.ETH]: {
360
+ id: CurrencyIds.ETH,
361
+ name: "ETH",
362
+ decimals: 18
363
+ },
364
+ [CurrencyIds.USDC]: {
365
+ id: CurrencyIds.USDC,
366
+ name: "USDC",
367
+ decimals: 6
368
+ },
369
+ [CurrencyIds.DAI]: {
370
+ id: CurrencyIds.DAI,
371
+ name: "Dai Stablecoin",
372
+ decimals: 18
373
+ }
374
+ };
375
+ function priceEth(amount) {
376
+ return {
377
+ amount,
378
+ currency: CurrencyIds.ETH
379
+ };
380
+ }
381
+ function priceUsdc(amount) {
382
+ return {
383
+ amount,
384
+ currency: CurrencyIds.USDC
385
+ };
386
+ }
387
+ function isPriceCurrencyEqual(priceA, priceB) {
388
+ return priceA.currency === priceB.currency;
389
+ }
390
+ function addPrices(...prices) {
391
+ const firstPrice = prices[0];
392
+ const allPricesInSameCurrency = prices.every((price) => isPriceCurrencyEqual(firstPrice, price));
393
+ if (allPricesInSameCurrency === false) {
394
+ throw new Error("All prices must have the same currency to be added together.");
395
+ }
396
+ const { currency } = firstPrice;
397
+ return prices.reduce(
398
+ (acc, price) => ({
399
+ amount: acc.amount + price.amount,
400
+ currency
401
+ }),
402
+ {
403
+ amount: 0n,
404
+ currency: firstPrice.currency
405
+ }
406
+ );
407
+ }
408
+ function subtractPrice(a, b) {
409
+ if (!isPriceCurrencyEqual(a, b)) {
410
+ throw new Error("All prices must have the same currency to be subtracted.");
411
+ }
412
+ const resultAmount = a.amount - b.amount;
413
+ if (resultAmount < 0n) {
414
+ throw new Error("subtractPrice result must be non-negative.");
415
+ }
416
+ return { amount: resultAmount, currency: a.currency };
417
+ }
418
+ function minPrice(...prices) {
419
+ const firstPrice = prices[0];
420
+ const allPricesInSameCurrency = prices.every((price) => isPriceCurrencyEqual(firstPrice, price));
421
+ if (allPricesInSameCurrency === false) {
422
+ throw new Error("All prices must have the same currency to be compared.");
423
+ }
424
+ return prices.reduce((acc, price) => price.amount < acc.amount ? price : acc);
425
+ }
426
+ function scalePrice(price, scaleFactor) {
427
+ const scaledAmount = scaleBigintByNumber(price.amount, scaleFactor);
428
+ return {
429
+ ...price,
430
+ amount: scaledAmount
431
+ };
437
432
  }
438
433
 
439
434
  // ../ensnode-sdk/src/shared/zod-schemas.ts
@@ -457,22 +452,78 @@ var makeDurationSchema = (valueLabel = "Value") => z.number({
457
452
  error: `${valueLabel} must be a number.`
458
453
  }).pipe(makeNonNegativeIntegerSchema(valueLabel));
459
454
  var makeChainIdSchema = (valueLabel = "Chain ID") => makePositiveIntegerSchema(valueLabel).transform((val) => val);
460
- var makeLowercaseAddressSchema = (valueLabel = "EVM address") => z.string().check((ctx) => {
461
- if (!isAddress2(ctx.value)) {
455
+ var makeNormalizedAddressSchema = (valueLabel = "EVM address") => z.string().check((ctx) => {
456
+ if (!isAddress(ctx.value, { strict: false })) {
462
457
  ctx.issues.push({
463
458
  code: "custom",
464
459
  message: `${valueLabel} must be a valid EVM address`,
465
460
  input: ctx.value
466
461
  });
467
462
  }
468
- }).transform((val) => asLowerCaseAddress(val));
463
+ }).transform((val) => toNormalizedAddress(val));
469
464
  var makeUnixTimestampSchema = (valueLabel = "Timestamp") => makeIntegerSchema(valueLabel);
465
+ var makeUrlSchema = (valueLabel = "Value") => z.url({
466
+ error: `${valueLabel} must be a valid URL string (e.g., http://localhost:8080 or https://example.com).`,
467
+ abort: true
468
+ }).transform((v) => new URL(v));
469
+ var makePriceAmountSchema = (valueLabel = "Amount") => z.coerce.bigint({
470
+ error: `${valueLabel} must represent a bigint.`
471
+ }).nonnegative({
472
+ error: `${valueLabel} must not be negative.`
473
+ });
474
+ var makePriceCurrencySchema = (currency, valueLabel = "Price Currency") => z.strictObject({
475
+ amount: makePriceAmountSchema(`${valueLabel} amount`),
476
+ currency: z.literal(currency, {
477
+ error: `${valueLabel} currency must be set to '${currency}'.`
478
+ })
479
+ });
480
+ var makePriceEthSchema = (valueLabel = "Price ETH") => makePriceCurrencySchema(CurrencyIds.ETH, valueLabel).transform((v) => v);
481
+ var makePriceUsdcSchema = (valueLabel = "Price USDC") => makePriceCurrencySchema(CurrencyIds.USDC, valueLabel).transform((v) => v);
470
482
  var makeAccountIdSchema = (valueLabel = "AccountId") => z.strictObject({
471
483
  chainId: makeChainIdSchema(`${valueLabel} chain ID`),
472
- address: makeLowercaseAddressSchema(`${valueLabel} address`)
484
+ address: makeNormalizedAddressSchema(`${valueLabel} address`)
473
485
  });
474
486
 
475
- // src/leaderboard-page.ts
487
+ // ../ensnode-sdk/src/shared/serialize.ts
488
+ function serializePrice(price) {
489
+ return {
490
+ currency: price.currency,
491
+ amount: price.amount.toString()
492
+ };
493
+ }
494
+ function serializePriceEth(price) {
495
+ return serializePrice(price);
496
+ }
497
+ function serializePriceUsdc(price) {
498
+ return serializePrice(price);
499
+ }
500
+
501
+ // src/award-models/pie-split/api/zod-schemas.ts
502
+ import z3 from "zod/v4";
503
+
504
+ // src/award-models/shared/api/zod-schemas.ts
505
+ import z2 from "zod/v4";
506
+
507
+ // src/number.ts
508
+ var isInteger = (value) => {
509
+ return Number.isInteger(value);
510
+ };
511
+ var isNonNegativeInteger = (value) => {
512
+ return value >= 0 && Number.isInteger(value);
513
+ };
514
+ var isPositiveInteger = (value) => {
515
+ return value >= 1 && Number.isInteger(value);
516
+ };
517
+ var validateNonNegativeInteger = (value) => {
518
+ if (!isNonNegativeInteger(value)) {
519
+ throw new Error(`Invalid non-negative integer: ${value}.`);
520
+ }
521
+ };
522
+ var isFiniteNonNegativeNumber = (value) => {
523
+ return value >= 0 && Number.isFinite(value);
524
+ };
525
+
526
+ // src/award-models/shared/leaderboard-page.ts
476
527
  var REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT = 25;
477
528
  var REFERRERS_PER_LEADERBOARD_PAGE_MAX = 100;
478
529
  var validateReferrerLeaderboardPageParams = (params) => {
@@ -504,18 +555,67 @@ var validateReferrerLeaderboardPageContext = (context) => {
504
555
  validateReferrerLeaderboardPageParams(context);
505
556
  if (!isNonNegativeInteger(context.totalRecords)) {
506
557
  throw new Error(
507
- `Invalid ReferrerLeaderboardPageContext: total must be a non-negative integer but is ${context.totalRecords}.`
558
+ `Invalid ReferrerLeaderboardPageContext: totalRecords must be a non-negative integer but is ${context.totalRecords}.`
559
+ );
560
+ }
561
+ if (!isPositiveInteger(context.totalPages)) {
562
+ throw new Error(
563
+ `Invalid ReferrerLeaderboardPageContext: totalPages must be a positive integer (>= 1) but is ${context.totalPages}.`
564
+ );
565
+ }
566
+ const expectedTotalPages = context.totalRecords === 0 ? 1 : Math.ceil(context.totalRecords / context.recordsPerPage);
567
+ if (context.totalPages !== expectedTotalPages) {
568
+ throw new Error(
569
+ `Invalid ReferrerLeaderboardPageContext: totalPages is ${context.totalPages} but expected ${expectedTotalPages} based on totalRecords (${context.totalRecords}) and recordsPerPage (${context.recordsPerPage}).`
570
+ );
571
+ }
572
+ if (context.page > context.totalPages) {
573
+ throw new Error(
574
+ `Invalid ReferrerLeaderboardPageContext: page ${context.page} exceeds totalPages ${context.totalPages}.`
508
575
  );
509
576
  }
577
+ const expectedStartIndex = (context.page - 1) * context.recordsPerPage;
578
+ const expectedEndIndex = Math.min(
579
+ expectedStartIndex + context.recordsPerPage - 1,
580
+ context.totalRecords - 1
581
+ );
582
+ if (context.totalRecords === 0) {
583
+ if (context.startIndex !== void 0) {
584
+ throw new Error(
585
+ `Invalid ReferrerLeaderboardPageContext: startIndex must be undefined when totalRecords is 0 but is ${context.startIndex}.`
586
+ );
587
+ }
588
+ if (context.endIndex !== void 0) {
589
+ throw new Error(
590
+ `Invalid ReferrerLeaderboardPageContext: endIndex must be undefined when totalRecords is 0 but is ${context.endIndex}.`
591
+ );
592
+ }
593
+ } else {
594
+ if (context.startIndex !== expectedStartIndex) {
595
+ throw new Error(
596
+ `Invalid ReferrerLeaderboardPageContext: startIndex is ${context.startIndex} but expected ${expectedStartIndex} based on page (${context.page}) and recordsPerPage (${context.recordsPerPage}).`
597
+ );
598
+ }
599
+ if (context.endIndex !== expectedEndIndex) {
600
+ throw new Error(
601
+ `Invalid ReferrerLeaderboardPageContext: endIndex is ${context.endIndex} but expected ${expectedEndIndex} based on startIndex (${expectedStartIndex}), recordsPerPage (${context.recordsPerPage}), and totalRecords (${context.totalRecords}).`
602
+ );
603
+ }
604
+ if (typeof context.endIndex !== "undefined" && typeof context.startIndex !== "undefined" && context.endIndex < context.startIndex) {
605
+ throw new Error(
606
+ `Invalid ReferrerLeaderboardPageContext: endIndex (${context.endIndex}) must be greater than or equal to startIndex (${context.startIndex}).`
607
+ );
608
+ }
609
+ }
510
610
  const startIndex = (context.page - 1) * context.recordsPerPage;
511
611
  const endIndex = startIndex + context.recordsPerPage;
512
612
  if (!context.hasNext && endIndex < context.totalRecords) {
513
613
  throw new Error(
514
- `Invalid ReferrerLeaderboardPageContext: if hasNext is false, endIndex (${endIndex}) must be greater than or equal to total (${context.totalRecords}).`
614
+ `Invalid ReferrerLeaderboardPageContext: if hasNext is false, endIndex (${endIndex}) must be greater than or equal to totalRecords (${context.totalRecords}).`
515
615
  );
516
616
  } else if (context.hasNext && context.page * context.recordsPerPage >= context.totalRecords) {
517
617
  throw new Error(
518
- `Invalid ReferrerLeaderboardPageContext: if hasNext is true, endIndex (${endIndex}) must be less than total (${context.totalRecords}).`
618
+ `Invalid ReferrerLeaderboardPageContext: if hasNext is true, endIndex (${endIndex}) must be less than totalRecords (${context.totalRecords}).`
519
619
  );
520
620
  }
521
621
  if (!context.hasPrev && context.page !== 1) {
@@ -565,59 +665,1373 @@ var buildReferrerLeaderboardPageContext = (optionalParams, leaderboard) => {
565
665
  validateReferrerLeaderboardPageContext(result);
566
666
  return result;
567
667
  };
568
- var getReferrerLeaderboardPage = (pageParams, leaderboard) => {
569
- const pageContext = buildReferrerLeaderboardPageContext(pageParams, leaderboard);
570
- let referrers;
571
- if (pageContext.totalRecords > 0 && typeof pageContext.startIndex !== "undefined" && typeof pageContext.endIndex !== "undefined") {
572
- referrers = Array.from(leaderboard.referrers.values()).slice(
573
- pageContext.startIndex,
574
- pageContext.endIndex + 1
575
- // For `slice`, this is exclusive of the element at the index 'end'. We need it to be inclusive, hence plus one.
576
- );
577
- } else {
578
- referrers = [];
668
+ function sliceReferrers(referrers, pageContext) {
669
+ if (pageContext.totalRecords === 0 || pageContext.startIndex === void 0 || pageContext.endIndex === void 0) {
670
+ return [];
579
671
  }
580
- return {
581
- rules: leaderboard.rules,
582
- referrers,
583
- aggregatedMetrics: leaderboard.aggregatedMetrics,
584
- pageContext,
585
- accurateAsOf: leaderboard.accurateAsOf
586
- };
672
+ const all = [...referrers.values()];
673
+ return all.slice(pageContext.startIndex, pageContext.endIndex + 1);
674
+ }
675
+
676
+ // src/award-models/shared/status.ts
677
+ var ReferralProgramEditionStatuses = {
678
+ /**
679
+ * Represents a referral program edition that has been announced, but hasn't started yet.
680
+ */
681
+ Scheduled: "Scheduled",
682
+ /**
683
+ * Represents a currently ongoing referral program edition.
684
+ */
685
+ Active: "Active",
686
+ /**
687
+ * Represents a referral program edition that is still within its active window
688
+ * but whose award pool has been fully consumed.
689
+ *
690
+ * @note Not all award models may support this status.
691
+ */
692
+ Exhausted: "Exhausted",
693
+ /**
694
+ * Represents a referral program edition that has passed its end time but whose awards have not yet
695
+ * been distributed. The edition is in a review window before full closure.
696
+ *
697
+ * Transitions to {@link ReferralProgramEditionStatuses.Closed} once `areAwardsDistributed` is set to `true`.
698
+ */
699
+ AwardsReview: "AwardsReview",
700
+ /**
701
+ * Represents a referral program edition that has already ended and whose awards have been distributed.
702
+ */
703
+ Closed: "Closed"
704
+ };
705
+ var calcBaseReferralProgramEditionStatus = (rules, now) => {
706
+ if (now < rules.startTime) return ReferralProgramEditionStatuses.Scheduled;
707
+ if (now > rules.endTime)
708
+ return rules.areAwardsDistributed ? ReferralProgramEditionStatuses.Closed : ReferralProgramEditionStatuses.AwardsReview;
709
+ return ReferralProgramEditionStatuses.Active;
587
710
  };
588
711
 
589
- // src/rank.ts
590
- var validateReferrerRank = (rank) => {
591
- if (!isPositiveInteger(rank)) {
592
- throw new Error(`Invalid ReferrerRank: ${rank}. ReferrerRank must be a positive integer.`);
712
+ // src/award-models/shared/api/zod-schemas.ts
713
+ var makeBaseReferralProgramRulesSchema = (valueLabel) => z2.object({
714
+ awardModel: z2.string(),
715
+ startTime: makeUnixTimestampSchema(`${valueLabel}.startTime`),
716
+ endTime: makeUnixTimestampSchema(`${valueLabel}.endTime`),
717
+ subregistryId: makeAccountIdSchema(`${valueLabel}.subregistryId`),
718
+ rulesUrl: makeUrlSchema(`${valueLabel}.rulesUrl`),
719
+ areAwardsDistributed: z2.boolean()
720
+ }).refine((data) => data.endTime >= data.startTime, {
721
+ message: `${valueLabel}.endTime must be >= ${valueLabel}.startTime`,
722
+ path: ["endTime"]
723
+ });
724
+ var makeReferrerLeaderboardPageContextSchema = (valueLabel = "ReferrerLeaderboardPageContext") => z2.object({
725
+ page: makePositiveIntegerSchema(`${valueLabel}.page`),
726
+ recordsPerPage: makePositiveIntegerSchema(`${valueLabel}.recordsPerPage`).max(
727
+ REFERRERS_PER_LEADERBOARD_PAGE_MAX,
728
+ `${valueLabel}.recordsPerPage must not exceed ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}`
729
+ ),
730
+ totalRecords: makeNonNegativeIntegerSchema(`${valueLabel}.totalRecords`),
731
+ totalPages: makePositiveIntegerSchema(`${valueLabel}.totalPages`),
732
+ hasNext: z2.boolean(),
733
+ hasPrev: z2.boolean(),
734
+ startIndex: z2.optional(makeNonNegativeIntegerSchema(`${valueLabel}.startIndex`)),
735
+ endIndex: z2.optional(makeNonNegativeIntegerSchema(`${valueLabel}.endIndex`))
736
+ });
737
+ var makeReferralProgramStatusSchema = (_valueLabel = "status") => z2.enum(ReferralProgramEditionStatuses);
738
+ var makeBaseReferralProgramEditionSummarySchema = (valueLabel) => z2.object({
739
+ awardModel: z2.string(),
740
+ slug: z2.string().min(1, `${valueLabel}.slug must not be empty`),
741
+ displayName: z2.string().min(1, `${valueLabel}.displayName must not be empty`),
742
+ status: makeReferralProgramStatusSchema(`${valueLabel}.status`),
743
+ rules: makeBaseReferralProgramRulesSchema(`${valueLabel}.rules`)
744
+ });
745
+ var makeBaseReferrerLeaderboardPageSchema = (valueLabel) => z2.object({
746
+ awardModel: z2.string(),
747
+ pageContext: makeReferrerLeaderboardPageContextSchema(`${valueLabel}.pageContext`),
748
+ status: makeReferralProgramStatusSchema(`${valueLabel}.status`),
749
+ accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
750
+ });
751
+
752
+ // src/award-models/shared/edition-metrics.ts
753
+ var ReferrerEditionMetricsTypeIds = {
754
+ /**
755
+ * Represents a referrer who is ranked on the leaderboard.
756
+ */
757
+ Ranked: "ranked",
758
+ /**
759
+ * Represents a referrer who is not ranked on the leaderboard.
760
+ */
761
+ Unranked: "unranked"
762
+ };
763
+
764
+ // src/time.ts
765
+ var validateUnixTimestamp = (timestamp) => {
766
+ if (!isInteger(timestamp)) {
767
+ throw new Error(`Invalid Unix timestamp: ${timestamp}. Unix timestamp must be an integer.`);
593
768
  }
594
769
  };
595
- function isReferrerQualified(rank, rules) {
596
- return rank <= rules.maxQualifiedReferrers;
597
- }
598
- function calcReferrerFinalScoreBoost(rank, rules) {
599
- if (!isReferrerQualified(rank, rules)) return 0;
600
- return 1 - (rank - 1) / (rules.maxQualifiedReferrers - 1);
601
- }
602
- function calcReferrerFinalScoreMultiplier(rank, rules) {
603
- return 1 + calcReferrerFinalScoreBoost(rank, rules);
604
- }
605
- function calcReferrerFinalScore(rank, totalIncrementalDuration, rules) {
606
- return calcReferrerScore(totalIncrementalDuration) * calcReferrerFinalScoreMultiplier(rank, rules);
770
+ var SECONDS_PER_YEAR = 31556952;
771
+ function isValidDuration(duration) {
772
+ return isNonNegativeInteger(duration);
607
773
  }
608
- var compareReferrerMetrics = (a, b) => {
609
- if (a.totalIncrementalDuration !== b.totalIncrementalDuration) {
610
- return b.totalIncrementalDuration - a.totalIncrementalDuration;
774
+ function validateDuration(duration) {
775
+ if (!isValidDuration(duration)) {
776
+ throw new Error(`Invalid duration: ${duration}. Duration must be a non-negative integer.`);
777
+ }
778
+ }
779
+
780
+ // src/award-models/shared/rules.ts
781
+ var ReferralProgramAwardModels = {
782
+ PieSplit: "pie-split",
783
+ RevShareCap: "rev-share-cap",
784
+ Unrecognized: "unrecognized"
785
+ };
786
+ var validateBaseReferralProgramRules = (rules) => {
787
+ makeAccountIdSchema("BaseReferralProgramRules.subregistryId").parse(rules.subregistryId);
788
+ validateUnixTimestamp(rules.startTime);
789
+ validateUnixTimestamp(rules.endTime);
790
+ if (!(rules.rulesUrl instanceof URL)) {
791
+ throw new Error(
792
+ `BaseReferralProgramRules: rulesUrl must be a URL instance, got ${typeof rules.rulesUrl}.`
793
+ );
794
+ }
795
+ if (rules.endTime < rules.startTime) {
796
+ throw new Error(
797
+ `BaseReferralProgramRules: startTime: ${rules.startTime} is after endTime: ${rules.endTime}.`
798
+ );
799
+ }
800
+ };
801
+
802
+ // src/award-models/pie-split/api/zod-schemas.ts
803
+ var makeReferralProgramRulesPieSplitSchema = (valueLabel = "ReferralProgramRulesPieSplit") => makeBaseReferralProgramRulesSchema(valueLabel).safeExtend({
804
+ awardModel: z3.literal(ReferralProgramAwardModels.PieSplit),
805
+ awardPool: makePriceUsdcSchema(`${valueLabel}.awardPool`),
806
+ maxQualifiedReferrers: makeNonNegativeIntegerSchema(`${valueLabel}.maxQualifiedReferrers`)
807
+ });
808
+ var makeAwardedReferrerMetricsPieSplitSchema = (valueLabel = "AwardedReferrerMetricsPieSplit") => z3.object({
809
+ referrer: makeNormalizedAddressSchema(`${valueLabel}.referrer`),
810
+ totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),
811
+ totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),
812
+ totalRevenueContribution: makePriceEthSchema(`${valueLabel}.totalRevenueContribution`),
813
+ score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),
814
+ rank: makePositiveIntegerSchema(`${valueLabel}.rank`),
815
+ isQualified: z3.boolean(),
816
+ finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(
817
+ 1,
818
+ `${valueLabel}.finalScoreBoost must be <= 1`
819
+ ),
820
+ finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),
821
+ awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(
822
+ 1,
823
+ `${valueLabel}.awardPoolShare must be <= 1`
824
+ ),
825
+ awardPoolApproxValue: makePriceUsdcSchema(`${valueLabel}.awardPoolApproxValue`)
826
+ });
827
+ var makeUnrankedReferrerMetricsPieSplitSchema = (valueLabel = "UnrankedReferrerMetricsPieSplit") => z3.object({
828
+ referrer: makeNormalizedAddressSchema(`${valueLabel}.referrer`),
829
+ totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),
830
+ totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),
831
+ totalRevenueContribution: makePriceEthSchema(`${valueLabel}.totalRevenueContribution`),
832
+ score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),
833
+ rank: z3.null(),
834
+ isQualified: z3.literal(false),
835
+ finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(
836
+ 1,
837
+ `${valueLabel}.finalScoreBoost must be <= 1`
838
+ ),
839
+ finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),
840
+ awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(
841
+ 1,
842
+ `${valueLabel}.awardPoolShare must be <= 1`
843
+ ),
844
+ awardPoolApproxValue: makePriceUsdcSchema(`${valueLabel}.awardPoolApproxValue`)
845
+ });
846
+ var makeAggregatedReferrerMetricsPieSplitSchema = (valueLabel = "AggregatedReferrerMetricsPieSplit") => z3.object({
847
+ grandTotalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.grandTotalReferrals`),
848
+ grandTotalIncrementalDuration: makeDurationSchema(
849
+ `${valueLabel}.grandTotalIncrementalDuration`
850
+ ),
851
+ grandTotalRevenueContribution: makePriceEthSchema(
852
+ `${valueLabel}.grandTotalRevenueContribution`
853
+ ),
854
+ grandTotalQualifiedReferrersFinalScore: makeFiniteNonNegativeNumberSchema(
855
+ `${valueLabel}.grandTotalQualifiedReferrersFinalScore`
856
+ ),
857
+ minFinalScoreToQualify: makeFiniteNonNegativeNumberSchema(
858
+ `${valueLabel}.minFinalScoreToQualify`
859
+ )
860
+ });
861
+ var makeReferrerEditionMetricsRankedPieSplitSchema = (valueLabel = "ReferrerEditionMetricsRankedPieSplit") => z3.object({
862
+ awardModel: z3.literal(ReferralProgramAwardModels.PieSplit),
863
+ type: z3.literal(ReferrerEditionMetricsTypeIds.Ranked),
864
+ rules: makeReferralProgramRulesPieSplitSchema(`${valueLabel}.rules`),
865
+ referrer: makeAwardedReferrerMetricsPieSplitSchema(`${valueLabel}.referrer`),
866
+ aggregatedMetrics: makeAggregatedReferrerMetricsPieSplitSchema(
867
+ `${valueLabel}.aggregatedMetrics`
868
+ ),
869
+ status: makeReferralProgramStatusSchema(`${valueLabel}.status`),
870
+ accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
871
+ }).refine((data) => data.awardModel === data.rules.awardModel, {
872
+ message: `${valueLabel}.awardModel must equal ${valueLabel}.rules.awardModel`,
873
+ path: ["awardModel"]
874
+ });
875
+ var makeReferrerEditionMetricsUnrankedPieSplitSchema = (valueLabel = "ReferrerEditionMetricsUnrankedPieSplit") => z3.object({
876
+ awardModel: z3.literal(ReferralProgramAwardModels.PieSplit),
877
+ type: z3.literal(ReferrerEditionMetricsTypeIds.Unranked),
878
+ rules: makeReferralProgramRulesPieSplitSchema(`${valueLabel}.rules`),
879
+ referrer: makeUnrankedReferrerMetricsPieSplitSchema(`${valueLabel}.referrer`),
880
+ aggregatedMetrics: makeAggregatedReferrerMetricsPieSplitSchema(
881
+ `${valueLabel}.aggregatedMetrics`
882
+ ),
883
+ status: makeReferralProgramStatusSchema(`${valueLabel}.status`),
884
+ accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
885
+ }).refine((data) => data.awardModel === data.rules.awardModel, {
886
+ message: `${valueLabel}.awardModel must equal ${valueLabel}.rules.awardModel`,
887
+ path: ["awardModel"]
888
+ });
889
+ var makeReferrerEditionMetricsPieSplitSchema = (valueLabel = "ReferrerEditionMetricsPieSplit") => z3.discriminatedUnion("type", [
890
+ makeReferrerEditionMetricsRankedPieSplitSchema(valueLabel),
891
+ makeReferrerEditionMetricsUnrankedPieSplitSchema(valueLabel)
892
+ ]);
893
+ var makeReferralProgramEditionSummaryPieSplitSchema = (valueLabel = "ReferralProgramEditionSummaryPieSplit") => makeBaseReferralProgramEditionSummarySchema(valueLabel).safeExtend({
894
+ awardModel: z3.literal(ReferralProgramAwardModels.PieSplit),
895
+ rules: makeReferralProgramRulesPieSplitSchema(`${valueLabel}.rules`)
896
+ }).refine((data) => data.awardModel === data.rules.awardModel, {
897
+ message: `${valueLabel}.awardModel must equal ${valueLabel}.rules.awardModel`,
898
+ path: ["awardModel"]
899
+ });
900
+ var makeReferrerLeaderboardPagePieSplitSchema = (valueLabel = "ReferrerLeaderboardPagePieSplit") => makeBaseReferrerLeaderboardPageSchema(valueLabel).safeExtend({
901
+ awardModel: z3.literal(ReferralProgramAwardModels.PieSplit),
902
+ rules: makeReferralProgramRulesPieSplitSchema(`${valueLabel}.rules`),
903
+ referrers: z3.array(
904
+ makeAwardedReferrerMetricsPieSplitSchema(`${valueLabel}.referrers[record]`)
905
+ ),
906
+ aggregatedMetrics: makeAggregatedReferrerMetricsPieSplitSchema(
907
+ `${valueLabel}.aggregatedMetrics`
908
+ )
909
+ }).refine((data) => data.awardModel === data.rules.awardModel, {
910
+ message: `${valueLabel}.awardModel must equal ${valueLabel}.rules.awardModel`,
911
+ path: ["awardModel"]
912
+ });
913
+
914
+ // src/award-models/rev-share-cap/api/zod-schemas.ts
915
+ import z4 from "zod/v4";
916
+
917
+ // src/award-models/rev-share-cap/rules.ts
918
+ var AdminActionTypes = {
919
+ /**
920
+ * The referrer is disqualified for awards.
921
+ */
922
+ Disqualification: "Disqualification",
923
+ /**
924
+ * The referrer is warned about a potential disqualification but may still be qualified for awards.
925
+ */
926
+ Warning: "Warning"
927
+ };
928
+ var validateReferralProgramRulesRevShareCap = (rules) => {
929
+ if (rules.awardModel !== ReferralProgramAwardModels.RevShareCap) {
930
+ throw new Error(
931
+ `ReferralProgramRulesRevShareCap: awardModel must be "${ReferralProgramAwardModels.RevShareCap}", got "${rules.awardModel}".`
932
+ );
933
+ }
934
+ makePriceUsdcSchema("ReferralProgramRulesRevShareCap.awardPool").parse(rules.awardPool);
935
+ makePriceUsdcSchema("ReferralProgramRulesRevShareCap.minBaseRevenueContribution").parse(
936
+ rules.minBaseRevenueContribution
937
+ );
938
+ makePriceUsdcSchema("ReferralProgramRulesRevShareCap.baseAnnualRevenueContribution").parse(
939
+ rules.baseAnnualRevenueContribution
940
+ );
941
+ if (!Number.isFinite(rules.maxBaseRevenueShare) || rules.maxBaseRevenueShare < 0 || rules.maxBaseRevenueShare > 1) {
942
+ throw new Error(
943
+ `ReferralProgramRulesRevShareCap: maxBaseRevenueShare must be between 0 and 1 (inclusive), got ${rules.maxBaseRevenueShare}.`
944
+ );
945
+ }
946
+ for (const action of rules.adminActions) {
947
+ validateNormalizedAddress(action.referrer);
948
+ if (action.reason.trim().length === 0 || action.reason !== action.reason.trim()) {
949
+ throw new Error(
950
+ "ReferralProgramRulesRevShareCap: admin action reason must be a trimmed, non-empty string."
951
+ );
952
+ }
953
+ }
954
+ const adminActionAddresses = rules.adminActions.map((a) => a.referrer);
955
+ const uniqueAdminActionAddresses = new Set(adminActionAddresses);
956
+ if (uniqueAdminActionAddresses.size !== adminActionAddresses.length) {
957
+ throw new Error(
958
+ "ReferralProgramRulesRevShareCap: adminActions must not contain duplicate referrer addresses."
959
+ );
960
+ }
961
+ validateBaseReferralProgramRules(rules);
962
+ };
963
+ var buildReferralProgramRulesRevShareCap = (awardPool, minBaseRevenueContribution, baseAnnualRevenueContribution, maxBaseRevenueShare, startTime, endTime, subregistryId, rulesUrl, areAwardsDistributed, adminActions = []) => {
964
+ const result = {
965
+ awardModel: ReferralProgramAwardModels.RevShareCap,
966
+ awardPool,
967
+ minBaseRevenueContribution,
968
+ baseAnnualRevenueContribution,
969
+ maxBaseRevenueShare,
970
+ startTime,
971
+ endTime,
972
+ subregistryId,
973
+ rulesUrl,
974
+ areAwardsDistributed,
975
+ adminActions
976
+ };
977
+ validateReferralProgramRulesRevShareCap(result);
978
+ return result;
979
+ };
980
+ function calcBaseRevenueContribution(rules, duration) {
981
+ return priceUsdc(
982
+ rules.baseAnnualRevenueContribution.amount * BigInt(duration) / BigInt(SECONDS_PER_YEAR)
983
+ );
984
+ }
985
+ function isReferrerQualifiedRevShareCap(referrer, totalBaseRevenueContribution, rules) {
986
+ const isAdminDisqualified = rules.adminActions.some(
987
+ (a) => a.referrer === referrer && a.actionType === AdminActionTypes.Disqualification
988
+ );
989
+ return totalBaseRevenueContribution.amount >= rules.minBaseRevenueContribution.amount && !isAdminDisqualified;
990
+ }
991
+
992
+ // src/award-models/rev-share-cap/api/zod-schemas.ts
993
+ var makeAdminActionDisqualificationSchema = (valueLabel = "AdminActionDisqualification") => z4.object({
994
+ actionType: z4.literal(AdminActionTypes.Disqualification),
995
+ referrer: makeNormalizedAddressSchema(`${valueLabel}.referrer`),
996
+ reason: z4.string().trim().min(1, `${valueLabel}.reason must not be empty`)
997
+ });
998
+ var makeAdminActionWarningSchema = (valueLabel = "AdminActionWarning") => z4.object({
999
+ actionType: z4.literal(AdminActionTypes.Warning),
1000
+ referrer: makeNormalizedAddressSchema(`${valueLabel}.referrer`),
1001
+ reason: z4.string().trim().min(1, `${valueLabel}.reason must not be empty`)
1002
+ });
1003
+ var makeAdminActionSchema = (valueLabel = "AdminAction") => z4.discriminatedUnion("actionType", [
1004
+ makeAdminActionDisqualificationSchema(valueLabel),
1005
+ makeAdminActionWarningSchema(valueLabel)
1006
+ ]);
1007
+ var makeReferralProgramRulesRevShareCapSchema = (valueLabel = "ReferralProgramRulesRevShareCap") => makeBaseReferralProgramRulesSchema(valueLabel).safeExtend({
1008
+ awardModel: z4.literal(ReferralProgramAwardModels.RevShareCap),
1009
+ awardPool: makePriceUsdcSchema(`${valueLabel}.awardPool`),
1010
+ minBaseRevenueContribution: makePriceUsdcSchema(`${valueLabel}.minBaseRevenueContribution`),
1011
+ baseAnnualRevenueContribution: makePriceUsdcSchema(
1012
+ `${valueLabel}.baseAnnualRevenueContribution`
1013
+ ),
1014
+ maxBaseRevenueShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.maxBaseRevenueShare`).max(
1015
+ 1,
1016
+ `${valueLabel}.maxBaseRevenueShare must be <= 1`
1017
+ ),
1018
+ adminActions: z4.array(makeAdminActionSchema(`${valueLabel}.adminActions[item]`)).refine(
1019
+ (items) => {
1020
+ const referrers = items.map((a) => a.referrer);
1021
+ return new Set(referrers).size === referrers.length;
1022
+ },
1023
+ {
1024
+ message: `${valueLabel}.adminActions must not contain duplicate referrer addresses`
1025
+ }
1026
+ ).default([])
1027
+ });
1028
+ var makeAwardedReferrerMetricsRevShareCapSchema = (valueLabel = "AwardedReferrerMetricsRevShareCap") => z4.object({
1029
+ referrer: makeNormalizedAddressSchema(`${valueLabel}.referrer`),
1030
+ totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),
1031
+ totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),
1032
+ totalRevenueContribution: makePriceEthSchema(`${valueLabel}.totalRevenueContribution`),
1033
+ totalBaseRevenueContribution: makePriceUsdcSchema(
1034
+ `${valueLabel}.totalBaseRevenueContribution`
1035
+ ),
1036
+ rank: makePositiveIntegerSchema(`${valueLabel}.rank`),
1037
+ isQualified: z4.boolean(),
1038
+ uncappedAward: makePriceUsdcSchema(`${valueLabel}.uncappedAward`),
1039
+ cappedAward: makePriceUsdcSchema(`${valueLabel}.cappedAward`),
1040
+ adminAction: makeAdminActionSchema(`${valueLabel}.adminAction`).nullable()
1041
+ }).refine((data) => data.cappedAward.amount <= data.uncappedAward.amount, {
1042
+ message: `${valueLabel}.cappedAward must be <= ${valueLabel}.uncappedAward`,
1043
+ path: ["cappedAward"]
1044
+ }).refine(
1045
+ (data) => data.adminAction?.actionType !== AdminActionTypes.Disqualification || data.isQualified === false && data.cappedAward.amount === 0n,
1046
+ {
1047
+ message: `When ${valueLabel}.adminAction.actionType is Disqualification, isQualified must be false and cappedAward.amount must be 0`,
1048
+ path: ["adminAction"]
1049
+ }
1050
+ ).refine((data) => data.isQualified || data.cappedAward.amount === 0n, {
1051
+ message: `${valueLabel}.cappedAward must be 0 when isQualified is false`,
1052
+ path: ["cappedAward"]
1053
+ }).refine((data) => data.adminAction === null || data.adminAction.referrer === data.referrer, {
1054
+ message: `${valueLabel}.adminAction.referrer must match ${valueLabel}.referrer`,
1055
+ path: ["adminAction", "referrer"]
1056
+ });
1057
+ var makeUnrankedReferrerMetricsRevShareCapSchema = (valueLabel = "UnrankedReferrerMetricsRevShareCap") => z4.object({
1058
+ referrer: makeNormalizedAddressSchema(`${valueLabel}.referrer`),
1059
+ totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),
1060
+ totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),
1061
+ totalRevenueContribution: makePriceEthSchema(`${valueLabel}.totalRevenueContribution`),
1062
+ totalBaseRevenueContribution: makePriceUsdcSchema(
1063
+ `${valueLabel}.totalBaseRevenueContribution`
1064
+ ),
1065
+ rank: z4.null(),
1066
+ isQualified: z4.literal(false),
1067
+ uncappedAward: makePriceUsdcSchema(`${valueLabel}.uncappedAward`),
1068
+ cappedAward: makePriceUsdcSchema(`${valueLabel}.cappedAward`),
1069
+ adminAction: makeAdminActionSchema(`${valueLabel}.adminAction`).nullable()
1070
+ }).refine((data) => data.totalReferrals === 0, {
1071
+ message: `${valueLabel}.totalReferrals must be 0 for unranked referrers`,
1072
+ path: ["totalReferrals"]
1073
+ }).refine((data) => data.totalIncrementalDuration === 0, {
1074
+ message: `${valueLabel}.totalIncrementalDuration must be 0 for unranked referrers`,
1075
+ path: ["totalIncrementalDuration"]
1076
+ }).refine((data) => data.totalRevenueContribution.amount === 0n, {
1077
+ message: `${valueLabel}.totalRevenueContribution must be 0 for unranked referrers`,
1078
+ path: ["totalRevenueContribution"]
1079
+ }).refine((data) => data.totalBaseRevenueContribution.amount === 0n, {
1080
+ message: `${valueLabel}.totalBaseRevenueContribution must be 0 for unranked referrers`,
1081
+ path: ["totalBaseRevenueContribution"]
1082
+ }).refine((data) => data.uncappedAward.amount === 0n, {
1083
+ message: `${valueLabel}.uncappedAward must be 0 for unranked referrers`,
1084
+ path: ["uncappedAward"]
1085
+ }).refine((data) => data.cappedAward.amount === 0n, {
1086
+ message: `${valueLabel}.cappedAward must be 0 for unranked referrers`,
1087
+ path: ["cappedAward"]
1088
+ }).refine((data) => data.adminAction === null || data.adminAction.referrer === data.referrer, {
1089
+ message: `${valueLabel}.adminAction.referrer must match ${valueLabel}.referrer`,
1090
+ path: ["adminAction", "referrer"]
1091
+ });
1092
+ var makeAggregatedReferrerMetricsRevShareCapSchema = (valueLabel = "AggregatedReferrerMetricsRevShareCap") => z4.object({
1093
+ grandTotalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.grandTotalReferrals`),
1094
+ grandTotalIncrementalDuration: makeDurationSchema(
1095
+ `${valueLabel}.grandTotalIncrementalDuration`
1096
+ ),
1097
+ grandTotalRevenueContribution: makePriceEthSchema(
1098
+ `${valueLabel}.grandTotalRevenueContribution`
1099
+ ),
1100
+ awardPoolRemaining: makePriceUsdcSchema(`${valueLabel}.awardPoolRemaining`)
1101
+ });
1102
+ var addAdminActionConsistencyIssues = (ctx, metricsAdminAction, referrer, rulesAdminActions, path) => {
1103
+ const expected = rulesAdminActions.find((a) => a.referrer === referrer) ?? null;
1104
+ if (expected === null && metricsAdminAction !== null) {
1105
+ ctx.addIssue({
1106
+ code: z4.ZodIssueCode.custom,
1107
+ message: `adminAction expected null, got actionType="${metricsAdminAction.actionType}"`,
1108
+ path
1109
+ });
1110
+ return;
1111
+ }
1112
+ if (expected !== null && (metricsAdminAction === null || metricsAdminAction.actionType !== expected.actionType || metricsAdminAction.referrer !== expected.referrer || metricsAdminAction.reason !== expected.reason)) {
1113
+ ctx.addIssue({
1114
+ code: z4.ZodIssueCode.custom,
1115
+ message: `adminAction does not match the corresponding entry in rules.adminActions`,
1116
+ path
1117
+ });
1118
+ }
1119
+ };
1120
+ var makeReferrerEditionMetricsRankedRevShareCapSchema = (valueLabel = "ReferrerEditionMetricsRankedRevShareCap") => z4.object({
1121
+ awardModel: z4.literal(ReferralProgramAwardModels.RevShareCap),
1122
+ type: z4.literal(ReferrerEditionMetricsTypeIds.Ranked),
1123
+ rules: makeReferralProgramRulesRevShareCapSchema(`${valueLabel}.rules`),
1124
+ referrer: makeAwardedReferrerMetricsRevShareCapSchema(`${valueLabel}.referrer`),
1125
+ aggregatedMetrics: makeAggregatedReferrerMetricsRevShareCapSchema(
1126
+ `${valueLabel}.aggregatedMetrics`
1127
+ ),
1128
+ status: makeReferralProgramStatusSchema(`${valueLabel}.status`),
1129
+ accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
1130
+ }).refine((data) => data.awardModel === data.rules.awardModel, {
1131
+ message: `${valueLabel}.awardModel must equal ${valueLabel}.rules.awardModel`,
1132
+ path: ["awardModel"]
1133
+ }).refine((data) => data.referrer.cappedAward.amount <= data.rules.awardPool.amount, {
1134
+ message: `${valueLabel}.referrer.cappedAward must be <= ${valueLabel}.rules.awardPool`,
1135
+ path: ["referrer", "cappedAward", "amount"]
1136
+ }).superRefine((data, ctx) => {
1137
+ addAdminActionConsistencyIssues(
1138
+ ctx,
1139
+ data.referrer.adminAction,
1140
+ data.referrer.referrer,
1141
+ data.rules.adminActions,
1142
+ ["referrer", "adminAction"]
1143
+ );
1144
+ });
1145
+ var makeReferrerEditionMetricsUnrankedRevShareCapSchema = (valueLabel = "ReferrerEditionMetricsUnrankedRevShareCap") => z4.object({
1146
+ awardModel: z4.literal(ReferralProgramAwardModels.RevShareCap),
1147
+ type: z4.literal(ReferrerEditionMetricsTypeIds.Unranked),
1148
+ rules: makeReferralProgramRulesRevShareCapSchema(`${valueLabel}.rules`),
1149
+ referrer: makeUnrankedReferrerMetricsRevShareCapSchema(`${valueLabel}.referrer`),
1150
+ aggregatedMetrics: makeAggregatedReferrerMetricsRevShareCapSchema(
1151
+ `${valueLabel}.aggregatedMetrics`
1152
+ ),
1153
+ status: makeReferralProgramStatusSchema(`${valueLabel}.status`),
1154
+ accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
1155
+ }).refine((data) => data.awardModel === data.rules.awardModel, {
1156
+ message: `${valueLabel}.awardModel must equal ${valueLabel}.rules.awardModel`,
1157
+ path: ["awardModel"]
1158
+ }).superRefine((data, ctx) => {
1159
+ addAdminActionConsistencyIssues(
1160
+ ctx,
1161
+ data.referrer.adminAction,
1162
+ data.referrer.referrer,
1163
+ data.rules.adminActions,
1164
+ ["referrer", "adminAction"]
1165
+ );
1166
+ });
1167
+ var makeReferrerEditionMetricsRevShareCapSchema = (valueLabel = "ReferrerEditionMetricsRevShareCap") => z4.discriminatedUnion("type", [
1168
+ makeReferrerEditionMetricsRankedRevShareCapSchema(valueLabel),
1169
+ makeReferrerEditionMetricsUnrankedRevShareCapSchema(valueLabel)
1170
+ ]);
1171
+ var makeReferralProgramEditionSummaryRevShareCapSchema = (valueLabel = "ReferralProgramEditionSummaryRevShareCap") => makeBaseReferralProgramEditionSummarySchema(valueLabel).safeExtend({
1172
+ awardModel: z4.literal(ReferralProgramAwardModels.RevShareCap),
1173
+ rules: makeReferralProgramRulesRevShareCapSchema(`${valueLabel}.rules`),
1174
+ awardPoolRemaining: makePriceUsdcSchema(`${valueLabel}.awardPoolRemaining`)
1175
+ }).refine((data) => data.awardModel === data.rules.awardModel, {
1176
+ message: `${valueLabel}.awardModel must equal ${valueLabel}.rules.awardModel`,
1177
+ path: ["awardModel"]
1178
+ });
1179
+ var makeReferrerLeaderboardPageRevShareCapSchema = (valueLabel = "ReferrerLeaderboardPageRevShareCap") => makeBaseReferrerLeaderboardPageSchema(valueLabel).safeExtend({
1180
+ awardModel: z4.literal(ReferralProgramAwardModels.RevShareCap),
1181
+ rules: makeReferralProgramRulesRevShareCapSchema(`${valueLabel}.rules`),
1182
+ referrers: z4.array(
1183
+ makeAwardedReferrerMetricsRevShareCapSchema(`${valueLabel}.referrers[record]`)
1184
+ ),
1185
+ aggregatedMetrics: makeAggregatedReferrerMetricsRevShareCapSchema(
1186
+ `${valueLabel}.aggregatedMetrics`
1187
+ )
1188
+ }).refine((data) => data.awardModel === data.rules.awardModel, {
1189
+ message: `${valueLabel}.awardModel must equal ${valueLabel}.rules.awardModel`,
1190
+ path: ["awardModel"]
1191
+ }).superRefine((data, ctx) => {
1192
+ data.referrers.forEach((referrer, index) => {
1193
+ if (referrer.cappedAward.amount > data.rules.awardPool.amount) {
1194
+ ctx.addIssue({
1195
+ code: z4.ZodIssueCode.custom,
1196
+ message: `${valueLabel}.referrers[${index}].cappedAward must be <= ${valueLabel}.rules.awardPool`,
1197
+ path: ["referrers", index, "cappedAward", "amount"]
1198
+ });
1199
+ }
1200
+ addAdminActionConsistencyIssues(
1201
+ ctx,
1202
+ referrer.adminAction,
1203
+ referrer.referrer,
1204
+ data.rules.adminActions,
1205
+ ["referrers", index, "adminAction"]
1206
+ );
1207
+ });
1208
+ });
1209
+
1210
+ // src/api/types.ts
1211
+ var ReferrerLeaderboardPageResponseCodes = {
1212
+ /**
1213
+ * Represents that the requested referrer leaderboard page is available.
1214
+ */
1215
+ Ok: "ok",
1216
+ /**
1217
+ * Represents that the referrer leaderboard data is not available.
1218
+ */
1219
+ Error: "error"
1220
+ };
1221
+ var MAX_EDITIONS_PER_REQUEST = 20;
1222
+ var ReferrerMetricsEditionsResponseCodes = {
1223
+ /**
1224
+ * Represents that the referrer metrics data for the requested editions is available.
1225
+ */
1226
+ Ok: "ok",
1227
+ /**
1228
+ * Represents that an error occurred while fetching the data.
1229
+ */
1230
+ Error: "error"
1231
+ };
1232
+ var ReferralProgramEditionSummariesResponseCodes = {
1233
+ /**
1234
+ * Represents that the edition summaries are available.
1235
+ */
1236
+ Ok: "ok",
1237
+ /**
1238
+ * Represents that the edition summaries are not available.
1239
+ */
1240
+ Error: "error"
1241
+ };
1242
+
1243
+ // src/api/zod-schemas.ts
1244
+ var reemitIssues = (ctx, issues, pathPrefix = []) => {
1245
+ for (const issue of issues) {
1246
+ ctx.addIssue({
1247
+ ...issue,
1248
+ path: [...pathPrefix, ...issue.path]
1249
+ });
1250
+ }
1251
+ };
1252
+ var makeReferralProgramRulesSchema = (valueLabel = "ReferralProgramRules") => z5.discriminatedUnion("awardModel", [
1253
+ makeReferralProgramRulesPieSplitSchema(valueLabel),
1254
+ makeReferralProgramRulesRevShareCapSchema(valueLabel)
1255
+ ]);
1256
+ var makeReferrerLeaderboardPageSchema = (valueLabel = "ReferrerLeaderboardPage") => {
1257
+ const knownAwardModels = Object.values(ReferralProgramAwardModels).filter(
1258
+ (m) => m !== ReferralProgramAwardModels.Unrecognized
1259
+ );
1260
+ const looseSchema = z5.looseObject({ awardModel: z5.string() });
1261
+ const knownSchema = z5.discriminatedUnion("awardModel", [
1262
+ makeReferrerLeaderboardPagePieSplitSchema(valueLabel),
1263
+ makeReferrerLeaderboardPageRevShareCapSchema(valueLabel)
1264
+ ]);
1265
+ const baseSchema = makeBaseReferrerLeaderboardPageSchema(valueLabel);
1266
+ return looseSchema.transform((data, ctx) => {
1267
+ if (knownAwardModels.includes(data.awardModel)) {
1268
+ const parsed2 = knownSchema.safeParse(data);
1269
+ if (!parsed2.success) {
1270
+ reemitIssues(ctx, parsed2.error.issues);
1271
+ return z5.NEVER;
1272
+ }
1273
+ return parsed2.data;
1274
+ }
1275
+ const parsed = baseSchema.safeParse(data);
1276
+ if (!parsed.success) {
1277
+ reemitIssues(ctx, parsed.error.issues);
1278
+ return z5.NEVER;
1279
+ }
1280
+ return {
1281
+ ...parsed.data,
1282
+ awardModel: ReferralProgramAwardModels.Unrecognized,
1283
+ originalAwardModel: data.awardModel
1284
+ };
1285
+ });
1286
+ };
1287
+ var makeReferrerLeaderboardPageResponseOkSchema = (valueLabel = "ReferrerLeaderboardPageResponseOk") => z5.object({
1288
+ responseCode: z5.literal(ReferrerLeaderboardPageResponseCodes.Ok),
1289
+ data: makeReferrerLeaderboardPageSchema(`${valueLabel}.data`)
1290
+ });
1291
+ var makeReferrerLeaderboardPageResponseErrorSchema = (_valueLabel = "ReferrerLeaderboardPageResponseError") => z5.object({
1292
+ responseCode: z5.literal(ReferrerLeaderboardPageResponseCodes.Error),
1293
+ error: z5.string(),
1294
+ errorMessage: z5.string()
1295
+ });
1296
+ var makeReferrerLeaderboardPageResponseSchema = (valueLabel = "ReferrerLeaderboardPageResponse") => z5.discriminatedUnion("responseCode", [
1297
+ makeReferrerLeaderboardPageResponseOkSchema(valueLabel),
1298
+ makeReferrerLeaderboardPageResponseErrorSchema(valueLabel)
1299
+ ]);
1300
+ var makeReferrerEditionMetricsSchema = (valueLabel = "ReferrerEditionMetrics") => {
1301
+ const knownAwardModels = Object.values(ReferralProgramAwardModels).filter(
1302
+ (m) => m !== ReferralProgramAwardModels.Unrecognized
1303
+ );
1304
+ const looseSchema = z5.looseObject({ awardModel: z5.string() });
1305
+ const knownSchema = z5.discriminatedUnion("awardModel", [
1306
+ makeReferrerEditionMetricsPieSplitSchema(valueLabel),
1307
+ makeReferrerEditionMetricsRevShareCapSchema(valueLabel)
1308
+ ]);
1309
+ return looseSchema.transform((data, ctx) => {
1310
+ if (knownAwardModels.includes(data.awardModel)) {
1311
+ const parsed = knownSchema.safeParse(data);
1312
+ if (!parsed.success) {
1313
+ reemitIssues(ctx, parsed.error.issues);
1314
+ return z5.NEVER;
1315
+ }
1316
+ return parsed.data;
1317
+ }
1318
+ return {
1319
+ awardModel: ReferralProgramAwardModels.Unrecognized,
1320
+ originalAwardModel: data.awardModel
1321
+ };
1322
+ });
1323
+ };
1324
+ var makeReferralProgramEditionSlugSchema = (valueLabel = "ReferralProgramEditionSlug") => z5.string().min(1, `${valueLabel} must not be empty`).regex(
1325
+ /^[a-z0-9]+(-[a-z0-9]+)*$/,
1326
+ `${valueLabel} must contain only lowercase letters, digits, and hyphens. Must not start or end with a hyphen.`
1327
+ );
1328
+ var makeReferrerMetricsEditionsResponseOkSchema = (valueLabel = "ReferrerMetricsEditionsResponseOk") => z5.object({
1329
+ responseCode: z5.literal(ReferrerMetricsEditionsResponseCodes.Ok),
1330
+ data: z5.record(
1331
+ makeReferralProgramEditionSlugSchema(`${valueLabel}.data[edition]`),
1332
+ makeReferrerEditionMetricsSchema(`${valueLabel}.data[edition]`)
1333
+ )
1334
+ });
1335
+ var makeReferrerMetricsEditionsResponseErrorSchema = (_valueLabel = "ReferrerMetricsEditionsResponseError") => z5.object({
1336
+ responseCode: z5.literal(ReferrerMetricsEditionsResponseCodes.Error),
1337
+ error: z5.string(),
1338
+ errorMessage: z5.string()
1339
+ });
1340
+ var makeReferrerMetricsEditionsResponseSchema = (valueLabel = "ReferrerMetricsEditionsResponse") => z5.discriminatedUnion("responseCode", [
1341
+ makeReferrerMetricsEditionsResponseOkSchema(valueLabel),
1342
+ makeReferrerMetricsEditionsResponseErrorSchema(valueLabel)
1343
+ ]);
1344
+ var makeReferralProgramEditionConfigBaseSchema = (valueLabel) => z5.object({
1345
+ slug: makeReferralProgramEditionSlugSchema(`${valueLabel}.slug`),
1346
+ displayName: z5.string().min(1, `${valueLabel}.displayName must not be empty`),
1347
+ rules: makeBaseReferralProgramRulesSchema(`${valueLabel}.rules`)
1348
+ });
1349
+ var makeReferralProgramEditionConfigSchema = (valueLabel = "ReferralProgramEditionConfig") => makeReferralProgramEditionConfigBaseSchema(valueLabel).safeExtend({
1350
+ rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`)
1351
+ });
1352
+ var makeReferralProgramEditionConfigSetArraySchema = (valueLabel = "ReferralProgramEditionConfigSetArray") => {
1353
+ const knownAwardModels = Object.values(ReferralProgramAwardModels).filter(
1354
+ (m) => m !== ReferralProgramAwardModels.Unrecognized
1355
+ );
1356
+ const configSchema = makeReferralProgramEditionConfigSchema(`${valueLabel}[edition]`);
1357
+ const looseItemSchema = z5.looseObject({
1358
+ rules: z5.looseObject({ awardModel: z5.string() })
1359
+ });
1360
+ const unrecognizedBaseSchema = makeReferralProgramEditionConfigBaseSchema(
1361
+ `${valueLabel}[edition]`
1362
+ );
1363
+ return z5.array(looseItemSchema).transform((items, ctx) => {
1364
+ const result = [];
1365
+ for (let i = 0; i < items.length; i++) {
1366
+ const item = items[i];
1367
+ if (knownAwardModels.includes(item.rules.awardModel)) {
1368
+ const parsed = configSchema.safeParse(item);
1369
+ if (!parsed.success) {
1370
+ reemitIssues(ctx, parsed.error.issues, [i]);
1371
+ } else {
1372
+ result.push(parsed.data);
1373
+ }
1374
+ } else {
1375
+ const parsed = unrecognizedBaseSchema.safeParse(item);
1376
+ if (!parsed.success) {
1377
+ reemitIssues(ctx, parsed.error.issues, [i]);
1378
+ continue;
1379
+ }
1380
+ result.push({
1381
+ ...parsed.data,
1382
+ rules: {
1383
+ ...parsed.data.rules,
1384
+ awardModel: ReferralProgramAwardModels.Unrecognized,
1385
+ originalAwardModel: item.rules.awardModel
1386
+ }
1387
+ });
1388
+ }
1389
+ }
1390
+ const slugs = /* @__PURE__ */ new Set();
1391
+ for (const edition of result) {
1392
+ if (slugs.has(edition.slug)) {
1393
+ ctx.addIssue({
1394
+ code: "custom",
1395
+ message: `${valueLabel} must not contain duplicate edition slugs`
1396
+ });
1397
+ return [];
1398
+ }
1399
+ slugs.add(edition.slug);
1400
+ }
1401
+ return result;
1402
+ });
1403
+ };
1404
+ var makeReferralProgramEditionSummarySchema = (valueLabel = "ReferralProgramEditionSummary") => {
1405
+ const knownAwardModels = Object.values(ReferralProgramAwardModels).filter(
1406
+ (m) => m !== ReferralProgramAwardModels.Unrecognized
1407
+ );
1408
+ const looseSchema = z5.looseObject({ awardModel: z5.string() });
1409
+ const knownSchema = z5.discriminatedUnion("awardModel", [
1410
+ makeReferralProgramEditionSummaryPieSplitSchema(valueLabel),
1411
+ makeReferralProgramEditionSummaryRevShareCapSchema(valueLabel)
1412
+ ]);
1413
+ const baseSchema = makeBaseReferralProgramEditionSummarySchema(valueLabel);
1414
+ return looseSchema.transform((data, ctx) => {
1415
+ if (knownAwardModels.includes(data.awardModel)) {
1416
+ const parsed2 = knownSchema.safeParse(data);
1417
+ if (!parsed2.success) {
1418
+ reemitIssues(ctx, parsed2.error.issues);
1419
+ return z5.NEVER;
1420
+ }
1421
+ return parsed2.data;
1422
+ }
1423
+ const parsed = baseSchema.safeParse(data);
1424
+ if (!parsed.success) {
1425
+ reemitIssues(ctx, parsed.error.issues);
1426
+ return z5.NEVER;
1427
+ }
1428
+ return {
1429
+ ...parsed.data,
1430
+ awardModel: ReferralProgramAwardModels.Unrecognized,
1431
+ rules: {
1432
+ ...parsed.data.rules,
1433
+ awardModel: ReferralProgramAwardModels.Unrecognized,
1434
+ originalAwardModel: data.awardModel
1435
+ }
1436
+ };
1437
+ });
1438
+ };
1439
+ var makeReferralProgramEditionSummariesDataSchema = (valueLabel = "ReferralProgramEditionSummariesData") => z5.object({
1440
+ editions: z5.array(makeReferralProgramEditionSummarySchema(`${valueLabel}.editions[edition]`))
1441
+ });
1442
+ var makeReferralProgramEditionSummariesResponseOkSchema = (valueLabel = "ReferralProgramEditionSummariesResponseOk") => z5.object({
1443
+ responseCode: z5.literal(ReferralProgramEditionSummariesResponseCodes.Ok),
1444
+ data: makeReferralProgramEditionSummariesDataSchema(`${valueLabel}.data`)
1445
+ });
1446
+ var makeReferralProgramEditionSummariesResponseErrorSchema = (_valueLabel = "ReferralProgramEditionSummariesResponseError") => z5.object({
1447
+ responseCode: z5.literal(ReferralProgramEditionSummariesResponseCodes.Error),
1448
+ error: z5.string(),
1449
+ errorMessage: z5.string()
1450
+ });
1451
+ var makeReferralProgramEditionSummariesResponseSchema = (valueLabel = "ReferralProgramEditionSummariesResponse") => z5.discriminatedUnion("responseCode", [
1452
+ makeReferralProgramEditionSummariesResponseOkSchema(valueLabel),
1453
+ makeReferralProgramEditionSummariesResponseErrorSchema(valueLabel)
1454
+ ]);
1455
+
1456
+ // src/api/deserialize.ts
1457
+ function deserializeReferrerLeaderboardPageResponse(maybeResponse, valueLabel) {
1458
+ const schema = makeReferrerLeaderboardPageResponseSchema(valueLabel);
1459
+ const parsed = schema.safeParse(maybeResponse);
1460
+ if (parsed.error) {
1461
+ throw new Error(
1462
+ `Cannot deserialize SerializedReferrerLeaderboardPageResponse:
1463
+ ${prettifyError(parsed.error)}
1464
+ `
1465
+ );
1466
+ }
1467
+ return parsed.data;
1468
+ }
1469
+ function deserializeReferrerMetricsEditionsResponse(maybeResponse, valueLabel) {
1470
+ const schema = makeReferrerMetricsEditionsResponseSchema(valueLabel);
1471
+ const parsed = schema.safeParse(maybeResponse);
1472
+ if (parsed.error) {
1473
+ throw new Error(
1474
+ `Cannot deserialize ReferrerMetricsEditionsResponse:
1475
+ ${prettifyError(parsed.error)}
1476
+ `
1477
+ );
1478
+ }
1479
+ return parsed.data;
1480
+ }
1481
+ function deserializeReferralProgramEditionConfigSetArray(maybeArray, valueLabel) {
1482
+ const schema = makeReferralProgramEditionConfigSetArraySchema(valueLabel);
1483
+ const parsed = schema.safeParse(maybeArray);
1484
+ if (parsed.error) {
1485
+ throw new Error(
1486
+ `Cannot deserialize ReferralProgramEditionConfigSetArray:
1487
+ ${prettifyError(parsed.error)}
1488
+ `
1489
+ );
1490
+ }
1491
+ return parsed.data;
1492
+ }
1493
+ function deserializeReferralProgramEditionSummariesResponse(maybeResponse, valueLabel) {
1494
+ const schema = makeReferralProgramEditionSummariesResponseSchema(valueLabel);
1495
+ const parsed = schema.safeParse(maybeResponse);
1496
+ if (parsed.error) {
1497
+ throw new Error(
1498
+ `Cannot deserialize ReferralProgramEditionSummariesResponse:
1499
+ ${prettifyError(parsed.error)}
1500
+ `
1501
+ );
1502
+ }
1503
+ return parsed.data;
1504
+ }
1505
+
1506
+ // src/award-models/pie-split/api/serialize.ts
1507
+ function serializeReferralProgramRulesPieSplit(rules) {
1508
+ return {
1509
+ awardModel: rules.awardModel,
1510
+ awardPool: serializePriceUsdc(rules.awardPool),
1511
+ maxQualifiedReferrers: rules.maxQualifiedReferrers,
1512
+ startTime: rules.startTime,
1513
+ endTime: rules.endTime,
1514
+ subregistryId: rules.subregistryId,
1515
+ rulesUrl: rules.rulesUrl.toString(),
1516
+ areAwardsDistributed: rules.areAwardsDistributed
1517
+ };
1518
+ }
1519
+ function serializeAggregatedReferrerMetricsPieSplit(metrics) {
1520
+ return {
1521
+ grandTotalReferrals: metrics.grandTotalReferrals,
1522
+ grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,
1523
+ grandTotalRevenueContribution: serializePriceEth(metrics.grandTotalRevenueContribution),
1524
+ grandTotalQualifiedReferrersFinalScore: metrics.grandTotalQualifiedReferrersFinalScore,
1525
+ minFinalScoreToQualify: metrics.minFinalScoreToQualify
1526
+ };
1527
+ }
1528
+ function serializeAwardedReferrerMetricsPieSplit(metrics) {
1529
+ return {
1530
+ referrer: metrics.referrer,
1531
+ totalReferrals: metrics.totalReferrals,
1532
+ totalIncrementalDuration: metrics.totalIncrementalDuration,
1533
+ totalRevenueContribution: serializePriceEth(metrics.totalRevenueContribution),
1534
+ score: metrics.score,
1535
+ rank: metrics.rank,
1536
+ isQualified: metrics.isQualified,
1537
+ finalScoreBoost: metrics.finalScoreBoost,
1538
+ finalScore: metrics.finalScore,
1539
+ awardPoolShare: metrics.awardPoolShare,
1540
+ awardPoolApproxValue: serializePriceUsdc(metrics.awardPoolApproxValue)
1541
+ };
1542
+ }
1543
+ function serializeUnrankedReferrerMetricsPieSplit(metrics) {
1544
+ return {
1545
+ referrer: metrics.referrer,
1546
+ totalReferrals: metrics.totalReferrals,
1547
+ totalIncrementalDuration: metrics.totalIncrementalDuration,
1548
+ totalRevenueContribution: serializePriceEth(metrics.totalRevenueContribution),
1549
+ score: metrics.score,
1550
+ rank: metrics.rank,
1551
+ isQualified: metrics.isQualified,
1552
+ finalScoreBoost: metrics.finalScoreBoost,
1553
+ finalScore: metrics.finalScore,
1554
+ awardPoolShare: metrics.awardPoolShare,
1555
+ awardPoolApproxValue: serializePriceUsdc(metrics.awardPoolApproxValue)
1556
+ };
1557
+ }
1558
+ function serializeReferrerEditionMetricsRankedPieSplit(detail) {
1559
+ return {
1560
+ awardModel: detail.awardModel,
1561
+ type: detail.type,
1562
+ rules: serializeReferralProgramRulesPieSplit(detail.rules),
1563
+ referrer: serializeAwardedReferrerMetricsPieSplit(detail.referrer),
1564
+ aggregatedMetrics: serializeAggregatedReferrerMetricsPieSplit(detail.aggregatedMetrics),
1565
+ status: detail.status,
1566
+ accurateAsOf: detail.accurateAsOf
1567
+ };
1568
+ }
1569
+ function serializeReferrerEditionMetricsUnrankedPieSplit(detail) {
1570
+ return {
1571
+ awardModel: detail.awardModel,
1572
+ type: detail.type,
1573
+ rules: serializeReferralProgramRulesPieSplit(detail.rules),
1574
+ referrer: serializeUnrankedReferrerMetricsPieSplit(detail.referrer),
1575
+ aggregatedMetrics: serializeAggregatedReferrerMetricsPieSplit(detail.aggregatedMetrics),
1576
+ status: detail.status,
1577
+ accurateAsOf: detail.accurateAsOf
1578
+ };
1579
+ }
1580
+ function serializeReferrerEditionMetricsPieSplit(detail) {
1581
+ switch (detail.type) {
1582
+ case ReferrerEditionMetricsTypeIds.Ranked:
1583
+ return serializeReferrerEditionMetricsRankedPieSplit(detail);
1584
+ case ReferrerEditionMetricsTypeIds.Unranked:
1585
+ return serializeReferrerEditionMetricsUnrankedPieSplit(detail);
1586
+ default: {
1587
+ const _exhaustiveCheck = detail;
1588
+ throw new Error(`Unknown type: ${_exhaustiveCheck.type}`);
1589
+ }
1590
+ }
1591
+ }
1592
+ function serializeReferrerLeaderboardPagePieSplit(page) {
1593
+ return {
1594
+ awardModel: page.awardModel,
1595
+ rules: serializeReferralProgramRulesPieSplit(page.rules),
1596
+ referrers: page.referrers.map(serializeAwardedReferrerMetricsPieSplit),
1597
+ aggregatedMetrics: serializeAggregatedReferrerMetricsPieSplit(page.aggregatedMetrics),
1598
+ pageContext: page.pageContext,
1599
+ status: page.status,
1600
+ accurateAsOf: page.accurateAsOf
1601
+ };
1602
+ }
1603
+ function serializeReferralProgramEditionSummaryPieSplit(summary) {
1604
+ return {
1605
+ awardModel: summary.awardModel,
1606
+ slug: summary.slug,
1607
+ displayName: summary.displayName,
1608
+ status: summary.status,
1609
+ rules: serializeReferralProgramRulesPieSplit(summary.rules)
1610
+ };
1611
+ }
1612
+
1613
+ // src/award-models/rev-share-cap/api/serialize.ts
1614
+ function serializeReferralProgramRulesRevShareCap(rules) {
1615
+ return {
1616
+ awardModel: rules.awardModel,
1617
+ awardPool: serializePriceUsdc(rules.awardPool),
1618
+ minBaseRevenueContribution: serializePriceUsdc(rules.minBaseRevenueContribution),
1619
+ baseAnnualRevenueContribution: serializePriceUsdc(rules.baseAnnualRevenueContribution),
1620
+ maxBaseRevenueShare: rules.maxBaseRevenueShare,
1621
+ startTime: rules.startTime,
1622
+ endTime: rules.endTime,
1623
+ subregistryId: rules.subregistryId,
1624
+ rulesUrl: rules.rulesUrl.toString(),
1625
+ areAwardsDistributed: rules.areAwardsDistributed,
1626
+ adminActions: rules.adminActions
1627
+ };
1628
+ }
1629
+ function serializeAggregatedReferrerMetricsRevShareCap(metrics) {
1630
+ return {
1631
+ grandTotalReferrals: metrics.grandTotalReferrals,
1632
+ grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,
1633
+ grandTotalRevenueContribution: serializePriceEth(metrics.grandTotalRevenueContribution),
1634
+ awardPoolRemaining: serializePriceUsdc(metrics.awardPoolRemaining)
1635
+ };
1636
+ }
1637
+ function serializeAwardedReferrerMetricsRevShareCap(metrics) {
1638
+ return {
1639
+ referrer: metrics.referrer,
1640
+ totalReferrals: metrics.totalReferrals,
1641
+ totalIncrementalDuration: metrics.totalIncrementalDuration,
1642
+ totalRevenueContribution: serializePriceEth(metrics.totalRevenueContribution),
1643
+ totalBaseRevenueContribution: serializePriceUsdc(metrics.totalBaseRevenueContribution),
1644
+ rank: metrics.rank,
1645
+ isQualified: metrics.isQualified,
1646
+ uncappedAward: serializePriceUsdc(metrics.uncappedAward),
1647
+ cappedAward: serializePriceUsdc(metrics.cappedAward),
1648
+ adminAction: metrics.adminAction
1649
+ };
1650
+ }
1651
+ function serializeUnrankedReferrerMetricsRevShareCap(metrics) {
1652
+ return {
1653
+ referrer: metrics.referrer,
1654
+ totalReferrals: metrics.totalReferrals,
1655
+ totalIncrementalDuration: metrics.totalIncrementalDuration,
1656
+ totalRevenueContribution: serializePriceEth(metrics.totalRevenueContribution),
1657
+ totalBaseRevenueContribution: serializePriceUsdc(metrics.totalBaseRevenueContribution),
1658
+ rank: metrics.rank,
1659
+ isQualified: metrics.isQualified,
1660
+ uncappedAward: serializePriceUsdc(metrics.uncappedAward),
1661
+ cappedAward: serializePriceUsdc(metrics.cappedAward),
1662
+ adminAction: metrics.adminAction
1663
+ };
1664
+ }
1665
+ function serializeReferrerEditionMetricsRankedRevShareCap(detail) {
1666
+ return {
1667
+ awardModel: detail.awardModel,
1668
+ type: detail.type,
1669
+ rules: serializeReferralProgramRulesRevShareCap(detail.rules),
1670
+ referrer: serializeAwardedReferrerMetricsRevShareCap(detail.referrer),
1671
+ aggregatedMetrics: serializeAggregatedReferrerMetricsRevShareCap(detail.aggregatedMetrics),
1672
+ status: detail.status,
1673
+ accurateAsOf: detail.accurateAsOf
1674
+ };
1675
+ }
1676
+ function serializeReferrerEditionMetricsUnrankedRevShareCap(detail) {
1677
+ return {
1678
+ awardModel: detail.awardModel,
1679
+ type: detail.type,
1680
+ rules: serializeReferralProgramRulesRevShareCap(detail.rules),
1681
+ referrer: serializeUnrankedReferrerMetricsRevShareCap(detail.referrer),
1682
+ aggregatedMetrics: serializeAggregatedReferrerMetricsRevShareCap(detail.aggregatedMetrics),
1683
+ status: detail.status,
1684
+ accurateAsOf: detail.accurateAsOf
1685
+ };
1686
+ }
1687
+ function serializeReferrerEditionMetricsRevShareCap(detail) {
1688
+ switch (detail.type) {
1689
+ case ReferrerEditionMetricsTypeIds.Ranked:
1690
+ return serializeReferrerEditionMetricsRankedRevShareCap(detail);
1691
+ case ReferrerEditionMetricsTypeIds.Unranked:
1692
+ return serializeReferrerEditionMetricsUnrankedRevShareCap(detail);
1693
+ default: {
1694
+ const _exhaustiveCheck = detail;
1695
+ throw new Error(
1696
+ `Unknown type: ${_exhaustiveCheck.type}`
1697
+ );
1698
+ }
1699
+ }
1700
+ }
1701
+ function serializeReferrerLeaderboardPageRevShareCap(page) {
1702
+ return {
1703
+ awardModel: page.awardModel,
1704
+ rules: serializeReferralProgramRulesRevShareCap(page.rules),
1705
+ referrers: page.referrers.map(serializeAwardedReferrerMetricsRevShareCap),
1706
+ aggregatedMetrics: serializeAggregatedReferrerMetricsRevShareCap(page.aggregatedMetrics),
1707
+ pageContext: page.pageContext,
1708
+ status: page.status,
1709
+ accurateAsOf: page.accurateAsOf
1710
+ };
1711
+ }
1712
+ function serializeReferralProgramEditionSummaryRevShareCap(summary) {
1713
+ return {
1714
+ awardModel: summary.awardModel,
1715
+ slug: summary.slug,
1716
+ displayName: summary.displayName,
1717
+ status: summary.status,
1718
+ rules: serializeReferralProgramRulesRevShareCap(summary.rules),
1719
+ awardPoolRemaining: serializePriceUsdc(summary.awardPoolRemaining)
1720
+ };
1721
+ }
1722
+
1723
+ // src/api/serialize.ts
1724
+ function serializeReferralProgramRules(rules) {
1725
+ switch (rules.awardModel) {
1726
+ case ReferralProgramAwardModels.PieSplit:
1727
+ return serializeReferralProgramRulesPieSplit(rules);
1728
+ case ReferralProgramAwardModels.RevShareCap:
1729
+ return serializeReferralProgramRulesRevShareCap(rules);
1730
+ case ReferralProgramAwardModels.Unrecognized: {
1731
+ const unrecognized = rules;
1732
+ throw new Error(
1733
+ `ReferralProgramRulesUnrecognized (originalAwardModel: '${unrecognized.originalAwardModel}') must not be serialized \u2014 it is a client-side forward-compatibility placeholder only.`
1734
+ );
1735
+ }
1736
+ default: {
1737
+ const _exhaustiveCheck = rules;
1738
+ throw new Error(
1739
+ `Unknown award model: ${_exhaustiveCheck.awardModel}`
1740
+ );
1741
+ }
1742
+ }
1743
+ }
1744
+ function serializeReferrerLeaderboardPage(page) {
1745
+ switch (page.awardModel) {
1746
+ case ReferralProgramAwardModels.PieSplit:
1747
+ return serializeReferrerLeaderboardPagePieSplit(page);
1748
+ case ReferralProgramAwardModels.RevShareCap:
1749
+ return serializeReferrerLeaderboardPageRevShareCap(page);
1750
+ case ReferralProgramAwardModels.Unrecognized: {
1751
+ const unrecognized = page;
1752
+ throw new Error(
1753
+ `ReferrerLeaderboardPageUnrecognized (originalAwardModel: '${unrecognized.originalAwardModel}') must not be serialized \u2014 it is a client-side forward-compatibility placeholder only.`
1754
+ );
1755
+ }
1756
+ default: {
1757
+ const _exhaustiveCheck = page;
1758
+ throw new Error(
1759
+ `Unknown award model: ${_exhaustiveCheck.awardModel}`
1760
+ );
1761
+ }
1762
+ }
1763
+ }
1764
+ function serializeReferrerEditionMetrics(detail) {
1765
+ switch (detail.awardModel) {
1766
+ case ReferralProgramAwardModels.PieSplit:
1767
+ return serializeReferrerEditionMetricsPieSplit(detail);
1768
+ case ReferralProgramAwardModels.RevShareCap:
1769
+ return serializeReferrerEditionMetricsRevShareCap(detail);
1770
+ case ReferralProgramAwardModels.Unrecognized: {
1771
+ const unrecognized = detail;
1772
+ throw new Error(
1773
+ `ReferrerEditionMetricsUnrecognized (originalAwardModel: '${unrecognized.originalAwardModel}') must not be serialized \u2014 it is a client-side forward-compatibility placeholder only.`
1774
+ );
1775
+ }
1776
+ default: {
1777
+ const _exhaustiveCheck = detail;
1778
+ throw new Error(
1779
+ `Unknown award model: ${_exhaustiveCheck.awardModel}`
1780
+ );
1781
+ }
1782
+ }
1783
+ }
1784
+ function serializeReferralProgramEditionSummary(summary) {
1785
+ switch (summary.awardModel) {
1786
+ case ReferralProgramAwardModels.PieSplit:
1787
+ return serializeReferralProgramEditionSummaryPieSplit(summary);
1788
+ case ReferralProgramAwardModels.RevShareCap:
1789
+ return serializeReferralProgramEditionSummaryRevShareCap(summary);
1790
+ case ReferralProgramAwardModels.Unrecognized: {
1791
+ const unrecognized = summary;
1792
+ throw new Error(
1793
+ `ReferralProgramEditionSummaryUnrecognized (originalAwardModel: '${unrecognized.rules.originalAwardModel}') must not be serialized \u2014 it is a client-side forward-compatibility placeholder only.`
1794
+ );
1795
+ }
1796
+ default: {
1797
+ const _exhaustiveCheck = summary;
1798
+ throw new Error(
1799
+ `Unknown award model: ${_exhaustiveCheck.awardModel}`
1800
+ );
1801
+ }
1802
+ }
1803
+ }
1804
+ function serializeReferrerLeaderboardPageResponse(response) {
1805
+ switch (response.responseCode) {
1806
+ case ReferrerLeaderboardPageResponseCodes.Ok:
1807
+ return {
1808
+ responseCode: response.responseCode,
1809
+ data: serializeReferrerLeaderboardPage(response.data)
1810
+ };
1811
+ case ReferrerLeaderboardPageResponseCodes.Error:
1812
+ return response;
1813
+ }
1814
+ }
1815
+ function serializeReferrerMetricsEditionsResponse(response) {
1816
+ switch (response.responseCode) {
1817
+ case ReferrerMetricsEditionsResponseCodes.Ok: {
1818
+ const serializedData = Object.fromEntries(
1819
+ Object.entries(response.data).map(([editionSlug, detail]) => [
1820
+ editionSlug,
1821
+ serializeReferrerEditionMetrics(detail)
1822
+ ])
1823
+ );
1824
+ return {
1825
+ responseCode: response.responseCode,
1826
+ data: serializedData
1827
+ };
1828
+ }
1829
+ case ReferrerMetricsEditionsResponseCodes.Error:
1830
+ return response;
1831
+ default: {
1832
+ const _exhaustiveCheck = response;
1833
+ throw new Error(
1834
+ `Unknown response code: ${_exhaustiveCheck.responseCode}`
1835
+ );
1836
+ }
1837
+ }
1838
+ }
1839
+ function serializeReferralProgramEditionSummariesResponse(response) {
1840
+ switch (response.responseCode) {
1841
+ case ReferralProgramEditionSummariesResponseCodes.Ok:
1842
+ return {
1843
+ responseCode: response.responseCode,
1844
+ data: {
1845
+ editions: response.data.editions.map(serializeReferralProgramEditionSummary)
1846
+ }
1847
+ };
1848
+ case ReferralProgramEditionSummariesResponseCodes.Error:
1849
+ return response;
1850
+ default: {
1851
+ const _exhaustiveCheck = response;
1852
+ throw new Error(
1853
+ `Unknown response code: ${_exhaustiveCheck.responseCode}`
1854
+ );
1855
+ }
1856
+ }
1857
+ }
1858
+
1859
+ // src/award-models/shared/score.ts
1860
+ var isValidReferrerScore = (score) => {
1861
+ return score >= 0 && Number.isFinite(score);
1862
+ };
1863
+ var validateReferrerScore = (score) => {
1864
+ if (!isValidReferrerScore(score)) {
1865
+ throw new Error(
1866
+ `Invalid referrer score: ${score}. Referrer score must be a finite non-negative number.`
1867
+ );
1868
+ }
1869
+ };
1870
+
1871
+ // src/award-models/pie-split/aggregations.ts
1872
+ var validateAggregatedReferrerMetricsPieSplit = (metrics) => {
1873
+ validateNonNegativeInteger(metrics.grandTotalReferrals);
1874
+ validateDuration(metrics.grandTotalIncrementalDuration);
1875
+ makePriceEthSchema("AggregatedReferrerMetricsPieSplit.grandTotalRevenueContribution").parse(
1876
+ metrics.grandTotalRevenueContribution
1877
+ );
1878
+ validateReferrerScore(metrics.grandTotalQualifiedReferrersFinalScore);
1879
+ validateReferrerScore(metrics.minFinalScoreToQualify);
1880
+ };
1881
+ var buildAggregatedReferrerMetricsPieSplit = (referrers, rules) => {
1882
+ let grandTotalReferrals = 0;
1883
+ let grandTotalIncrementalDuration = 0;
1884
+ let grandTotalRevenueContributionAmount = 0n;
1885
+ let grandTotalQualifiedReferrersFinalScore = 0;
1886
+ let minFinalScoreToQualify = Number.MAX_SAFE_INTEGER;
1887
+ for (const referrer of referrers) {
1888
+ grandTotalReferrals += referrer.totalReferrals;
1889
+ grandTotalIncrementalDuration += referrer.totalIncrementalDuration;
1890
+ grandTotalRevenueContributionAmount += referrer.totalRevenueContribution.amount;
1891
+ if (referrer.isQualified) {
1892
+ grandTotalQualifiedReferrersFinalScore += referrer.finalScore;
1893
+ if (referrer.finalScore < minFinalScoreToQualify) {
1894
+ minFinalScoreToQualify = referrer.finalScore;
1895
+ }
1896
+ }
1897
+ }
1898
+ if (minFinalScoreToQualify === Number.MAX_SAFE_INTEGER) {
1899
+ if (rules.maxQualifiedReferrers === 0) {
1900
+ } else {
1901
+ if (referrers.length !== 0) {
1902
+ throw new Error(
1903
+ "AggregatedReferrerMetricsPieSplit: There are referrers on the leaderboard, and the rules allow for qualified referrers, but no qualified referrers."
1904
+ );
1905
+ }
1906
+ minFinalScoreToQualify = 0;
1907
+ }
1908
+ }
1909
+ const result = {
1910
+ grandTotalReferrals,
1911
+ grandTotalIncrementalDuration,
1912
+ grandTotalRevenueContribution: priceEth(grandTotalRevenueContributionAmount),
1913
+ grandTotalQualifiedReferrersFinalScore,
1914
+ minFinalScoreToQualify
1915
+ };
1916
+ validateAggregatedReferrerMetricsPieSplit(result);
1917
+ return result;
1918
+ };
1919
+
1920
+ // src/edition.ts
1921
+ var REFERRAL_PROGRAM_EDITION_SLUG_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
1922
+ function validateReferralProgramEditionConfigSet(configSet) {
1923
+ const violation = Array.from(configSet.entries()).find(([key, config]) => key !== config.slug);
1924
+ if (violation) {
1925
+ const [key, config] = violation;
1926
+ throw new Error(
1927
+ `Edition config set invariant violation: map key "${key}" does not match config.slug "${config.slug}"`
1928
+ );
1929
+ }
1930
+ }
1931
+ function buildReferralProgramEditionConfigSet(configs) {
1932
+ const slugCounts = configs.reduce((counts, config) => {
1933
+ counts.set(config.slug, (counts.get(config.slug) || 0) + 1);
1934
+ return counts;
1935
+ }, /* @__PURE__ */ new Map());
1936
+ const duplicates = Array.from(slugCounts.entries()).filter(([_, count]) => count > 1).map(([slug, count]) => `"${slug}" (${count} occurrences)`);
1937
+ if (duplicates.length > 0) {
1938
+ throw new Error(`Duplicate edition config slugs detected: ${duplicates.join(", ")}`);
1939
+ }
1940
+ const configSet = new Map(configs.map((config) => [config.slug, config]));
1941
+ validateReferralProgramEditionConfigSet(configSet);
1942
+ return configSet;
1943
+ }
1944
+
1945
+ // src/award-models/shared/edition-summary.ts
1946
+ var validateBaseReferralProgramEditionSummary = (summary) => {
1947
+ if (!REFERRAL_PROGRAM_EDITION_SLUG_PATTERN.test(summary.slug)) {
1948
+ throw new Error(
1949
+ `BaseReferralProgramEditionSummary: slug "${summary.slug}" does not match required pattern ${REFERRAL_PROGRAM_EDITION_SLUG_PATTERN}.`
1950
+ );
1951
+ }
1952
+ if (summary.displayName.length === 0) {
1953
+ throw new Error("BaseReferralProgramEditionSummary: displayName must not be empty.");
1954
+ }
1955
+ if (summary.awardModel !== summary.rules.awardModel) {
1956
+ throw new Error(
1957
+ `BaseReferralProgramEditionSummary: awardModel (${summary.awardModel}) must equal rules.awardModel (${summary.rules.awardModel}).`
1958
+ );
1959
+ }
1960
+ };
1961
+
1962
+ // src/award-models/pie-split/rules.ts
1963
+ var validateReferralProgramRulesPieSplit = (rules) => {
1964
+ makePriceUsdcSchema("ReferralProgramRulesPieSplit.awardPool").parse(rules.awardPool);
1965
+ validateNonNegativeInteger(rules.maxQualifiedReferrers);
1966
+ validateBaseReferralProgramRules(rules);
1967
+ };
1968
+ var buildReferralProgramRulesPieSplit = (awardPool, maxQualifiedReferrers, startTime, endTime, subregistryId, rulesUrl, areAwardsDistributed) => {
1969
+ const result = {
1970
+ awardModel: ReferralProgramAwardModels.PieSplit,
1971
+ awardPool,
1972
+ maxQualifiedReferrers,
1973
+ startTime,
1974
+ endTime,
1975
+ subregistryId,
1976
+ rulesUrl,
1977
+ areAwardsDistributed
1978
+ };
1979
+ validateReferralProgramRulesPieSplit(result);
1980
+ return result;
1981
+ };
1982
+
1983
+ // src/award-models/pie-split/status.ts
1984
+ var calcReferralProgramEditionStatusPieSplit = (rules, now) => calcBaseReferralProgramEditionStatus(rules, now);
1985
+
1986
+ // src/award-models/pie-split/edition-summary.ts
1987
+ var validateEditionSummaryPieSplit = (summary) => {
1988
+ validateReferralProgramRulesPieSplit(summary.rules);
1989
+ validateBaseReferralProgramEditionSummary(summary);
1990
+ };
1991
+ function buildEditionSummaryPieSplit(slug, displayName, rules, leaderboard) {
1992
+ const status = calcReferralProgramEditionStatusPieSplit(rules, leaderboard.accurateAsOf);
1993
+ const result = { awardModel: rules.awardModel, slug, displayName, status, rules };
1994
+ validateEditionSummaryPieSplit(result);
1995
+ return result;
1996
+ }
1997
+
1998
+ // src/award-models/shared/leaderboard-guards.ts
1999
+ var assertLeaderboardInputs = (allReferrers, rules, accurateAsOf) => {
2000
+ const uniqueReferrers = new Set(allReferrers.map((r) => r.referrer));
2001
+ if (uniqueReferrers.size !== allReferrers.length) {
2002
+ throw new Error(
2003
+ "ReferrerLeaderboard: Cannot build a leaderboard containing duplicate referrers"
2004
+ );
2005
+ }
2006
+ if (accurateAsOf < rules.startTime && allReferrers.length > 0) {
2007
+ throw new Error(
2008
+ `ReferrerLeaderboard: accurateAsOf (${accurateAsOf}) is before startTime (${rules.startTime}) which indicates allReferrers should be empty, but allReferrers is not empty.`
2009
+ );
2010
+ }
2011
+ };
2012
+
2013
+ // src/award-models/shared/rank.ts
2014
+ var validateReferrerRank = (rank) => {
2015
+ if (!isPositiveInteger(rank)) {
2016
+ throw new Error(`Invalid ReferrerRank: ${rank}. ReferrerRank must be a positive integer.`);
2017
+ }
2018
+ };
2019
+ var compareReferrerMetrics = (a, b) => {
2020
+ if (a.totalIncrementalDuration !== b.totalIncrementalDuration) {
2021
+ return b.totalIncrementalDuration - a.totalIncrementalDuration;
611
2022
  }
612
2023
  if (b.referrer > a.referrer) return 1;
613
2024
  if (b.referrer < a.referrer) return -1;
614
2025
  return 0;
615
2026
  };
2027
+ var sortReferrerMetrics = (referrers) => {
2028
+ return [...referrers].sort(compareReferrerMetrics);
2029
+ };
616
2030
 
617
2031
  // src/referrer-metrics.ts
618
2032
  var buildReferrerMetrics = (referrer, totalReferrals, totalIncrementalDuration, totalRevenueContribution) => {
619
2033
  const result = {
620
- referrer: normalizeAddress(referrer),
2034
+ referrer,
621
2035
  totalReferrals,
622
2036
  totalIncrementalDuration,
623
2037
  totalRevenueContribution
@@ -626,153 +2040,189 @@ var buildReferrerMetrics = (referrer, totalReferrals, totalIncrementalDuration,
626
2040
  return result;
627
2041
  };
628
2042
  var validateReferrerMetrics = (metrics) => {
629
- validateLowercaseAddress(metrics.referrer);
2043
+ validateNormalizedAddress(metrics.referrer);
630
2044
  validateNonNegativeInteger(metrics.totalReferrals);
631
2045
  validateDuration(metrics.totalIncrementalDuration);
632
- validateRevenueContribution(metrics.totalRevenueContribution);
2046
+ makePriceEthSchema("ReferrerMetrics.totalRevenueContribution").parse(
2047
+ metrics.totalRevenueContribution
2048
+ );
633
2049
  };
634
- var sortReferrerMetrics = (referrers) => {
635
- return [...referrers].sort(compareReferrerMetrics);
2050
+
2051
+ // src/award-models/pie-split/score.ts
2052
+ var calcReferrerScorePieSplit = (totalIncrementalDuration) => {
2053
+ return totalIncrementalDuration / SECONDS_PER_YEAR;
636
2054
  };
637
- var buildScoredReferrerMetrics = (referrer) => {
2055
+
2056
+ // src/award-models/pie-split/rank.ts
2057
+ function isReferrerQualifiedPieSplit(rank, rules) {
2058
+ return rank <= rules.maxQualifiedReferrers;
2059
+ }
2060
+ function calcReferrerFinalScoreBoostPieSplit(rank, rules) {
2061
+ if (!isReferrerQualifiedPieSplit(rank, rules)) return 0;
2062
+ if (rules.maxQualifiedReferrers === 1) return 1;
2063
+ return 1 - (rank - 1) / (rules.maxQualifiedReferrers - 1);
2064
+ }
2065
+ function calcReferrerFinalScoreMultiplierPieSplit(rank, rules) {
2066
+ return 1 + calcReferrerFinalScoreBoostPieSplit(rank, rules);
2067
+ }
2068
+ function calcReferrerFinalScorePieSplit(rank, totalIncrementalDuration, rules) {
2069
+ return calcReferrerScorePieSplit(totalIncrementalDuration) * calcReferrerFinalScoreMultiplierPieSplit(rank, rules);
2070
+ }
2071
+
2072
+ // src/award-models/pie-split/metrics.ts
2073
+ var buildScoredReferrerMetricsPieSplit = (referrer) => {
638
2074
  const result = {
639
2075
  ...referrer,
640
- score: calcReferrerScore(referrer.totalIncrementalDuration)
2076
+ score: calcReferrerScorePieSplit(referrer.totalIncrementalDuration)
641
2077
  };
642
- validateScoredReferrerMetrics(result);
2078
+ validateScoredReferrerMetricsPieSplit(result);
643
2079
  return result;
644
2080
  };
645
- var validateScoredReferrerMetrics = (metrics) => {
2081
+ var validateScoredReferrerMetricsPieSplit = (metrics) => {
646
2082
  validateReferrerMetrics(metrics);
647
2083
  validateReferrerScore(metrics.score);
648
- const expectedScore = calcReferrerScore(metrics.totalIncrementalDuration);
2084
+ const expectedScore = calcReferrerScorePieSplit(metrics.totalIncrementalDuration);
649
2085
  if (metrics.score !== expectedScore) {
650
2086
  throw new Error(`Referrer: Invalid score: ${metrics.score}, expected: ${expectedScore}.`);
651
2087
  }
652
2088
  };
653
- var validateRankedReferrerMetrics = (metrics, rules) => {
654
- validateScoredReferrerMetrics(metrics);
2089
+ var validateRankedReferrerMetricsPieSplit = (metrics, rules) => {
2090
+ validateScoredReferrerMetricsPieSplit(metrics);
655
2091
  validateReferrerRank(metrics.rank);
656
2092
  if (metrics.finalScoreBoost < 0 || metrics.finalScoreBoost > 1) {
657
2093
  throw new Error(
658
- `Invalid RankedReferrerMetrics: Invalid finalScoreBoost: ${metrics.finalScoreBoost}. finalScoreBoost must be between 0 and 1 (inclusive).`
2094
+ `Invalid RankedReferrerMetricsPieSplit: Invalid finalScoreBoost: ${metrics.finalScoreBoost}. finalScoreBoost must be between 0 and 1 (inclusive).`
659
2095
  );
660
2096
  }
661
2097
  validateReferrerScore(metrics.finalScore);
662
- const expectedIsQualified = isReferrerQualified(metrics.rank, rules);
2098
+ const expectedIsQualified = isReferrerQualifiedPieSplit(metrics.rank, rules);
663
2099
  if (metrics.isQualified !== expectedIsQualified) {
664
2100
  throw new Error(
665
- `RankedReferrerMetrics: Invalid isQualified: ${metrics.isQualified}, expected: ${expectedIsQualified}.`
2101
+ `RankedReferrerMetricsPieSplit: Invalid isQualified: ${metrics.isQualified}, expected: ${expectedIsQualified}.`
666
2102
  );
667
2103
  }
668
- const expectedFinalScoreBoost = calcReferrerFinalScoreBoost(metrics.rank, rules);
2104
+ const expectedFinalScoreBoost = calcReferrerFinalScoreBoostPieSplit(metrics.rank, rules);
669
2105
  if (metrics.finalScoreBoost !== expectedFinalScoreBoost) {
670
2106
  throw new Error(
671
- `RankedReferrerMetrics: Invalid finalScoreBoost: ${metrics.finalScoreBoost}, expected: ${expectedFinalScoreBoost}.`
2107
+ `RankedReferrerMetricsPieSplit: Invalid finalScoreBoost: ${metrics.finalScoreBoost}, expected: ${expectedFinalScoreBoost}.`
672
2108
  );
673
2109
  }
674
- const expectedFinalScore = calcReferrerFinalScore(
2110
+ const expectedFinalScore = calcReferrerFinalScorePieSplit(
675
2111
  metrics.rank,
676
2112
  metrics.totalIncrementalDuration,
677
2113
  rules
678
2114
  );
679
2115
  if (metrics.finalScore !== expectedFinalScore) {
680
2116
  throw new Error(
681
- `RankedReferrerMetrics: Invalid finalScore: ${metrics.finalScore}, expected: ${expectedFinalScore}.`
2117
+ `RankedReferrerMetricsPieSplit: Invalid finalScore: ${metrics.finalScore}, expected: ${expectedFinalScore}.`
682
2118
  );
683
2119
  }
684
2120
  };
685
- var buildRankedReferrerMetrics = (referrer, rank, rules) => {
2121
+ var buildRankedReferrerMetricsPieSplit = (referrer, rank, rules) => {
686
2122
  const result = {
687
2123
  ...referrer,
688
2124
  rank,
689
- isQualified: isReferrerQualified(rank, rules),
690
- finalScoreBoost: calcReferrerFinalScoreBoost(rank, rules),
691
- finalScore: calcReferrerFinalScore(rank, referrer.totalIncrementalDuration, rules)
2125
+ isQualified: isReferrerQualifiedPieSplit(rank, rules),
2126
+ finalScoreBoost: calcReferrerFinalScoreBoostPieSplit(rank, rules),
2127
+ finalScore: calcReferrerFinalScorePieSplit(rank, referrer.totalIncrementalDuration, rules)
692
2128
  };
693
- validateRankedReferrerMetrics(result, rules);
2129
+ validateRankedReferrerMetricsPieSplit(result, rules);
694
2130
  return result;
695
2131
  };
696
- var calcReferrerAwardPoolShare = (referrer, aggregatedMetrics, rules) => {
697
- if (!isReferrerQualified(referrer.rank, rules)) return 0;
2132
+ var calcReferrerAwardPoolSharePieSplit = (referrer, aggregatedMetrics) => {
2133
+ if (!referrer.isQualified) return 0;
698
2134
  if (aggregatedMetrics.grandTotalQualifiedReferrersFinalScore === 0) return 0;
699
- return calcReferrerFinalScore(referrer.rank, referrer.totalIncrementalDuration, rules) / aggregatedMetrics.grandTotalQualifiedReferrersFinalScore;
2135
+ return referrer.finalScore / aggregatedMetrics.grandTotalQualifiedReferrersFinalScore;
700
2136
  };
701
- var validateAwardedReferrerMetrics = (referrer, rules) => {
702
- validateRankedReferrerMetrics(referrer, rules);
2137
+ var validateAwardedReferrerMetricsPieSplit = (referrer, rules) => {
2138
+ validateRankedReferrerMetricsPieSplit(referrer, rules);
703
2139
  if (referrer.awardPoolShare < 0 || referrer.awardPoolShare > 1) {
704
2140
  throw new Error(
705
- `Invalid AwardedReferrerMetrics: ${referrer.awardPoolShare}. awardPoolShare must be between 0 and 1 (inclusive).`
2141
+ `Invalid AwardedReferrerMetricsPieSplit: ${referrer.awardPoolShare}. awardPoolShare must be between 0 and 1 (inclusive).`
706
2142
  );
707
2143
  }
708
- if (referrer.awardPoolApproxValue < 0 || referrer.awardPoolApproxValue > rules.totalAwardPoolValue) {
2144
+ makePriceUsdcSchema("AwardedReferrerMetricsPieSplit.awardPoolApproxValue").parse(
2145
+ referrer.awardPoolApproxValue
2146
+ );
2147
+ if (referrer.awardPoolApproxValue.amount > rules.awardPool.amount) {
709
2148
  throw new Error(
710
- `Invalid AwardedReferrerMetrics: ${referrer.awardPoolApproxValue}. awardPoolApproxValue must be between 0 and ${rules.totalAwardPoolValue} (inclusive).`
2149
+ `AwardedReferrerMetricsPieSplit: awardPoolApproxValue.amount ${referrer.awardPoolApproxValue.amount.toString()} exceeds awardPool.amount ${rules.awardPool.amount.toString()}.`
711
2150
  );
712
2151
  }
713
2152
  };
714
- var buildAwardedReferrerMetrics = (referrer, aggregatedMetrics, rules) => {
715
- const awardPoolShare = calcReferrerAwardPoolShare(referrer, aggregatedMetrics, rules);
2153
+ var buildAwardedReferrerMetricsPieSplit = (referrer, aggregatedMetrics, rules) => {
2154
+ const awardPoolShare = calcReferrerAwardPoolSharePieSplit(referrer, aggregatedMetrics);
2155
+ const awardPoolApproxValue = scalePrice(rules.awardPool, awardPoolShare);
716
2156
  const result = {
717
2157
  ...referrer,
718
2158
  awardPoolShare,
719
- awardPoolApproxValue: awardPoolShare * rules.totalAwardPoolValue
2159
+ awardPoolApproxValue
720
2160
  };
721
- validateAwardedReferrerMetrics(result, rules);
2161
+ validateAwardedReferrerMetricsPieSplit(result, rules);
722
2162
  return result;
723
2163
  };
724
- var validateUnrankedReferrerMetrics = (metrics) => {
725
- validateScoredReferrerMetrics(metrics);
2164
+ var validateUnrankedReferrerMetricsPieSplit = (metrics) => {
2165
+ validateScoredReferrerMetricsPieSplit(metrics);
726
2166
  if (metrics.rank !== null) {
727
- throw new Error(`Invalid UnrankedReferrerMetrics: rank must be null, got: ${metrics.rank}.`);
2167
+ throw new Error(
2168
+ `Invalid UnrankedReferrerMetricsPieSplit: rank must be null, got: ${metrics.rank}.`
2169
+ );
728
2170
  }
729
2171
  if (metrics.isQualified !== false) {
730
2172
  throw new Error(
731
- `Invalid UnrankedReferrerMetrics: isQualified must be false, got: ${metrics.isQualified}.`
2173
+ `Invalid UnrankedReferrerMetricsPieSplit: isQualified must be false, got: ${metrics.isQualified}.`
732
2174
  );
733
2175
  }
734
2176
  if (metrics.totalReferrals !== 0) {
735
2177
  throw new Error(
736
- `Invalid UnrankedReferrerMetrics: totalReferrals must be 0, got: ${metrics.totalReferrals}.`
2178
+ `Invalid UnrankedReferrerMetricsPieSplit: totalReferrals must be 0, got: ${metrics.totalReferrals}.`
737
2179
  );
738
2180
  }
739
2181
  if (metrics.totalIncrementalDuration !== 0) {
740
2182
  throw new Error(
741
- `Invalid UnrankedReferrerMetrics: totalIncrementalDuration must be 0, got: ${metrics.totalIncrementalDuration}.`
2183
+ `Invalid UnrankedReferrerMetricsPieSplit: totalIncrementalDuration must be 0, got: ${metrics.totalIncrementalDuration}.`
742
2184
  );
743
2185
  }
744
- if (metrics.totalRevenueContribution !== 0n) {
2186
+ makePriceEthSchema("UnrankedReferrerMetricsPieSplit.totalRevenueContribution").parse(
2187
+ metrics.totalRevenueContribution
2188
+ );
2189
+ if (metrics.totalRevenueContribution.amount !== 0n) {
745
2190
  throw new Error(
746
- `Invalid UnrankedReferrerMetrics: totalRevenueContribution must be 0n, got: ${metrics.totalRevenueContribution.toString()}.`
2191
+ `Invalid UnrankedReferrerMetricsPieSplit: totalRevenueContribution.amount must be 0n, got: ${metrics.totalRevenueContribution.amount.toString()}.`
747
2192
  );
748
2193
  }
749
2194
  if (metrics.score !== 0) {
750
- throw new Error(`Invalid UnrankedReferrerMetrics: score must be 0, got: ${metrics.score}.`);
2195
+ throw new Error(
2196
+ `Invalid UnrankedReferrerMetricsPieSplit: score must be 0, got: ${metrics.score}.`
2197
+ );
751
2198
  }
752
2199
  if (metrics.finalScoreBoost !== 0) {
753
2200
  throw new Error(
754
- `Invalid UnrankedReferrerMetrics: finalScoreBoost must be 0, got: ${metrics.finalScoreBoost}.`
2201
+ `Invalid UnrankedReferrerMetricsPieSplit: finalScoreBoost must be 0, got: ${metrics.finalScoreBoost}.`
755
2202
  );
756
2203
  }
757
2204
  if (metrics.finalScore !== 0) {
758
2205
  throw new Error(
759
- `Invalid UnrankedReferrerMetrics: finalScore must be 0, got: ${metrics.finalScore}.`
2206
+ `Invalid UnrankedReferrerMetricsPieSplit: finalScore must be 0, got: ${metrics.finalScore}.`
760
2207
  );
761
2208
  }
762
2209
  if (metrics.awardPoolShare !== 0) {
763
2210
  throw new Error(
764
- `Invalid UnrankedReferrerMetrics: awardPoolShare must be 0, got: ${metrics.awardPoolShare}.`
2211
+ `Invalid UnrankedReferrerMetricsPieSplit: awardPoolShare must be 0, got: ${metrics.awardPoolShare}.`
765
2212
  );
766
2213
  }
767
- if (metrics.awardPoolApproxValue !== 0) {
2214
+ makePriceUsdcSchema("UnrankedReferrerMetricsPieSplit.awardPoolApproxValue").parse(
2215
+ metrics.awardPoolApproxValue
2216
+ );
2217
+ if (metrics.awardPoolApproxValue.amount !== 0n) {
768
2218
  throw new Error(
769
- `Invalid UnrankedReferrerMetrics: awardPoolApproxValue must be 0, got: ${metrics.awardPoolApproxValue}.`
2219
+ `Invalid UnrankedReferrerMetricsPieSplit: awardPoolApproxValue must be 0n, got: ${metrics.awardPoolApproxValue.amount.toString()}.`
770
2220
  );
771
2221
  }
772
2222
  };
773
- var buildUnrankedReferrerMetrics = (referrer) => {
774
- const baseMetrics = buildReferrerMetrics(referrer, 0, 0, 0n);
775
- const scoredMetrics = buildScoredReferrerMetrics(baseMetrics);
2223
+ var buildUnrankedReferrerMetricsPieSplit = (referrer) => {
2224
+ const metrics = buildReferrerMetrics(referrer, 0, 0, priceEth(0n));
2225
+ const scoredMetrics = buildScoredReferrerMetricsPieSplit(metrics);
776
2226
  const result = {
777
2227
  ...scoredMetrics,
778
2228
  rank: null,
@@ -780,438 +2230,411 @@ var buildUnrankedReferrerMetrics = (referrer) => {
780
2230
  finalScoreBoost: 0,
781
2231
  finalScore: 0,
782
2232
  awardPoolShare: 0,
783
- awardPoolApproxValue: 0
2233
+ awardPoolApproxValue: priceUsdc(0n)
784
2234
  };
785
- validateUnrankedReferrerMetrics(result);
2235
+ validateUnrankedReferrerMetricsPieSplit(result);
786
2236
  return result;
787
2237
  };
788
2238
 
789
- // src/referrer-detail.ts
790
- var ReferrerDetailTypeIds = {
791
- /**
792
- * Represents a referrer who is ranked on the leaderboard.
793
- */
794
- Ranked: "ranked",
795
- /**
796
- * Represents a referrer who is not ranked on the leaderboard.
797
- */
798
- Unranked: "unranked"
2239
+ // src/award-models/pie-split/leaderboard.ts
2240
+ var buildReferrerLeaderboardPieSplit = (allReferrers, rules, accurateAsOf) => {
2241
+ assertLeaderboardInputs(allReferrers, rules, accurateAsOf);
2242
+ const sortedReferrers = sortReferrerMetrics(allReferrers);
2243
+ const scoredReferrers = sortedReferrers.map((r) => buildScoredReferrerMetricsPieSplit(r));
2244
+ const rankedReferrers = scoredReferrers.map(
2245
+ (r, index) => buildRankedReferrerMetricsPieSplit(r, index + 1, rules)
2246
+ );
2247
+ const aggregatedMetrics = buildAggregatedReferrerMetricsPieSplit(rankedReferrers, rules);
2248
+ const awardedReferrers = rankedReferrers.map(
2249
+ (r) => buildAwardedReferrerMetricsPieSplit(r, aggregatedMetrics, rules)
2250
+ );
2251
+ const referrers = new Map(awardedReferrers.map((r) => [r.referrer, r]));
2252
+ return { awardModel: rules.awardModel, rules, aggregatedMetrics, referrers, accurateAsOf };
799
2253
  };
800
- var getReferrerDetail = (referrer, leaderboard) => {
801
- const awardedReferrerMetrics = leaderboard.referrers.get(referrer);
802
- if (awardedReferrerMetrics) {
803
- return {
804
- type: ReferrerDetailTypeIds.Ranked,
805
- rules: leaderboard.rules,
806
- referrer: awardedReferrerMetrics,
807
- aggregatedMetrics: leaderboard.aggregatedMetrics,
808
- accurateAsOf: leaderboard.accurateAsOf
809
- };
810
- }
2254
+
2255
+ // src/award-models/pie-split/leaderboard-page.ts
2256
+ function buildLeaderboardPagePieSplit(pageContext, leaderboard) {
2257
+ const status = calcReferralProgramEditionStatusPieSplit(
2258
+ leaderboard.rules,
2259
+ leaderboard.accurateAsOf
2260
+ );
811
2261
  return {
812
- type: ReferrerDetailTypeIds.Unranked,
2262
+ awardModel: leaderboard.awardModel,
813
2263
  rules: leaderboard.rules,
814
- referrer: buildUnrankedReferrerMetrics(referrer),
2264
+ referrers: sliceReferrers(leaderboard.referrers, pageContext),
815
2265
  aggregatedMetrics: leaderboard.aggregatedMetrics,
2266
+ pageContext,
2267
+ status,
816
2268
  accurateAsOf: leaderboard.accurateAsOf
817
2269
  };
818
- };
2270
+ }
819
2271
 
820
- // src/api/types.ts
821
- var ReferrerLeaderboardPageResponseCodes = {
822
- /**
823
- * Represents that the requested referrer leaderboard page is available.
824
- */
825
- Ok: "ok",
826
- /**
827
- * Represents that the referrer leaderboard data is not available.
828
- */
829
- Error: "error"
2272
+ // src/award-models/rev-share-cap/aggregations.ts
2273
+ var validateAggregatedReferrerMetricsRevShareCap = (metrics) => {
2274
+ validateNonNegativeInteger(metrics.grandTotalReferrals);
2275
+ validateDuration(metrics.grandTotalIncrementalDuration);
2276
+ makePriceEthSchema("AggregatedReferrerMetricsRevShareCap.grandTotalRevenueContribution").parse(
2277
+ metrics.grandTotalRevenueContribution
2278
+ );
2279
+ makePriceUsdcSchema("AggregatedReferrerMetricsRevShareCap.awardPoolRemaining").parse(
2280
+ metrics.awardPoolRemaining
2281
+ );
830
2282
  };
831
- var ReferrerDetailResponseCodes = {
832
- /**
833
- * Represents that the referrer detail data is available.
834
- */
835
- Ok: "ok",
836
- /**
837
- * Represents that an error occurred while fetching the data.
838
- */
839
- Error: "error"
2283
+ var buildAggregatedReferrerMetricsRevShareCap = (referrers, awardPoolRemaining) => {
2284
+ let grandTotalReferrals = 0;
2285
+ let grandTotalIncrementalDuration = 0;
2286
+ let grandTotalRevenueContributionAmount = 0n;
2287
+ for (const referrer of referrers) {
2288
+ grandTotalReferrals += referrer.totalReferrals;
2289
+ grandTotalIncrementalDuration += referrer.totalIncrementalDuration;
2290
+ grandTotalRevenueContributionAmount += referrer.totalRevenueContribution.amount;
2291
+ }
2292
+ const aggregatedMetrics = {
2293
+ grandTotalReferrals,
2294
+ grandTotalIncrementalDuration,
2295
+ grandTotalRevenueContribution: priceEth(grandTotalRevenueContributionAmount),
2296
+ awardPoolRemaining
2297
+ };
2298
+ validateAggregatedReferrerMetricsRevShareCap(aggregatedMetrics);
2299
+ return aggregatedMetrics;
840
2300
  };
841
2301
 
842
- // src/api/zod-schemas.ts
843
- var makeRevenueContributionSchema = (valueLabel = "RevenueContribution") => z2.coerce.bigint({
844
- error: `${valueLabel} must represent a bigint.`
845
- }).nonnegative({
846
- error: `${valueLabel} must not be negative.`
847
- });
848
- var makeReferralProgramRulesSchema = (valueLabel = "ReferralProgramRules") => z2.object({
849
- totalAwardPoolValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.totalAwardPoolValue`),
850
- maxQualifiedReferrers: makeNonNegativeIntegerSchema(`${valueLabel}.maxQualifiedReferrers`),
851
- startTime: makeUnixTimestampSchema(`${valueLabel}.startTime`),
852
- endTime: makeUnixTimestampSchema(`${valueLabel}.endTime`),
853
- subregistryId: makeAccountIdSchema(`${valueLabel}.subregistryId`)
854
- });
855
- var makeAwardedReferrerMetricsSchema = (valueLabel = "AwardedReferrerMetrics") => z2.object({
856
- referrer: makeLowercaseAddressSchema(`${valueLabel}.referrer`),
857
- totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),
858
- totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),
859
- totalRevenueContribution: makeRevenueContributionSchema(
860
- `${valueLabel}.totalRevenueContribution`
861
- ),
862
- score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),
863
- rank: makePositiveIntegerSchema(`${valueLabel}.rank`),
864
- isQualified: z2.boolean(),
865
- finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(
866
- 1,
867
- `${valueLabel}.finalScoreBoost must be <= 1`
868
- ),
869
- finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),
870
- awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(
871
- 1,
872
- `${valueLabel}.awardPoolShare must be <= 1`
873
- ),
874
- awardPoolApproxValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolApproxValue`)
875
- });
876
- var makeUnrankedReferrerMetricsSchema = (valueLabel = "UnrankedReferrerMetrics") => z2.object({
877
- referrer: makeLowercaseAddressSchema(`${valueLabel}.referrer`),
878
- totalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.totalReferrals`),
879
- totalIncrementalDuration: makeDurationSchema(`${valueLabel}.totalIncrementalDuration`),
880
- totalRevenueContribution: makeRevenueContributionSchema(
881
- `${valueLabel}.totalRevenueContribution`
882
- ),
883
- score: makeFiniteNonNegativeNumberSchema(`${valueLabel}.score`),
884
- rank: z2.null(),
885
- isQualified: z2.literal(false),
886
- finalScoreBoost: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScoreBoost`).max(
887
- 1,
888
- `${valueLabel}.finalScoreBoost must be <= 1`
889
- ),
890
- finalScore: makeFiniteNonNegativeNumberSchema(`${valueLabel}.finalScore`),
891
- awardPoolShare: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolShare`).max(
892
- 1,
893
- `${valueLabel}.awardPoolShare must be <= 1`
894
- ),
895
- awardPoolApproxValue: makeFiniteNonNegativeNumberSchema(`${valueLabel}.awardPoolApproxValue`)
896
- });
897
- var makeAggregatedReferrerMetricsSchema = (valueLabel = "AggregatedReferrerMetrics") => z2.object({
898
- grandTotalReferrals: makeNonNegativeIntegerSchema(`${valueLabel}.grandTotalReferrals`),
899
- grandTotalIncrementalDuration: makeDurationSchema(
900
- `${valueLabel}.grandTotalIncrementalDuration`
901
- ),
902
- grandTotalRevenueContribution: makeRevenueContributionSchema(
903
- `${valueLabel}.grandTotalRevenueContribution`
904
- ),
905
- grandTotalQualifiedReferrersFinalScore: makeFiniteNonNegativeNumberSchema(
906
- `${valueLabel}.grandTotalQualifiedReferrersFinalScore`
907
- ),
908
- minFinalScoreToQualify: makeFiniteNonNegativeNumberSchema(
909
- `${valueLabel}.minFinalScoreToQualify`
910
- )
911
- });
912
- var makeReferrerLeaderboardPageContextSchema = (valueLabel = "ReferrerLeaderboardPageContext") => z2.object({
913
- page: makePositiveIntegerSchema(`${valueLabel}.page`),
914
- recordsPerPage: makePositiveIntegerSchema(`${valueLabel}.recordsPerPage`).max(
915
- REFERRERS_PER_LEADERBOARD_PAGE_MAX,
916
- `${valueLabel}.recordsPerPage must not exceed ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}`
917
- ),
918
- totalRecords: makeNonNegativeIntegerSchema(`${valueLabel}.totalRecords`),
919
- totalPages: makePositiveIntegerSchema(`${valueLabel}.totalPages`),
920
- hasNext: z2.boolean(),
921
- hasPrev: z2.boolean(),
922
- startIndex: z2.optional(makeNonNegativeIntegerSchema(`${valueLabel}.startIndex`)),
923
- endIndex: z2.optional(makeNonNegativeIntegerSchema(`${valueLabel}.endIndex`))
924
- });
925
- var makeReferrerLeaderboardPageSchema = (valueLabel = "ReferrerLeaderboardPage") => z2.object({
926
- rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),
927
- referrers: z2.array(makeAwardedReferrerMetricsSchema(`${valueLabel}.referrers[record]`)),
928
- aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),
929
- pageContext: makeReferrerLeaderboardPageContextSchema(`${valueLabel}.pageContext`),
930
- accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
931
- });
932
- var makeReferrerLeaderboardPageResponseOkSchema = (valueLabel = "ReferrerLeaderboardPageResponseOk") => z2.object({
933
- responseCode: z2.literal(ReferrerLeaderboardPageResponseCodes.Ok),
934
- data: makeReferrerLeaderboardPageSchema(`${valueLabel}.data`)
935
- });
936
- var makeReferrerLeaderboardPageResponseErrorSchema = (_valueLabel = "ReferrerLeaderboardPageResponseError") => z2.object({
937
- responseCode: z2.literal(ReferrerLeaderboardPageResponseCodes.Error),
938
- error: z2.string(),
939
- errorMessage: z2.string()
940
- });
941
- var makeReferrerLeaderboardPageResponseSchema = (valueLabel = "ReferrerLeaderboardPageResponse") => z2.union([
942
- makeReferrerLeaderboardPageResponseOkSchema(valueLabel),
943
- makeReferrerLeaderboardPageResponseErrorSchema(valueLabel)
944
- ]);
945
- var makeReferrerDetailRankedSchema = (valueLabel = "ReferrerDetailRanked") => z2.object({
946
- type: z2.literal(ReferrerDetailTypeIds.Ranked),
947
- rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),
948
- referrer: makeAwardedReferrerMetricsSchema(`${valueLabel}.referrer`),
949
- aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),
950
- accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
951
- });
952
- var makeReferrerDetailUnrankedSchema = (valueLabel = "ReferrerDetailUnranked") => z2.object({
953
- type: z2.literal(ReferrerDetailTypeIds.Unranked),
954
- rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`),
955
- referrer: makeUnrankedReferrerMetricsSchema(`${valueLabel}.referrer`),
956
- aggregatedMetrics: makeAggregatedReferrerMetricsSchema(`${valueLabel}.aggregatedMetrics`),
957
- accurateAsOf: makeUnixTimestampSchema(`${valueLabel}.accurateAsOf`)
958
- });
959
- var makeReferrerDetailResponseOkSchema = (valueLabel = "ReferrerDetailResponse") => z2.object({
960
- responseCode: z2.literal(ReferrerDetailResponseCodes.Ok),
961
- data: z2.union([
962
- makeReferrerDetailRankedSchema(`${valueLabel}.data`),
963
- makeReferrerDetailUnrankedSchema(`${valueLabel}.data`)
964
- ])
965
- });
966
- var makeReferrerDetailResponseErrorSchema = (_valueLabel = "ReferrerDetailResponse") => z2.object({
967
- responseCode: z2.literal(ReferrerDetailResponseCodes.Error),
968
- error: z2.string(),
969
- errorMessage: z2.string()
970
- });
971
- var makeReferrerDetailResponseSchema = (valueLabel = "ReferrerDetailResponse") => z2.union([
972
- makeReferrerDetailResponseOkSchema(valueLabel),
973
- makeReferrerDetailResponseErrorSchema(valueLabel)
974
- ]);
2302
+ // src/award-models/rev-share-cap/status.ts
2303
+ var calcReferralProgramEditionStatusRevShareCap = (rules, now, aggregatedMetrics) => {
2304
+ const base = calcBaseReferralProgramEditionStatus(rules, now);
2305
+ if (base === ReferralProgramEditionStatuses.Active && aggregatedMetrics.awardPoolRemaining.amount === 0n) {
2306
+ return ReferralProgramEditionStatuses.Exhausted;
2307
+ }
2308
+ return base;
2309
+ };
975
2310
 
976
- // src/api/deserialize.ts
977
- function deserializeRevenueContribution(value) {
978
- return BigInt(value);
979
- }
980
- function deserializeReferralProgramRules(rules) {
981
- return rules;
982
- }
983
- function deserializeAwardedReferrerMetrics(metrics) {
984
- return {
985
- referrer: metrics.referrer,
986
- totalReferrals: metrics.totalReferrals,
987
- totalIncrementalDuration: metrics.totalIncrementalDuration,
988
- totalRevenueContribution: deserializeRevenueContribution(metrics.totalRevenueContribution),
989
- score: metrics.score,
990
- rank: metrics.rank,
991
- isQualified: metrics.isQualified,
992
- finalScoreBoost: metrics.finalScoreBoost,
993
- finalScore: metrics.finalScore,
994
- awardPoolShare: metrics.awardPoolShare,
995
- awardPoolApproxValue: metrics.awardPoolApproxValue
2311
+ // src/award-models/rev-share-cap/edition-summary.ts
2312
+ var validateEditionSummaryRevShareCap = (summary) => {
2313
+ validateReferralProgramRulesRevShareCap(summary.rules);
2314
+ makePriceUsdcSchema("ReferralProgramEditionSummaryRevShareCap.awardPoolRemaining").parse(
2315
+ summary.awardPoolRemaining
2316
+ );
2317
+ validateBaseReferralProgramEditionSummary(summary);
2318
+ };
2319
+ function buildEditionSummaryRevShareCap(slug, displayName, rules, leaderboard) {
2320
+ const status = calcReferralProgramEditionStatusRevShareCap(
2321
+ rules,
2322
+ leaderboard.accurateAsOf,
2323
+ leaderboard.aggregatedMetrics
2324
+ );
2325
+ const result = {
2326
+ awardModel: rules.awardModel,
2327
+ slug,
2328
+ displayName,
2329
+ status,
2330
+ rules,
2331
+ awardPoolRemaining: leaderboard.aggregatedMetrics.awardPoolRemaining
996
2332
  };
2333
+ validateEditionSummaryRevShareCap(result);
2334
+ return result;
997
2335
  }
998
- function deserializeUnrankedReferrerMetrics(metrics) {
999
- return {
1000
- referrer: metrics.referrer,
1001
- totalReferrals: metrics.totalReferrals,
1002
- totalIncrementalDuration: metrics.totalIncrementalDuration,
1003
- totalRevenueContribution: deserializeRevenueContribution(metrics.totalRevenueContribution),
1004
- score: metrics.score,
1005
- rank: metrics.rank,
1006
- isQualified: metrics.isQualified,
1007
- finalScoreBoost: metrics.finalScoreBoost,
1008
- finalScore: metrics.finalScore,
1009
- awardPoolShare: metrics.awardPoolShare,
1010
- awardPoolApproxValue: metrics.awardPoolApproxValue
2336
+
2337
+ // src/award-models/rev-share-cap/metrics.ts
2338
+ var validateReferrerMetricsRevShareCap = (metrics, rules) => {
2339
+ validateReferrerMetrics(metrics);
2340
+ makePriceUsdcSchema("ReferrerMetricsRevShareCap.totalBaseRevenueContribution").parse(
2341
+ metrics.totalBaseRevenueContribution
2342
+ );
2343
+ const expectedTotalBaseRevenueContribution = calcBaseRevenueContribution(
2344
+ rules,
2345
+ metrics.totalIncrementalDuration
2346
+ );
2347
+ if (metrics.totalBaseRevenueContribution.amount !== expectedTotalBaseRevenueContribution.amount) {
2348
+ throw new Error(
2349
+ `ReferrerMetricsRevShareCap: Invalid totalBaseRevenueContribution: ${metrics.totalBaseRevenueContribution.amount.toString()}, expected: ${expectedTotalBaseRevenueContribution.amount.toString()}.`
2350
+ );
2351
+ }
2352
+ };
2353
+ var buildReferrerMetricsRevShareCap = (metrics, rules) => {
2354
+ const totalBaseRevenueContribution = calcBaseRevenueContribution(
2355
+ rules,
2356
+ metrics.totalIncrementalDuration
2357
+ );
2358
+ const result = {
2359
+ ...metrics,
2360
+ totalBaseRevenueContribution
1011
2361
  };
1012
- }
1013
- function deserializeAggregatedReferrerMetrics(metrics) {
1014
- return {
1015
- grandTotalReferrals: metrics.grandTotalReferrals,
1016
- grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,
1017
- grandTotalRevenueContribution: deserializeRevenueContribution(
1018
- metrics.grandTotalRevenueContribution
2362
+ validateReferrerMetricsRevShareCap(result, rules);
2363
+ return result;
2364
+ };
2365
+ var validateAdminActionConsistency = (metricsAdminAction, referrer, rules, context) => {
2366
+ const expected = rules.adminActions.find((a) => a.referrer === referrer) ?? null;
2367
+ if (expected === null && metricsAdminAction !== null) {
2368
+ throw new Error(
2369
+ `${context}: expected null, got actionType="${metricsAdminAction.actionType}".`
2370
+ );
2371
+ }
2372
+ if (expected !== null) {
2373
+ if (metricsAdminAction === null || metricsAdminAction.actionType !== expected.actionType || metricsAdminAction.referrer !== expected.referrer || metricsAdminAction.reason !== expected.reason) {
2374
+ throw new Error(`${context}: does not match expected action from rules.`);
2375
+ }
2376
+ }
2377
+ };
2378
+ var validateRankedReferrerMetricsRevShareCap = (metrics, rules) => {
2379
+ validateReferrerMetricsRevShareCap(metrics, rules);
2380
+ validateReferrerRank(metrics.rank);
2381
+ const expectedIsQualified = isReferrerQualifiedRevShareCap(
2382
+ metrics.referrer,
2383
+ metrics.totalBaseRevenueContribution,
2384
+ rules
2385
+ );
2386
+ if (metrics.isQualified !== expectedIsQualified) {
2387
+ throw new Error(
2388
+ `RankedReferrerMetricsRevShareCap: Invalid isQualified: ${metrics.isQualified}, expected: ${expectedIsQualified}.`
2389
+ );
2390
+ }
2391
+ validateAdminActionConsistency(
2392
+ metrics.adminAction,
2393
+ metrics.referrer,
2394
+ rules,
2395
+ "RankedReferrerMetricsRevShareCap: Invalid adminAction"
2396
+ );
2397
+ };
2398
+ var buildRankedReferrerMetricsRevShareCap = (referrer, rank, rules) => {
2399
+ const adminAction = rules.adminActions.find((a) => a.referrer === referrer.referrer) ?? null;
2400
+ const result = {
2401
+ ...referrer,
2402
+ rank,
2403
+ isQualified: isReferrerQualifiedRevShareCap(
2404
+ referrer.referrer,
2405
+ referrer.totalBaseRevenueContribution,
2406
+ rules
1019
2407
  ),
1020
- grandTotalQualifiedReferrersFinalScore: metrics.grandTotalQualifiedReferrersFinalScore,
1021
- minFinalScoreToQualify: metrics.minFinalScoreToQualify
1022
- };
1023
- }
1024
- function deserializeReferrerLeaderboardPage(page) {
1025
- return {
1026
- rules: deserializeReferralProgramRules(page.rules),
1027
- referrers: page.referrers.map(deserializeAwardedReferrerMetrics),
1028
- aggregatedMetrics: deserializeAggregatedReferrerMetrics(page.aggregatedMetrics),
1029
- pageContext: page.pageContext,
1030
- accurateAsOf: page.accurateAsOf
1031
- };
1032
- }
1033
- function deserializeReferrerDetailRanked(detail) {
1034
- return {
1035
- type: detail.type,
1036
- rules: deserializeReferralProgramRules(detail.rules),
1037
- referrer: deserializeAwardedReferrerMetrics(detail.referrer),
1038
- aggregatedMetrics: deserializeAggregatedReferrerMetrics(detail.aggregatedMetrics),
1039
- accurateAsOf: detail.accurateAsOf
2408
+ adminAction
1040
2409
  };
1041
- }
1042
- function deserializeReferrerDetailUnranked(detail) {
1043
- return {
1044
- type: detail.type,
1045
- rules: deserializeReferralProgramRules(detail.rules),
1046
- referrer: deserializeUnrankedReferrerMetrics(detail.referrer),
1047
- aggregatedMetrics: deserializeAggregatedReferrerMetrics(detail.aggregatedMetrics),
1048
- accurateAsOf: detail.accurateAsOf
2410
+ validateRankedReferrerMetricsRevShareCap(result, rules);
2411
+ return result;
2412
+ };
2413
+ var validateAwardedReferrerMetricsRevShareCap = (metrics, rules) => {
2414
+ validateRankedReferrerMetricsRevShareCap(metrics, rules);
2415
+ makePriceUsdcSchema("AwardedReferrerMetricsRevShareCap.uncappedAward").parse(
2416
+ metrics.uncappedAward
2417
+ );
2418
+ makePriceUsdcSchema("AwardedReferrerMetricsRevShareCap.cappedAward").parse(metrics.cappedAward);
2419
+ if (metrics.adminAction?.actionType === AdminActionTypes.Disqualification && metrics.cappedAward.amount !== 0n) {
2420
+ throw new Error(
2421
+ `AwardedReferrerMetricsRevShareCap: cappedAward.amount must be 0n for admin-disqualified referrers, got ${metrics.cappedAward.amount.toString()}.`
2422
+ );
2423
+ }
2424
+ if (!metrics.isQualified && metrics.cappedAward.amount !== 0n) {
2425
+ throw new Error(
2426
+ `AwardedReferrerMetricsRevShareCap: cappedAward.amount must be 0n for unqualified referrers, got ${metrics.cappedAward.amount.toString()}.`
2427
+ );
2428
+ }
2429
+ if (metrics.cappedAward.amount > rules.awardPool.amount) {
2430
+ throw new Error(
2431
+ `AwardedReferrerMetricsRevShareCap: cappedAward.amount ${metrics.cappedAward.amount.toString()} exceeds awardPool.amount ${rules.awardPool.amount.toString()}.`
2432
+ );
2433
+ }
2434
+ if (metrics.cappedAward.amount > metrics.uncappedAward.amount) {
2435
+ throw new Error(
2436
+ `AwardedReferrerMetricsRevShareCap: cappedAward.amount ${metrics.cappedAward.amount.toString()} exceeds uncappedAward.amount ${metrics.uncappedAward.amount.toString()}.`
2437
+ );
2438
+ }
2439
+ };
2440
+ var buildAwardedReferrerMetricsRevShareCap = (referrer, uncappedAward, cappedAward, rules) => {
2441
+ const result = {
2442
+ ...referrer,
2443
+ uncappedAward,
2444
+ cappedAward
1049
2445
  };
1050
- }
1051
- function deserializeReferrerLeaderboardPageResponse(maybeResponse, valueLabel) {
1052
- let deserialized;
1053
- switch (maybeResponse.responseCode) {
1054
- case "ok": {
1055
- deserialized = {
1056
- responseCode: maybeResponse.responseCode,
1057
- data: deserializeReferrerLeaderboardPage(maybeResponse.data)
1058
- };
1059
- break;
1060
- }
1061
- case "error":
1062
- deserialized = maybeResponse;
1063
- break;
2446
+ validateAwardedReferrerMetricsRevShareCap(result, rules);
2447
+ return result;
2448
+ };
2449
+ var validateUnrankedReferrerMetricsRevShareCap = (metrics, rules) => {
2450
+ validateReferrerMetrics(metrics);
2451
+ if (metrics.rank !== null) {
2452
+ throw new Error(
2453
+ `Invalid UnrankedReferrerMetricsRevShareCap: rank must be null, got: ${metrics.rank}.`
2454
+ );
1064
2455
  }
1065
- const schema = makeReferrerLeaderboardPageResponseSchema(valueLabel);
1066
- const parsed = schema.safeParse(deserialized);
1067
- if (parsed.error) {
2456
+ if (metrics.isQualified !== false) {
1068
2457
  throw new Error(
1069
- `Cannot deserialize SerializedReferrerLeaderboardPageResponse:
1070
- ${prettifyError(parsed.error)}
1071
- `
2458
+ `Invalid UnrankedReferrerMetricsRevShareCap: isQualified must be false, got: ${metrics.isQualified}.`
1072
2459
  );
1073
2460
  }
1074
- return parsed.data;
1075
- }
1076
- function deserializeReferrerDetailResponse(maybeResponse, valueLabel) {
1077
- let deserialized;
1078
- switch (maybeResponse.responseCode) {
1079
- case "ok": {
1080
- switch (maybeResponse.data.type) {
1081
- case "ranked":
1082
- deserialized = {
1083
- responseCode: maybeResponse.responseCode,
1084
- data: deserializeReferrerDetailRanked(maybeResponse.data)
1085
- };
1086
- break;
1087
- case "unranked":
1088
- deserialized = {
1089
- responseCode: maybeResponse.responseCode,
1090
- data: deserializeReferrerDetailUnranked(maybeResponse.data)
1091
- };
1092
- break;
1093
- }
1094
- break;
1095
- }
1096
- case "error":
1097
- deserialized = maybeResponse;
1098
- break;
2461
+ validateAdminActionConsistency(
2462
+ metrics.adminAction,
2463
+ metrics.referrer,
2464
+ rules,
2465
+ "Invalid UnrankedReferrerMetricsRevShareCap: adminAction"
2466
+ );
2467
+ if (metrics.totalReferrals !== 0) {
2468
+ throw new Error(
2469
+ `Invalid UnrankedReferrerMetricsRevShareCap: totalReferrals must be 0, got: ${metrics.totalReferrals}.`
2470
+ );
1099
2471
  }
1100
- const schema = makeReferrerDetailResponseSchema(valueLabel);
1101
- const parsed = schema.safeParse(deserialized);
1102
- if (parsed.error) {
1103
- throw new Error(`Cannot deserialize ReferrerDetailResponse:
1104
- ${prettifyError(parsed.error)}
1105
- `);
2472
+ if (metrics.totalIncrementalDuration !== 0) {
2473
+ throw new Error(
2474
+ `Invalid UnrankedReferrerMetricsRevShareCap: totalIncrementalDuration must be 0, got: ${metrics.totalIncrementalDuration}.`
2475
+ );
1106
2476
  }
1107
- return parsed.data;
1108
- }
1109
-
1110
- // src/api/serialize.ts
1111
- function serializeRevenueContribution(revenueContribution) {
1112
- return revenueContribution.toString();
1113
- }
1114
- function serializeReferralProgramRules(rules) {
1115
- return rules;
1116
- }
1117
- function serializeAwardedReferrerMetrics(metrics) {
1118
- return {
1119
- referrer: metrics.referrer,
1120
- totalReferrals: metrics.totalReferrals,
1121
- totalIncrementalDuration: metrics.totalIncrementalDuration,
1122
- totalRevenueContribution: serializeRevenueContribution(metrics.totalRevenueContribution),
1123
- score: metrics.score,
1124
- rank: metrics.rank,
1125
- isQualified: metrics.isQualified,
1126
- finalScoreBoost: metrics.finalScoreBoost,
1127
- finalScore: metrics.finalScore,
1128
- awardPoolShare: metrics.awardPoolShare,
1129
- awardPoolApproxValue: metrics.awardPoolApproxValue
1130
- };
1131
- }
1132
- function serializeUnrankedReferrerMetrics(metrics) {
1133
- return {
1134
- referrer: metrics.referrer,
1135
- totalReferrals: metrics.totalReferrals,
1136
- totalIncrementalDuration: metrics.totalIncrementalDuration,
1137
- totalRevenueContribution: serializeRevenueContribution(metrics.totalRevenueContribution),
1138
- score: metrics.score,
1139
- rank: metrics.rank,
1140
- isQualified: metrics.isQualified,
1141
- finalScoreBoost: metrics.finalScoreBoost,
1142
- finalScore: metrics.finalScore,
1143
- awardPoolShare: metrics.awardPoolShare,
1144
- awardPoolApproxValue: metrics.awardPoolApproxValue
1145
- };
1146
- }
1147
- function serializeAggregatedReferrerMetrics(metrics) {
1148
- return {
1149
- grandTotalReferrals: metrics.grandTotalReferrals,
1150
- grandTotalIncrementalDuration: metrics.grandTotalIncrementalDuration,
1151
- grandTotalRevenueContribution: serializeRevenueContribution(
1152
- metrics.grandTotalRevenueContribution
1153
- ),
1154
- grandTotalQualifiedReferrersFinalScore: metrics.grandTotalQualifiedReferrersFinalScore,
1155
- minFinalScoreToQualify: metrics.minFinalScoreToQualify
1156
- };
1157
- }
1158
- function serializeReferrerLeaderboardPage(page) {
1159
- return {
1160
- rules: serializeReferralProgramRules(page.rules),
1161
- referrers: page.referrers.map(serializeAwardedReferrerMetrics),
1162
- aggregatedMetrics: serializeAggregatedReferrerMetrics(page.aggregatedMetrics),
1163
- pageContext: page.pageContext,
1164
- accurateAsOf: page.accurateAsOf
1165
- };
1166
- }
1167
- function serializeReferrerDetailRanked(detail) {
1168
- return {
1169
- type: detail.type,
1170
- rules: serializeReferralProgramRules(detail.rules),
1171
- referrer: serializeAwardedReferrerMetrics(detail.referrer),
1172
- aggregatedMetrics: serializeAggregatedReferrerMetrics(detail.aggregatedMetrics),
1173
- accurateAsOf: detail.accurateAsOf
1174
- };
1175
- }
1176
- function serializeReferrerDetailUnranked(detail) {
1177
- return {
1178
- type: detail.type,
1179
- rules: serializeReferralProgramRules(detail.rules),
1180
- referrer: serializeUnrankedReferrerMetrics(detail.referrer),
1181
- aggregatedMetrics: serializeAggregatedReferrerMetrics(detail.aggregatedMetrics),
1182
- accurateAsOf: detail.accurateAsOf
2477
+ makePriceEthSchema("UnrankedReferrerMetricsRevShareCap.totalRevenueContribution").parse(
2478
+ metrics.totalRevenueContribution
2479
+ );
2480
+ if (metrics.totalRevenueContribution.amount !== 0n) {
2481
+ throw new Error(
2482
+ `Invalid UnrankedReferrerMetricsRevShareCap: totalRevenueContribution.amount must be 0n, got: ${metrics.totalRevenueContribution.amount.toString()}.`
2483
+ );
2484
+ }
2485
+ makePriceUsdcSchema("UnrankedReferrerMetricsRevShareCap.totalBaseRevenueContribution").parse(
2486
+ metrics.totalBaseRevenueContribution
2487
+ );
2488
+ if (metrics.totalBaseRevenueContribution.amount !== 0n) {
2489
+ throw new Error(
2490
+ `Invalid UnrankedReferrerMetricsRevShareCap: totalBaseRevenueContribution.amount must be 0n, got: ${metrics.totalBaseRevenueContribution.amount.toString()}.`
2491
+ );
2492
+ }
2493
+ makePriceUsdcSchema("UnrankedReferrerMetricsRevShareCap.uncappedAward").parse(
2494
+ metrics.uncappedAward
2495
+ );
2496
+ if (metrics.uncappedAward.amount !== 0n) {
2497
+ throw new Error(
2498
+ `Invalid UnrankedReferrerMetricsRevShareCap: uncappedAward.amount must be 0n, got: ${metrics.uncappedAward.amount.toString()}.`
2499
+ );
2500
+ }
2501
+ makePriceUsdcSchema("UnrankedReferrerMetricsRevShareCap.cappedAward").parse(metrics.cappedAward);
2502
+ if (metrics.cappedAward.amount !== 0n) {
2503
+ throw new Error(
2504
+ `Invalid UnrankedReferrerMetricsRevShareCap: cappedAward.amount must be 0n, got: ${metrics.cappedAward.amount.toString()}.`
2505
+ );
2506
+ }
2507
+ };
2508
+ var buildUnrankedReferrerMetricsRevShareCap = (referrer, rules) => {
2509
+ const metrics = buildReferrerMetrics(referrer, 0, 0, priceEth(0n));
2510
+ const adminAction = rules.adminActions.find((a) => a.referrer === metrics.referrer) ?? null;
2511
+ const result = {
2512
+ ...metrics,
2513
+ totalBaseRevenueContribution: priceUsdc(0n),
2514
+ rank: null,
2515
+ isQualified: false,
2516
+ uncappedAward: priceUsdc(0n),
2517
+ cappedAward: priceUsdc(0n),
2518
+ adminAction
1183
2519
  };
2520
+ validateUnrankedReferrerMetricsRevShareCap(result, rules);
2521
+ return result;
2522
+ };
2523
+
2524
+ // src/award-models/rev-share-cap/sort-referral-events.ts
2525
+ function sortReferralEvents(events) {
2526
+ return [...events].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
1184
2527
  }
1185
- function serializeReferrerLeaderboardPageResponse(response) {
1186
- switch (response.responseCode) {
1187
- case ReferrerLeaderboardPageResponseCodes.Ok:
1188
- return {
1189
- responseCode: response.responseCode,
1190
- data: serializeReferrerLeaderboardPage(response.data)
2528
+
2529
+ // src/award-models/rev-share-cap/leaderboard.ts
2530
+ var buildReferrerLeaderboardRevShareCap = (events, rules, accurateAsOf) => {
2531
+ const sortedEvents = sortReferralEvents(events);
2532
+ const referrerStates = /* @__PURE__ */ new Map();
2533
+ let awardPoolRemaining = rules.awardPool;
2534
+ for (const event of sortedEvents) {
2535
+ const referrerId = event.referrer;
2536
+ let referrerState = referrerStates.get(referrerId);
2537
+ if (!referrerState) {
2538
+ referrerState = {
2539
+ totalReferrals: 0,
2540
+ totalIncrementalDuration: 0,
2541
+ totalRevenueContribution: priceEth(0n),
2542
+ hasQualified: false,
2543
+ cappedAward: priceUsdc(0n)
1191
2544
  };
1192
- case ReferrerLeaderboardPageResponseCodes.Error:
1193
- return response;
2545
+ referrerStates.set(referrerId, referrerState);
2546
+ }
2547
+ referrerState.totalReferrals += 1;
2548
+ referrerState.totalIncrementalDuration += event.incrementalDuration;
2549
+ referrerState.totalRevenueContribution = addPrices(
2550
+ referrerState.totalRevenueContribution,
2551
+ event.incrementalRevenueContribution
2552
+ );
2553
+ const totalBaseRevenue = calcBaseRevenueContribution(
2554
+ rules,
2555
+ referrerState.totalIncrementalDuration
2556
+ );
2557
+ const isNowQualified = isReferrerQualifiedRevShareCap(referrerId, totalBaseRevenue, rules);
2558
+ if (isNowQualified && !referrerState.hasQualified) {
2559
+ const accumulatedUncappedAward = scalePrice(totalBaseRevenue, rules.maxBaseRevenueShare);
2560
+ const incrementalCappedAward = minPrice(accumulatedUncappedAward, awardPoolRemaining);
2561
+ referrerState.cappedAward = addPrices(referrerState.cappedAward, incrementalCappedAward);
2562
+ awardPoolRemaining = subtractPrice(awardPoolRemaining, incrementalCappedAward);
2563
+ referrerState.hasQualified = true;
2564
+ } else if (referrerState.hasQualified) {
2565
+ const incrementalBaseRevenue = calcBaseRevenueContribution(rules, event.incrementalDuration);
2566
+ const incrementalUncappedAward = scalePrice(
2567
+ incrementalBaseRevenue,
2568
+ rules.maxBaseRevenueShare
2569
+ );
2570
+ const incrementalCappedAward = minPrice(incrementalUncappedAward, awardPoolRemaining);
2571
+ referrerState.cappedAward = addPrices(referrerState.cappedAward, incrementalCappedAward);
2572
+ awardPoolRemaining = subtractPrice(awardPoolRemaining, incrementalCappedAward);
2573
+ }
1194
2574
  }
1195
- }
1196
- function serializeReferrerDetailResponse(response) {
1197
- switch (response.responseCode) {
1198
- case ReferrerDetailResponseCodes.Ok:
1199
- switch (response.data.type) {
1200
- case "ranked":
1201
- return {
1202
- responseCode: response.responseCode,
1203
- data: serializeReferrerDetailRanked(response.data)
1204
- };
1205
- case "unranked":
1206
- return {
1207
- responseCode: response.responseCode,
1208
- data: serializeReferrerDetailUnranked(response.data)
1209
- };
2575
+ const sortedEntries = [...referrerStates.entries()].sort(
2576
+ ([referrerIdA, referrerStateA], [referrerIdB, referrerStateB]) => {
2577
+ if (referrerStateB.cappedAward.amount !== referrerStateA.cappedAward.amount) {
2578
+ return referrerStateB.cappedAward.amount > referrerStateA.cappedAward.amount ? 1 : -1;
1210
2579
  }
1211
- break;
1212
- case ReferrerDetailResponseCodes.Error:
1213
- return response;
1214
- }
2580
+ if (referrerStateB.totalIncrementalDuration !== referrerStateA.totalIncrementalDuration) {
2581
+ return referrerStateB.totalIncrementalDuration - referrerStateA.totalIncrementalDuration;
2582
+ }
2583
+ if (referrerIdB > referrerIdA) return 1;
2584
+ if (referrerIdB < referrerIdA) return -1;
2585
+ return 0;
2586
+ }
2587
+ );
2588
+ const awardedReferrers = sortedEntries.map(
2589
+ ([referrerId, referrerState], index) => {
2590
+ const baseMetrics = buildReferrerMetrics(
2591
+ referrerId,
2592
+ referrerState.totalReferrals,
2593
+ referrerState.totalIncrementalDuration,
2594
+ referrerState.totalRevenueContribution
2595
+ );
2596
+ const revShareMetrics = buildReferrerMetricsRevShareCap(baseMetrics, rules);
2597
+ const rankedMetrics = buildRankedReferrerMetricsRevShareCap(
2598
+ revShareMetrics,
2599
+ index + 1,
2600
+ rules
2601
+ );
2602
+ const uncappedAward = scalePrice(
2603
+ revShareMetrics.totalBaseRevenueContribution,
2604
+ rules.maxBaseRevenueShare
2605
+ );
2606
+ return buildAwardedReferrerMetricsRevShareCap(
2607
+ rankedMetrics,
2608
+ uncappedAward,
2609
+ referrerState.cappedAward,
2610
+ rules
2611
+ );
2612
+ }
2613
+ );
2614
+ const aggregatedMetrics = buildAggregatedReferrerMetricsRevShareCap(
2615
+ awardedReferrers,
2616
+ awardPoolRemaining
2617
+ );
2618
+ const referrers = new Map(awardedReferrers.map((r) => [r.referrer, r]));
2619
+ return { awardModel: rules.awardModel, rules, aggregatedMetrics, referrers, accurateAsOf };
2620
+ };
2621
+
2622
+ // src/award-models/rev-share-cap/leaderboard-page.ts
2623
+ function buildLeaderboardPageRevShareCap(pageContext, leaderboard) {
2624
+ const status = calcReferralProgramEditionStatusRevShareCap(
2625
+ leaderboard.rules,
2626
+ leaderboard.accurateAsOf,
2627
+ leaderboard.aggregatedMetrics
2628
+ );
2629
+ return {
2630
+ awardModel: leaderboard.awardModel,
2631
+ rules: leaderboard.rules,
2632
+ referrers: sliceReferrers(leaderboard.referrers, pageContext),
2633
+ aggregatedMetrics: leaderboard.aggregatedMetrics,
2634
+ pageContext,
2635
+ status,
2636
+ accurateAsOf: leaderboard.accurateAsOf
2637
+ };
1215
2638
  }
1216
2639
 
1217
2640
  // src/client.ts
@@ -1234,51 +2657,96 @@ var ENSReferralsClient = class _ENSReferralsClient {
1234
2657
  url: new URL(this.options.url.href)
1235
2658
  });
1236
2659
  }
2660
+ /**
2661
+ * Get Referral Program Edition Config Set
2662
+ *
2663
+ * Fetches and deserializes a referral program edition config set from a remote URL.
2664
+ *
2665
+ * @param url - The URL to fetch the edition config set from
2666
+ * @returns A ReferralProgramEditionConfigSet (Map of edition slugs to edition configurations)
2667
+ *
2668
+ * @remarks Editions whose `rules.awardModel` is not recognized by this client version are
2669
+ * preserved as {@link ReferralProgramRulesUnrecognized}. The returned map includes all
2670
+ * editions — recognized and unrecognized alike. Callers should check `editionConfig.rules.awardModel`
2671
+ * and skip editions with `"unrecognized"` as appropriate. The returned map may be empty.
2672
+ *
2673
+ * @throws if the fetch fails
2674
+ * @throws if the response is not valid JSON
2675
+ * @throws if the data doesn't match the expected schema
2676
+ *
2677
+ * @example
2678
+ * ```typescript
2679
+ * const url = new URL("https://example.com/editions.json");
2680
+ * const editionConfigSet = await ENSReferralsClient.getReferralProgramEditionConfigSet(url);
2681
+ * console.log(`Loaded ${editionConfigSet.size} editions`);
2682
+ * ```
2683
+ */
2684
+ static async getReferralProgramEditionConfigSet(url) {
2685
+ const response = await fetch(url);
2686
+ if (!response.ok) {
2687
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
2688
+ }
2689
+ let json;
2690
+ try {
2691
+ json = await response.json();
2692
+ } catch {
2693
+ throw new Error("Malformed response data: invalid JSON");
2694
+ }
2695
+ const editionConfigs = deserializeReferralProgramEditionConfigSetArray(json);
2696
+ return buildReferralProgramEditionConfigSet(editionConfigs);
2697
+ }
1237
2698
  /**
1238
2699
  * Fetch Referrer Leaderboard Page
1239
2700
  *
1240
- * Retrieves a paginated list of referrer leaderboard metrics with contribution percentages.
1241
- * Each referrer's contribution is calculated as a percentage of the grand totals across all referrers.
2701
+ * Retrieves a paginated list of referrer leaderboard metrics for a specific referral program edition.
1242
2702
  *
1243
- * @param request - Pagination parameters
2703
+ * @param request - Request parameters including edition and pagination
2704
+ * @param request.edition - The referral program edition slug (e.g., "2025-12", "2026-03", or any other configured edition slug)
1244
2705
  * @param request.page - The page number to retrieve (1-indexed, default: 1)
1245
2706
  * @param request.recordsPerPage - Number of records per page (default: 25, max: 100)
1246
2707
  * @returns {ReferrerLeaderboardPageResponse}
1247
2708
  *
2709
+ * @remarks If the server returns a leaderboard page whose `awardModel` is not recognized by
2710
+ * this client version, it is preserved as {@link ReferrerLeaderboardPageUnrecognized}. Callers
2711
+ * should check `response.data.awardModel` and handle the `"unrecognized"` case accordingly.
2712
+ *
1248
2713
  * @throws if the ENSNode request fails
1249
2714
  * @throws if the ENSNode API returns an error response
1250
2715
  * @throws if the ENSNode response breaks required invariants
1251
2716
  *
1252
2717
  * @example
1253
2718
  * ```typescript
1254
- * // Get first page with default page size (25 records)
1255
- * const response = await client.getReferrerLeaderboardPage();
2719
+ * // Get first page of 2025-12 leaderboard with default page size (25 records)
2720
+ * const editionSlug = "2025-12";
2721
+ * const response = await client.getReferrerLeaderboardPage({ edition: editionSlug });
1256
2722
  * if (response.responseCode === ReferrerLeaderboardPageResponseCodes.Ok) {
1257
- * const {
1258
- * aggregatedMetrics,
1259
- * referrers,
1260
- * rules,
1261
- * pageContext,
1262
- * updatedAt
1263
- * } = response.data;
1264
- * console.log(aggregatedMetrics);
1265
- * console.log(referrers);
1266
- * console.log(rules);
1267
- * console.log(updatedAt);
1268
- * console.log(`Page ${pageContext.page} of ${pageContext.totalPages}`);
2723
+ * const { awardModel, pageContext, accurateAsOf } = response.data;
2724
+ * if (awardModel === ReferralProgramAwardModels.Unrecognized) {
2725
+ * console.log(`Unrecognized award model: ${response.data.originalAwardModel} — skipping`);
2726
+ * } else {
2727
+ * const { aggregatedMetrics, referrers, rules } = response.data;
2728
+ * console.log(`Edition: ${editionSlug}`);
2729
+ * console.log(`Subregistry: ${rules.subregistryId}`);
2730
+ * console.log(`Total Referrers: ${pageContext.totalRecords}`);
2731
+ * console.log(`Page ${pageContext.page} of ${pageContext.totalPages}`);
2732
+ * }
1269
2733
  * }
1270
2734
  * ```
1271
2735
  *
1272
2736
  * @example
1273
2737
  * ```typescript
1274
- * // Get second page with 50 records per page
1275
- * const response = await client.getReferrerLeaderboardPage({ page: 2, recordsPerPage: 50 });
2738
+ * // Get second page of 2026-03 with 50 records per page
2739
+ * const response = await client.getReferrerLeaderboardPage({
2740
+ * edition: "2026-03",
2741
+ * page: 2,
2742
+ * recordsPerPage: 50
2743
+ * });
1276
2744
  * ```
1277
2745
  *
1278
2746
  * @example
1279
2747
  * ```typescript
1280
- * // Handle error response, ie. when Referrer Leaderboard is not currently available.
1281
- * const response = await client.getReferrerLeaderboardPage();
2748
+ * // Handle error response (e.g., unknown edition or data not available)
2749
+ * const response = await client.getReferrerLeaderboardPage({ edition: "2025-12" });
1282
2750
  *
1283
2751
  * if (response.responseCode === ReferrerLeaderboardPageResponseCodes.Error) {
1284
2752
  * console.error(response.error);
@@ -1287,9 +2755,10 @@ var ENSReferralsClient = class _ENSReferralsClient {
1287
2755
  * ```
1288
2756
  */
1289
2757
  async getReferrerLeaderboardPage(request) {
1290
- const url = new URL(`/ensanalytics/referrers`, this.options.url);
1291
- if (request?.page) url.searchParams.set("page", request.page.toString());
1292
- if (request?.recordsPerPage)
2758
+ const url = new URL(`/v1/ensanalytics/referral-leaderboard`, this.options.url);
2759
+ url.searchParams.set("edition", request.edition);
2760
+ if (request.page !== void 0) url.searchParams.set("page", request.page.toString());
2761
+ if (request.recordsPerPage !== void 0)
1293
2762
  url.searchParams.set("recordsPerPage", request.recordsPerPage.toString());
1294
2763
  const response = await fetch(url);
1295
2764
  let responseData;
@@ -1303,86 +2772,151 @@ var ENSReferralsClient = class _ENSReferralsClient {
1303
2772
  );
1304
2773
  }
1305
2774
  /**
1306
- * Fetch Referrer Detail
2775
+ * Fetch Referrer Metrics for Specific Editions
1307
2776
  *
1308
- * Retrieves detailed information about a specific referrer, whether they are on the
1309
- * leaderboard or not.
2777
+ * Retrieves detailed information about a specific referrer for the requested
2778
+ * referral program editions. Returns a record mapping each requested edition slug
2779
+ * to the referrer's metrics for that edition.
1310
2780
  *
1311
- * The response data is a discriminated union type with a `type` field:
2781
+ * The response data maps edition slugs to referrer metrics. Each edition's entry is a
2782
+ * {@link ReferrerEditionMetrics} discriminated union. Narrow on `awardModel` first to
2783
+ * exclude unrecognized models, then on `type` to distinguish ranked from unranked:
1312
2784
  *
1313
- * **For referrers on the leaderboard** (`ReferrerDetailRanked`):
1314
- * - `type`: {@link ReferrerDetailTypeIds.Ranked}
1315
- * - `referrer`: The `AwardedReferrerMetrics` from @namehash/ens-referrals
1316
- * - `rules`: The referral program rules
1317
- * - `aggregatedMetrics`: Aggregated metrics for all referrers on the leaderboard
1318
- * - `accurateAsOf`: Unix timestamp indicating when the data was last updated
2785
+ * - `awardModel: "unrecognized"` ({@link ReferrerEditionMetricsUnrecognized}): the server
2786
+ * returned an award model this client does not recognize. Only `originalAwardModel` is
2787
+ * available; no model-specific fields are present.
2788
+ * - `type: "ranked"` ({@link ReferrerEditionMetricsTypeIds.Ranked}): the referrer appears on
2789
+ * the leaderboard. `referrer` contains rank, qualification status, and award share.
2790
+ * - `type: "unranked"` ({@link ReferrerEditionMetricsTypeIds.Unranked}): the referrer has no
2791
+ * activity in this edition. `referrer` contains zero-value placeholders.
1319
2792
  *
1320
- * **For referrers NOT on the leaderboard** (`ReferrerDetailUnranked`):
1321
- * - `type`: {@link ReferrerDetailTypeIds.Unranked}
1322
- * - `referrer`: The `UnrankedReferrerMetrics` from @namehash/ens-referrals
1323
- * - `rules`: The referral program rules
1324
- * - `aggregatedMetrics`: Aggregated metrics for all referrers on the leaderboard
1325
- * - `accurateAsOf`: Unix timestamp indicating when the data was last updated
2793
+ * **Note:** This endpoint does not allow partial success. When `responseCode === Ok`,
2794
+ * all requested editions are guaranteed to be present in the response data. If any
2795
+ * requested edition cannot be returned, the entire request fails with an error.
1326
2796
  *
1327
2797
  * @see {@link https://www.npmjs.com/package/@namehash/ens-referrals|@namehash/ens-referrals} for calculation details
1328
2798
  *
1329
- * @param request The referrer address to query
1330
- * @returns {ReferrerDetailResponse} Returns the referrer detail response
2799
+ * @param request The referrer address and edition slugs to query
2800
+ * @returns {ReferrerMetricsEditionsResponse} Returns the referrer metrics for requested editions
2801
+ *
2802
+ * @remarks If the server returns metrics for an edition whose `awardModel` is not recognized by
2803
+ * this client version, that edition's entry in `response.data` is preserved as
2804
+ * {@link ReferrerEditionMetricsUnrecognized}. Callers should check each edition's `awardModel`
2805
+ * and handle the `"unrecognized"` case accordingly.
1331
2806
  *
1332
2807
  * @throws if the ENSNode request fails
1333
2808
  * @throws if the response data is malformed
1334
2809
  *
1335
2810
  * @example
1336
2811
  * ```typescript
1337
- * // Get referrer detail for a specific address
1338
- * const response = await client.getReferrerDetail({
1339
- * referrer: "0x1234567890123456789012345678901234567890"
2812
+ * // Get referrer metrics for specific editions
2813
+ * const response = await client.getReferrerMetricsEditions({
2814
+ * referrer: "0x1234567890123456789012345678901234567890",
2815
+ * editions: ["2025-12", "2026-01"]
1340
2816
  * });
1341
- * if (response.responseCode === ReferrerDetailResponseCodes.Ok) {
1342
- * const { type, referrer, rules, aggregatedMetrics, accurateAsOf } = response.data;
1343
- * console.log(type); // ReferrerDetailTypeIds.Ranked or ReferrerDetailTypeIds.Unranked
1344
- * console.log(referrer);
1345
- * console.log(accurateAsOf);
2817
+ * if (response.responseCode === ReferrerMetricsEditionsResponseCodes.Ok) {
2818
+ * // All requested editions are present in response.data
2819
+ * for (const [editionSlug, detail] of Object.entries(response.data)) {
2820
+ * console.log(`Edition: ${editionSlug}`);
2821
+ * if (detail.awardModel === ReferralProgramAwardModels.Unrecognized) {
2822
+ * console.log(`Unrecognized award model: ${detail.originalAwardModel} — skipping`);
2823
+ * continue;
2824
+ * }
2825
+ * console.log(`Type: ${detail.type}`);
2826
+ * if (detail.type === ReferrerEditionMetricsTypeIds.Ranked) {
2827
+ * console.log(`Rank: ${detail.referrer.rank}`);
2828
+ * console.log(`Award Share: ${detail.referrer.awardPoolShare * 100}%`);
2829
+ * }
2830
+ * }
1346
2831
  * }
1347
2832
  * ```
1348
2833
  *
1349
2834
  * @example
1350
2835
  * ```typescript
1351
- * // Use discriminated union to check if referrer is ranked
1352
- * const response = await client.getReferrerDetail({
1353
- * referrer: "0x1234567890123456789012345678901234567890"
2836
+ * // Access specific edition data directly (edition is guaranteed to exist when OK)
2837
+ * const response = await client.getReferrerMetricsEditions({
2838
+ * referrer: "0x1234567890123456789012345678901234567890",
2839
+ * editions: ["2025-12"]
1354
2840
  * });
1355
- * if (response.responseCode === ReferrerDetailResponseCodes.Ok) {
1356
- * if (response.data.type === ReferrerDetailTypeIds.Ranked) {
1357
- * // TypeScript knows this is ReferrerDetailRanked
1358
- * console.log(`Rank: ${response.data.referrer.rank}`);
1359
- * console.log(`Qualified: ${response.data.referrer.isQualified}`);
1360
- * console.log(`Award Pool Share: ${response.data.referrer.awardPoolShare * 100}%`);
1361
- * } else {
1362
- * // TypeScript knows this is ReferrerDetailUnranked
1363
- * console.log("Referrer is not on the leaderboard (no referrals yet)");
2841
+ * if (response.responseCode === ReferrerMetricsEditionsResponseCodes.Ok) {
2842
+ * const detail = response.data["2025-12"];
2843
+ * if (detail && detail.awardModel === ReferralProgramAwardModels.Unrecognized) {
2844
+ * console.log(`Unrecognized award model: ${detail.originalAwardModel} — skipping`);
2845
+ * } else if (detail && detail.type === ReferrerEditionMetricsTypeIds.Ranked) {
2846
+ * console.log(`Edition 2025-12 Rank: ${detail.referrer.rank}`);
2847
+ * } else if (detail) {
2848
+ * console.log("Referrer is not on the leaderboard for 2025-12");
1364
2849
  * }
1365
2850
  * }
1366
2851
  * ```
1367
2852
  *
1368
2853
  * @example
1369
2854
  * ```typescript
1370
- * // Handle error response, ie. when Referrer Detail is not currently available.
1371
- * const response = await client.getReferrerDetail({
1372
- * referrer: "0x1234567890123456789012345678901234567890"
2855
+ * // Handle error response (e.g., unknown edition or data not available)
2856
+ * const response = await client.getReferrerMetricsEditions({
2857
+ * referrer: "0x1234567890123456789012345678901234567890",
2858
+ * editions: ["2025-12", "invalid-edition"]
1373
2859
  * });
1374
2860
  *
1375
- * if (response.responseCode === ReferrerDetailResponseCodes.Error) {
2861
+ * if (response.responseCode === ReferrerMetricsEditionsResponseCodes.Error) {
1376
2862
  * console.error(response.error);
1377
2863
  * console.error(response.errorMessage);
1378
2864
  * }
1379
2865
  * ```
1380
2866
  */
1381
- async getReferrerDetail(request) {
2867
+ async getReferrerMetricsEditions(request) {
1382
2868
  const url = new URL(
1383
- `/ensanalytics/referrers/${encodeURIComponent(request.referrer)}`,
2869
+ `/v1/ensanalytics/referrer/${encodeURIComponent(request.referrer)}`,
1384
2870
  this.options.url
1385
2871
  );
2872
+ url.searchParams.set("editions", request.editions.join(","));
2873
+ const response = await fetch(url);
2874
+ let responseData;
2875
+ try {
2876
+ responseData = await response.json();
2877
+ } catch {
2878
+ throw new Error("Malformed response data: invalid JSON");
2879
+ }
2880
+ return deserializeReferrerMetricsEditionsResponse(
2881
+ responseData
2882
+ );
2883
+ }
2884
+ /**
2885
+ * Get the currently configured referral program edition summaries.
2886
+ * Editions are sorted in descending order by start timestamp (most recent first).
2887
+ *
2888
+ * @returns A response containing edition summaries, or an error response if unavailable.
2889
+ *
2890
+ * @remarks Editions whose `rules.awardModel` is not recognized by this client version are
2891
+ * preserved as {@link ReferralProgramEditionSummaryUnrecognized}. The returned response includes all
2892
+ * editions — recognized and unrecognized alike. Callers should check `edition.awardModel`
2893
+ * and skip editions with `"unrecognized"` as appropriate. The returned editions list may be empty.
2894
+ *
2895
+ * @example
2896
+ * ```typescript
2897
+ * const response = await client.getEditionSummaries();
2898
+ *
2899
+ * if (response.responseCode === ReferralProgramEditionSummariesResponseCodes.Ok) {
2900
+ * console.log(`Found ${response.data.editions.length} editions`);
2901
+ * for (const edition of response.data.editions) {
2902
+ * console.log(`${edition.slug}: ${edition.displayName}`);
2903
+ * }
2904
+ * }
2905
+ * ```
2906
+ *
2907
+ * @example
2908
+ * ```typescript
2909
+ * // Handle error response
2910
+ * const response = await client.getEditionSummaries();
2911
+ *
2912
+ * if (response.responseCode === ReferralProgramEditionSummariesResponseCodes.Error) {
2913
+ * console.error(response.error);
2914
+ * console.error(response.errorMessage);
2915
+ * }
2916
+ * ```
2917
+ */
2918
+ async getEditionSummaries() {
2919
+ const url = new URL(`/v1/ensanalytics/editions`, this.options.url);
1386
2920
  const response = await fetch(url);
1387
2921
  let responseData;
1388
2922
  try {
@@ -1390,53 +2924,111 @@ var ENSReferralsClient = class _ENSReferralsClient {
1390
2924
  } catch {
1391
2925
  throw new Error("Malformed response data: invalid JSON");
1392
2926
  }
1393
- return deserializeReferrerDetailResponse(responseData);
2927
+ return deserializeReferralProgramEditionSummariesResponse(
2928
+ responseData
2929
+ );
1394
2930
  }
1395
2931
  };
1396
2932
 
1397
- // src/currency.ts
1398
- function isValidUSDQuantity(value) {
1399
- return isFiniteNonNegativeNumber(value);
1400
- }
1401
- function validateUSDQuantity(value) {
1402
- if (!isValidUSDQuantity(value)) {
1403
- throw new Error(`Invalid USD quantity: ${value}.`);
2933
+ // src/edition-metrics.ts
2934
+ var getReferrerEditionMetrics = (referrer, leaderboard) => {
2935
+ switch (leaderboard.awardModel) {
2936
+ case ReferralProgramAwardModels.PieSplit: {
2937
+ const status = calcReferralProgramEditionStatusPieSplit(
2938
+ leaderboard.rules,
2939
+ leaderboard.accurateAsOf
2940
+ );
2941
+ const awardedReferrerMetrics = leaderboard.referrers.get(referrer);
2942
+ if (awardedReferrerMetrics) {
2943
+ return {
2944
+ awardModel: leaderboard.awardModel,
2945
+ type: ReferrerEditionMetricsTypeIds.Ranked,
2946
+ rules: leaderboard.rules,
2947
+ referrer: awardedReferrerMetrics,
2948
+ aggregatedMetrics: leaderboard.aggregatedMetrics,
2949
+ status,
2950
+ accurateAsOf: leaderboard.accurateAsOf
2951
+ };
2952
+ }
2953
+ return {
2954
+ awardModel: leaderboard.awardModel,
2955
+ type: ReferrerEditionMetricsTypeIds.Unranked,
2956
+ rules: leaderboard.rules,
2957
+ referrer: buildUnrankedReferrerMetricsPieSplit(referrer),
2958
+ aggregatedMetrics: leaderboard.aggregatedMetrics,
2959
+ status,
2960
+ accurateAsOf: leaderboard.accurateAsOf
2961
+ };
2962
+ }
2963
+ case ReferralProgramAwardModels.RevShareCap: {
2964
+ const status = calcReferralProgramEditionStatusRevShareCap(
2965
+ leaderboard.rules,
2966
+ leaderboard.accurateAsOf,
2967
+ leaderboard.aggregatedMetrics
2968
+ );
2969
+ const awardedReferrerMetrics = leaderboard.referrers.get(referrer);
2970
+ if (awardedReferrerMetrics) {
2971
+ return {
2972
+ awardModel: leaderboard.awardModel,
2973
+ type: ReferrerEditionMetricsTypeIds.Ranked,
2974
+ rules: leaderboard.rules,
2975
+ referrer: awardedReferrerMetrics,
2976
+ aggregatedMetrics: leaderboard.aggregatedMetrics,
2977
+ status,
2978
+ accurateAsOf: leaderboard.accurateAsOf
2979
+ };
2980
+ }
2981
+ return {
2982
+ awardModel: leaderboard.awardModel,
2983
+ type: ReferrerEditionMetricsTypeIds.Unranked,
2984
+ rules: leaderboard.rules,
2985
+ referrer: buildUnrankedReferrerMetricsRevShareCap(referrer, leaderboard.rules),
2986
+ aggregatedMetrics: leaderboard.aggregatedMetrics,
2987
+ status,
2988
+ accurateAsOf: leaderboard.accurateAsOf
2989
+ };
2990
+ }
2991
+ default: {
2992
+ const _exhaustiveCheck = leaderboard;
2993
+ throw new Error(
2994
+ `Unknown award model: ${_exhaustiveCheck.awardModel}`
2995
+ );
2996
+ }
1404
2997
  }
1405
- }
2998
+ };
1406
2999
 
1407
- // src/leaderboard.ts
1408
- var buildReferrerLeaderboard = (allReferrers, rules, accurateAsOf) => {
1409
- const uniqueReferrers = allReferrers.map((referrer) => referrer.referrer);
1410
- if (uniqueReferrers.length !== allReferrers.length) {
1411
- throw new Error(
1412
- "ReferrerLeaderboard: Cannot buildReferrerLeaderboard containing duplicate referrers"
1413
- );
3000
+ // src/edition-summary.ts
3001
+ function buildEditionSummary(config, leaderboard) {
3002
+ const { slug, displayName } = config;
3003
+ switch (leaderboard.awardModel) {
3004
+ case ReferralProgramAwardModels.PieSplit:
3005
+ return buildEditionSummaryPieSplit(slug, displayName, leaderboard.rules, leaderboard);
3006
+ case ReferralProgramAwardModels.RevShareCap:
3007
+ return buildEditionSummaryRevShareCap(slug, displayName, leaderboard.rules, leaderboard);
3008
+ default: {
3009
+ const _exhaustiveCheck = leaderboard;
3010
+ throw new Error(
3011
+ `Unknown award model: ${_exhaustiveCheck.awardModel}`
3012
+ );
3013
+ }
1414
3014
  }
1415
- if (accurateAsOf < rules.startTime && allReferrers.length > 0) {
1416
- throw new Error(
1417
- `ReferrerLeaderboard: accurateAsOf (${accurateAsOf}) is before startTime (${rules.startTime}) which indicates allReferrers should be empty, but allReferrers is not empty.`
1418
- );
3015
+ }
3016
+
3017
+ // src/leaderboard-page.ts
3018
+ var getReferrerLeaderboardPage = (pageParams, leaderboard) => {
3019
+ const pageContext = buildReferrerLeaderboardPageContext(pageParams, leaderboard);
3020
+ switch (leaderboard.awardModel) {
3021
+ case ReferralProgramAwardModels.PieSplit:
3022
+ return buildLeaderboardPagePieSplit(pageContext, leaderboard);
3023
+ case ReferralProgramAwardModels.RevShareCap:
3024
+ return buildLeaderboardPageRevShareCap(pageContext, leaderboard);
3025
+ default: {
3026
+ const _exhaustiveCheck = leaderboard;
3027
+ throw new Error(
3028
+ `Unknown award model: ${_exhaustiveCheck.awardModel}`
3029
+ );
3030
+ }
1419
3031
  }
1420
- const sortedReferrers = sortReferrerMetrics(allReferrers);
1421
- const scoredReferrers = sortedReferrers.map((referrer) => buildScoredReferrerMetrics(referrer));
1422
- const rankedReferrers = scoredReferrers.map((referrer, index) => {
1423
- return buildRankedReferrerMetrics(referrer, index + 1, rules);
1424
- });
1425
- const aggregatedMetrics = buildAggregatedReferrerMetrics(rankedReferrers, rules);
1426
- const awardedReferrers = rankedReferrers.map((referrer) => {
1427
- return buildAwardedReferrerMetrics(referrer, aggregatedMetrics, rules);
1428
- });
1429
- const referrers = new Map(
1430
- awardedReferrers.map((referrer) => {
1431
- return [referrer.referrer, referrer];
1432
- })
1433
- );
1434
- return {
1435
- rules,
1436
- aggregatedMetrics,
1437
- referrers,
1438
- accurateAsOf
1439
- };
1440
3032
  };
1441
3033
 
1442
3034
  // src/link.ts
@@ -1446,119 +3038,96 @@ function buildEnsReferralUrl(address) {
1446
3038
  ensAppUrl.searchParams.set("referrer", getAddress(address));
1447
3039
  return ensAppUrl;
1448
3040
  }
1449
-
1450
- // src/rules.ts
1451
- var ENS_HOLIDAY_AWARDS_START_DATE = 1764547200;
1452
- var ENS_HOLIDAY_AWARDS_END_DATE = 1767225599;
1453
- var ENS_HOLIDAY_AWARDS_MAX_QUALIFIED_REFERRERS = 10;
1454
- var ENS_HOLIDAY_AWARDS_TOTAL_AWARD_POOL_VALUE = 1e4;
1455
- var validateReferralProgramRules = (rules) => {
1456
- validateUSDQuantity(rules.totalAwardPoolValue);
1457
- validateNonNegativeInteger(rules.maxQualifiedReferrers);
1458
- validateUnixTimestamp(rules.startTime);
1459
- validateUnixTimestamp(rules.endTime);
1460
- if (rules.endTime < rules.startTime) {
1461
- throw new Error(
1462
- `ReferralProgramRules: startTime: ${rules.startTime} is after endTime: ${rules.endTime}.`
1463
- );
1464
- }
1465
- };
1466
- var buildReferralProgramRules = (totalAwardPoolValue, maxQualifiedReferrers, startTime, endTime, subregistryId) => {
1467
- const result = {
1468
- totalAwardPoolValue,
1469
- maxQualifiedReferrers,
1470
- startTime,
1471
- endTime,
1472
- subregistryId
1473
- };
1474
- validateReferralProgramRules(result);
1475
- return result;
1476
- };
1477
-
1478
- // src/status.ts
1479
- var ReferralProgramStatuses = {
1480
- /**
1481
- * Represents a referral program that has been announced, but hasn't started yet.
1482
- */
1483
- Scheduled: "Scheduled",
1484
- /**
1485
- * Represents a currently ongoing referral program.
1486
- */
1487
- Active: "Active",
1488
- /**
1489
- * Represents a referral program that has already ended.
1490
- */
1491
- Closed: "Closed"
1492
- };
1493
- var calcReferralProgramStatus = (referralProgramRules, now) => {
1494
- if (now < referralProgramRules.startTime) return ReferralProgramStatuses.Scheduled;
1495
- if (now > referralProgramRules.endTime) return ReferralProgramStatuses.Closed;
1496
- return ReferralProgramStatuses.Active;
1497
- };
1498
3041
  export {
3042
+ AdminActionTypes,
1499
3043
  DEFAULT_ENSNODE_API_URL,
1500
3044
  ENSReferralsClient,
1501
- ENS_HOLIDAY_AWARDS_END_DATE,
1502
- ENS_HOLIDAY_AWARDS_MAX_QUALIFIED_REFERRERS,
1503
- ENS_HOLIDAY_AWARDS_START_DATE,
1504
- ENS_HOLIDAY_AWARDS_TOTAL_AWARD_POOL_VALUE,
3045
+ MAX_EDITIONS_PER_REQUEST,
3046
+ REFERRAL_PROGRAM_EDITION_SLUG_PATTERN,
1505
3047
  REFERRERS_PER_LEADERBOARD_PAGE_DEFAULT,
1506
3048
  REFERRERS_PER_LEADERBOARD_PAGE_MAX,
1507
- ReferralProgramStatuses,
1508
- ReferrerDetailResponseCodes,
1509
- ReferrerDetailTypeIds,
3049
+ ReferralProgramAwardModels,
3050
+ ReferralProgramEditionStatuses,
3051
+ ReferralProgramEditionSummariesResponseCodes,
3052
+ ReferrerEditionMetricsTypeIds,
1510
3053
  ReferrerLeaderboardPageResponseCodes,
3054
+ ReferrerMetricsEditionsResponseCodes,
1511
3055
  SECONDS_PER_YEAR,
1512
- buildAggregatedReferrerMetrics,
1513
- buildAwardedReferrerMetrics,
3056
+ buildAggregatedReferrerMetricsPieSplit,
3057
+ buildAggregatedReferrerMetricsRevShareCap,
3058
+ buildAwardedReferrerMetricsPieSplit,
3059
+ buildAwardedReferrerMetricsRevShareCap,
3060
+ buildEditionSummary,
3061
+ buildEditionSummaryPieSplit,
3062
+ buildEditionSummaryRevShareCap,
1514
3063
  buildEnsReferralUrl,
1515
- buildRankedReferrerMetrics,
1516
- buildReferralProgramRules,
1517
- buildReferrerLeaderboard,
3064
+ buildLeaderboardPagePieSplit,
3065
+ buildLeaderboardPageRevShareCap,
3066
+ buildRankedReferrerMetricsPieSplit,
3067
+ buildRankedReferrerMetricsRevShareCap,
3068
+ buildReferralProgramEditionConfigSet,
3069
+ buildReferralProgramRulesPieSplit,
3070
+ buildReferralProgramRulesRevShareCap,
1518
3071
  buildReferrerLeaderboardPageContext,
1519
3072
  buildReferrerLeaderboardPageParams,
3073
+ buildReferrerLeaderboardPieSplit,
3074
+ buildReferrerLeaderboardRevShareCap,
1520
3075
  buildReferrerMetrics,
1521
- buildScoredReferrerMetrics,
1522
- buildUnrankedReferrerMetrics,
1523
- calcReferralProgramStatus,
1524
- calcReferrerAwardPoolShare,
1525
- calcReferrerFinalScore,
1526
- calcReferrerFinalScoreBoost,
1527
- calcReferrerFinalScoreMultiplier,
1528
- calcReferrerScore,
3076
+ buildReferrerMetricsRevShareCap,
3077
+ buildScoredReferrerMetricsPieSplit,
3078
+ buildUnrankedReferrerMetricsPieSplit,
3079
+ buildUnrankedReferrerMetricsRevShareCap,
3080
+ calcBaseReferralProgramEditionStatus,
3081
+ calcBaseRevenueContribution,
3082
+ calcReferralProgramEditionStatusPieSplit,
3083
+ calcReferralProgramEditionStatusRevShareCap,
3084
+ calcReferrerAwardPoolSharePieSplit,
3085
+ calcReferrerScorePieSplit,
1529
3086
  compareReferrerMetrics,
1530
- deserializeReferrerDetailResponse,
3087
+ deserializeReferralProgramEditionConfigSetArray,
3088
+ deserializeReferralProgramEditionSummariesResponse,
1531
3089
  deserializeReferrerLeaderboardPageResponse,
1532
- getReferrerDetail,
3090
+ deserializeReferrerMetricsEditionsResponse,
3091
+ getReferrerEditionMetrics,
1533
3092
  getReferrerLeaderboardPage,
1534
3093
  isFiniteNonNegativeNumber,
1535
3094
  isInteger,
1536
3095
  isNonNegativeInteger,
1537
3096
  isPositiveInteger,
1538
- isReferrerQualified,
3097
+ isReferrerQualifiedRevShareCap,
1539
3098
  isValidDuration,
1540
3099
  isValidReferrerScore,
1541
- isValidRevenueContribution,
1542
- isValidUSDQuantity,
1543
- normalizeAddress,
1544
- serializeReferrerDetailResponse,
3100
+ serializeReferralProgramEditionSummariesResponse,
3101
+ serializeReferralProgramEditionSummary,
3102
+ serializeReferralProgramRules,
1545
3103
  serializeReferrerLeaderboardPageResponse,
3104
+ serializeReferrerMetricsEditionsResponse,
3105
+ sliceReferrers,
1546
3106
  sortReferrerMetrics,
1547
- validateAggregatedReferrerMetrics,
1548
- validateAwardedReferrerMetrics,
3107
+ validateAggregatedReferrerMetricsPieSplit,
3108
+ validateAggregatedReferrerMetricsRevShareCap,
3109
+ validateAwardedReferrerMetricsPieSplit,
3110
+ validateAwardedReferrerMetricsRevShareCap,
3111
+ validateBaseReferralProgramEditionSummary,
3112
+ validateBaseReferralProgramRules,
1549
3113
  validateDuration,
1550
- validateLowercaseAddress,
3114
+ validateEditionSummaryPieSplit,
3115
+ validateEditionSummaryRevShareCap,
1551
3116
  validateNonNegativeInteger,
1552
- validateRankedReferrerMetrics,
1553
- validateReferralProgramRules,
3117
+ validateNormalizedAddress,
3118
+ validateRankedReferrerMetricsPieSplit,
3119
+ validateRankedReferrerMetricsRevShareCap,
3120
+ validateReferralProgramEditionConfigSet,
3121
+ validateReferralProgramRulesPieSplit,
3122
+ validateReferralProgramRulesRevShareCap,
1554
3123
  validateReferrerLeaderboardPageContext,
1555
3124
  validateReferrerMetrics,
3125
+ validateReferrerMetricsRevShareCap,
1556
3126
  validateReferrerRank,
1557
3127
  validateReferrerScore,
1558
- validateRevenueContribution,
1559
- validateScoredReferrerMetrics,
1560
- validateUSDQuantity,
3128
+ validateScoredReferrerMetricsPieSplit,
1561
3129
  validateUnixTimestamp,
1562
- validateUnrankedReferrerMetrics
3130
+ validateUnrankedReferrerMetricsPieSplit,
3131
+ validateUnrankedReferrerMetricsRevShareCap
1563
3132
  };
1564
3133
  //# sourceMappingURL=index.js.map