@merkl/api 0.20.91 → 0.20.93
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/src/cache/redis.js +1 -0
- package/dist/src/engine/campaignTVL/factory.js +2 -0
- package/dist/src/engine/{dynamicData → campaignTVL}/implementations/Ambiant.d.ts +3 -3
- package/dist/src/engine/campaignTVL/implementations/Ambiant.js +178 -0
- package/dist/src/engine/dynamicData/factory.js +1 -2
- package/dist/src/jobs/update-analytics.js +123 -99
- package/dist/src/modules/v4/router.js +8 -1
- package/dist/tsconfig.package.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/dist/src/engine/dynamicData/implementations/Ambiant.js +0 -232
- package/dist/src/engine/dynamicData/utils/fetchAmbientInfo.d.ts +0 -12
- package/dist/src/engine/dynamicData/utils/fetchAmbientInfo.js +0 -59
package/dist/src/cache/redis.js
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
import { Campaign } from "@sdk";
|
2
2
|
import { AjnaCampaignTVLBuilder } from "./implementations/Ajna";
|
3
|
+
import { AmbiantCampaignTVLBuilder } from "./implementations/Ambiant";
|
3
4
|
// @dev Casts are made to enforce type safety
|
4
5
|
// @dev A type error must be thrown if a new campaign type is added and the corresponding builder is not implemented
|
5
6
|
const map = {
|
6
7
|
[Campaign.AJNA]: new AjnaCampaignTVLBuilder(),
|
8
|
+
[Campaign.AMBIENTPROCESSOR]: new AmbiantCampaignTVLBuilder(),
|
7
9
|
};
|
8
10
|
export const campaignDynamicDataBuilderFactory = (campaignType) => {
|
9
11
|
if (!map[campaignType]) {
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { type Campaign, type CampaignParameters, type MerklChainId } from "@sdk";
|
2
|
-
import type {
|
2
|
+
import type { CampaignTVLBuilder, TVLData } from "../interface";
|
3
3
|
type campaignType = Campaign.AMBIENTPROCESSOR;
|
4
|
-
export declare class
|
5
|
-
build(chainId: MerklChainId, campaigns: CampaignParameters<campaignType>[]): Promise<
|
4
|
+
export declare class AmbiantCampaignTVLBuilder implements CampaignTVLBuilder<campaignType> {
|
5
|
+
build(chainId: MerklChainId, campaigns: CampaignParameters<campaignType>[]): Promise<TVLData>;
|
6
6
|
}
|
7
7
|
export {};
|
@@ -0,0 +1,178 @@
|
|
1
|
+
import { TokenService } from "@/modules/v4/token/token.service";
|
2
|
+
import { TvlType } from "@db/api";
|
3
|
+
import { AmbientAddresses, AmbientLens, BN2Number, ChainInteractionService, NETWORK_LABELS, subgraphAmbientEndpoints, withRetry, } from "@sdk";
|
4
|
+
import request, { gql } from "graphql-request";
|
5
|
+
import { log } from "../../../utils/logger";
|
6
|
+
var AmbiantPositionType;
|
7
|
+
(function (AmbiantPositionType) {
|
8
|
+
AmbiantPositionType["Concentrated"] = "concentrated";
|
9
|
+
AmbiantPositionType["Ambient"] = "ambient";
|
10
|
+
AmbiantPositionType["Knockout"] = "knockout";
|
11
|
+
})(AmbiantPositionType || (AmbiantPositionType = {}));
|
12
|
+
function encodeCall(chainId, holder) {
|
13
|
+
if (holder.positionType === AmbiantPositionType.Concentrated) {
|
14
|
+
return [
|
15
|
+
{
|
16
|
+
allowFailure: true,
|
17
|
+
callData: AmbientLens.encodeFunctionData("queryRangeTokens", [
|
18
|
+
holder.owner,
|
19
|
+
holder.base,
|
20
|
+
holder.quote,
|
21
|
+
holder.poolIdx,
|
22
|
+
holder.lowerTick,
|
23
|
+
holder.upperTick,
|
24
|
+
]),
|
25
|
+
target: AmbientAddresses[chainId].CrocQuery,
|
26
|
+
},
|
27
|
+
];
|
28
|
+
}
|
29
|
+
return [
|
30
|
+
{
|
31
|
+
allowFailure: true,
|
32
|
+
callData: AmbientLens.encodeFunctionData("queryAmbientTokens", [
|
33
|
+
holder.owner,
|
34
|
+
holder.base,
|
35
|
+
holder.quote,
|
36
|
+
holder.poolIdx,
|
37
|
+
]),
|
38
|
+
target: AmbientAddresses[chainId].CrocQuery,
|
39
|
+
},
|
40
|
+
];
|
41
|
+
}
|
42
|
+
async function decodeCall(result, holder) {
|
43
|
+
let amount0 = BigInt(0n);
|
44
|
+
let amount1 = BigInt(0n);
|
45
|
+
if (holder.positionType === AmbiantPositionType.Concentrated) {
|
46
|
+
const resTok = AmbientLens.decodeFunctionResult("queryRangeTokens", result);
|
47
|
+
amount0 = BigInt(resTok[1]);
|
48
|
+
amount1 = BigInt(resTok[2]);
|
49
|
+
}
|
50
|
+
if (holder.positionType === AmbiantPositionType.Ambient) {
|
51
|
+
const resTok = AmbientLens.decodeFunctionResult("queryAmbientTokens", result);
|
52
|
+
amount0 = BigInt(resTok[1]);
|
53
|
+
amount1 = BigInt(resTok[2]);
|
54
|
+
}
|
55
|
+
return { amount0, amount1 };
|
56
|
+
}
|
57
|
+
async function poolFromCampaign(campaign) {
|
58
|
+
return {
|
59
|
+
id: campaign.campaignParameters.poolId,
|
60
|
+
mainParameter: campaign.mainParameter, // main parameter containes info of poolAddress + AMM (in case its a priority AMM)
|
61
|
+
baseToken: campaign.campaignParameters.baseToken,
|
62
|
+
quoteToken: campaign.campaignParameters.quoteToken,
|
63
|
+
poolIdx: campaign.campaignParameters.poolIdx,
|
64
|
+
potentialHolders: await fetchAmbientPotentialPositions(campaign.campaignParameters.poolId, campaign.computeChainId),
|
65
|
+
};
|
66
|
+
}
|
67
|
+
const BATCH_NUMBER = 1000;
|
68
|
+
const holdersQuery = gql `
|
69
|
+
query LiquidityChanges($poolId: String!, $minId: String!) {
|
70
|
+
liquidityChanges(
|
71
|
+
where: { pool_: { id: $poolId }, id_gt: $minId , positionType_not: "knockout"},
|
72
|
+
first: ${BATCH_NUMBER},
|
73
|
+
orderBy: pool__id
|
74
|
+
) {
|
75
|
+
id
|
76
|
+
user
|
77
|
+
positionType
|
78
|
+
bidTick
|
79
|
+
askTick
|
80
|
+
pool {
|
81
|
+
base
|
82
|
+
quote
|
83
|
+
poolIdx
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
`;
|
88
|
+
async function fetchAmbientPotentialPositions(poolId, chainId) {
|
89
|
+
let isFullyFetched = false;
|
90
|
+
let holders = [];
|
91
|
+
let minId = "";
|
92
|
+
while (!isFullyFetched) {
|
93
|
+
const data = await withRetry(request, [
|
94
|
+
subgraphAmbientEndpoints[chainId],
|
95
|
+
holdersQuery,
|
96
|
+
{
|
97
|
+
poolId: poolId,
|
98
|
+
minId: minId,
|
99
|
+
},
|
100
|
+
]);
|
101
|
+
const fetchedHolders = data.liquidityChanges?.map(entry => {
|
102
|
+
return {
|
103
|
+
owner: entry.user,
|
104
|
+
base: entry.pool.base,
|
105
|
+
quote: entry.pool.quote,
|
106
|
+
poolIdx: Number(entry.pool.poolIdx),
|
107
|
+
lowerTick: Number(entry.bidTick),
|
108
|
+
upperTick: Number(entry.askTick),
|
109
|
+
positionType: entry.positionType,
|
110
|
+
};
|
111
|
+
});
|
112
|
+
if (fetchedHolders.length < BATCH_NUMBER) {
|
113
|
+
isFullyFetched = true;
|
114
|
+
}
|
115
|
+
else {
|
116
|
+
minId = data.liquidityChanges[fetchedHolders.length - 1].id;
|
117
|
+
}
|
118
|
+
holders = holders.concat(fetchedHolders);
|
119
|
+
}
|
120
|
+
// Only keep unique positions
|
121
|
+
holders = Array.from(new Set(holders.map(h => JSON.stringify(h)))).map(h => JSON.parse(h));
|
122
|
+
return holders;
|
123
|
+
}
|
124
|
+
export class AmbiantCampaignTVLBuilder {
|
125
|
+
async build(chainId, campaigns) {
|
126
|
+
const tvls = [];
|
127
|
+
let calls = [];
|
128
|
+
for (const campaign of campaigns) {
|
129
|
+
const pool = await poolFromCampaign(campaign);
|
130
|
+
calls = calls.concat(...pool.potentialHolders.map(holder => encodeCall(chainId, holder)));
|
131
|
+
}
|
132
|
+
const result = await ChainInteractionService(chainId).fetchState(calls);
|
133
|
+
let i = 0;
|
134
|
+
for (const campaign of campaigns) {
|
135
|
+
const pool = await poolFromCampaign(campaign);
|
136
|
+
let baseTokenBalance = 0n;
|
137
|
+
let quoteTokenBalance = 0n;
|
138
|
+
const prevI = i;
|
139
|
+
try {
|
140
|
+
for (let index = 0; index < pool.potentialHolders.length; index++) {
|
141
|
+
const res = await decodeCall(result[i++].returnData, pool.potentialHolders[index]);
|
142
|
+
baseTokenBalance += BigInt(res.amount0);
|
143
|
+
quoteTokenBalance += BigInt(res.amount1);
|
144
|
+
}
|
145
|
+
}
|
146
|
+
catch {
|
147
|
+
log.warn(`merklDynamic data - failed to decode state of pool ${pool.id} on ${NETWORK_LABELS[chainId]}`);
|
148
|
+
i = prevI + pool.potentialHolders.length;
|
149
|
+
}
|
150
|
+
const baseTokenId = TokenService.hashId({
|
151
|
+
chainId,
|
152
|
+
address: pool.baseToken,
|
153
|
+
});
|
154
|
+
const quoteTokenId = TokenService.hashId({
|
155
|
+
chainId,
|
156
|
+
address: pool.quoteToken,
|
157
|
+
});
|
158
|
+
tvls.push({
|
159
|
+
campaign,
|
160
|
+
tvl: (await TokenService.getValueByTokenId(baseTokenId, baseTokenBalance)) +
|
161
|
+
(await TokenService.getValueByTokenId(quoteTokenId, quoteTokenBalance)),
|
162
|
+
tvlBreakdown: [
|
163
|
+
{
|
164
|
+
identifier: baseTokenId,
|
165
|
+
type: TvlType.TOKEN,
|
166
|
+
value: BN2Number(baseTokenBalance, campaign.campaignParameters.decimalsBaseToken),
|
167
|
+
},
|
168
|
+
{
|
169
|
+
identifier: quoteTokenId,
|
170
|
+
type: TvlType.TOKEN,
|
171
|
+
value: BN2Number(quoteTokenBalance, campaign.campaignParameters.decimalsQuoteToken),
|
172
|
+
},
|
173
|
+
],
|
174
|
+
});
|
175
|
+
}
|
176
|
+
return tvls;
|
177
|
+
}
|
178
|
+
}
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import { Campaign } from "@sdk";
|
2
2
|
import { AjnaDynamicData } from "./implementations/Ajna";
|
3
|
-
import { AmbiantDynamicData } from "./implementations/Ambiant";
|
4
3
|
import { BadgerDynamicData } from "./implementations/Badger";
|
5
4
|
import { ClammDynamicData } from "./implementations/Clamm";
|
6
5
|
import { CompoundDynamicData } from "./implementations/Compound";
|
@@ -26,7 +25,7 @@ const map = {
|
|
26
25
|
[Campaign.INVALID]: new DefaultDynamicData(),
|
27
26
|
[Campaign.JSON_AIRDROP]: new DefaultDynamicData(),
|
28
27
|
[Campaign.AJNA]: new AjnaDynamicData(),
|
29
|
-
[Campaign.AMBIENTPROCESSOR]: new
|
28
|
+
[Campaign.AMBIENTPROCESSOR]: new DefaultDynamicData(),
|
30
29
|
[Campaign.BADGER]: new BadgerDynamicData(),
|
31
30
|
[Campaign.CLAMM]: new ClammDynamicData(),
|
32
31
|
[Campaign.COMPOUND]: new CompoundDynamicData(),
|
@@ -13,7 +13,7 @@ const CAMPAIGNS_BY_CHAINS_DATABASE_ID = "1cbcfed0d48c8001b1ccf5c0900669ea";
|
|
13
13
|
const CAMPAIGNS_BY_PROTOCOLS_DATABASE_ID = "1cecfed0d48c8066b016f580e54a6b33";
|
14
14
|
const CAMPAIGNS_BY_TYPES_DATABASE_ID = "1cecfed0d48c80dcb6bccf3ac3889b5b";
|
15
15
|
const getCurrentMonthPages = async (databaseId, firstDayOfMonth) => {
|
16
|
-
const
|
16
|
+
const currentMonthPages = await notion.databases.query({
|
17
17
|
database_id: databaseId,
|
18
18
|
filter: {
|
19
19
|
property: "From",
|
@@ -22,57 +22,82 @@ const getCurrentMonthPages = async (databaseId, firstDayOfMonth) => {
|
|
22
22
|
},
|
23
23
|
},
|
24
24
|
});
|
25
|
-
return
|
25
|
+
return currentMonthPages.results;
|
26
26
|
};
|
27
27
|
const main = async () => {
|
28
28
|
const chains = (await ChainService.findMany({})).reduce((prev, curr) => {
|
29
29
|
return Object.assign(prev, { [curr.id]: curr.name });
|
30
30
|
}, {});
|
31
31
|
const today = new Date();
|
32
|
-
const firstDayOfMonth = new Date(today.
|
32
|
+
const firstDayOfMonth = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), 1, // Day 1 of the month
|
33
|
+
0, // 0 hours
|
34
|
+
0, // 0 minutes
|
35
|
+
0, // 0 seconds
|
36
|
+
0 // 0 milliseconds
|
37
|
+
)).getTime() / 1000;
|
33
38
|
const promises = [
|
39
|
+
// ─── Rewards By Types ────────────────────────────────────────
|
34
40
|
CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByType, firstDayOfMonth).then(async (result) => {
|
35
|
-
const
|
41
|
+
const currentMonthPages = await getCurrentMonthPages(REWARDS_BY_TYPES_DATABASE_ID, firstDayOfMonth);
|
36
42
|
const promises = [];
|
37
|
-
|
38
|
-
|
43
|
+
// ─── Check If Page Already Exists ────────────────────
|
44
|
+
for (const type of Object.keys(result)) {
|
45
|
+
const page = currentMonthPages.find(page => "properties" in page &&
|
46
|
+
page.properties.Types.title[0].text.content === type);
|
47
|
+
// ─── If Page Exists, Update It ───────────────
|
48
|
+
if (page) {
|
49
|
+
promises.push(notion.pages.update({
|
50
|
+
page_id: page.id,
|
51
|
+
properties: {
|
52
|
+
Rewards: {
|
53
|
+
type: "number",
|
54
|
+
number: result[type],
|
55
|
+
},
|
56
|
+
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
57
|
+
},
|
58
|
+
}));
|
59
|
+
// ─── Else, Create It ─────────────────
|
60
|
+
}
|
61
|
+
else {
|
39
62
|
promises.push(notion.pages.create({
|
40
63
|
parent: { type: "database_id", database_id: REWARDS_BY_TYPES_DATABASE_ID },
|
41
64
|
properties: {
|
42
|
-
|
65
|
+
Types: {
|
43
66
|
type: "title",
|
44
67
|
title: [{ type: "text", text: { content: type } }],
|
45
68
|
},
|
46
|
-
Rewards: { type: "number", number:
|
69
|
+
Rewards: { type: "number", number: result[type] },
|
47
70
|
From: { type: "date", date: { start: new Date(firstDayOfMonth * 1000).toISOString().split("T")[0] } },
|
48
71
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
49
72
|
},
|
50
73
|
}));
|
51
74
|
}
|
52
75
|
}
|
53
|
-
|
54
|
-
|
76
|
+
// ─── Run All The Promises In Parallel ────────────────
|
77
|
+
await Promise.all(promises);
|
78
|
+
log.info("Total Distributed by Types data pushed to Notion successfully");
|
79
|
+
}),
|
80
|
+
// ─── Rewards By Chains ───────────────────────────────────────
|
81
|
+
CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByChains, firstDayOfMonth).then(async (result) => {
|
82
|
+
const currentMonthPages = await getCurrentMonthPages(REWARDS_BY_CHAINS_DATABASE_ID, firstDayOfMonth);
|
83
|
+
const promises = [];
|
84
|
+
for (const chain of Object.keys(result)) {
|
85
|
+
const page = currentMonthPages.find(page => "properties" in page &&
|
86
|
+
page.properties.Chains.title[0].text.content ===
|
87
|
+
chains[chain]);
|
88
|
+
if (page) {
|
55
89
|
promises.push(notion.pages.update({
|
56
90
|
page_id: page.id,
|
57
91
|
properties: {
|
58
92
|
Rewards: {
|
59
93
|
type: "number",
|
60
|
-
number: result[
|
61
|
-
.title[0].text.content],
|
94
|
+
number: result[chain],
|
62
95
|
},
|
63
96
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
64
97
|
},
|
65
98
|
}));
|
66
99
|
}
|
67
|
-
|
68
|
-
log.info("Total Distributed by Type data pushed to Notion successfully");
|
69
|
-
}
|
70
|
-
}),
|
71
|
-
CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByChains, firstDayOfMonth).then(async (result) => {
|
72
|
-
const pagesToModify = await getCurrentMonthPages(REWARDS_BY_CHAINS_DATABASE_ID, firstDayOfMonth);
|
73
|
-
const promises = [];
|
74
|
-
if (today.getDate() === 1 || pagesToModify.length === 0) {
|
75
|
-
for (const [chain, monthlyTotalRewards] of Object.entries(result)) {
|
100
|
+
else {
|
76
101
|
promises.push(notion.pages.create({
|
77
102
|
parent: { type: "database_id", database_id: REWARDS_BY_CHAINS_DATABASE_ID },
|
78
103
|
properties: {
|
@@ -80,54 +105,45 @@ const main = async () => {
|
|
80
105
|
type: "title",
|
81
106
|
title: [{ type: "text", text: { content: chains[chain] } }],
|
82
107
|
},
|
83
|
-
Rewards: { type: "number", number:
|
108
|
+
Rewards: { type: "number", number: result[chain] },
|
84
109
|
From: { type: "date", date: { start: new Date(firstDayOfMonth * 1000).toISOString().split("T")[0] } },
|
85
110
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
86
111
|
},
|
87
112
|
}));
|
88
113
|
}
|
89
114
|
}
|
90
|
-
|
91
|
-
|
115
|
+
await Promise.all(promises);
|
116
|
+
log.info("Total Distributed by Chains data pushed to Notion successfully");
|
117
|
+
}),
|
118
|
+
// ─── Rewards By Protocols ────────────────────────────────────
|
119
|
+
CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByProtocol, firstDayOfMonth).then(async (result) => {
|
120
|
+
const currentMonthPages = await getCurrentMonthPages(REWARDS_BY_PROTOCOLS_DATABASE_ID, firstDayOfMonth);
|
121
|
+
const promises = [];
|
122
|
+
for (const protocol of Object.keys(result)) {
|
123
|
+
const page = currentMonthPages.find(page => "properties" in page &&
|
124
|
+
page.properties.Protocols.title[0].text.content ===
|
125
|
+
protocol);
|
126
|
+
if (page) {
|
92
127
|
promises.push(notion.pages.update({
|
93
128
|
page_id: page.id,
|
94
129
|
properties: {
|
95
130
|
Rewards: {
|
96
131
|
type: "number",
|
97
|
-
number: result[
|
132
|
+
number: result[page.properties.Protocols.title[0].text.content],
|
98
133
|
},
|
99
134
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
100
135
|
},
|
101
136
|
}));
|
102
137
|
}
|
103
|
-
|
104
|
-
log.info("Total Distributed by Chains data pushed to Notion successfully");
|
105
|
-
}
|
106
|
-
}),
|
107
|
-
CacheService.set(TTLPresets.DAY_1, RewardService.getTotalDistributedByProtocol, firstDayOfMonth).then(async (result) => {
|
108
|
-
const pagesToModify = await getCurrentMonthPages(REWARDS_BY_PROTOCOLS_DATABASE_ID, firstDayOfMonth);
|
109
|
-
const promises = [];
|
110
|
-
if (today.getDate() === 1 || pagesToModify.length === 0) {
|
111
|
-
for (const [protocol, monthlyTotalRewards] of Object.entries(result)) {
|
138
|
+
else {
|
112
139
|
promises.push(notion.pages.create({
|
113
140
|
parent: { type: "database_id", database_id: REWARDS_BY_PROTOCOLS_DATABASE_ID },
|
114
141
|
properties: {
|
115
142
|
Protocols: { type: "title", title: [{ type: "text", text: { content: protocol } }] },
|
116
|
-
Rewards: { type: "number", number:
|
117
|
-
From: {
|
118
|
-
|
119
|
-
|
120
|
-
}));
|
121
|
-
}
|
122
|
-
}
|
123
|
-
else {
|
124
|
-
for (const page of pagesToModify) {
|
125
|
-
promises.push(notion.pages.update({
|
126
|
-
page_id: page.id,
|
127
|
-
properties: {
|
128
|
-
Rewards: {
|
129
|
-
type: "number",
|
130
|
-
number: result[page.properties.Protocols.title[0].text.content],
|
143
|
+
Rewards: { type: "number", number: result[protocol] },
|
144
|
+
From: {
|
145
|
+
type: "date",
|
146
|
+
date: { start: new Date(firstDayOfMonth * 1000).toISOString().split("T")[0] },
|
131
147
|
},
|
132
148
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
133
149
|
},
|
@@ -141,10 +157,25 @@ const main = async () => {
|
|
141
157
|
CacheService.set(TTLPresets.DAY_1, CampaignService.countByChains, {
|
142
158
|
createdAfter: new Date(firstDayOfMonth * 1000),
|
143
159
|
}).then(async (result) => {
|
144
|
-
const
|
160
|
+
const currentMonthPages = await getCurrentMonthPages(CAMPAIGNS_BY_CHAINS_DATABASE_ID, firstDayOfMonth);
|
145
161
|
const promises = [];
|
146
|
-
|
147
|
-
|
162
|
+
for (const chain of Object.keys(result)) {
|
163
|
+
const page = currentMonthPages.find(page => "properties" in page &&
|
164
|
+
page.properties.Chains.title[0].text.content ===
|
165
|
+
chains[chain]);
|
166
|
+
if (page) {
|
167
|
+
promises.push(notion.pages.update({
|
168
|
+
page_id: page.id,
|
169
|
+
properties: {
|
170
|
+
Campaigns: {
|
171
|
+
type: "number",
|
172
|
+
number: result[Object.keys(chains).find(key => page.properties.Chains.title[0].text.content === chains[key])],
|
173
|
+
},
|
174
|
+
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
175
|
+
},
|
176
|
+
}));
|
177
|
+
}
|
178
|
+
else {
|
148
179
|
promises.push(notion.pages.create({
|
149
180
|
parent: { type: "database_id", database_id: CAMPAIGNS_BY_CHAINS_DATABASE_ID },
|
150
181
|
properties: {
|
@@ -152,37 +183,41 @@ const main = async () => {
|
|
152
183
|
type: "title",
|
153
184
|
title: [{ type: "text", text: { content: chains[chain] } }],
|
154
185
|
},
|
155
|
-
Campaigns: { type: "number", number:
|
156
|
-
From: {
|
186
|
+
Campaigns: { type: "number", number: result[chain] },
|
187
|
+
From: {
|
188
|
+
type: "date",
|
189
|
+
date: { start: new Date(firstDayOfMonth * 1000).toISOString().split("T")[0] },
|
190
|
+
},
|
157
191
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
158
192
|
},
|
159
193
|
}));
|
160
194
|
}
|
161
195
|
}
|
162
|
-
|
163
|
-
|
196
|
+
await Promise.all(promises);
|
197
|
+
log.info("Campaigns by Chains data pushed to Notion successfully");
|
198
|
+
}),
|
199
|
+
// ─── Campaigns By Protocols ──────────────────────────────────
|
200
|
+
CacheService.set(TTLPresets.DAY_1, CampaignService.countByProtocols, {
|
201
|
+
createdAfter: new Date(firstDayOfMonth * 1000),
|
202
|
+
}).then(async (result) => {
|
203
|
+
const currentMonthPages = await getCurrentMonthPages(CAMPAIGNS_BY_PROTOCOLS_DATABASE_ID, firstDayOfMonth);
|
204
|
+
const promises = [];
|
205
|
+
for (const protocol of Object.keys(result)) {
|
206
|
+
const page = currentMonthPages.find(page => "properties" in page &&
|
207
|
+
page.properties.Protocols.title[0].text.content === protocol);
|
208
|
+
if (page) {
|
164
209
|
promises.push(notion.pages.update({
|
165
210
|
page_id: page.id,
|
166
211
|
properties: {
|
167
212
|
Campaigns: {
|
168
213
|
type: "number",
|
169
|
-
number: result[
|
214
|
+
number: result[page.properties.Protocols.title[0].text.content],
|
170
215
|
},
|
171
216
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
172
217
|
},
|
173
218
|
}));
|
174
219
|
}
|
175
|
-
|
176
|
-
await Promise.all(promises);
|
177
|
-
log.info("Campaigns by Chains data pushed to Notion successfully");
|
178
|
-
}),
|
179
|
-
CacheService.set(TTLPresets.DAY_1, CampaignService.countByProtocols, {
|
180
|
-
createdAfter: new Date(firstDayOfMonth * 1000),
|
181
|
-
}).then(async (result) => {
|
182
|
-
const pagesToModify = await getCurrentMonthPages(CAMPAIGNS_BY_PROTOCOLS_DATABASE_ID, firstDayOfMonth);
|
183
|
-
const promises = [];
|
184
|
-
if (today.getDate() === 1 || pagesToModify.length === 0) {
|
185
|
-
for (const [protocol, monthlyTotalCampaigns] of Object.entries(result)) {
|
220
|
+
else {
|
186
221
|
promises.push(notion.pages.create({
|
187
222
|
parent: { type: "database_id", database_id: CAMPAIGNS_BY_PROTOCOLS_DATABASE_ID },
|
188
223
|
properties: {
|
@@ -190,37 +225,38 @@ const main = async () => {
|
|
190
225
|
type: "title",
|
191
226
|
title: [{ type: "text", text: { content: protocol } }],
|
192
227
|
},
|
193
|
-
Campaigns: { type: "number", number:
|
228
|
+
Campaigns: { type: "number", number: result[protocol] },
|
194
229
|
From: { type: "date", date: { start: new Date(firstDayOfMonth * 1000).toISOString().split("T")[0] } },
|
195
230
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
196
231
|
},
|
197
232
|
}));
|
198
233
|
}
|
199
234
|
}
|
200
|
-
|
201
|
-
|
235
|
+
await Promise.all(promises);
|
236
|
+
log.info("Campaigns by Protocols data pushed to Notion successfully");
|
237
|
+
}),
|
238
|
+
// ─── Campaigns By Types ──────────────────────────────────────
|
239
|
+
CacheService.set(TTLPresets.DAY_1, CampaignService.countByTypes, {
|
240
|
+
createdAfter: new Date(firstDayOfMonth * 1000),
|
241
|
+
}).then(async (result) => {
|
242
|
+
const currentMonthPages = await getCurrentMonthPages(CAMPAIGNS_BY_TYPES_DATABASE_ID, firstDayOfMonth);
|
243
|
+
const promises = [];
|
244
|
+
for (const type of Object.keys(result)) {
|
245
|
+
const page = currentMonthPages.find(page => "properties" in page &&
|
246
|
+
page.properties.Types.title[0].text.content === type);
|
247
|
+
if (page) {
|
202
248
|
promises.push(notion.pages.update({
|
203
249
|
page_id: page.id,
|
204
250
|
properties: {
|
205
251
|
Campaigns: {
|
206
252
|
type: "number",
|
207
|
-
number: result[page.properties.
|
253
|
+
number: result[page.properties.Types.title[0].text.content],
|
208
254
|
},
|
209
255
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
210
256
|
},
|
211
257
|
}));
|
212
258
|
}
|
213
|
-
|
214
|
-
await Promise.all(promises);
|
215
|
-
log.info("Campaigns by Protocols data pushed to Notion successfully");
|
216
|
-
}),
|
217
|
-
CacheService.set(TTLPresets.DAY_1, CampaignService.countByTypes, {
|
218
|
-
createdAfter: new Date(firstDayOfMonth * 1000),
|
219
|
-
}).then(async (result) => {
|
220
|
-
const pagesToModify = await getCurrentMonthPages(CAMPAIGNS_BY_TYPES_DATABASE_ID, firstDayOfMonth);
|
221
|
-
const promises = [];
|
222
|
-
if (today.getDate() === 1 || pagesToModify.length === 0) {
|
223
|
-
for (const [type, monthlyTotalCampaigns] of Object.entries(result)) {
|
259
|
+
else {
|
224
260
|
promises.push(notion.pages.create({
|
225
261
|
parent: { type: "database_id", database_id: CAMPAIGNS_BY_TYPES_DATABASE_ID },
|
226
262
|
properties: {
|
@@ -228,22 +264,10 @@ const main = async () => {
|
|
228
264
|
type: "title",
|
229
265
|
title: [{ type: "text", text: { content: type } }],
|
230
266
|
},
|
231
|
-
Campaigns: { type: "number", number:
|
232
|
-
From: {
|
233
|
-
|
234
|
-
|
235
|
-
}));
|
236
|
-
}
|
237
|
-
}
|
238
|
-
else {
|
239
|
-
for (const page of pagesToModify) {
|
240
|
-
promises.push(notion.pages.update({
|
241
|
-
page_id: page.id,
|
242
|
-
properties: {
|
243
|
-
Campaigns: {
|
244
|
-
type: "number",
|
245
|
-
number: result[page.properties.Types
|
246
|
-
.title[0].text.content],
|
267
|
+
Campaigns: { type: "number", number: result[type] },
|
268
|
+
From: {
|
269
|
+
type: "date",
|
270
|
+
date: { start: new Date(firstDayOfMonth * 1000).toISOString().split("T")[0] },
|
247
271
|
},
|
248
272
|
To: { type: "date", date: { start: today.toISOString().split("T")[0] } },
|
249
273
|
},
|
@@ -27,6 +27,7 @@ import bigintToString from "@/utils/bigintToString";
|
|
27
27
|
import { opentelemetry } from "@elysiajs/opentelemetry";
|
28
28
|
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
|
29
29
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
30
|
+
import { RedisInstrumentation } from "@opentelemetry/instrumentation-redis-4";
|
30
31
|
import { AlwaysOffSampler, BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
|
31
32
|
import { PrismaInstrumentation } from "@prisma/instrumentation";
|
32
33
|
import Elysia from "elysia";
|
@@ -47,9 +48,15 @@ export const v4 = new Elysia({ tags: ["v4"], prefix: "/v4" })
|
|
47
48
|
instrumentations: [
|
48
49
|
getNodeAutoInstrumentations({
|
49
50
|
"@opentelemetry/instrumentation-redis": { enabled: false },
|
50
|
-
"@opentelemetry/instrumentation-redis-4": { enabled: true },
|
51
51
|
}),
|
52
52
|
new PrismaInstrumentation(),
|
53
|
+
new RedisInstrumentation({
|
54
|
+
enabled: true,
|
55
|
+
requireParentSpan: false,
|
56
|
+
dbStatementSerializer: (cmdName, cmdArgs) => {
|
57
|
+
return [cmdName, ...cmdArgs].join(" ");
|
58
|
+
},
|
59
|
+
}),
|
53
60
|
],
|
54
61
|
serviceName: "merkl-api",
|
55
62
|
}))
|