@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.
@@ -57,56 +57,11 @@ const main = async () => {
57
57
  }, {});
58
58
  const now = new Date();
59
59
  const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 0, 0, 0, 0)).getTime() / 1000;
60
- const firstDayOfMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1, // Day 1 of the month
61
- 0, // 0 hours
62
- 0, // 0 minutes
63
- 0, // 0 seconds
64
- 0 // 0 milliseconds
65
- )).getTime() / 1000;
60
+ const firstDayOfMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1, 0, 0, 0, 0)).getTime() / 1000;
66
61
  const promises = [
67
- // ─── Rewards By Types ────────────────────────────────────────
68
- CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByType, firstDayOfMonth).then(async (result) => {
69
- const currentMonthPages = await getPagesOfTheMonth(MONTHLY_REWARDS_BY_TYPES_DATABASE_ID);
70
- const promises = [];
71
- // ─── Check If Page Already Exists ────────────────────
72
- for (const type of Object.keys(result)) {
73
- const page = currentMonthPages.find(page => "properties" in page &&
74
- page.properties.Types.title[0].text.content === type);
75
- // ─── If Page Exists, Update It ───────────────
76
- if (page) {
77
- promises.push(notion.pages.update({
78
- page_id: page.id,
79
- properties: {
80
- Rewards: {
81
- type: "number",
82
- number: result[type],
83
- },
84
- To: { type: "date", date: { start: now.toISOString().split("T")[0] } },
85
- },
86
- }));
87
- // ─── Else, Create It ─────────────────
88
- }
89
- else {
90
- promises.push(notion.pages.create({
91
- parent: { type: "database_id", database_id: MONTHLY_REWARDS_BY_TYPES_DATABASE_ID },
92
- properties: {
93
- Types: {
94
- type: "title",
95
- title: [{ type: "text", text: { content: type } }],
96
- },
97
- Rewards: { type: "number", number: result[type] },
98
- From: { type: "date", date: { start: new Date(firstDayOfMonth * 1000).toISOString().split("T")[0] } },
99
- To: { type: "date", date: { start: now.toISOString().split("T")[0] } },
100
- },
101
- }));
102
- }
103
- }
104
- // ─── Run All The Promises In Parallel ────────────────
105
- await Promise.all(promises);
106
- log.info("Total Distributed by Types data pushed to Notion successfully");
107
- }),
108
- // ─── Rewards By Chains ───────────────────────────────────────
109
- CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByChains, firstDayOfMonth).then(async (result) => {
62
+ // ─── Monthly Rewards ─────────────────────────────────────────────────────────
63
+ // ─── By Chains ───────────────────────────────────────────────
64
+ CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByChain, firstDayOfMonth).then(async (result) => {
110
65
  const currentMonthPages = await getPagesOfTheMonth(MONTHLY_REWARDS_BY_CHAINS_DATABASE_ID);
111
66
  const promises = [];
112
67
  for (const chain of Object.keys(result)) {
@@ -143,7 +98,7 @@ const main = async () => {
143
98
  await Promise.all(promises);
144
99
  log.info("Total Distributed by Chains data pushed to Notion successfully");
145
100
  }),
146
- // ─── Rewards By Protocols ────────────────────────────────────
101
+ // ─── By Protocols ────────────────────────────────────────────
147
102
  CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByProtocol, firstDayOfMonth).then(async (result) => {
148
103
  const currentMonthPages = await getPagesOfTheMonth(MONTHLY_REWARDS_BY_PROTOCOLS_DATABASE_ID);
149
104
  const promises = [];
@@ -181,44 +136,50 @@ const main = async () => {
181
136
  await Promise.all(promises);
182
137
  log.info("Total Distributed by Protocols data pushed to Notion successfully");
183
138
  }),
184
- // ─── Daily Rewards ───────────────────────────────────────────
185
- CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByProtocol, today).then(async (result) => {
186
- const pagesOfTheDay = await getPagesOfTheDay(DAILY_REWARDS_BY_PROTOCOLS_DATABASE_ID);
139
+ // ─── By Types ────────────────────────────────────────────────
140
+ CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByType, firstDayOfMonth).then(async (result) => {
141
+ const currentMonthPages = await getPagesOfTheMonth(MONTHLY_REWARDS_BY_TYPES_DATABASE_ID);
187
142
  const promises = [];
188
- for (const protocol of Object.keys(result)) {
189
- const page = pagesOfTheDay.find(page => "properties" in page &&
190
- page.properties.Protocols.title[0].text.content === protocol);
143
+ // ─── Check If Page Already Exists ────────────────────
144
+ for (const type of Object.keys(result)) {
145
+ const page = currentMonthPages.find(page => "properties" in page &&
146
+ page.properties.Types.title[0].text.content === type);
147
+ // ─── If Page Exists, Update It ───────────────
191
148
  if (page) {
192
149
  promises.push(notion.pages.update({
193
150
  page_id: page.id,
194
151
  properties: {
195
152
  Rewards: {
196
153
  type: "number",
197
- number: result[page.properties.Protocols.title[0].text.content],
154
+ number: result[type],
198
155
  },
199
- Date: { type: "date", date: { start: now.toISOString().split("T")[0] } },
156
+ To: { type: "date", date: { start: now.toISOString().split("T")[0] } },
200
157
  },
201
158
  }));
159
+ // ─── Else, Create It ─────────────────
202
160
  }
203
161
  else {
204
162
  promises.push(notion.pages.create({
205
- parent: { type: "database_id", database_id: DAILY_REWARDS_BY_PROTOCOLS_DATABASE_ID },
163
+ parent: { type: "database_id", database_id: MONTHLY_REWARDS_BY_TYPES_DATABASE_ID },
206
164
  properties: {
207
- Protocols: { type: "title", title: [{ type: "text", text: { content: protocol } }] },
208
- Rewards: { type: "number", number: result[protocol] },
209
- Date: {
210
- type: "date",
211
- date: { start: now.toISOString().split("T")[0] },
165
+ Types: {
166
+ type: "title",
167
+ title: [{ type: "text", text: { content: type } }],
212
168
  },
169
+ Rewards: { type: "number", number: result[type] },
170
+ From: { type: "date", date: { start: new Date(firstDayOfMonth * 1000).toISOString().split("T")[0] } },
171
+ To: { type: "date", date: { start: now.toISOString().split("T")[0] } },
213
172
  },
214
173
  }));
215
174
  }
216
175
  }
176
+ // ─── Run All The Promises In Parallel ────────────────
217
177
  await Promise.all(promises);
218
- log.info("Total Distributed by Protocols data pushed to Notion successfully");
178
+ log.info("Total Distributed by Types data pushed to Notion successfully");
219
179
  }),
180
+ // ─── Daily Rewards ───────────────────────────────────────────────────────────
220
181
  // ─── By Chains ───────────────────────────────────────────────
221
- CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByChains, today).then(async (result) => {
182
+ CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByChain, today).then(async (result) => {
222
183
  const pagesOfTheDay = await getPagesOfTheDay(DAILY_REWARDS_BY_CHAINS_DATABASE_ID);
223
184
  const promises = [];
224
185
  for (const chain of Object.keys(result)) {
@@ -254,7 +215,43 @@ const main = async () => {
254
215
  await Promise.all(promises);
255
216
  log.info("Total Distributed by Chains data pushed to Notion successfully");
256
217
  }),
257
- // ─── Daily Rewards By Types ──────────────────────────────────
218
+ // ─── By Protocols ────────────────────────────────────────────
219
+ CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByProtocol, today).then(async (result) => {
220
+ const pagesOfTheDay = await getPagesOfTheDay(DAILY_REWARDS_BY_PROTOCOLS_DATABASE_ID);
221
+ const promises = [];
222
+ for (const protocol of Object.keys(result)) {
223
+ const page = pagesOfTheDay.find(page => "properties" in page &&
224
+ page.properties.Protocols.title[0].text.content === protocol);
225
+ if (page) {
226
+ promises.push(notion.pages.update({
227
+ page_id: page.id,
228
+ properties: {
229
+ Rewards: {
230
+ type: "number",
231
+ number: result[page.properties.Protocols.title[0].text.content],
232
+ },
233
+ Date: { type: "date", date: { start: now.toISOString().split("T")[0] } },
234
+ },
235
+ }));
236
+ }
237
+ else {
238
+ promises.push(notion.pages.create({
239
+ parent: { type: "database_id", database_id: DAILY_REWARDS_BY_PROTOCOLS_DATABASE_ID },
240
+ properties: {
241
+ Protocols: { type: "title", title: [{ type: "text", text: { content: protocol } }] },
242
+ Rewards: { type: "number", number: result[protocol] },
243
+ Date: {
244
+ type: "date",
245
+ date: { start: now.toISOString().split("T")[0] },
246
+ },
247
+ },
248
+ }));
249
+ }
250
+ }
251
+ await Promise.all(promises);
252
+ log.info("Total Distributed by Protocols data pushed to Notion successfully");
253
+ }),
254
+ // ─── By Types ────────────────────────────────────────────────
258
255
  CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByType, today).then(async (result) => {
259
256
  const currentMonthPages = await getPagesOfTheDay(DAILY_REWARDS_BY_TYPES_DATABASE_ID);
260
257
  const promises = [];
@@ -294,7 +291,8 @@ const main = async () => {
294
291
  await Promise.all(promises);
295
292
  log.info("Total Distributed by Types data pushed to Notion successfully");
296
293
  }),
297
- // ─── Campaigns ───────────────────────────────────────────────
294
+ // ─── Monthly New Campaigns ───────────────────────────────────────────────────
295
+ // ─── By Chains ───────────────────────────────────────────────
298
296
  CacheService.set(TTLPresets.DAY_1, CampaignService.countByChains, {
299
297
  createdAfter: new Date(firstDayOfMonth * 1000),
300
298
  }).then(async (result) => {
@@ -337,7 +335,7 @@ const main = async () => {
337
335
  await Promise.all(promises);
338
336
  log.info("Campaigns by Chains data pushed to Notion successfully");
339
337
  }),
340
- // ─── Campaigns By Protocols ──────────────────────────────────
338
+ // ─── By Protocols ────────────────────────────────────────────
341
339
  CacheService.set(TTLPresets.DAY_1, CampaignService.countByProtocols, {
342
340
  createdAfter: new Date(firstDayOfMonth * 1000),
343
341
  }).then(async (result) => {
@@ -376,7 +374,7 @@ const main = async () => {
376
374
  await Promise.all(promises);
377
375
  log.info("Campaigns by Protocols data pushed to Notion successfully");
378
376
  }),
379
- // ─── Campaigns By Types ──────────────────────────────────────
377
+ // ─── By Types ────────────────────────────────────────────────
380
378
  CacheService.set(TTLPresets.DAY_1, CampaignService.countByTypes, {
381
379
  createdAfter: new Date(firstDayOfMonth * 1000),
382
380
  }).then(async (result) => {
@@ -418,7 +416,8 @@ const main = async () => {
418
416
  await Promise.all(promises);
419
417
  log.info("Campaigns by Types data pushed to Notion successfully");
420
418
  }),
421
- // ─── Daily Campaigns ─────────────────────────────────────────
419
+ // ─── Daily New Campaigns ─────────────────────────────────────────────────────
420
+ // ─── By Chains ───────────────────────────────────────────────
422
421
  CacheService.set(TTLPresets.DAY_1, CampaignService.countByChains, {
423
422
  createdAfter: new Date(today * 1000),
424
423
  }).then(async (result) => {
@@ -457,7 +456,7 @@ const main = async () => {
457
456
  await Promise.all(promises);
458
457
  log.info("Campaigns by Chains data pushed to Notion successfully");
459
458
  }),
460
- // ─── Daily New Campaigns By Protocols ────────────────────────
459
+ // ─── By Protocols ────────────────────────────────────────────
461
460
  CacheService.set(TTLPresets.DAY_1, CampaignService.countByProtocols, {
462
461
  createdAfter: new Date(today * 1000),
463
462
  }).then(async (result) => {
@@ -495,7 +494,7 @@ const main = async () => {
495
494
  await Promise.all(promises);
496
495
  log.info("Campaigns by Protocols data pushed to Notion successfully");
497
496
  }),
498
- // ─── Daily Campaigns By Types ────────────────────────────────
497
+ // ─── By Types ────────────────────────────────────────────────
499
498
  CacheService.set(TTLPresets.DAY_1, CampaignService.countByTypes, {
500
499
  createdAfter: new Date(today * 1000),
501
500
  }).then(async (result) => {
@@ -534,10 +533,15 @@ const main = async () => {
534
533
  log.info("Campaigns by Types data pushed to Notion successfully");
535
534
  }),
536
535
  ];
537
- await Promise.all(promises);
536
+ return await Promise.allSettled(promises);
538
537
  };
539
538
  main()
540
- .then(() => process.exit(0))
539
+ .then(results => {
540
+ const rejected = results.find(result => result.status === "rejected");
541
+ if (rejected)
542
+ throw new Error(`One or more promises were rejected: ${JSON.stringify(rejected.reason)}`);
543
+ process.exit(0);
544
+ })
541
545
  .catch(err => {
542
546
  console.error(err);
543
547
  process.exit(1);
@@ -441,6 +441,31 @@ export declare const CampaignController: Elysia<"/campaigns", false, {
441
441
  };
442
442
  };
443
443
  };
444
+ } & {
445
+ ":id": {
446
+ timeseries: {
447
+ get: {
448
+ body: unknown;
449
+ params: {
450
+ id: string;
451
+ };
452
+ query: unknown;
453
+ headers: unknown;
454
+ response: {
455
+ 200: {
456
+ tvlRecords: {
457
+ total: number;
458
+ timestamp: bigint;
459
+ }[];
460
+ aprRecords: {
461
+ timestamp: bigint;
462
+ cumulated: number;
463
+ }[];
464
+ };
465
+ };
466
+ };
467
+ };
468
+ };
444
469
  } & {
445
470
  "campaigns-to-process": {
446
471
  index: {
@@ -3,6 +3,7 @@ import { BackOfficeGuard } from "@/guards/BackOffice.guard";
3
3
  import { AuthorizationHeadersDto, EngineGuard } from "@/guards/Engine.guard";
4
4
  import { CacheService } from "@/modules/v4/cache/cache.service";
5
5
  import { ChainUniqueDto } from "@/modules/v4/chain/chain.model";
6
+ import { log } from "@/utils/logger";
6
7
  import { Campaign } from "@sdk";
7
8
  import Elysia, { t } from "elysia";
8
9
  import { throwOnUnsupportedChainId } from "src/utils/throw";
@@ -84,7 +85,7 @@ export const CampaignController = new Elysia({ prefix: "/campaigns", detail: { t
84
85
  return CampaignService.format(await CampaignService.findUniqueOrThrow({ distributionChain: +distributionChain, campaignId }));
85
86
  }
86
87
  catch (err) {
87
- console.log(err);
88
+ log.error(`Error getting campaign: ${params.id}`, err);
88
89
  throw new NotFoundError("Campaign not found.");
89
90
  }
90
91
  }, {
@@ -94,6 +95,12 @@ export const CampaignController = new Elysia({ prefix: "/campaigns", detail: { t
94
95
  description: `**Retrieve A Campaign**
95
96
  <p>This endpoint enables you to retrieve a campaign by providing its unique identifier.</p>`,
96
97
  },
98
+ })
99
+ .get("/:id/timeseries", async ({ params }) => {
100
+ if (!params.id.includes("-"))
101
+ return await CampaignService.getTimeSeries(params.id);
102
+ const [distributionChain, campaignId] = params.id.split("-");
103
+ return await CampaignService.getTimeSeries({ distributionChain: +distributionChain, campaignId });
97
104
  })
98
105
  .group("/campaigns-to-process", app => {
99
106
  return (app
@@ -775,4 +775,20 @@ export declare abstract class CampaignRepository {
775
775
  manualOverrides: import("@db/api").$Enums.CampaignManualOverride[];
776
776
  createdAt: Date;
777
777
  }>;
778
+ static getTvlRecords(campaign: {
779
+ opportunityId: string;
780
+ startTimestamp: bigint;
781
+ endTimestamp: bigint;
782
+ }): Promise<{
783
+ total: number;
784
+ timestamp: bigint;
785
+ }[]>;
786
+ static getAprRecords(campaign: {
787
+ opportunityId: string;
788
+ startTimestamp: bigint;
789
+ endTimestamp: bigint;
790
+ }): Promise<{
791
+ timestamp: bigint;
792
+ cumulated: number;
793
+ }[]>;
778
794
  }
@@ -449,4 +449,22 @@ export class CampaignRepository {
449
449
  };
450
450
  return await apiDbClient.campaign.update({ where: { id }, data: updateData });
451
451
  }
452
+ static async getTvlRecords(campaign) {
453
+ return await apiDbClient.tVLRecord.findMany({
454
+ where: {
455
+ opportunityId: campaign.opportunityId,
456
+ timestamp: { gte: campaign.startTimestamp, lte: campaign.endTimestamp },
457
+ },
458
+ select: { timestamp: true, total: true },
459
+ });
460
+ }
461
+ static async getAprRecords(campaign) {
462
+ return await apiDbClient.aprRecord.findMany({
463
+ where: {
464
+ opportunityId: campaign.opportunityId,
465
+ timestamp: { gte: campaign.startTimestamp, lte: campaign.endTimestamp },
466
+ },
467
+ select: { timestamp: true, cumulated: true },
468
+ });
469
+ }
452
470
  }
@@ -914,4 +914,14 @@ export declare abstract class CampaignService {
914
914
  endTimestamp: any;
915
915
  params: string;
916
916
  };
917
+ static getTimeSeries(campaignId: CampaignUnique | string): Promise<{
918
+ tvlRecords: {
919
+ total: number;
920
+ timestamp: bigint;
921
+ }[];
922
+ aprRecords: {
923
+ timestamp: bigint;
924
+ cumulated: number;
925
+ }[];
926
+ }>;
917
927
  }
@@ -384,4 +384,11 @@ export class CampaignService {
384
384
  params: JSON.stringify(fakeCampaign.campaignParameters),
385
385
  };
386
386
  }
387
+ static async getTimeSeries(campaignId) {
388
+ const id = typeof campaignId === "string" ? campaignId : CampaignService.hashId(campaignId);
389
+ const campaign = await CampaignRepository.findUniqueOrThrow(id, false);
390
+ const tvlRecords = await CampaignRepository.getTvlRecords(campaign);
391
+ const aprRecords = await CampaignRepository.getAprRecords(campaign);
392
+ return { tvlRecords, aprRecords };
393
+ }
387
394
  }