@merkl/api 0.19.33 → 0.19.35

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.
@@ -7,7 +7,8 @@ import Elysia, { t } from "elysia";
7
7
  import { throwOnUnsupportedChainId } from "src/utils/throw";
8
8
  import { DynamicDataService } from "../dynamicData/dynamicData.service";
9
9
  import { OpportunityService } from "../opportunity";
10
- import { CampaignResourceDto, CreateCampaignDto, GetCampaignQueryDto, RemoveManualOverrideDto, UpdateCampaignCreatorDto, UpdateCampaignDto, UpdateMetaDataCampaignDto, } from "./campaign.model";
10
+ import { OpportunityConvertorService } from "../opportunity/opportunity.converter";
11
+ import { CampaignResourceDto, CampaignUniqueDto, CreateCampaignDto, GetCampaignQueryDto, RemoveManualOverrideDto, UpdateCampaignCreatorDto, UpdateCampaignDto, UpdateMetaDataCampaignDto, } from "./campaign.model";
11
12
  import { CampaignService } from "./campaign.service";
12
13
  // ─── Campaigns Controller ────────────────────────────────────────────────────
13
14
  export const CampaignController = new Elysia({ prefix: "/campaigns", detail: { tags: ["Campaigns"] } })
@@ -50,71 +51,36 @@ export const CampaignController = new Elysia({ prefix: "/campaigns", detail: { t
50
51
  if (!id)
51
52
  throw new NotFoundError();
52
53
  const campaign = await CampaignService.findUniqueOrThrow(id, true);
53
- const campaignV3 = {
54
- amount: campaign.amount,
55
- campaignId: campaign.campaignId,
56
- mainParameter: campaign.Opportunity.identifier,
57
- campaignParameters: campaign.params,
58
- campaignSubType: campaign.subType,
59
- campaignType: Campaign[campaign.type],
60
- chainId: campaign.distributionChainId,
61
- computeChainId: campaign.computeChainId,
62
- creator: campaign.creatorAddress,
63
- endTimestamp: Number(campaign.endTimestamp),
64
- rewardToken: campaign.RewardToken.address,
65
- startTimestamp: Number(campaign.startTimestamp),
66
- index: 0,
67
- };
54
+ const campaignV3 = OpportunityConvertorService.convertV4CampaignToV3(Campaign[campaign.type], CampaignService.format(campaign), campaign.Opportunity.identifier);
68
55
  return await DynamicDataService.updateForCampaigns([campaignV3]);
69
56
  }, { beforeHandle: BackOfficeGuard, headers: AuthorizationHeadersDto, detail: { hide: true } })
70
- // ─── Test Dynamic and MetaData ──────────────────────────────────────────────
71
- .get("/dry-run/:campaignId/dynamic-data", async ({ params }) => {
57
+ // ─── Route for dev and test only ──────────────────────────────────────────────
58
+ .group("/dry-run", app => app
59
+ // ─── Test Dynamic data computation given a campaignId ───────────────────────
60
+ .get("/:campaignId/dynamic-data", async ({ params }) => {
72
61
  const id = (await CampaignService.findMany({ campaignId: params.campaignId, test: true }))[0].id;
73
62
  if (!id)
74
63
  throw new NotFoundError();
75
64
  const campaign = await CampaignService.findUniqueOrThrow(id, true);
76
- const campaignV3 = {
77
- amount: campaign.amount,
78
- campaignId: campaign.campaignId,
79
- mainParameter: campaign.Opportunity.identifier,
80
- campaignParameters: campaign.params,
81
- campaignSubType: campaign.subType,
82
- campaignType: Campaign[campaign.type],
83
- chainId: campaign.distributionChainId,
84
- computeChainId: campaign.computeChainId,
85
- creator: campaign.creatorAddress,
86
- endTimestamp: Number(campaign.endTimestamp),
87
- rewardToken: campaign.RewardToken.address,
88
- startTimestamp: Number(campaign.startTimestamp),
89
- index: 0,
90
- };
65
+ const campaignV3 = OpportunityConvertorService.convertV4CampaignToV3(Campaign[campaign.type], CampaignService.format(campaign), campaign.Opportunity.identifier);
91
66
  return await DynamicDataService.updateForCampaigns([campaignV3], true);
92
67
  }, { beforeHandle: BackOfficeGuard, headers: AuthorizationHeadersDto, detail: { hide: true } })
93
- .get("/dry-run/:campaignId/meta-data", async ({ params }) => {
94
- const id = (await CampaignService.findMany({ campaignId: params.campaignId, test: true }))[0].id;
95
- if (!id)
96
- throw new NotFoundError();
97
- const campaign = await CampaignService.findUniqueOrThrow(id, true);
98
- const campaignV3 = {
99
- amount: campaign.amount,
100
- campaignId: campaign.campaignId,
101
- mainParameter: campaign.Opportunity.identifier,
102
- campaignParameters: campaign.params,
103
- campaignSubType: campaign.subType,
104
- chainId: campaign.distributionChainId,
105
- computeChainId: campaign.computeChainId,
106
- creator: campaign.creatorAddress,
107
- endTimestamp: campaign.endTimestamp.toString(),
108
- rewardToken: campaign.RewardToken.address,
109
- startTimestamp: campaign.startTimestamp.toString(),
110
- index: 0,
111
- type: Campaign[campaign.type],
112
- params: JSON.stringify(campaign.params),
113
- rewardTokenAddress: campaign.RewardToken.address,
114
- opportunityIdentifier: campaign.Opportunity.identifier,
115
- };
116
- return await OpportunityService.fakeCreateFromCampaign(campaignV3);
117
- }, { beforeHandle: BackOfficeGuard, headers: AuthorizationHeadersDto, detail: { hide: true } })
68
+ // ─── Test Opportunity creation through a campaign Id and a chain ───────────────────────
69
+ // @dev Starts from the engine db to debug opportunity creation failing and preventing the api db to be filled
70
+ .get("/metadata", async ({ query }) => {
71
+ const [campaign] = await CampaignService.findEngineCampaigns([
72
+ {
73
+ distributionChain: query.distributionChain,
74
+ campaignId: query.campaignId,
75
+ },
76
+ ]);
77
+ return await OpportunityService.createFromCampaign(campaign, false, false);
78
+ }, {
79
+ beforeHandle: BackOfficeGuard,
80
+ headers: AuthorizationHeadersDto,
81
+ query: CampaignUniqueDto,
82
+ detail: { hide: true },
83
+ }))
118
84
  // ─── Get Many Campaigns ──────────────────────────────────────────────
119
85
  .get("/", async ({ query }) => {
120
86
  if (query.items === 0)
@@ -715,7 +715,7 @@ export declare abstract class CampaignRepository {
715
715
  static removeManualOverride(id: string, field: CampaignManualOverride): Promise<void>;
716
716
  static updateOpportunity(id: string, data: extendedUpdateCampaignModel): Promise<void>;
717
717
  static updateCreator(id: string, creatorAddress: string): Promise<void>;
718
- static updateMetaData(id: string, params: string): Promise<{
718
+ static updateParams(id: string, params: string): Promise<{
719
719
  id: string;
720
720
  type: string;
721
721
  params: Prisma.JsonValue;
@@ -439,7 +439,7 @@ export class CampaignRepository {
439
439
  });
440
440
  await CampaignRepository.addManualOverride(id, "creatorAddress");
441
441
  }
442
- static async updateMetaData(id, params) {
442
+ static async updateParams(id, params) {
443
443
  const updateData = {
444
444
  params: JSON.parse(params),
445
445
  };
@@ -616,6 +616,20 @@ export declare abstract class CampaignService {
616
616
  static pickCampaignToProcess(chainId: ChainId): Promise<{
617
617
  campaignId: string;
618
618
  }>;
619
+ static findEngineCampaigns(campaigns: CampaignUnique[]): Promise<{
620
+ amount: string;
621
+ chainId: number;
622
+ computeChainId: number;
623
+ creator: string;
624
+ endTimestamp: string;
625
+ campaignId: string;
626
+ opportunityIdentifier: string;
627
+ params: string;
628
+ rewardTokenAddress: string;
629
+ startTimestamp: string;
630
+ type: number;
631
+ subType: number;
632
+ }[]>;
619
633
  static fill(campaigns: CampaignUnique[]): Promise<{
620
634
  success: number;
621
635
  fail: number;
@@ -36,7 +36,8 @@ export class CampaignService {
36
36
  try {
37
37
  await OpportunityService.createFromCampaign(campaign);
38
38
  }
39
- catch {
39
+ catch (e) {
40
+ console.error(e);
40
41
  throw new CannotParseOpportunity(campaign.campaignId, campaign.chainId, campaign.type);
41
42
  }
42
43
  return await CampaignRepository.upsert({ id, ...campaign });
@@ -46,17 +47,22 @@ export class CampaignService {
46
47
  * @dev deprecated should be replaced with a manual override
47
48
  */
48
49
  static async updateMetaData(campaign) {
49
- const id = CampaignService.hashId({
50
+ const campaignUnique = {
50
51
  distributionChain: campaign.distributionChain,
51
52
  campaignId: campaign.campaignId,
52
- });
53
- const existingCampaign = await CampaignService.findUniqueOrThrow(campaign);
53
+ };
54
+ const id = CampaignService.hashId(campaignUnique);
55
+ let existingCampaign = await CampaignService.findUnique(campaign);
56
+ if (!existingCampaign) {
57
+ await CampaignService.fill([campaignUnique]);
58
+ existingCampaign = await CampaignService.findUniqueOrThrow(campaign);
59
+ }
54
60
  const params = existingCampaign.params;
55
61
  if ("url" in params) {
56
62
  params.url = campaign.url;
57
63
  }
58
64
  const updatedParams = JSON.stringify(params);
59
- return await CampaignRepository.updateMetaData(id, updatedParams);
65
+ return await CampaignRepository.updateParams(id, updatedParams);
60
66
  }
61
67
  /**
62
68
  * @dev back-office function for manual overrides
@@ -181,8 +187,8 @@ export class CampaignService {
181
187
  }
182
188
  static async findCampaignsToProcess(distributionChainId) {
183
189
  return (await CampaignRepository.findCampaignsToProcess(distributionChainId))
184
- .filter(campaign => campaign.endTimestamp > (campaign?.CampaignStatus?.[0]?.computedUntil ?? 0n))
185
- ?.sort((a, b) => Number((a.CampaignStatus?.[0]?.processingStarted ?? 0n) - (b.CampaignStatus?.[0]?.processingStarted ?? 0n)));
190
+ .filter(campaign => campaign.endTimestamp > (campaign?.CampaignStatus?.[0]?.computedUntil ?? 0n)) // Filter out campaigns that have already been processed
191
+ ?.sort((a, b) => Number((a.CampaignStatus?.[0]?.processingStarted ?? 0n) - (b.CampaignStatus?.[0]?.processingStarted ?? 0n))); // Sort by processingStarted, that is to say campaigns that were processed the most long ago
186
192
  }
187
193
  static async findNextCampaignToProcess(chainId) {
188
194
  const campaigns = await CampaignService.findCampaignsToProcess(chainId);
@@ -202,31 +208,37 @@ export class CampaignService {
202
208
  }
203
209
  throw new Error(`No campaign to process found on ${NETWORK_LABELS[chainId]}`);
204
210
  }
205
- static async fill(campaigns) {
211
+ static async findEngineCampaigns(campaigns) {
206
212
  const campaignsFromEngine = await CampaignRepository.getFromEngineDbWithId(campaigns);
207
213
  for (const campaign of campaigns) {
208
214
  if (campaignsFromEngine.findIndex(c => c.campaignId === campaign.campaignId) === -1) {
209
215
  log.warn(`Campaign ${campaign.campaignId} on ${NETWORK_LABELS[campaign.distributionChain]} not found in engine db`);
210
216
  }
211
217
  }
218
+ return campaignsFromEngine.map(campaign => {
219
+ return {
220
+ amount: campaign.amount,
221
+ chainId: campaign.chainId,
222
+ computeChainId: campaign.computeChainId,
223
+ creator: campaign.creator,
224
+ endTimestamp: campaign.endTimestamp.toString(),
225
+ campaignId: campaign.campaignId,
226
+ opportunityIdentifier: campaign.mainParameter,
227
+ params: JSON.stringify(campaign.campaignParameters),
228
+ rewardTokenAddress: campaign.rewardToken,
229
+ startTimestamp: campaign.startTimestamp.toString(),
230
+ type: campaign.campaignType,
231
+ subType: campaign.campaignSubType,
232
+ };
233
+ });
234
+ }
235
+ static async fill(campaigns) {
236
+ const campaignsFromEngine = await CampaignService.findEngineCampaigns(campaigns);
212
237
  let success = 0;
213
238
  let fail = 0;
214
239
  for (const engineCampaign of campaignsFromEngine) {
215
240
  try {
216
- await CampaignService.create({
217
- amount: engineCampaign.amount,
218
- chainId: engineCampaign.chainId,
219
- computeChainId: engineCampaign.computeChainId,
220
- creator: engineCampaign.creator,
221
- endTimestamp: engineCampaign.endTimestamp.toString(),
222
- campaignId: engineCampaign.campaignId,
223
- opportunityIdentifier: engineCampaign.mainParameter,
224
- params: JSON.stringify(engineCampaign.campaignParameters),
225
- rewardTokenAddress: engineCampaign.rewardToken,
226
- startTimestamp: engineCampaign.startTimestamp.toString(),
227
- type: engineCampaign.campaignType,
228
- subType: engineCampaign.campaignSubType,
229
- });
241
+ await CampaignService.create(engineCampaign);
230
242
  success++;
231
243
  }
232
244
  catch {
@@ -26,34 +26,12 @@ export declare abstract class OpportunityService {
26
26
  apr: number;
27
27
  dailyRewards: number;
28
28
  } | null>;
29
- static fakeCreateFromCampaign(campaign: Omit<CreateCampaignModel, "id">): Promise<{
30
- id: string;
31
- chainId: number;
32
- type: string;
33
- identifier: string;
34
- name: string;
35
- status: "PAST" | "LIVE" | "SOON";
36
- action: OpportunityAction;
37
- tokens: ({
38
- symbol: string;
39
- id: string;
40
- name: string | null;
41
- icon: string;
42
- address: string;
43
- chainId: number;
44
- decimals: number;
45
- verified: boolean;
46
- isTest: boolean;
47
- isPoint: boolean;
48
- isNative: boolean;
49
- } & {
50
- price?: number | null | undefined;
51
- })[][];
52
- mainProtocol: "splice" | "morpho" | "euler" | "ambient" | "uniswap" | "arthswap" | "base-swap" | "camelot" | "crust" | "fenix" | "horiza" | "izumi" | "kim" | "pancake-swap" | "quick-swap" | "ramses" | "retro" | "stryke" | "sushiswap" | "swapr" | "thruster" | "voltage" | "zero" | "koi" | "supswap" | "zk-swap" | "thirdtrade" | "swap-x" | "velodrome" | "aerodrome" | "balancer" | "curve" | "cross_curve" | "curveNPool" | "aura" | "akron" | "beefy" | "dragonswap" | "poolside" | "syncswap" | "neptune" | "zkSwapThreePool" | "rfx" | "ra" | "maverick" | "trader-joe" | "hanji" | "radiant" | "aave" | "fraxlend" | "ironclad" | "gearbox" | "compound" | "sturdy" | "frax" | "ionic" | "moonwell" | "fluid" | "silo" | "dolomite" | "badger" | "ajna" | "layerbank" | "ion" | "venus" | "woofi" | "reactor_fusion" | "eigenlayer" | "vest" | "zerolend" | "hyperdrive" | "gamma" | "oku" | "hourglass" | "veda" | "kyo" | "sonex" | "lendle" | "tako-tako" | "equalizer" | "spectra" | "beraborrow" | "superlend" | "avalon" | "angles" | "enzyme" | "toros" | "vicuna" | "bunni" | "beratrax" | "concrete" | "cian" | "pendle" | "yei" | "filament" | "gammaswap" | "maha" | "tempest" | "uranium" | "holdstation" | "katana" | "satlayer" | undefined;
53
- depositUrl: any;
54
- tags: string[];
55
- }>;
56
- static createFromCampaign(campaign: Omit<CreateCampaignModel, "id">, upsert?: boolean): Promise<{
29
+ /**
30
+ * @param upsert whether to update the opportunity if it already exists in database
31
+ * @param dryRun whether to skip the opportunity table interaction and just return the computed opportunity
32
+ * @returns the opportunity entity computed
33
+ */
34
+ static createFromCampaign(campaign: Omit<CreateCampaignModel, "id">, upsert?: boolean, dryRun?: boolean): Promise<{
57
35
  id: string;
58
36
  chainId: number;
59
37
  type: string;
@@ -36,50 +36,12 @@ export class OpportunityService {
36
36
  const distributionChainId = campaign.chainId;
37
37
  return await metadataBuilderFactory(campaignType).build(computeChainId, campaignParams, campaign.subType, campaign.rewardTokenAddress, distributionChainId, campaign.campaignId, campaign.creator);
38
38
  }
39
- static async fakeCreateFromCampaign(campaign) {
40
- const campaignType = CampaignService.getTypeFromV3(campaign.type);
41
- const metadata = await OpportunityService.#getMetadata(campaign);
42
- const tags = [...((await UserService.findUnique(campaign.creator))?.tags ?? []), ...(campaign?.tags ?? [])];
43
- const opportunityId = OpportunityService.hashId({
44
- chainId: campaign.computeChainId,
45
- identifier: campaign.opportunityIdentifier,
46
- type: campaignType,
47
- });
48
- const protocol = (await ProtocolService.findMany({ id: metadata.mainProtocol }))?.[0];
49
- const tokens = await Promise.all(metadata.tokens.map(async (t) => {
50
- return await TokenService.findMany(t);
51
- }));
52
- const params = JSON.parse(campaign.params);
53
- const now = moment().unix();
54
- const opportunity = {
55
- id: opportunityId,
56
- chainId: campaign.computeChainId,
57
- type: campaignType,
58
- identifier: campaign.opportunityIdentifier, // mainParameter
59
- name: metadata.name,
60
- status: now >= +campaign.startTimestamp && now < +campaign.endTimestamp
61
- ? Status.LIVE
62
- : now > +campaign.endTimestamp
63
- ? Status.PAST
64
- : Status.SOON,
65
- action: metadata.action,
66
- tokens,
67
- mainProtocol: metadata.mainProtocol,
68
- // If creator has specified a deposit URL, use it
69
- // Else if we have the specific logic to handle the deposit URL, use it
70
- // Else if the protocol has a deposit URL, use it
71
- depositUrl: !!params.url
72
- ? params.url
73
- : !!metadata.depositUrl
74
- ? metadata.depositUrl
75
- : !!metadata.mainProtocol && !!protocol.url
76
- ? protocol.url
77
- : undefined,
78
- tags,
79
- };
80
- return opportunity;
81
- }
82
- static async createFromCampaign(campaign, upsert = false) {
39
+ /**
40
+ * @param upsert whether to update the opportunity if it already exists in database
41
+ * @param dryRun whether to skip the opportunity table interaction and just return the computed opportunity
42
+ * @returns the opportunity entity computed
43
+ */
44
+ static async createFromCampaign(campaign, upsert = false, dryRun = false) {
83
45
  const campaignType = CampaignService.getTypeFromV3(campaign.type);
84
46
  const metadata = await OpportunityService.#getMetadata(campaign);
85
47
  const tags = [...((await UserService.findUnique(campaign.creator))?.tags ?? []), ...(campaign?.tags ?? [])];
@@ -118,7 +80,8 @@ export class OpportunityService {
118
80
  : undefined,
119
81
  tags,
120
82
  };
121
- await OpportunityRepository.create(opportunity, upsert);
83
+ if (!dryRun)
84
+ await OpportunityRepository.create(opportunity, upsert);
122
85
  return opportunity;
123
86
  }
124
87
  static async updateStatus(opportunityId, status) {
@@ -1143,45 +1143,44 @@ export declare const v4: Elysia<"/v4", false, {
1143
1143
  };
1144
1144
  } & {
1145
1145
  "dry-run": {
1146
- ":campaignId": {
1147
- "meta-data": {
1148
- get: {
1149
- body: unknown;
1150
- params: {
1151
- campaignId: string;
1152
- };
1153
- query: unknown;
1154
- headers: {
1155
- authorization: string;
1156
- };
1157
- response: {
1158
- 200: {
1146
+ metadata: {
1147
+ get: {
1148
+ body: unknown;
1149
+ params: {};
1150
+ query: {
1151
+ campaignId: string;
1152
+ distributionChain: number;
1153
+ };
1154
+ headers: {
1155
+ authorization: string;
1156
+ };
1157
+ response: {
1158
+ 200: {
1159
+ id: string;
1160
+ chainId: number;
1161
+ type: string;
1162
+ identifier: string;
1163
+ name: string;
1164
+ status: "PAST" | "LIVE" | "SOON";
1165
+ action: any;
1166
+ tokens: ({
1167
+ symbol: string;
1159
1168
  id: string;
1169
+ name: string | null;
1170
+ icon: string;
1171
+ address: string;
1160
1172
  chainId: number;
1161
- type: string;
1162
- identifier: string;
1163
- name: string;
1164
- status: "PAST" | "LIVE" | "SOON";
1165
- action: any;
1166
- tokens: ({
1167
- symbol: string;
1168
- id: string;
1169
- name: string | null;
1170
- icon: string;
1171
- address: string;
1172
- chainId: number;
1173
- decimals: number;
1174
- verified: boolean;
1175
- isTest: boolean;
1176
- isPoint: boolean;
1177
- isNative: boolean;
1178
- } & {
1179
- price?: number | null | undefined;
1180
- })[][];
1181
- mainProtocol: "splice" | "morpho" | "euler" | "ambient" | "uniswap" | "arthswap" | "base-swap" | "camelot" | "crust" | "fenix" | "horiza" | "izumi" | "kim" | "pancake-swap" | "quick-swap" | "ramses" | "retro" | "stryke" | "sushiswap" | "swapr" | "thruster" | "voltage" | "zero" | "koi" | "supswap" | "zk-swap" | "thirdtrade" | "swap-x" | "velodrome" | "aerodrome" | "balancer" | "curve" | "cross_curve" | "curveNPool" | "aura" | "akron" | "beefy" | "dragonswap" | "poolside" | "syncswap" | "neptune" | "zkSwapThreePool" | "rfx" | "ra" | "maverick" | "trader-joe" | "hanji" | "radiant" | "aave" | "fraxlend" | "ironclad" | "gearbox" | "compound" | "sturdy" | "frax" | "ionic" | "moonwell" | "fluid" | "silo" | "dolomite" | "badger" | "ajna" | "layerbank" | "ion" | "venus" | "woofi" | "reactor_fusion" | "eigenlayer" | "vest" | "zerolend" | "hyperdrive" | "gamma" | "oku" | "hourglass" | "veda" | "kyo" | "sonex" | "lendle" | "tako-tako" | "equalizer" | "spectra" | "beraborrow" | "superlend" | "avalon" | "angles" | "enzyme" | "toros" | "vicuna" | "bunni" | "beratrax" | "concrete" | "cian" | "pendle" | "yei" | "filament" | "gammaswap" | "maha" | "tempest" | "uranium" | "holdstation" | "katana" | "satlayer" | undefined;
1182
- depositUrl: any;
1183
- tags: string[];
1184
- };
1173
+ decimals: number;
1174
+ verified: boolean;
1175
+ isTest: boolean;
1176
+ isPoint: boolean;
1177
+ isNative: boolean;
1178
+ } & {
1179
+ price?: number | null | undefined;
1180
+ })[];
1181
+ mainProtocol: "splice" | "morpho" | "euler" | "ambient" | "uniswap" | "arthswap" | "base-swap" | "camelot" | "crust" | "fenix" | "horiza" | "izumi" | "kim" | "pancake-swap" | "quick-swap" | "ramses" | "retro" | "stryke" | "sushiswap" | "swapr" | "thruster" | "voltage" | "zero" | "koi" | "supswap" | "zk-swap" | "thirdtrade" | "swap-x" | "velodrome" | "aerodrome" | "balancer" | "curve" | "cross_curve" | "curveNPool" | "aura" | "akron" | "beefy" | "dragonswap" | "poolside" | "syncswap" | "neptune" | "zkSwapThreePool" | "rfx" | "ra" | "maverick" | "trader-joe" | "hanji" | "radiant" | "aave" | "fraxlend" | "ironclad" | "gearbox" | "compound" | "sturdy" | "frax" | "ionic" | "moonwell" | "fluid" | "silo" | "dolomite" | "badger" | "ajna" | "layerbank" | "ion" | "venus" | "woofi" | "reactor_fusion" | "eigenlayer" | "vest" | "zerolend" | "hyperdrive" | "gamma" | "oku" | "hourglass" | "veda" | "kyo" | "sonex" | "lendle" | "tako-tako" | "equalizer" | "spectra" | "beraborrow" | "superlend" | "avalon" | "angles" | "enzyme" | "toros" | "vicuna" | "bunni" | "beratrax" | "concrete" | "cian" | "pendle" | "yei" | "filament" | "gammaswap" | "maha" | "tempest" | "uranium" | "holdstation" | "katana" | "satlayer" | undefined;
1182
+ depositUrl: any;
1183
+ tags: string[];
1185
1184
  };
1186
1185
  };
1187
1186
  };