@merkl/api 0.20.114 → 0.20.115

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.
Files changed (23) hide show
  1. package/dist/src/eden/index.d.ts +3 -3
  2. package/dist/src/engine/deprecated/dynamicData/factory.js +1 -0
  3. package/dist/src/engine/deprecated/dynamicData/implementations/EventBased.js +1 -1
  4. package/dist/src/engine/deprecated/erc20SubTypeProcessors/subtypesRound1.js +3 -8
  5. package/dist/src/engine/implementations/EigenLayer/tvl.d.ts +7 -0
  6. package/dist/src/engine/implementations/EigenLayer/tvl.js +60 -0
  7. package/dist/src/engine/implementations/Erc20/subTypes/factories.js +6 -0
  8. package/dist/src/engine/implementations/Erc20/subTypes/implementations/gearbox/tvl.js +1 -1
  9. package/dist/src/engine/implementations/Erc20/subTypes/implementations/superlend/metadata.d.ts +17 -0
  10. package/dist/src/engine/implementations/Erc20/subTypes/implementations/superlend/metadata.js +29 -0
  11. package/dist/src/engine/implementations/Erc20/subTypes/implementations/superlend/tvl.d.ts +6 -0
  12. package/dist/src/engine/implementations/Erc20/subTypes/implementations/superlend/tvl.js +48 -0
  13. package/dist/src/engine/implementations/Erc20/tvl.js +1 -1
  14. package/dist/src/engine/metadata/factory.js +1 -0
  15. package/dist/src/engine/tvl/factory.js +2 -0
  16. package/dist/src/index.d.ts +1 -1
  17. package/dist/src/modules/v4/campaign/campaign.test.controller.d.ts +1 -1
  18. package/dist/src/modules/v4/campaign/campaign.test.controller.js +14 -3
  19. package/dist/src/modules/v4/router.d.ts +1 -1
  20. package/dist/src/modules/v4/token/token.service.d.ts +20 -0
  21. package/dist/src/modules/v4/token/token.service.js +19 -0
  22. package/dist/tsconfig.package.tsbuildinfo +1 -1
  23. package/package.json +1 -1
@@ -1734,8 +1734,8 @@ declare const eden: {
1734
1734
  authorization: string;
1735
1735
  };
1736
1736
  query: {
1737
+ distributionChain?: number | undefined;
1737
1738
  campaignId: string;
1738
- distributionChain: number;
1739
1739
  };
1740
1740
  fetch?: RequestInit | undefined;
1741
1741
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
@@ -7099,8 +7099,8 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
7099
7099
  body: unknown;
7100
7100
  params: {};
7101
7101
  query: {
7102
+ distributionChain?: number | undefined;
7102
7103
  campaignId: string;
7103
- distributionChain: number;
7104
7104
  };
7105
7105
  headers: {
7106
7106
  authorization: string;
@@ -12892,8 +12892,8 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
12892
12892
  authorization: string;
12893
12893
  };
12894
12894
  query: {
12895
+ distributionChain?: number | undefined;
12895
12896
  campaignId: string;
12896
- distributionChain: number;
12897
12897
  };
12898
12898
  fetch?: RequestInit | undefined;
12899
12899
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
@@ -61,5 +61,6 @@ const map = {
61
61
  [Campaign.ERC1155FIXAPR]: new ERCMultiTokenDynamicData(),
62
62
  [Campaign.ERC721]: new ERC721DynamicData(),
63
63
  [Campaign.ERC721FIXAPR]: new ERC721DynamicData(),
64
+ [Campaign.MULTILOG]: new DefaultDynamicData(), // TODO
64
65
  };
65
66
  export const dynamicDataBuilderFactory = (campaignType) => map[campaignType];
