@merkl/api 0.20.167 → 0.20.168

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.
@@ -84,6 +84,12 @@ export const OpportunityController = new Elysia({
84
84
  },
85
85
  detail: { description: "Get the count of opportunities corresponding to the query." },
86
86
  response: { 200: t.Number() },
87
+ })
88
+ .get("/bins/apr", async ({ query }) => await OpportunityService.getAprBins(query), {
89
+ query: GetOpportunitiesQueryDto,
90
+ })
91
+ .get("/bins/tvl", async ({ query }) => await OpportunityService.getTvlBins(query), {
92
+ query: GetOpportunitiesQueryDto,
87
93
  })
88
94
  // ─── Get An Opportunity By Id ────────────────────────────────────────
89
95
  .get("/:id", async ({ params, query }) => {
@@ -131,10 +131,8 @@ export declare abstract class OpportunityRepository {
131
131
  TvlRecords: ({
132
132
  TvlBreakdown: {
133
133
  type: import("@db/api").$Enums.TvlType;
134
- id: string;
135
134
  identifier: string;
136
135
  value: number;
137
- tvlRecordId: string;
138
136
  }[];
139
137
  } & {
140
138
  total: number;
@@ -145,10 +143,8 @@ export declare abstract class OpportunityRepository {
145
143
  AprRecords: ({
146
144
  AprBreakdown: {
147
145
  type: import("@db/api").$Enums.AprType;
148
- id: string;
149
146
  identifier: string;
150
147
  value: number;
151
- aprRecordId: string;
152
148
  }[];
153
149
  } & {
154
150
  id: string;
@@ -281,10 +277,8 @@ export declare abstract class OpportunityRepository {
281
277
  TvlRecords: ({
282
278
  TvlBreakdown: {
283
279
  type: import("@db/api").$Enums.TvlType;
284
- id: string;
285
280
  identifier: string;
286
281
  value: number;
287
- tvlRecordId: string;
288
282
  }[];
289
283
  } & {
290
284
  total: number;
@@ -295,10 +289,8 @@ export declare abstract class OpportunityRepository {
295
289
  AprRecords: ({
296
290
  AprBreakdown: {
297
291
  type: import("@db/api").$Enums.AprType;
298
- id: string;
299
292
  identifier: string;
300
293
  value: number;
301
- aprRecordId: string;
302
294
  }[];
303
295
  } & {
304
296
  id: string;
@@ -490,10 +482,8 @@ export declare abstract class OpportunityRepository {
490
482
  TvlRecords: ({
491
483
  TvlBreakdown: {
492
484
  type: import("@db/api").$Enums.TvlType;
493
- id: string;
494
485
  identifier: string;
495
486
  value: number;
496
- tvlRecordId: string;
497
487
  }[];
498
488
  } & {
499
489
  total: number;
@@ -504,10 +494,8 @@ export declare abstract class OpportunityRepository {
504
494
  AprRecords: ({
505
495
  AprBreakdown: {
506
496
  type: import("@db/api").$Enums.AprType;
507
- id: string;
508
497
  identifier: string;
509
498
  value: number;
510
- aprRecordId: string;
511
499
  }[];
512
500
  } & {
513
501
  id: string;
@@ -647,10 +635,8 @@ export declare abstract class OpportunityRepository {
647
635
  TvlRecords: ({
648
636
  TvlBreakdown: {
649
637
  type: import("@db/api").$Enums.TvlType;
650
- id: string;
651
638
  identifier: string;
652
639
  value: number;
653
- tvlRecordId: string;
654
640
  }[];
655
641
  } & {
656
642
  total: number;
@@ -661,10 +647,8 @@ export declare abstract class OpportunityRepository {
661
647
  AprRecords: ({
662
648
  AprBreakdown: {
663
649
  type: import("@db/api").$Enums.AprType;
664
- id: string;
665
650
  identifier: string;
666
651
  value: number;
667
- aprRecordId: string;
668
652
  }[];
669
653
  } & {
670
654
  id: string;
@@ -858,10 +842,8 @@ export declare abstract class OpportunityRepository {
858
842
  TvlRecords: ({
859
843
  TvlBreakdown: {
860
844
  type: import("@db/api").$Enums.TvlType;
861
- id: string;
862
845
  identifier: string;
863
846
  value: number;
864
- tvlRecordId: string;
865
847
  }[];
866
848
  } & {
867
849
  total: number;
@@ -872,10 +854,8 @@ export declare abstract class OpportunityRepository {
872
854
  AprRecords: ({
873
855
  AprBreakdown: {
874
856
  type: import("@db/api").$Enums.AprType;
875
- id: string;
876
857
  identifier: string;
877
858
  value: number;
878
- aprRecordId: string;
879
859
  }[];
880
860
  } & {
881
861
  id: string;
@@ -111,8 +111,16 @@ export class OpportunityRepository {
111
111
  }
112
112
  static #getRecordInclusion(withTest = true, withPoints = true) {
113
113
  return {
114
- AprRecords: { take: 1, orderBy: { timestamp: "desc" }, include: { AprBreakdown: true } },
115
- TvlRecords: { take: 1, orderBy: { timestamp: "desc" }, include: { TvlBreakdown: true } },
114
+ AprRecords: {
115
+ take: 1,
116
+ orderBy: { timestamp: "desc" },
117
+ include: { AprBreakdown: { select: { identifier: true, type: true, value: true } } },
118
+ },
119
+ TvlRecords: {
120
+ take: 1,
121
+ orderBy: { timestamp: "desc" },
122
+ include: { TvlBreakdown: { select: { identifier: true, type: true, value: true } } },
123
+ },
116
124
  DailyRewardsRecords: {
117
125
  take: 1,
118
126
  orderBy: { timestamp: "desc" },
@@ -8,6 +8,19 @@ import { OpportunityRepository } from "./opportunity.repository";
8
8
  export declare abstract class OpportunityService {
9
9
  #private;
10
10
  static hashId(opportunity: OpportunityUnique): string;
11
+ static getAprBins(query: GetOpportunitiesQueryModel): Promise<{
12
+ min: number;
13
+ max: number;
14
+ overThreshold: number;
15
+ binWidth: number;
16
+ bins: any[];
17
+ }>;
18
+ static getTvlBins(query: GetOpportunitiesQueryModel): Promise<{
19
+ min: number;
20
+ max: number;
21
+ binWidth: number;
22
+ bins: any[];
23
+ }>;
11
24
  static override(id: string, data: OpportunityOverrideModel): Promise<{
12
25
  status: import("@db/api").$Enums.Status;
13
26
  type: string;
@@ -625,16 +638,12 @@ export declare abstract class OpportunityService {
625
638
  cumulated: number;
626
639
  timestamp: bigint;
627
640
  breakdowns: ({
628
- id: string;
629
641
  value: number;
630
- aprRecordId: string;
631
642
  distributionType: import("@db/api").$Enums.DistributionType;
632
643
  identifier: string;
633
644
  type: "CAMPAIGN";
634
645
  } | {
635
- id: string;
636
646
  value: number;
637
- aprRecordId: string;
638
647
  identifier: string;
639
648
  type: import("@db/api").$Enums.AprType;
640
649
  })[];
@@ -645,10 +654,8 @@ export declare abstract class OpportunityService {
645
654
  timestamp: bigint;
646
655
  breakdowns: {
647
656
  type: import("@db/api").$Enums.TvlType;
648
- id: string;
649
657
  identifier: string;
650
658
  value: number;
651
- tvlRecordId: string;
652
659
  }[];
653
660
  };
654
661
  rewardsRecord: {
@@ -815,16 +822,12 @@ export declare abstract class OpportunityService {
815
822
  cumulated: number;
816
823
  timestamp: bigint;
817
824
  breakdowns: ({
818
- id: string;
819
825
  value: number;
820
- aprRecordId: string;
821
826
  distributionType: import("@db/api").$Enums.DistributionType;
822
827
  identifier: string;
823
828
  type: "CAMPAIGN";
824
829
  } | {
825
- id: string;
826
830
  value: number;
827
- aprRecordId: string;
828
831
  identifier: string;
829
832
  type: import("@db/api").$Enums.AprType;
830
833
  })[];
@@ -835,10 +838,8 @@ export declare abstract class OpportunityService {
835
838
  timestamp: bigint;
836
839
  breakdowns: {
837
840
  type: import("@db/api").$Enums.TvlType;
838
- id: string;
839
841
  identifier: string;
840
842
  value: number;
841
- tvlRecordId: string;
842
843
  }[];
843
844
  };
844
845
  rewardsRecord: {
@@ -998,16 +999,12 @@ export declare abstract class OpportunityService {
998
999
  cumulated: number;
999
1000
  timestamp: bigint;
1000
1001
  breakdowns: ({
1001
- id: string;
1002
1002
  value: number;
1003
- aprRecordId: string;
1004
1003
  distributionType: import("@db/api").$Enums.DistributionType;
1005
1004
  identifier: string;
1006
1005
  type: "CAMPAIGN";
1007
1006
  } | {
1008
- id: string;
1009
1007
  value: number;
1010
- aprRecordId: string;
1011
1008
  identifier: string;
1012
1009
  type: import("@db/api").$Enums.AprType;
1013
1010
  })[];
@@ -1018,10 +1015,8 @@ export declare abstract class OpportunityService {
1018
1015
  timestamp: bigint;
1019
1016
  breakdowns: {
1020
1017
  type: import("@db/api").$Enums.TvlType;
1021
- id: string;
1022
1018
  identifier: string;
1023
1019
  value: number;
1024
- tvlRecordId: string;
1025
1020
  }[];
1026
1021
  };
1027
1022
  rewardsRecord: {
@@ -17,6 +17,67 @@ export class OpportunityService {
17
17
  static hashId(opportunity) {
18
18
  return Bun.hash(`${opportunity.chainId}${opportunity.type}${opportunity.identifier}`).toString();
19
19
  }
20
+ static async getAprBins(query) {
21
+ const BINS_COUNT = 20;
22
+ const opportunities = await OpportunityRepository.findMany({
23
+ ...query,
24
+ status: "LIVE",
25
+ sort: "apr",
26
+ order: "asc",
27
+ items: 0,
28
+ });
29
+ const mid = Math.floor(opportunities.length / 2);
30
+ const median = opportunities.length % 2 !== 0
31
+ ? opportunities[mid].apr
32
+ : (opportunities[mid - 1].apr + opportunities[mid].apr) / 2;
33
+ const threshold = 5 * median;
34
+ if (opportunities.length < 2)
35
+ throw new Error("Not enough opportunities");
36
+ const maxAprUnderThreshold = opportunities.filter(o => o.apr <= threshold).at(-1)?.apr ?? 0;
37
+ const minAprAbove0 = opportunities.find(o => o.apr > 0)?.apr ?? 0;
38
+ const binWidth = (maxAprUnderThreshold - minAprAbove0) / BINS_COUNT;
39
+ const bins = new Array(BINS_COUNT);
40
+ for (let i = 0; i < BINS_COUNT; i++)
41
+ bins[i] = 0;
42
+ let overThreshold = 0;
43
+ for (const opportunity of opportunities) {
44
+ if (opportunity.apr > 0 && opportunity.apr < threshold)
45
+ bins[Math.min(Math.floor(opportunity.apr / binWidth), BINS_COUNT - 1)]++;
46
+ else
47
+ overThreshold++;
48
+ }
49
+ return {
50
+ min: opportunities[0].apr,
51
+ max: opportunities[opportunities.length - 1].apr,
52
+ overThreshold,
53
+ binWidth,
54
+ bins,
55
+ };
56
+ }
57
+ static async getTvlBins(query) {
58
+ const BINS_COUNT = 20;
59
+ const opportunities = await OpportunityRepository.findMany({
60
+ ...query,
61
+ status: "LIVE,SOON",
62
+ sort: "tvl",
63
+ order: "asc",
64
+ items: 0,
65
+ });
66
+ if (opportunities.length < 2)
67
+ throw new Error("Not enough opportunities");
68
+ const binWidth = (opportunities[opportunities.length - 1].tvl - opportunities[0].tvl) / BINS_COUNT;
69
+ const bins = new Array(BINS_COUNT);
70
+ for (let i = 0; i < BINS_COUNT; i++)
71
+ bins[i] = 0;
72
+ for (const opportunity of opportunities)
73
+ bins[Math.min(Math.floor(opportunity.tvl / binWidth), BINS_COUNT - 1)]++;
74
+ return {
75
+ min: opportunities[0].tvl,
76
+ max: opportunities[opportunities.length - 1].tvl,
77
+ binWidth,
78
+ bins,
79
+ };
80
+ }
20
81
  static async override(id, data) {
21
82
  const opportunity = await OpportunityRepository.findUniqueOrThrow(id);
22
83
  const overrides = opportunity.manualOverrides ?? [];
@@ -129,6 +129,6 @@ export const RewardController = new Elysia({ prefix: "/rewards", detail: { tags:
129
129
  detail: { hide: true },
130
130
  })
131
131
  .get("/total/distributed", async ({ query }) => await RewardService.getTotalDistributed(query.since.getTime() / 1000))
132
- .get("/total/distributed/by-chains", async ({ query }) => await CacheService.wrap(TTLPresets.DAY_1, RewardService.getTotalDistributedByChains, query.since.getTime() / 1000))
132
+ .get("/total/distributed/by-chains", async ({ query }) => await CacheService.wrap(TTLPresets.DAY_1, RewardService.getTotalDistributedByChain, query.since.getTime() / 1000))
133
133
  .get("/total/distributed/by-types", async ({ query }) => await CacheService.wrap(TTLPresets.DAY_1, RewardService.getTotalDistributedByType, query.since.getTime() / 1000))
134
134
  .get("/total/distributed/by-protocols", async ({ query }) => await CacheService.wrap(TTLPresets.DAY_1, RewardService.getTotalDistributedByProtocol, query.since.getTime() / 1000));
@@ -14,16 +14,12 @@ export declare abstract class RewardService {
14
14
  cumulated: number;
15
15
  timestamp: bigint;
16
16
  breakdowns: ({
17
- id: string;
18
17
  value: number;
19
- aprRecordId: string;
20
18
  distributionType: import("@db/api").$Enums.DistributionType;
21
19
  identifier: string;
22
20
  type: "CAMPAIGN";
23
21
  } | {
24
- id: string;
25
22
  value: number;
26
- aprRecordId: string;
27
23
  identifier: string;
28
24
  type: import("@db/api").$Enums.AprType;
29
25
  })[];
@@ -34,10 +30,8 @@ export declare abstract class RewardService {
34
30
  timestamp: bigint;
35
31
  breakdowns: {
36
32
  type: import("@db/api").$Enums.TvlType;
37
- id: string;
38
33
  identifier: string;
39
34
  value: number;
40
- tvlRecordId: string;
41
35
  }[];
42
36
  };
43
37
  rewardsRecord: {
@@ -192,7 +186,7 @@ export declare abstract class RewardService {
192
186
  dailyRewards: number;
193
187
  }, number>>;
194
188
  static getTotalDistributed(since: number): Promise<number>;
195
- static getTotalDistributedByChains(since: number): Promise<any>;
189
+ static getTotalDistributedByChain(since: number): Promise<any>;
196
190
  static getTotalDistributedByProtocol(since: number): Promise<any>;
197
191
  static getTotalDistributedByType(since: number): Promise<any>;
198
192
  /**
@@ -44,7 +44,7 @@ export class RewardService {
44
44
  const oppToDailyRewards = await RewardService.getTotalDistributedByOpportunities(since);
45
45
  return oppToDailyRewards.values().reduce((prev, curr) => prev + curr, 0);
46
46
  }
47
- static async getTotalDistributedByChains(since) {
47
+ static async getTotalDistributedByChain(since) {
48
48
  const oppToDailyRewards = await RewardService.getTotalDistributedByOpportunities(since);
49
49
  const chainsToDailyRewards = new Map();
50
50
  for (const [opp, dr] of oppToDailyRewards.entries()) {