@namehash/ens-referrals 1.10.1 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -56,13 +56,13 @@ __export(index_exports, {
56
56
  buildLeaderboardPageRevShareCap: () => buildLeaderboardPageRevShareCap,
57
57
  buildRankedReferrerMetricsPieSplit: () => buildRankedReferrerMetricsPieSplit,
58
58
  buildRankedReferrerMetricsRevShareCap: () => buildRankedReferrerMetricsRevShareCap,
59
+ buildReferralEditionSnapshotPieSplit: () => buildReferralEditionSnapshotPieSplit,
60
+ buildReferralEditionSnapshotRevShareCap: () => buildReferralEditionSnapshotRevShareCap,
59
61
  buildReferralProgramEditionConfigSet: () => buildReferralProgramEditionConfigSet,
60
62
  buildReferralProgramRulesPieSplit: () => buildReferralProgramRulesPieSplit,
61
63
  buildReferralProgramRulesRevShareCap: () => buildReferralProgramRulesRevShareCap,
62
64
  buildReferrerLeaderboardPageContext: () => buildReferrerLeaderboardPageContext,
63
65
  buildReferrerLeaderboardPageParams: () => buildReferrerLeaderboardPageParams,
64
- buildReferrerLeaderboardPieSplit: () => buildReferrerLeaderboardPieSplit,
65
- buildReferrerLeaderboardRevShareCap: () => buildReferrerLeaderboardRevShareCap,
66
66
  buildReferrerMetrics: () => buildReferrerMetrics,
67
67
  buildReferrerMetricsRevShareCap: () => buildReferrerMetricsRevShareCap,
68
68
  buildScoredReferrerMetricsPieSplit: () => buildScoredReferrerMetricsPieSplit,
@@ -79,8 +79,11 @@ __export(index_exports, {
79
79
  deserializeReferralProgramEditionSummariesResponse: () => deserializeReferralProgramEditionSummariesResponse,
80
80
  deserializeReferrerLeaderboardPageResponse: () => deserializeReferrerLeaderboardPageResponse,
81
81
  deserializeReferrerMetricsEditionsResponse: () => deserializeReferrerMetricsEditionsResponse,
82
+ findOverlappingEditionPair: () => findOverlappingEditionPair,
82
83
  getReferrerEditionMetrics: () => getReferrerEditionMetrics,
83
84
  getReferrerLeaderboardPage: () => getReferrerLeaderboardPage,
85
+ hasEnsAnalyticsConfigSupport: () => hasEnsAnalyticsConfigSupport,
86
+ hasEnsAnalyticsIndexingStatusSupport: () => hasEnsAnalyticsIndexingStatusSupport,
84
87
  isFiniteNonNegativeNumber: () => isFiniteNonNegativeNumber,
85
88
  isInteger: () => isInteger,
86
89
  isNonNegativeInteger: () => isNonNegativeInteger,
@@ -478,7 +481,8 @@ function scaleBigintByNumber(value, scaleFactor) {
478
481
  var CurrencyIds = {
479
482
  ETH: "ETH",
480
483
  USDC: "USDC",
481
- DAI: "DAI"
484
+ DAI: "DAI",
485
+ ENSTokens: "ENSTokens"
482
486
  };
483
487
  var currencyInfo = {
484
488
  [CurrencyIds.ETH]: {
@@ -495,6 +499,11 @@ var currencyInfo = {
495
499
  id: CurrencyIds.DAI,
496
500
  name: "Dai Stablecoin",
497
501
  decimals: 18
502
+ },
503
+ [CurrencyIds.ENSTokens]: {
504
+ id: CurrencyIds.ENSTokens,
505
+ name: "$ENS Tokens",
506
+ decimals: 18
498
507
  }
499
508
  };
500
509
  function priceEth(amount) {
@@ -609,6 +618,34 @@ var makeAccountIdSchema = (valueLabel = "AccountId") => import_v4.z.strictObject
609
618
  address: makeNormalizedAddressSchema(`${valueLabel} address`)
610
619
  });
611
620
 
621
+ // ../ensnode-sdk/src/indexing-status/omnichain-indexing-status-snapshot.ts
622
+ var OmnichainIndexingStatusIds = {
623
+ /**
624
+ * Represents that omnichain indexing is not ready to begin yet because
625
+ * ENSIndexer is in its initialization phase and the data to build a "true"
626
+ * {@link OmnichainIndexingStatusSnapshot} is still being loaded.
627
+ */
628
+ Unstarted: "omnichain-unstarted",
629
+ /**
630
+ * Represents that omnichain indexing is in an overall "backfill" status because
631
+ * - At least one indexed chain has a `chainStatus` of
632
+ * {@link ChainIndexingStatusIds.Backfill}; and
633
+ * - No indexed chain has a `chainStatus` of {@link ChainIndexingStatusIds.Following}.
634
+ */
635
+ Backfill: "omnichain-backfill",
636
+ /**
637
+ * Represents that omnichain indexing is in an overall "following" status because
638
+ * at least one indexed chain has a `chainStatus` of
639
+ * {@link ChainIndexingStatusIds.Following}.
640
+ */
641
+ Following: "omnichain-following",
642
+ /**
643
+ * Represents that omnichain indexing has completed because all indexed chains have
644
+ * a `chainStatus` of {@link ChainIndexingStatusIds.Completed}.
645
+ */
646
+ Completed: "omnichain-completed"
647
+ };
648
+
612
649
  // ../ensnode-sdk/src/shared/serialize.ts
613
650
  function serializePrice(price) {
614
651
  return {
@@ -629,6 +666,62 @@ var import_v43 = __toESM(require("zod/v4"), 1);
629
666
  // src/award-models/shared/api/zod-schemas.ts
630
667
  var import_v42 = __toESM(require("zod/v4"), 1);
631
668
 
669
+ // src/edition.ts
670
+ var REFERRAL_PROGRAM_EDITION_SLUG_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
671
+ function validateReferralProgramEditionConfigSet(configSet) {
672
+ const violation = Array.from(configSet.entries()).find(([key, config]) => key !== config.slug);
673
+ if (violation) {
674
+ const [key, config] = violation;
675
+ throw new Error(
676
+ `Edition config set invariant violation: map key "${key}" does not match config.slug "${config.slug}"`
677
+ );
678
+ }
679
+ const overlap = findOverlappingEditionPair(Array.from(configSet.values()));
680
+ if (overlap) {
681
+ const [a, b] = overlap;
682
+ throw new Error(
683
+ `Edition config set invariant violation: editions "${a.slug}" and "${b.slug}" have overlapping time ranges for subregistryId ${a.rules.subregistryId.chainId}:${a.rules.subregistryId.address} (startTime and endTime are inclusive)`
684
+ );
685
+ }
686
+ }
687
+ function findOverlappingEditionPair(editions) {
688
+ const byRegistry = /* @__PURE__ */ new Map();
689
+ for (const edition of editions) {
690
+ const key = `${edition.rules.subregistryId.chainId}:${edition.rules.subregistryId.address}`;
691
+ const group = byRegistry.get(key);
692
+ if (group) {
693
+ group.push(edition);
694
+ } else {
695
+ byRegistry.set(key, [edition]);
696
+ }
697
+ }
698
+ for (const group of byRegistry.values()) {
699
+ if (group.length < 2) continue;
700
+ group.sort((a, b) => a.rules.startTime - b.rules.startTime);
701
+ for (let i = 1; i < group.length; i++) {
702
+ const prev = group[i - 1];
703
+ const curr = group[i];
704
+ if (curr.rules.startTime <= prev.rules.endTime) {
705
+ return [prev, curr];
706
+ }
707
+ }
708
+ }
709
+ return null;
710
+ }
711
+ function buildReferralProgramEditionConfigSet(configs) {
712
+ const slugCounts = configs.reduce((counts, config) => {
713
+ counts.set(config.slug, (counts.get(config.slug) || 0) + 1);
714
+ return counts;
715
+ }, /* @__PURE__ */ new Map());
716
+ const duplicates = Array.from(slugCounts.entries()).filter(([_, count]) => count > 1).map(([slug, count]) => `"${slug}" (${count} occurrences)`);
717
+ if (duplicates.length > 0) {
718
+ throw new Error(`Duplicate edition config slugs detected: ${duplicates.join(", ")}`);
719
+ }
720
+ const configSet = new Map(configs.map((config) => [config.slug, config]));
721
+ validateReferralProgramEditionConfigSet(configSet);
722
+ return configSet;
723
+ }
724
+
632
725
  // src/number.ts
633
726
  var isInteger = (value) => {
634
727
  return Number.isInteger(value);
@@ -835,6 +928,15 @@ var calcBaseReferralProgramEditionStatus = (rules, now) => {
835
928
  };
836
929
 
837
930
  // src/award-models/shared/api/zod-schemas.ts
931
+ var makeReferralProgramEditionSlugSchema = (valueLabel = "ReferralProgramEditionSlug") => import_v42.default.string().min(1, `${valueLabel} must not be empty`).regex(
932
+ REFERRAL_PROGRAM_EDITION_SLUG_PATTERN,
933
+ `${valueLabel} must contain only lowercase letters, digits, and hyphens. Must not start or end with a hyphen.`
934
+ );
935
+ var makeBaseReferralProgramEditionConfigSchema = (valueLabel = "BaseReferralProgramEditionConfig") => import_v42.default.object({
936
+ slug: makeReferralProgramEditionSlugSchema(`${valueLabel}.slug`),
937
+ displayName: import_v42.default.string().min(1, `${valueLabel}.displayName must not be empty`),
938
+ rules: makeBaseReferralProgramRulesSchema(`${valueLabel}.rules`)
939
+ });
838
940
  var makeBaseReferralProgramRulesSchema = (valueLabel) => import_v42.default.object({
839
941
  awardModel: import_v42.default.string(),
840
942
  startTime: makeUnixTimestampSchema(`${valueLabel}.startTime`),
@@ -860,12 +962,9 @@ var makeReferrerLeaderboardPageContextSchema = (valueLabel = "ReferrerLeaderboar
860
962
  endIndex: import_v42.default.optional(makeNonNegativeIntegerSchema(`${valueLabel}.endIndex`))
861
963
  });
862
964
  var makeReferralProgramStatusSchema = (_valueLabel = "status") => import_v42.default.enum(ReferralProgramEditionStatuses);
863
- var makeBaseReferralProgramEditionSummarySchema = (valueLabel) => import_v42.default.object({
965
+ var makeBaseReferralProgramEditionSummarySchema = (valueLabel) => makeBaseReferralProgramEditionConfigSchema(valueLabel).safeExtend({
864
966
  awardModel: import_v42.default.string(),
865
- slug: import_v42.default.string().min(1, `${valueLabel}.slug must not be empty`),
866
- displayName: import_v42.default.string().min(1, `${valueLabel}.displayName must not be empty`),
867
- status: makeReferralProgramStatusSchema(`${valueLabel}.status`),
868
- rules: makeBaseReferralProgramRulesSchema(`${valueLabel}.rules`)
967
+ status: makeReferralProgramStatusSchema(`${valueLabel}.status`)
869
968
  });
870
969
  var makeBaseReferrerLeaderboardPageSchema = (valueLabel) => import_v42.default.object({
871
970
  awardModel: import_v42.default.string(),
@@ -1446,10 +1545,6 @@ var makeReferrerEditionMetricsSchema = (valueLabel = "ReferrerEditionMetrics") =
1446
1545
  };
1447
1546
  });
1448
1547
  };
1449
- var makeReferralProgramEditionSlugSchema = (valueLabel = "ReferralProgramEditionSlug") => import_v45.default.string().min(1, `${valueLabel} must not be empty`).regex(
1450
- /^[a-z0-9]+(-[a-z0-9]+)*$/,
1451
- `${valueLabel} must contain only lowercase letters, digits, and hyphens. Must not start or end with a hyphen.`
1452
- );
1453
1548
  var makeReferrerMetricsEditionsResponseOkSchema = (valueLabel = "ReferrerMetricsEditionsResponseOk") => import_v45.default.object({
1454
1549
  responseCode: import_v45.default.literal(ReferrerMetricsEditionsResponseCodes.Ok),
1455
1550
  data: import_v45.default.record(
@@ -1466,12 +1561,7 @@ var makeReferrerMetricsEditionsResponseSchema = (valueLabel = "ReferrerMetricsEd
1466
1561
  makeReferrerMetricsEditionsResponseOkSchema(valueLabel),
1467
1562
  makeReferrerMetricsEditionsResponseErrorSchema(valueLabel)
1468
1563
  ]);
1469
- var makeReferralProgramEditionConfigBaseSchema = (valueLabel) => import_v45.default.object({
1470
- slug: makeReferralProgramEditionSlugSchema(`${valueLabel}.slug`),
1471
- displayName: import_v45.default.string().min(1, `${valueLabel}.displayName must not be empty`),
1472
- rules: makeBaseReferralProgramRulesSchema(`${valueLabel}.rules`)
1473
- });
1474
- var makeReferralProgramEditionConfigSchema = (valueLabel = "ReferralProgramEditionConfig") => makeReferralProgramEditionConfigBaseSchema(valueLabel).safeExtend({
1564
+ var makeReferralProgramEditionConfigSchema = (valueLabel = "ReferralProgramEditionConfig") => makeBaseReferralProgramEditionConfigSchema(valueLabel).safeExtend({
1475
1565
  rules: makeReferralProgramRulesSchema(`${valueLabel}.rules`)
1476
1566
  });
1477
1567
  var makeReferralProgramEditionConfigSetArraySchema = (valueLabel = "ReferralProgramEditionConfigSetArray") => {
@@ -1482,7 +1572,7 @@ var makeReferralProgramEditionConfigSetArraySchema = (valueLabel = "ReferralProg
1482
1572
  const looseItemSchema = import_v45.default.looseObject({
1483
1573
  rules: import_v45.default.looseObject({ awardModel: import_v45.default.string() })
1484
1574
  });
1485
- const unrecognizedBaseSchema = makeReferralProgramEditionConfigBaseSchema(
1575
+ const unrecognizedBaseSchema = makeBaseReferralProgramEditionConfigSchema(
1486
1576
  `${valueLabel}[edition]`
1487
1577
  );
1488
1578
  return import_v45.default.array(looseItemSchema).transform((items, ctx) => {
@@ -1523,6 +1613,15 @@ var makeReferralProgramEditionConfigSetArraySchema = (valueLabel = "ReferralProg
1523
1613
  }
1524
1614
  slugs.add(edition.slug);
1525
1615
  }
1616
+ const overlap = findOverlappingEditionPair(result);
1617
+ if (overlap) {
1618
+ const [a, b] = overlap;
1619
+ ctx.addIssue({
1620
+ code: "custom",
1621
+ message: `${valueLabel}: editions "${a.slug}" and "${b.slug}" have overlapping time ranges for subregistryId ${a.rules.subregistryId.chainId}:${a.rules.subregistryId.address} (startTime and endTime are inclusive)`
1622
+ });
1623
+ return [];
1624
+ }
1526
1625
  return result;
1527
1626
  });
1528
1627
  };
@@ -1563,6 +1662,15 @@ var makeReferralProgramEditionSummarySchema = (valueLabel = "ReferralProgramEdit
1563
1662
  };
1564
1663
  var makeReferralProgramEditionSummariesDataSchema = (valueLabel = "ReferralProgramEditionSummariesData") => import_v45.default.object({
1565
1664
  editions: import_v45.default.array(makeReferralProgramEditionSummarySchema(`${valueLabel}.editions[edition]`))
1665
+ }).superRefine((data, ctx) => {
1666
+ const overlap = findOverlappingEditionPair(data.editions);
1667
+ if (!overlap) return;
1668
+ const [a, b] = overlap;
1669
+ ctx.addIssue({
1670
+ code: "custom",
1671
+ path: ["editions"],
1672
+ message: `${valueLabel}: editions "${a.slug}" and "${b.slug}" have overlapping time ranges for subregistryId ${a.rules.subregistryId.chainId}:${a.rules.subregistryId.address} (startTime and endTime are inclusive)`
1673
+ });
1566
1674
  });
1567
1675
  var makeReferralProgramEditionSummariesResponseOkSchema = (valueLabel = "ReferralProgramEditionSummariesResponseOk") => import_v45.default.object({
1568
1676
  responseCode: import_v45.default.literal(ReferralProgramEditionSummariesResponseCodes.Ok),
@@ -1628,6 +1736,36 @@ ${(0, import_v46.prettifyError)(parsed.error)}
1628
1736
  return parsed.data;
1629
1737
  }
1630
1738
 
1739
+ // src/api/prerequisites.ts
1740
+ var ensAnalyticsRequiredPlugins = [
1741
+ "subgraph" /* Subgraph */,
1742
+ "basenames" /* Basenames */,
1743
+ "lineanames" /* Lineanames */,
1744
+ "registrars" /* Registrars */
1745
+ ];
1746
+ function hasEnsAnalyticsConfigSupport(config) {
1747
+ const supported = ensAnalyticsRequiredPlugins.every((plugin) => config.plugins.includes(plugin));
1748
+ if (supported) return { supported };
1749
+ return {
1750
+ supported: false,
1751
+ reason: `The ENSAnalytics API requires all of the following plugins to be activated in the connected ENSNode's Config: ${ensAnalyticsRequiredPlugins.map((plugin) => `'${plugin}'`).join(", ")}.`
1752
+ };
1753
+ }
1754
+ var ensAnalyticsSupportedIndexingStatusIds = [
1755
+ OmnichainIndexingStatusIds.Completed,
1756
+ OmnichainIndexingStatusIds.Following
1757
+ ];
1758
+ function hasEnsAnalyticsIndexingStatusSupport(omnichainIndexingStatusId) {
1759
+ const supported = ensAnalyticsSupportedIndexingStatusIds.some(
1760
+ (supportedIndexingStatusId) => supportedIndexingStatusId === omnichainIndexingStatusId
1761
+ );
1762
+ if (supported) return { supported };
1763
+ return {
1764
+ supported: false,
1765
+ reason: `The ENSAnalytics API requires the connected ENSNode's Indexing Status to be one of the following: ${ensAnalyticsSupportedIndexingStatusIds.join(", ")}.`
1766
+ };
1767
+ }
1768
+
1631
1769
  // src/award-models/pie-split/api/serialize.ts
1632
1770
  function serializeReferralProgramRulesPieSplit(rules) {
1633
1771
  return {
@@ -2042,31 +2180,6 @@ var buildAggregatedReferrerMetricsPieSplit = (referrers, rules) => {
2042
2180
  return result;
2043
2181
  };
2044
2182
 
2045
- // src/edition.ts
2046
- var REFERRAL_PROGRAM_EDITION_SLUG_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
2047
- function validateReferralProgramEditionConfigSet(configSet) {
2048
- const violation = Array.from(configSet.entries()).find(([key, config]) => key !== config.slug);
2049
- if (violation) {
2050
- const [key, config] = violation;
2051
- throw new Error(
2052
- `Edition config set invariant violation: map key "${key}" does not match config.slug "${config.slug}"`
2053
- );
2054
- }
2055
- }
2056
- function buildReferralProgramEditionConfigSet(configs) {
2057
- const slugCounts = configs.reduce((counts, config) => {
2058
- counts.set(config.slug, (counts.get(config.slug) || 0) + 1);
2059
- return counts;
2060
- }, /* @__PURE__ */ new Map());
2061
- const duplicates = Array.from(slugCounts.entries()).filter(([_, count]) => count > 1).map(([slug, count]) => `"${slug}" (${count} occurrences)`);
2062
- if (duplicates.length > 0) {
2063
- throw new Error(`Duplicate edition config slugs detected: ${duplicates.join(", ")}`);
2064
- }
2065
- const configSet = new Map(configs.map((config) => [config.slug, config]));
2066
- validateReferralProgramEditionConfigSet(configSet);
2067
- return configSet;
2068
- }
2069
-
2070
2183
  // src/award-models/shared/edition-summary.ts
2071
2184
  var validateBaseReferralProgramEditionSummary = (summary) => {
2072
2185
  if (!REFERRAL_PROGRAM_EDITION_SLUG_PATTERN.test(summary.slug)) {
@@ -2362,7 +2475,7 @@ var buildUnrankedReferrerMetricsPieSplit = (referrer) => {
2362
2475
  };
2363
2476
 
2364
2477
  // src/award-models/pie-split/leaderboard.ts
2365
- var buildReferrerLeaderboardPieSplit = (allReferrers, rules, accurateAsOf) => {
2478
+ var buildReferralEditionSnapshotPieSplit = (allReferrers, rules, accurateAsOf) => {
2366
2479
  assertLeaderboardInputs(allReferrers, rules, accurateAsOf);
2367
2480
  const sortedReferrers = sortReferrerMetrics(allReferrers);
2368
2481
  const scoredReferrers = sortedReferrers.map((r) => buildScoredReferrerMetricsPieSplit(r));
@@ -2374,7 +2487,14 @@ var buildReferrerLeaderboardPieSplit = (allReferrers, rules, accurateAsOf) => {
2374
2487
  (r) => buildAwardedReferrerMetricsPieSplit(r, aggregatedMetrics, rules)
2375
2488
  );
2376
2489
  const referrers = new Map(awardedReferrers.map((r) => [r.referrer, r]));
2377
- return { awardModel: rules.awardModel, rules, aggregatedMetrics, referrers, accurateAsOf };
2490
+ const leaderboard = {
2491
+ awardModel: rules.awardModel,
2492
+ rules,
2493
+ aggregatedMetrics,
2494
+ referrers,
2495
+ accurateAsOf
2496
+ };
2497
+ return { awardModel: rules.awardModel, leaderboard };
2378
2498
  };
2379
2499
 
2380
2500
  // src/award-models/pie-split/leaderboard-page.ts
@@ -2652,9 +2772,14 @@ function sortReferralEvents(events) {
2652
2772
  }
2653
2773
 
2654
2774
  // src/award-models/rev-share-cap/leaderboard.ts
2655
- var buildReferrerLeaderboardRevShareCap = (events, rules, accurateAsOf) => {
2775
+ var buildReferralEditionSnapshotRevShareCap = (events, rules, accurateAsOf) => {
2656
2776
  const sortedEvents = sortReferralEvents(events);
2777
+ const adminActionByReferrer = /* @__PURE__ */ new Map();
2778
+ for (const action of rules.adminActions) {
2779
+ adminActionByReferrer.set(action.referrer, action);
2780
+ }
2657
2781
  const referrerStates = /* @__PURE__ */ new Map();
2782
+ const accountingRecords = [];
2658
2783
  let awardPoolRemaining = rules.awardPool;
2659
2784
  for (const event of sortedEvents) {
2660
2785
  const referrerId = event.referrer;
@@ -2675,27 +2800,65 @@ var buildReferrerLeaderboardRevShareCap = (events, rules, accurateAsOf) => {
2675
2800
  referrerState.totalRevenueContribution,
2676
2801
  event.incrementalRevenueContribution
2677
2802
  );
2678
- const totalBaseRevenue = calcBaseRevenueContribution(
2803
+ const hasQualifiedBefore = referrerState.hasQualified;
2804
+ const awardPoolRemainingBefore = awardPoolRemaining;
2805
+ const adminAction = adminActionByReferrer.get(referrerId);
2806
+ const adminDisqualification = adminAction?.actionType === AdminActionTypes.Disqualification ? adminAction : null;
2807
+ const accumulatedBaseRevenueContribution = calcBaseRevenueContribution(
2679
2808
  rules,
2680
2809
  referrerState.totalIncrementalDuration
2681
2810
  );
2682
- const isNowQualified = isReferrerQualifiedRevShareCap(referrerId, totalBaseRevenue, rules);
2683
- if (isNowQualified && !referrerState.hasQualified) {
2684
- const accumulatedUncappedAward = scalePrice(totalBaseRevenue, rules.maxBaseRevenueShare);
2685
- const incrementalCappedAward = minPrice(accumulatedUncappedAward, awardPoolRemaining);
2686
- referrerState.cappedAward = addPrices(referrerState.cappedAward, incrementalCappedAward);
2687
- awardPoolRemaining = subtractPrice(awardPoolRemaining, incrementalCappedAward);
2811
+ const incrementalBaseRevenueContribution = calcBaseRevenueContribution(
2812
+ rules,
2813
+ event.incrementalDuration
2814
+ );
2815
+ const isNowQualified = isReferrerQualifiedRevShareCap(
2816
+ referrerId,
2817
+ accumulatedBaseRevenueContribution,
2818
+ rules
2819
+ );
2820
+ let incrementalTentativeAward = priceUsdc(0n);
2821
+ if (isNowQualified && !hasQualifiedBefore) {
2822
+ const accumulatedUncappedAward = scalePrice(
2823
+ accumulatedBaseRevenueContribution,
2824
+ rules.maxBaseRevenueShare
2825
+ );
2826
+ incrementalTentativeAward = minPrice(accumulatedUncappedAward, awardPoolRemainingBefore);
2688
2827
  referrerState.hasQualified = true;
2689
- } else if (referrerState.hasQualified) {
2690
- const incrementalBaseRevenue = calcBaseRevenueContribution(rules, event.incrementalDuration);
2828
+ } else if (hasQualifiedBefore) {
2691
2829
  const incrementalUncappedAward = scalePrice(
2692
- incrementalBaseRevenue,
2830
+ incrementalBaseRevenueContribution,
2693
2831
  rules.maxBaseRevenueShare
2694
2832
  );
2695
- const incrementalCappedAward = minPrice(incrementalUncappedAward, awardPoolRemaining);
2696
- referrerState.cappedAward = addPrices(referrerState.cappedAward, incrementalCappedAward);
2697
- awardPoolRemaining = subtractPrice(awardPoolRemaining, incrementalCappedAward);
2833
+ incrementalTentativeAward = minPrice(incrementalUncappedAward, awardPoolRemainingBefore);
2698
2834
  }
2835
+ referrerState.cappedAward = addPrices(referrerState.cappedAward, incrementalTentativeAward);
2836
+ awardPoolRemaining = subtractPrice(awardPoolRemaining, incrementalTentativeAward);
2837
+ const tentativeAward = {
2838
+ incrementalRevenueContribution: event.incrementalRevenueContribution,
2839
+ accumulatedRevenueContribution: referrerState.totalRevenueContribution,
2840
+ incrementalBaseRevenueContribution,
2841
+ accumulatedBaseRevenueContribution,
2842
+ awardPoolRemaining: awardPoolRemainingBefore,
2843
+ disqualified: adminDisqualification !== null,
2844
+ ...adminDisqualification !== null && {
2845
+ disqualificationReason: adminDisqualification.reason
2846
+ },
2847
+ maxRevShare: rules.maxBaseRevenueShare,
2848
+ effectiveBaseRevShare: incrementalBaseRevenueContribution.amount === 0n ? 0 : Number(incrementalTentativeAward.amount) / Number(incrementalBaseRevenueContribution.amount),
2849
+ incrementalTentativeAward
2850
+ };
2851
+ accountingRecords.push({
2852
+ registrarActionId: event.id,
2853
+ timestamp: event.timestamp,
2854
+ name: event.name,
2855
+ actionType: event.actionType,
2856
+ transactionHash: event.transactionHash,
2857
+ registrant: event.registrant,
2858
+ referrer: referrerId,
2859
+ incrementalDuration: event.incrementalDuration,
2860
+ tentativeAward
2861
+ });
2699
2862
  }
2700
2863
  const sortedEntries = [...referrerStates.entries()].sort(
2701
2864
  ([referrerIdA, referrerStateA], [referrerIdB, referrerStateB]) => {
@@ -2741,7 +2904,17 @@ var buildReferrerLeaderboardRevShareCap = (events, rules, accurateAsOf) => {
2741
2904
  awardPoolRemaining
2742
2905
  );
2743
2906
  const referrers = new Map(awardedReferrers.map((r) => [r.referrer, r]));
2744
- return { awardModel: rules.awardModel, rules, aggregatedMetrics, referrers, accurateAsOf };
2907
+ return {
2908
+ awardModel: rules.awardModel,
2909
+ leaderboard: {
2910
+ awardModel: rules.awardModel,
2911
+ rules,
2912
+ aggregatedMetrics,
2913
+ referrers,
2914
+ accurateAsOf
2915
+ },
2916
+ accountingRecords
2917
+ };
2745
2918
  };
2746
2919
 
2747
2920
  // src/award-models/rev-share-cap/leaderboard-page.ts