@@ -69,7 +69,7 @@ export class EventBasedDynamicData {
69
69
  const { distributedRewards } = await computeEventBasedPoolRewardsFromMostRecentStateSave(chainId, campaign.campaignId, priceToken, decimalsCurrency0);
70
70
  const c = campaign;
71
71
  const amount = BN2Number(c.amount, c.campaignParameters.decimalsRewardToken);
72
- const multiplier = BN2Number(c.campaignParameters.topicToData[0].multiplier, 12 + 9);
72
+ const multiplier = BN2Number(c.campaignParameters.topicToData[0].multipliers[0], 12 + 9);
73
73
  const startTimestamp = BN2Number(c.startTimestamp, 0);
74
74
  const endTimestamp = BN2Number(c.endTimestamp, 0);
75
75
  const isLive = moment().unix() > startTimestamp && moment().unix() < endTimestamp;
@@ -190,18 +190,13 @@ function generateResult(type, name, targetToken, typeInfo, campaign) {
190
190
  };
191
191
  return processorObject.computeRound1(type, typeInfo);
192
192
  }
193
- function processNamingConditions(type, name, targetToken, campaign) {
194
- if (satisfiesNameConditions(name, type)) {
195
- return generateResult(type, name, targetToken, {}, campaign);
196
- }
197
- }
198
193
  export function processNamingConditionsInOrder(name, targetToken, campaign) {
199
194
  // Order matters
200
195
  const types = Object.values(Erc20SubType).filter(value => typeof value === "string");
201
196
  for (const type of types) {
202
- const result = processNamingConditions(type, name, targetToken, campaign);
203
- if (result)
204
- return result;
197
+ if (satisfiesNameConditions(name, type)) {
198
+ return generateResult(type, name, targetToken, {}, campaign);
199
+ }
205
200
  }
206
201
  }
