@merkl/api 0.20.19 → 0.20.21
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/eden/index.d.ts +60 -0
- package/dist/src/engine/dynamicData/implementations/EventBased.js +0 -2
- package/dist/src/engine/dynamicData/implementations/UniswapV4.js +4 -7
- package/dist/src/engine/dynamicData/utils/getEulerV2Vaults.js +3 -3
- package/dist/src/engine/opportunityMetadata/implementations/Morpho.js +6 -1
- package/dist/src/index.d.ts +16 -0
- package/dist/src/jobs/update-euler-vaults.js +2 -0
- package/dist/src/modules/v4/campaign/campaign.controller.d.ts +16 -0
- package/dist/src/modules/v4/campaign/campaign.controller.js +14 -1
- package/dist/src/modules/v4/campaign/campaign.model.d.ts +1 -0
- package/dist/src/modules/v4/campaign/campaign.model.js +1 -0
- package/dist/src/modules/v4/dynamicData/dynamicData.service.d.ts +2 -3
- package/dist/src/modules/v4/dynamicData/dynamicData.service.js +22 -24
- package/dist/src/modules/v4/router.d.ts +16 -0
- package/dist/tsconfig.package.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/src/eden/index.d.ts
CHANGED
@@ -1195,6 +1195,17 @@ declare const eden: {
|
|
1195
1195
|
}>>;
|
1196
1196
|
};
|
1197
1197
|
}) & {
|
1198
|
+
"dynamic-data": {
|
1199
|
+
post: (body: string[], options: {
|
1200
|
+
headers: {
|
1201
|
+
authorization: string;
|
1202
|
+
};
|
1203
|
+
query?: Record<string, unknown> | undefined;
|
1204
|
+
fetch?: RequestInit | undefined;
|
1205
|
+
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
1206
|
+
200: unknown[];
|
1207
|
+
}>>;
|
1208
|
+
};
|
1198
1209
|
metadata: {
|
1199
1210
|
get: (options: {
|
1200
1211
|
headers: {
|
@@ -4946,6 +4957,17 @@ declare const eden: {
|
|
4946
4957
|
}>>;
|
4947
4958
|
};
|
4948
4959
|
}) & {
|
4960
|
+
"dynamic-data": {
|
4961
|
+
post: (body: string[], options: {
|
4962
|
+
headers: {
|
4963
|
+
authorization: string;
|
4964
|
+
};
|
4965
|
+
query?: Record<string, unknown> | undefined;
|
4966
|
+
fetch?: RequestInit | undefined;
|
4967
|
+
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
4968
|
+
200: unknown[];
|
4969
|
+
}>>;
|
4970
|
+
};
|
4949
4971
|
metadata: {
|
4950
4972
|
get: (options: {
|
4951
4973
|
headers: {
|
@@ -9469,6 +9491,22 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
9469
9491
|
};
|
9470
9492
|
};
|
9471
9493
|
};
|
9494
|
+
} & {
|
9495
|
+
"dry-run": {
|
9496
|
+
"dynamic-data": {
|
9497
|
+
post: {
|
9498
|
+
body: string[];
|
9499
|
+
params: {};
|
9500
|
+
query: unknown;
|
9501
|
+
headers: {
|
9502
|
+
authorization: string;
|
9503
|
+
};
|
9504
|
+
response: {
|
9505
|
+
200: unknown[];
|
9506
|
+
};
|
9507
|
+
};
|
9508
|
+
};
|
9509
|
+
};
|
9472
9510
|
} & {
|
9473
9511
|
"dry-run": {
|
9474
9512
|
metadata: {
|
@@ -14965,6 +15003,17 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
14965
15003
|
}>>;
|
14966
15004
|
};
|
14967
15005
|
}) & {
|
15006
|
+
"dynamic-data": {
|
15007
|
+
post: (body: string[], options: {
|
15008
|
+
headers: {
|
15009
|
+
authorization: string;
|
15010
|
+
};
|
15011
|
+
query?: Record<string, unknown> | undefined;
|
15012
|
+
fetch?: RequestInit | undefined;
|
15013
|
+
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
15014
|
+
200: unknown[];
|
15015
|
+
}>>;
|
15016
|
+
};
|
14968
15017
|
metadata: {
|
14969
15018
|
get: (options: {
|
14970
15019
|
headers: {
|
@@ -18716,6 +18765,17 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
|
|
18716
18765
|
}>>;
|
18717
18766
|
};
|
18718
18767
|
}) & {
|
18768
|
+
"dynamic-data": {
|
18769
|
+
post: (body: string[], options: {
|
18770
|
+
headers: {
|
18771
|
+
authorization: string;
|
18772
|
+
};
|
18773
|
+
query?: Record<string, unknown> | undefined;
|
18774
|
+
fetch?: RequestInit | undefined;
|
18775
|
+
}) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
|
18776
|
+
200: unknown[];
|
18777
|
+
}>>;
|
18778
|
+
};
|
18719
18779
|
metadata: {
|
18720
18780
|
get: (options: {
|
18721
18781
|
headers: {
|
@@ -39,8 +39,6 @@ async function computeEventBasedPoolTVLFromMostRecentStateSave(chainId, campaign
|
|
39
39
|
// Bucket service
|
40
40
|
let tvl = 0;
|
41
41
|
try {
|
42
|
-
if (bucketName === undefined)
|
43
|
-
console.log("EVENT_BASED:", states);
|
44
42
|
const bucket = new BucketService("merkl-production-states", "merkl-production");
|
45
43
|
const storedStates = JSON.parse(await bucket.pull(fileName));
|
46
44
|
for (const [_, { value, params: _params }] of Object.entries(storedStates)) {
|
@@ -32,19 +32,17 @@ async function computeUniV4PoolTVLFromMostRecentStateSave(chainId, poolID, price
|
|
32
32
|
stateSave = mostRecentStateSave.state;
|
33
33
|
blockNumber = mostRecentStateSave?.blockNumber;
|
34
34
|
states = stateSave.states;
|
35
|
-
// const globalState = stateSave.globalState as { tick: number; liquidity: string };
|
36
35
|
}
|
37
|
-
catch
|
36
|
+
catch {
|
38
37
|
log.warn(`merklDynamic data - failed to read a recent state of pool ${poolID} on ${NETWORK_LABELS[chainId]}`);
|
38
|
+
return { tvl: 0, amount0: 0, amount1: 0, blockNumber: blockNumber ?? 0 };
|
39
39
|
}
|
40
|
-
const { fileName
|
40
|
+
const { fileName } = states;
|
41
41
|
// Bucket service
|
42
42
|
let tvl = 0;
|
43
43
|
let amount0 = 0;
|
44
44
|
let amount1 = 0;
|
45
45
|
try {
|
46
|
-
if (bucketName === undefined)
|
47
|
-
console.log("UNIV4", states);
|
48
46
|
const bucket = new BucketService("merkl-production-states", "merkl-production");
|
49
47
|
const storedStates = JSON.parse(await bucket.pull(fileName));
|
50
48
|
for (const [_, { value, params: _params }] of Object.entries(storedStates)) {
|
@@ -53,8 +51,7 @@ async function computeUniV4PoolTVLFromMostRecentStateSave(chainId, poolID, price
|
|
53
51
|
}
|
54
52
|
tvl = amount0 * (priceCurrency0 ?? 0) + amount1 * (priceCurrency1 ?? 0);
|
55
53
|
}
|
56
|
-
catch
|
57
|
-
console.log(e);
|
54
|
+
catch {
|
58
55
|
log.warn(`merklDynamic data - failed to decode state of pool ${poolID} on ${NETWORK_LABELS[chainId]}`);
|
59
56
|
}
|
60
57
|
return { tvl, amount0, amount1, blockNumber: blockNumber };
|
@@ -156,7 +156,7 @@ export async function getEulerV2Vaults(chainId) {
|
|
156
156
|
const aux = EulerEVKInterface.decodeEventLog("EVaultCreated", log.data, log.topics);
|
157
157
|
const name = (await EulerVault__factory.connect(log.address, providers[chainId]).name()).split(" ");
|
158
158
|
const vaultName = (await fetchEulerVaultName(getAddress(log.address), chainId)) ?? name[name.length - 1];
|
159
|
-
/**
|
159
|
+
/** Match previous typing */
|
160
160
|
return {
|
161
161
|
address: log.address.toString(),
|
162
162
|
asset: aux[1].toString(),
|
@@ -167,8 +167,8 @@ export async function getEulerV2Vaults(chainId) {
|
|
167
167
|
};
|
168
168
|
}
|
169
169
|
catch {
|
170
|
-
logger.
|
171
|
-
|
170
|
+
logger.error(`issue when fetching data on ${NETWORK_LABELS[chainId]} for vault ${log.address}`);
|
171
|
+
return {};
|
172
172
|
}
|
173
173
|
}));
|
174
174
|
log.info(`fetched ${decodedVaults.length} vaults(s) on ${NETWORK_LABELS[chainId]} between blocks ${fromBlock} and ${toBlock}`);
|
@@ -12,9 +12,14 @@ export class MorphoMetadata {
|
|
12
12
|
{ name: `Lend ${morphoParams.symbolBorrowToken} on ${market}`, action: OpportunityAction.LEND },
|
13
13
|
];
|
14
14
|
const subtype = subtypes[subType];
|
15
|
+
const tokens = [{ chainId: computeChainId, address: params.targetToken }];
|
16
|
+
if (subType === MorphoSubCampaignType.META) {
|
17
|
+
const typedParams = params;
|
18
|
+
tokens.push({ chainId: computeChainId, address: typedParams.underlyingToken });
|
19
|
+
}
|
15
20
|
return {
|
16
21
|
action: subtype.action,
|
17
|
-
tokens
|
22
|
+
tokens,
|
18
23
|
name: subtype.name,
|
19
24
|
mainProtocol: (computeChainId === ChainId.POLYGON ? "compound" : "morpho"),
|
20
25
|
depositUrl: MorphoMetadata.generateUrl(computeChainId, params, morphoParams, subType),
|
package/dist/src/index.d.ts
CHANGED
@@ -1280,6 +1280,22 @@ declare const app: Elysia<"", false, {
|
|
1280
1280
|
};
|
1281
1281
|
};
|
1282
1282
|
};
|
1283
|
+
} & {
|
1284
|
+
"dry-run": {
|
1285
|
+
"dynamic-data": {
|
1286
|
+
post: {
|
1287
|
+
body: string[];
|
1288
|
+
params: {};
|
1289
|
+
query: unknown;
|
1290
|
+
headers: {
|
1291
|
+
authorization: string;
|
1292
|
+
};
|
1293
|
+
response: {
|
1294
|
+
200: unknown[];
|
1295
|
+
};
|
1296
|
+
};
|
1297
|
+
};
|
1298
|
+
};
|
1283
1299
|
} & {
|
1284
1300
|
"dry-run": {
|
1285
1301
|
metadata: {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { Redis } from "@/cache";
|
2
2
|
import { getEulerV2Vaults, updateEulerVaultsCollatInDatabase } from "@/engine/dynamicData/utils/getEulerV2Vaults";
|
3
|
+
import { logger } from "@/utils/logger";
|
3
4
|
(async () => {
|
4
5
|
await Redis.safeSet("EulerV2Vaults", await getEulerV2Vaults());
|
5
6
|
try {
|
@@ -9,5 +10,6 @@ import { getEulerV2Vaults, updateEulerVaultsCollatInDatabase } from "@/engine/dy
|
|
9
10
|
console.error(e);
|
10
11
|
process.exit(1);
|
11
12
|
}
|
13
|
+
logger.info("✅ Euler update exited successfully");
|
12
14
|
process.exit(0);
|
13
15
|
})();
|
@@ -183,6 +183,22 @@ export declare const CampaignController: Elysia<"/campaigns", false, {
|
|
183
183
|
};
|
184
184
|
};
|
185
185
|
};
|
186
|
+
} & {
|
187
|
+
"dry-run": {
|
188
|
+
"dynamic-data": {
|
189
|
+
post: {
|
190
|
+
body: string[];
|
191
|
+
params: {};
|
192
|
+
query: unknown;
|
193
|
+
headers: {
|
194
|
+
authorization: string;
|
195
|
+
};
|
196
|
+
response: {
|
197
|
+
200: unknown[];
|
198
|
+
};
|
199
|
+
};
|
200
|
+
};
|
201
|
+
};
|
186
202
|
} & {
|
187
203
|
"dry-run": {
|
188
204
|
metadata: {
|
@@ -8,7 +8,7 @@ import { throwOnUnsupportedChainId } from "src/utils/throw";
|
|
8
8
|
import { DynamicDataService } from "../dynamicData/dynamicData.service";
|
9
9
|
import { OpportunityService } from "../opportunity";
|
10
10
|
import { OpportunityConvertorService } from "../opportunity/opportunity.converter";
|
11
|
-
import { CampaignResourceDto, CampaignUniqueDto, CreateCampaignDto, GetCampaignQueryDto, RemoveManualOverrideDto, UpdateCampaignCreatorDto, UpdateCampaignDto, UpdateMetaDataCampaignDto, } from "./campaign.model";
|
11
|
+
import { CampaignResourceDto, CampaignUniqueDto, CampaignsDto, CreateCampaignDto, GetCampaignQueryDto, RemoveManualOverrideDto, UpdateCampaignCreatorDto, UpdateCampaignDto, UpdateMetaDataCampaignDto, } from "./campaign.model";
|
12
12
|
import { CampaignService } from "./campaign.service";
|
13
13
|
// ─── Campaigns Controller ────────────────────────────────────────────────────
|
14
14
|
export const CampaignController = new Elysia({ prefix: "/campaigns", detail: { tags: ["Campaigns"] } })
|
@@ -65,6 +65,19 @@ export const CampaignController = new Elysia({ prefix: "/campaigns", detail: { t
|
|
65
65
|
const campaignV3 = OpportunityConvertorService.convertV4CampaignToV3(Campaign[campaign.type], CampaignService.format(campaign), campaign.Opportunity.identifier);
|
66
66
|
return await DynamicDataService.updateForCampaigns([campaignV3], true);
|
67
67
|
}, { beforeHandle: BackOfficeGuard, headers: AuthorizationHeadersDto, detail: { hide: true } })
|
68
|
+
// ─── Test Dynamic data computation with a list of campaignId ───────────────────────
|
69
|
+
.post("/dynamic-data", async ({ body }) => {
|
70
|
+
const listCampaigns = [];
|
71
|
+
for (const campaignId of body) {
|
72
|
+
const id = (await CampaignService.findMany({ campaignId: campaignId, test: true }))?.[0]?.id;
|
73
|
+
if (!id)
|
74
|
+
throw new NotFoundError();
|
75
|
+
const campaign = await CampaignService.findUniqueOrThrow(id, true);
|
76
|
+
const campaignV3 = OpportunityConvertorService.convertV4CampaignToV3(Campaign[campaign.type], CampaignService.format(campaign), campaign.Opportunity.identifier);
|
77
|
+
listCampaigns.push(campaignV3);
|
78
|
+
}
|
79
|
+
return await DynamicDataService.updateForCampaigns(listCampaigns, true);
|
80
|
+
}, { beforeHandle: BackOfficeGuard, body: CampaignsDto, headers: AuthorizationHeadersDto, detail: { hide: true } })
|
68
81
|
// ─── Test Opportunity creation through a campaign Id and a chain ───────────────────────
|
69
82
|
// @dev Starts from the engine db to debug opportunity creation failing and preventing the api db to be filled
|
70
83
|
.get("/metadata", async ({ query }) => {
|
@@ -29,6 +29,7 @@ export declare const CampaignUniqueDto: import("@sinclair/typebox").TObject<{
|
|
29
29
|
distributionChain: import("@sinclair/typebox").TNumber;
|
30
30
|
campaignId: import("@sinclair/typebox").TString;
|
31
31
|
}>;
|
32
|
+
export declare const CampaignsDto: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
32
33
|
export declare const CampaignResourceDto: import("@sinclair/typebox").TObject<{
|
33
34
|
id: import("@sinclair/typebox").TString;
|
34
35
|
computeChainId: import("@sinclair/typebox").TNumber;
|
@@ -1,5 +1,4 @@
|
|
1
|
-
import type
|
2
|
-
import { Campaign, type CampaignParameters, type ChainId } from "@sdk";
|
1
|
+
import { Campaign, type CampaignDynamicData, type CampaignParameters, type ChainId } from "@sdk";
|
3
2
|
import { Campaign as CampaignEnum } from "@sdk";
|
4
3
|
export declare class DynamicDataService {
|
5
4
|
static queryERC20DynamicData(chainId: ChainId, tokenAddress: string, decimals?: number): Promise<{
|
@@ -10,7 +9,7 @@ export declare class DynamicDataService {
|
|
10
9
|
priceTargetToken: number;
|
11
10
|
type: string;
|
12
11
|
}>;
|
13
|
-
static getDynamicData(campaigns: CampaignParameters<CampaignEnum>[], type: Campaign, chainId: number): Promise<
|
12
|
+
static getDynamicData(campaigns: CampaignParameters<CampaignEnum>[], type: Campaign, chainId: number): Promise<CampaignDynamicData<CampaignEnum>[]>;
|
14
13
|
static updateForCampaignType(campaigns: CampaignParameters<CampaignEnum>[], type: Campaign, dryRun?: boolean): Promise<unknown[]>;
|
15
14
|
static updateForCampaigns(campaigns: CampaignParameters<CampaignEnum>[], dryRun?: boolean): Promise<unknown[]>;
|
16
15
|
}
|
@@ -53,36 +53,34 @@ export class DynamicDataService {
|
|
53
53
|
};
|
54
54
|
}
|
55
55
|
static async getDynamicData(campaigns, type, chainId) {
|
56
|
+
// Base case: empty input
|
57
|
+
if (campaigns.length === 0)
|
58
|
+
return [];
|
56
59
|
try {
|
57
|
-
const
|
58
|
-
return
|
60
|
+
const campaignType = typeof type === "number" ? type : Campaign[type];
|
61
|
+
return await dynamicDataBuilderFactory(campaignType).build(chainId, campaigns);
|
59
62
|
}
|
60
|
-
catch (
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
return [];
|
63
|
+
catch (error) {
|
64
|
+
// Base case: single failing campaign
|
65
|
+
if (campaigns.length === 1) {
|
66
|
+
log.error(`Permanent failure for campaign ${campaigns[0].campaignId}`, error);
|
67
|
+
return [];
|
68
|
+
}
|
69
|
+
// Recursive binary split
|
70
|
+
const mid = Math.ceil(campaigns.length / 2);
|
71
|
+
const [firstResults, secondResults] = await Promise.all([
|
72
|
+
// Process first half with error propagation
|
73
|
+
DynamicDataService.getDynamicData(campaigns.slice(0, mid), type, chainId),
|
74
|
+
// Process second half with error propagation
|
75
|
+
DynamicDataService.getDynamicData(campaigns.slice(mid), type, chainId),
|
76
|
+
]);
|
77
|
+
return [...firstResults, ...secondResults];
|
75
78
|
}
|
76
79
|
}
|
77
80
|
static async updateForCampaignType(campaigns, type, dryRun = false) {
|
78
81
|
const chainId = campaigns[0].computeChainId;
|
79
82
|
const dynamicDataArray = [];
|
80
|
-
const dynamicData = await
|
81
|
-
// const dynamicData = await DynamicDataService.getDynamicData(
|
82
|
-
// campaigns,
|
83
|
-
// typeof type === "number" ? type : Campaign[type as keyof typeof Campaign],
|
84
|
-
// chainId
|
85
|
-
// );
|
83
|
+
const dynamicData = await DynamicDataService.getDynamicData(campaigns, typeof type === "number" ? type : Campaign[type], chainId);
|
86
84
|
const oppMap = {};
|
87
85
|
for (const data of dynamicData) {
|
88
86
|
if (!!data) {
|
@@ -123,6 +121,7 @@ export class DynamicDataService {
|
|
123
121
|
}
|
124
122
|
dynamicDataArray.push(bigintToString({ campaignId: Object.values(entry[1])[0].campaignId, apr, tvl, dailyRewards }));
|
125
123
|
}
|
124
|
+
log.info(`[${CampaignEnum[type]}] Updated ${dynamicData.length}/${campaigns.length} campaigns`);
|
126
125
|
return dynamicDataArray;
|
127
126
|
}
|
128
127
|
static async updateForCampaigns(campaigns, dryRun = false) {
|
@@ -136,7 +135,6 @@ export class DynamicDataService {
|
|
136
135
|
const dynamicDataArray = [];
|
137
136
|
for (const [campaignType, campaigns] of campaignTypeToCampaigns.entries()) {
|
138
137
|
try {
|
139
|
-
log.info(`updating dynamic data for ${campaigns.length} campaigns of type ${CampaignEnum[campaignType]}`);
|
140
138
|
try {
|
141
139
|
dynamicDataArray.push(await DynamicDataService.updateForCampaignType(campaigns, campaignType, dryRun));
|
142
140
|
}
|
@@ -1150,6 +1150,22 @@ export declare const v4: Elysia<"/v4", false, {
|
|
1150
1150
|
};
|
1151
1151
|
};
|
1152
1152
|
};
|
1153
|
+
} & {
|
1154
|
+
"dry-run": {
|
1155
|
+
"dynamic-data": {
|
1156
|
+
post: {
|
1157
|
+
body: string[];
|
1158
|
+
params: {};
|
1159
|
+
query: unknown;
|
1160
|
+
headers: {
|
1161
|
+
authorization: string;
|
1162
|
+
};
|
1163
|
+
response: {
|
1164
|
+
200: unknown[];
|
1165
|
+
};
|
1166
|
+
};
|
1167
|
+
};
|
1168
|
+
};
|
1153
1169
|
} & {
|
1154
1170
|
"dry-run": {
|
1155
1171
|
metadata: {
|