@namehash/ens-referrals 1.9.0 → 1.10.0

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