207
202
  function parseForFactory(calls, targetToken, campaign) {
@@ -0,0 +1,7 @@
1
+ import type { TVLBuilder, TVLData } from "@/engine/tvl/interface";
2
+ import { type Campaign, type CampaignParameters, type MerklChainId } from "@sdk";
3
+ type campaignType = Campaign.EIGENLAYER;
4
+ export declare class EigenLayerTVLBuilder implements TVLBuilder<campaignType> {
5
+ build(computeChainId: MerklChainId, campaigns: CampaignParameters<campaignType>[]): Promise<TVLData<Campaign.EIGENLAYER>>;
6
+ }
7
+ export {};
@@ -0,0 +1,60 @@
1
+ import { TokenService } from "@/modules/v4/token/token.service";
2
+ import { log } from "@/utils/logger";
3
+ import { TvlType } from "@db/api";
4
+ import { ChainInteractionService, EigenLayerStrategyInterface, bigIntToNumber, } from "@sdk";
5
+ export class EigenLayerTVLBuilder {
6
+ async build(computeChainId, campaigns) {
7
+ const tvls = [];
8
+ const firstRound = await ChainInteractionService(computeChainId).fetchAndDecodeObject(campaigns.flatMap(campaign => {
9
+ const { campaignId, campaignParameters } = campaign;
10
+ const { strategy } = campaignParameters;
11
+ return [
12
+ {
13
+ callData: EigenLayerStrategyInterface.encodeFunctionData("totalShares"),
14
+ target: strategy,
15
+ key: `${campaignId}_totalShares`,
16
+ decoder: (data) => BigInt(EigenLayerStrategyInterface.decodeFunctionResult("totalShares", data)[0].toString()),
17
+ },
18
+ ];
19
+ }));
20
+ const secondRound = await ChainInteractionService(computeChainId).fetchAndDecodeObject(campaigns.flatMap(campaign => {
21
+ const { campaignId, campaignParameters } = campaign;
22
+ const { strategy } = campaignParameters;
23
+ let totalShares = firstRound[`${campaignId}_totalShares`];
24
+ if (!totalShares) {
25
+ log.warn(`Error getting totalShares for campaign ${campaign.campaignId} and strategy ${campaign.campaignParameters.strategy}`);
26
+ totalShares = 10n;
27
+ }
28
+ return [
29
+ {
30
+ callData: EigenLayerStrategyInterface.encodeFunctionData("sharesToUnderlying", [totalShares]),
31
+ target: strategy,
32
+ key: `${campaignId}_totalUnderlying`,
33
+ decoder: (data) => BigInt(EigenLayerStrategyInterface.decodeFunctionResult("sharesToUnderlying", data)[0].toString()),
34
+ },
35
+ ];
36
+ }));
37
+ for (const campaign of campaigns) {
38
+ const { campaignId, campaignParameters } = campaign;
39
+ const { underlyingToken: underlyingTokenAddress } = campaignParameters;
40
+ const totalUnderlying = secondRound[`${campaignId}_totalUnderlying`];
41
+ // We don't fetch token data everytime, we use the database and the associated service
42
+ const underlyingToken = await TokenService.findUniqueFillOrThrow({
43
+ chainId: computeChainId,
44
+ address: underlyingTokenAddress,
45
+ });
46
+ tvls.push({
47
+ campaign,
48
+ tvl: (bigIntToNumber(totalUnderlying, underlyingToken.decimals) ?? 0) * (underlyingToken.price ?? 0),
49
+ tvlBreakdown: [
50
+ {
51
+ identifier: underlyingToken.id,
52
+ type: TvlType.TOKEN,
53
+ value: bigIntToNumber(totalUnderlying, underlyingToken.decimals),
54
+ },
55
+ ],
56
+ });
57
+ }
58
+ return tvls;
59
+ }
60
+ }
@@ -1,6 +1,8 @@
1
1
  import { Erc20SubType } from ".";
2
2
  import { GearboxMetadata } from "./implementations/gearbox/metadata";
3
3
  import { GearboxTVLBuilder } from "./implementations/gearbox/tvl";
4
+ import { SuperlendMetadata } from "./implementations/superlend/metadata";
5
+ import { SuperlendTVLBuilder } from "./implementations/superlend/tvl";
4
6
  /**
5
7
  * @dev TYPE SAFETY DISABLED FOR NOW AS WE DON'T HAVE ALL THE CAMPAIGNS IMPLEMENTED
6
8
  *
@@ -9,6 +11,8 @@ import { GearboxTVLBuilder } from "./implementations/gearbox/tvl";
9
11
  */
10
12
  const tvlMap = {
11
13
  [Erc20SubType.gearbox]: new GearboxTVLBuilder(),
14
+ [Erc20SubType.superlend_borrowing]: new SuperlendTVLBuilder(),
15
+ [Erc20SubType.superlend_lending]: new SuperlendTVLBuilder(),
12
16
  };
13
17
  export const erc20SubTypeTVLBuilderFactory = (erc20Subtype) => {
14
18
  if (!tvlMap[erc20Subtype]) {
@@ -24,6 +28,8 @@ export const erc20SubTypeTVLBuilderFactory = (erc20Subtype) => {
24
28
  */
25
29
  const metadataMap = {
26
30
  [Erc20SubType.gearbox]: new GearboxMetadata(),
31
+ [Erc20SubType.superlend_borrowing]: new SuperlendMetadata(),
32
+ [Erc20SubType.superlend_lending]: new SuperlendMetadata(),
27
33
  };
28
34
  export const erc20SubTypeMetadataBuilderFactory = (erc20Subtype) => {
29
35
  if (!metadataMap[erc20Subtype]) {
@@ -21,7 +21,7 @@ export class GearboxTVLBuilder {
21
21
  for (const [index, campaign] of campaigns.entries()) {
22
22
  const underlyingTokenAddress = GearboxVaultInterface.decodeFunctionResult("underlyingToken", result[2 * index].returnData)[0];
23
23
  const totalAssets = ERC4626Interface.decodeFunctionResult("totalAssets", result[2 * index + 1].returnData)[0];
24
- const underlyingToken = await TokenService.findUniqueOrThrow({
24
+ const underlyingToken = await TokenService.findUniqueFillOrThrow({
25
25
  chainId: computeChainId,
26
26
  address: underlyingTokenAddress,
27
27
  });
@@ -0,0 +1,17 @@
1
+ import type { MetadataBuilder } from "@/engine/metadata/interface";
2
+ import type { CampaignWithParams } from "@/modules/v4/campaign";
3
+ import type { ProtocolId } from "@/modules/v4/protocol/protocol.model";
4
+ import type { Erc20LikeCampaignEnum } from "../..";
5
+ export declare class SuperlendMetadata implements MetadataBuilder<Erc20LikeCampaignEnum> {
6
+ build(campaign: Omit<CampaignWithParams<Erc20LikeCampaignEnum>, "manualOverrides">): Promise<{
7
+ action: "LEND" | "BORROW";
8
+ protocol: ProtocolId;
9
+ name: string;
10
+ tokens: {
11
+ chainId: number;
12
+ address: any;
13
+ }[];
14
+ depositUrl: string;
15
+ explorerAddress: any;
16
+ }>;
17
+ }
@@ -0,0 +1,29 @@
1
+ import { TokenService } from "@/modules/v4/token/token.service";
2
+ import { OpportunityAction } from "@db/api";
3
+ import { Aave__factory, ChainInteractionService, TokenInteractionService } from "@sdk";
4
+ export class SuperlendMetadata {
5
+ async build(campaign) {
6
+ const { params, computeChainId } = campaign;
7
+ const { targetToken } = params;
8
+ const targetTokenInfo = await TokenService.fetchOnChain({
9
+ chainId: computeChainId,
10
+ address: targetToken,
11
+ });
12
+ const underlyingToken = await Aave__factory.connect(targetToken, ChainInteractionService(computeChainId).provider()).UNDERLYING_ASSET_ADDRESS();
13
+ const underlyingTokenSymbol = await TokenInteractionService(computeChainId).symbol(underlyingToken);
14
+ const action = targetTokenInfo?.name?.toLowerCase().includes("debt")
15
+ ? OpportunityAction.BORROW
16
+ : OpportunityAction.LEND;
17
+ return {
18
+ action,
19
+ protocol: "superlend",
20
+ name: `${action === OpportunityAction.BORROW ? "Borrow" : "Supply"} ${underlyingTokenSymbol} on Superlend`,
21
+ tokens: [
22
+ { chainId: computeChainId, address: targetToken },
23
+ { chainId: computeChainId, address: underlyingToken },
24
+ ],
25
+ depositUrl: `https://markets.superlend.xyz/reserve-overview/?underlyingAsset=${underlyingToken}`,
26
+ explorerAddress: params.targetToken,
27
+ };
28
+ }
29
+ }
@@ -0,0 +1,6 @@
1
+ import type { Erc20LikeCampaignEnum } from "@/engine/implementations/Erc20/subTypes";
2
+ import type { TVLBuilder, TVLData } from "@/engine/tvl/interface";
3
+ import { type CampaignParameters, type MerklChainId } from "@sdk";
4
+ export declare class SuperlendTVLBuilder implements TVLBuilder<Erc20LikeCampaignEnum> {
5
+ build(computeChainId: MerklChainId, campaigns: CampaignParameters<Erc20LikeCampaignEnum>[]): Promise<TVLData<any>>;
6
+ }
@@ -0,0 +1,48 @@
1
+ import { TokenService } from "@/modules/v4/token/token.service";
2
+ import { TvlType } from "@db/api";
3
+ import { AaveInterface, ChainInteractionService, ERC20Interface, bigIntToNumber, } from "@sdk";
4
+ export class SuperlendTVLBuilder {
5
+ async build(computeChainId, campaigns) {
6
+ const tvls = [];
7
+ const firstRound = await ChainInteractionService(computeChainId).fetchAndDecodeObject(campaigns.flatMap(campaign => {
8
+ const { campaignId, campaignParameters } = campaign;
9
+ const { targetToken } = campaignParameters;
10
+ return [
11
+ {
12
+ callData: AaveInterface.encodeFunctionData("UNDERLYING_ASSET_ADDRESS"),
13
+ target: targetToken,
14
+ key: `${campaignId}_underlyingToken`,
15
+ decoder: (data) => AaveInterface.decodeFunctionResult("UNDERLYING_ASSET_ADDRESS", data)[0],
16
+ },
17
+ {
18
+ callData: ERC20Interface.encodeFunctionData("totalSupply"),
19
+ target: targetToken,
20
+ key: `${campaignId}_totalSupply`,
21
+ decoder: (data) => BigInt(ERC20Interface.decodeFunctionResult("totalSupply", data)[0].toString()),
22
+ },
23
+ ];
24
+ }));
25
+ for (const campaign of campaigns) {
26
+ const { campaignId } = campaign;
27
+ const underlyingTokenAddress = firstRound[`${campaignId}_underlyingToken`];
28
+ const totalSupply = firstRound[`${campaignId}_totalSupply`];
29
+ // We don't fetch token data everytime, we use the database and the associated service
30
+ const underlyingToken = await TokenService.findUniqueFillOrThrow({
31
+ chainId: computeChainId,
32
+ address: underlyingTokenAddress,
33
+ });
34
+ tvls.push({
35
+ campaign,
36
+ tvl: (bigIntToNumber(totalSupply, underlyingToken.decimals) ?? 0) * (underlyingToken.price ?? 0),
37
+ tvlBreakdown: [
38
+ {
39
+ identifier: underlyingToken.id,
40
+ type: TvlType.TOKEN,
41
+ value: bigIntToNumber(totalSupply, underlyingToken.decimals),
42
+ },
43
+ ],
44
+ });
45
+ }
46
+ return tvls;
47
+ }
48
+ }
@@ -93,7 +93,7 @@ export class Erc20TVLBuilder {
93
93
  for (const subType of new Set(subTypes)) {
94
94
  promises.push(processSubtype(subType));
95
95
  }
96
- await Promise.allSettled(promises);
96
+ await Promise.all(promises);
97
97
  return tvls;
98
98
  }
99
99
  }
@@ -67,5 +67,6 @@ const map = {
67
67
  [Campaign.ERC1155FIXAPR]: new ErcMultiTokenMetadata(),
68
68
  [Campaign.ERC721]: new Erc721Metadata(),
69
69
  [Campaign.ERC721FIXAPR]: new Erc721Metadata(),
70
+ [Campaign.MULTILOG]: new DefaultMetadata(), // TODO
70
71
  };
71
72
  export const metadataBuilderFactory = (campaignType) => map[campaignType];
@@ -2,6 +2,7 @@ import { UniswapV4TVLBuilder } from "@/engine/implementations/UniswapV4/tvl";
2
2
  import { Campaign } from "@sdk";
3
3
  import { AjnaTVLBuilder } from "../implementations/Ajna/tvl";
4
4
  import { AmbiantTVLBuilder } from "../implementations/Ambient/tvl";
5
+ import { EigenLayerTVLBuilder } from "../implementations/EigenLayer/tvl";
5
6
  import { Erc20TVLBuilder } from "../implementations/Erc20/tvl";
6
7
  /**
7
8
  * @dev TYPE SAFETY DISABLED FOR NOW AS WE DON'T HAVE ALL THE CAMPAIGNS IMPLEMENTED
@@ -11,6 +12,7 @@ import { Erc20TVLBuilder } from "../implementations/Erc20/tvl";
11
12
  */
12
13
  const map = {
13
14
  [Campaign.AJNA]: new AjnaTVLBuilder(),
15
+ [Campaign.EIGENLAYER]: new EigenLayerTVLBuilder(),
14
16
  [Campaign.AMBIENTPROCESSOR]: new AmbiantTVLBuilder(),
15
17
  [Campaign.UNISWAP_V4]: new UniswapV4TVLBuilder(),
16
18
  [Campaign.ERC20]: new Erc20TVLBuilder(),
@@ -2133,8 +2133,8 @@ declare const app: Elysia<"", false, {
2133
2133
  body: unknown;
2134
2134
  params: {};
2135
2135
  query: {
2136
+ distributionChain?: number | undefined;
2136
2137
  campaignId: string;
2137
- distributionChain: number;
2138
2138
  };
2139
2139
  headers: {
2140
2140
  authorization: string;
@@ -204,8 +204,8 @@ export declare const CampaignTestController: Elysia<"/campaigns", false, {
204
204
  body: unknown;
205
205
  params: {};
206
206
  query: {
207
+ distributionChain?: number | undefined;
207
208
  campaignId: string;
208
- distributionChain: number;
209
209
  };
210
210
  headers: {
211
211
  authorization: string;
@@ -4,11 +4,11 @@ import { BackOfficeGuard } from "@/guards/BackOffice.guard";
4
4
  import { AuthorizationHeadersDto } from "@/guards/Engine.guard";
5
5
  import { throwOnUnsupportedChainId } from "@/utils/throw";
6
6
  import { Campaign as CampaignType } from "@sdk";
7
- import Elysia from "elysia";
7
+ import Elysia, { t } from "elysia";
8
8
  import { DynamicDataSourceIdentifier } from "../dynamicData/dynamicData.model";
9
9
  import { DynamicDataService } from "../dynamicData/dynamicData.service";
10
10
  import { OpportunityConvertorService } from "../opportunity/opportunity.converter";
11
- import { CampaignConfigMinimal, CampaignUniqueDto, CampaignsDto } from "./campaign.model";
11
+ import { CampaignConfigMinimal, CampaignsDto } from "./campaign.model";
12
12
  import { CampaignService } from "./campaign.service";
13
13
  // ─── Routes for dev and test only ──────────────────────────────────────────────
14
14
  export const CampaignTestController = new Elysia({
@@ -84,6 +84,14 @@ export const CampaignTestController = new Elysia({
84
84
  // ─── Test Opportunity creation through a campaign Id and a chain ───────────────────────
85
85
  // @dev Starts from the engine db to debug opportunity creation failing and preventing the api db to be filled
86
86
  .get("/metadata", async ({ query }) => {
87
+ if (!query.distributionChain) {
88
+ try {
89
+ query.distributionChain = (await CampaignService.findMany({ campaignId: query.campaignId, test: true }))?.[0]?.distributionChainId;
90
+ }
91
+ catch {
92
+ throw new NotFoundError("Campaign not found");
93
+ }
94
+ }
87
95
  const engineCampaigns = await CampaignService.findEngineCampaigns([
88
96
  {
89
97
  distributionChain: query.distributionChain,
@@ -94,5 +102,8 @@ export const CampaignTestController = new Elysia({
94
102
  throw new NotFoundError("Campaign not found in engine db");
95
103
  return await CampaignService.create(engineCampaigns[0], true);
96
104
  }, {
97
- query: CampaignUniqueDto,
105
+ query: t.Object({
106
+ distributionChain: t.Optional(t.Numeric()),
107
+ campaignId: t.String(),
108
+ }),
98
109
  }));
@@ -2003,8 +2003,8 @@ export declare const v4: Elysia<"/v4", false, {
2003
2003
  body: unknown;
2004
2004
  params: {};
2005
2005
  query: {
2006
+ distributionChain?: number | undefined;
2006
2007
  campaignId: string;
2007
- distributionChain: number;
2008
2008
  };
2009
2009
  headers: {
2010
2010
  authorization: string;
@@ -114,6 +114,26 @@ export declare abstract class TokenService {
114
114
  } & {
115
115
  price?: number | null | undefined;
116
116
  }>;
117
+ /**
118
+ * Read token from database, tries to fill it if unexistant
119
+ * @param chainId
120
+ * @param address
121
+ */
122
+ static findUniqueFillOrThrow(token: TokenUnique): Promise<{
123
+ symbol: string;
124
+ id: string;
125
+ name: string | null;
126
+ icon: string;
127
+ address: string;
128
+ chainId: number;
129
+ decimals: number;
130
+ verified: boolean;
131
+ isTest: boolean;
132
+ isPoint: boolean;
133
+ isNative: boolean;
134
+ } & {
135
+ price?: number | null | undefined;
136
+ }>;
117
137
  /**
118
138
  * Checks if two tokens are the same based on chainId/address combo
119
139
  * @param a token
@@ -163,6 +163,25 @@ export class TokenService {
163
163
  const id = typeof token === "string" ? token : TokenService.hashId(token);
164
164
  return await TokenRepository.findUniqueOrThrow(id);
165
165
  }
166
+ /**
167
+ * Read token from database, tries to fill it if unexistant
168
+ * @param chainId
169
+ * @param address
170
+ */
171
+ static async findUniqueFillOrThrow(token) {
172
+ const id = TokenService.hashId(token);
173
+ let result = await TokenRepository.findUnique(id);
174
+ if (!result) {
175
+ await TokenService.fillAndCreate({
176
+ chainId: token.chainId,
177
+ address: token.address,
178
+ verified: false,
179
+ icon: "",
180
+ });
181
+ result = await TokenRepository.findUniqueOrThrow(id);
182
+ }
183
+ return result;
184
+ }
166
185
  /**
167
186
  * Checks if two tokens are the same based on chainId/address combo
168
187
  * @param a token