@merkl/api 0.14.0 → 0.14.2

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.
@@ -1,6 +1,6 @@
1
1
  import { Redis } from "../cache";
2
2
  import { redisClient } from "../cache/redis";
3
- import { getEulerV2Vaults } from "../libs/campaigns/utils/getEulerV2Vaults";
3
+ import { getEulerV2Vaults, updateEulerVaultsCollatInDatabase } from "../libs/campaigns/utils/getEulerV2Vaults";
4
4
  import { getUniswapV4Pools } from "../libs/campaigns/utils/getUniswapV4Pools";
5
5
  import { DungeonKeeperController } from "../modules/v4/dungeonKeeper";
6
6
  import { log } from "../utils/logger";
@@ -30,6 +30,7 @@ new Elysia({
30
30
  .use(sync) // GET /jobs/api/sync-with-engine
31
31
  .get("/eulerUpdate", async () => {
32
32
  log.info("🔃 updating Euler vaults...");
33
+ await updateEulerVaultsCollatInDatabase();
33
34
  await Redis.safeSet("EulerV2Vaults", await getEulerV2Vaults());
34
35
  })
35
36
  .get("/uniswapv4Update", async () => {
@@ -6372,7 +6372,16 @@ declare const eden: {
6372
6372
  query: {};
6373
6373
  fetch?: RequestInit | undefined;
6374
6374
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
6375
- 200: import("../libs/campaigns/utils/getEulerV2Vaults").EulerVaultType[];
6375
+ 200: EulerVaultType[];
6376
+ }>>;
6377
+ };
6378
+ "euler-update-collat": {
6379
+ get: (options: {
6380
+ headers?: Record<string, unknown> | undefined;
6381
+ query: {};
6382
+ fetch?: RequestInit | undefined;
6383
+ }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
6384
+ 200: void;
6376
6385
  }>>;
6377
6386
  };
6378
6387
  fetch: {
@@ -10930,7 +10939,19 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
10930
10939
  query: {};
10931
10940
  headers: unknown;
10932
10941
  response: {
10933
- 200: import("../libs/campaigns/utils/getEulerV2Vaults").EulerVaultType[];
10942
+ 200: EulerVaultType[];
10943
+ };
10944
+ };
10945
+ };
10946
+ } & {
10947
+ "euler-update-collat": {
10948
+ get: {
10949
+ body: unknown;
10950
+ params: {};
10951
+ query: {};
10952
+ headers: unknown;
10953
+ response: {
10954
+ 200: void;
10934
10955
  };
10935
10956
  };
10936
10957
  };
@@ -17827,7 +17848,16 @@ export declare const MerklApi: (domain: string | import("elysia").default<"", fa
17827
17848
  query: {};
17828
17849
  fetch?: RequestInit | undefined;
17829
17850
  }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
17830
- 200: import("../libs/campaigns/utils/getEulerV2Vaults").EulerVaultType[];
17851
+ 200: EulerVaultType[];
17852
+ }>>;
17853
+ };
17854
+ "euler-update-collat": {
17855
+ get: (options: {
17856
+ headers?: Record<string, unknown> | undefined;
17857
+ query: {};
17858
+ fetch?: RequestInit | undefined;
17859
+ }) => Promise<import("@elysiajs/eden").Treaty.TreatyResponse<{
17860
+ 200: void;
17831
17861
  }>>;
17832
17862
  };
17833
17863
  fetch: {
@@ -328,7 +328,10 @@ export const extractOpportunities = {
328
328
  },
329
329
  },
330
330
  };
331
- const action = Object.entries(map.actions).find(([_action, _types]) => _types.includes(campaign.type ?? ""))?.[0] ?? "hold";
331
+ const action = typeInfo.action.toLowerCase() ?? "hold";
332
+ // (Object.entries(map.actions).find(([_action, _types]) =>
333
+ // _types.includes(campaign.type ?? "")
334
+ // )?.[0] as ERC20Actions) ?? "hold";
332
335
  const icons = map.icons[action]();
333
336
  const opportunity = {
334
337
  id: `${Campaign.ERC20}_${mainParameter}`,
@@ -4147,7 +4147,19 @@ declare const app: Elysia<"", false, {
4147
4147
  query: {};
4148
4148
  headers: unknown;
4149
4149
  response: {
4150
- 200: import("./libs/campaigns/utils/getEulerV2Vaults").EulerVaultType[];
4150
+ 200: EulerVaultType[];
4151
+ };
4152
+ };
4153
+ };
4154
+ } & {
4155
+ "euler-update-collat": {
4156
+ get: {
4157
+ body: unknown;
4158
+ params: {};
4159
+ query: {};
4160
+ headers: unknown;
4161
+ response: {
4162
+ 200: void;
4151
4163
  };
4152
4164
  };
4153
4165
  };
@@ -17,9 +17,7 @@ const gcsClient = new S3Client({
17
17
  endpoint: process.env.GCS_ENDPOINT,
18
18
  bucket: `merkl-rewards-lake-${process.env.ENV}`,
19
19
  });
20
- let file = gcsClient.file(`pendings/${process.env.FILENAME}`);
21
- if (!(await file.exists))
22
- file = gcsClient.file(`pendings/${process.env.FILENAME}.gz`);
20
+ const file = gcsClient.file(`pendings/${process.env.FILENAME}`);
23
21
  // ─── Extract ─────────────────────────────────────────────────────────────────
24
22
  const extract = async () => {
25
23
  if (!file.exists())
@@ -1,3 +1,4 @@
1
+ import { OpportunityAction } from "../../../../../../database/api/.generated";
1
2
  import type { CallDto } from "@sdk";
2
3
  export declare enum tokenType {
3
4
  aura = "aura",
@@ -85,7 +86,7 @@ export declare enum tokenType {
85
86
  }
86
87
  export declare const tokenTypeToProtocol: {
87
88
  [key in tokenType]: {
88
- [key: string]: string;
89
+ [key: string]: string | OpportunityAction;
89
90
  };
90
91
  };
91
92
  export type tokenTypeStruct = {
@@ -1,3 +1,4 @@
1
+ import { OpportunityAction } from "../../../../../../database/api/.generated";
1
2
  // This enum's order is important, do not change it unless you know what you are doing
2
3
  export var tokenType;
3
4
  (function (tokenType) {
@@ -85,116 +86,86 @@ export var tokenType;
85
86
  tokenType["vicuna_borrowing"] = "vicuna_borrowing";
86
87
  })(tokenType || (tokenType = {}));
87
88
  export const tokenTypeToProtocol = {
88
- [tokenType.aave_borrowing]: { protocol: "Aave" },
89
- [tokenType.aave_lending]: { protocol: "Aave" },
90
- [tokenType.aerodrome]: { protocol: "Aerodrome V2" },
91
- [tokenType.akron]: { protocol: "Akron V2" },
92
- [tokenType.aura]: { protocol: "Aura" },
93
- [tokenType.balancerGauge]: { protocol: "Balancer Gauge" },
94
- [tokenType.balancerPool]: { protocol: "Balancer Pool" },
95
- [tokenType.baseswap]: { protocol: "Baseswap V2" },
96
- [tokenType.beefy]: { protocol: "Moo Velodrome V2" },
97
- [tokenType.compound]: { protocol: "Compound" },
98
- [tokenType.curve]: { protocol: "Curve" },
99
- [tokenType.curve_2]: { protocol: "Curve" },
100
- [tokenType.dragonswap]: { protocol: "Dragonswap V2" },
101
- [tokenType.enzyme]: { protocol: "Enzyme" },
102
- [tokenType.euler_borrow]: { protocol: "Euler V2" },
103
- [tokenType.euler_lend]: { protocol: "Euler V2" },
104
- [tokenType.fenix]: { protocol: "Fenix V2" },
105
- [tokenType.filament]: { protocol: "Filament" },
106
- [tokenType.fluid]: { protocol: "Fluid" },
107
- [tokenType.fraxlend]: { protocol: "Fraxlend" },
108
- [tokenType.gearbox]: { protocol: "Gearbox" },
109
- [tokenType.ionic]: { protocol: "Ionic" },
110
- [tokenType.ironclad_borrowing]: { protocol: "Ironclad" },
111
- [tokenType.ironclad_lending]: { protocol: "Ironclad" },
112
- [tokenType.koi]: { protocol: "Koi" },
113
- [tokenType.layerbank]: { protocol: "Layerbank" },
114
- [tokenType.metamorpho]: { protocol: "Metamorpho" },
115
- [tokenType.moonwell]: { protocol: "Moonwell" },
116
- [tokenType.pendle]: { protocol: "Pendle" },
117
- [tokenType.poolside]: { protocol: "Poolside" },
118
- [tokenType.ra]: { protocol: "Ra" },
119
- [tokenType.radiant_borrow]: { protocol: "Radiant" },
120
- [tokenType.radiant_lend]: { protocol: "Radiant" },
121
- [tokenType.reactor_fusion]: { protocol: "Reactor Fusion" },
122
- [tokenType.silostaking]: { protocol: "Silo Staking", symbolUnderlyingToken: "SEI" },
123
- [tokenType.splice]: { protocol: "Splice" },
124
- [tokenType.sturdy_aggregator]: { protocol: "Sturdy" },
125
- [tokenType.sturdy_silo]: { protocol: "Sturdy" },
126
- [tokenType.syncswap]: { protocol: "SyncSwap" },
127
- [tokenType.toros]: { protocol: "Toros" },
128
- [tokenType.uniswapv2]: { protocol: "Uniswap V2" },
129
- [tokenType.velodrome]: { protocol: "Velodrome V2" },
130
- [tokenType.venus]: { protocol: "Venus" },
131
- [tokenType.unknown]: { protocol: "Unknown" },
132
- [tokenType.yei_borrowing]: { protocol: "Yei Finance" },
133
- [tokenType.yei_lending]: { protocol: "Yei Finance" },
134
- [tokenType.zerolend_borrowing]: { protocol: "ZeroLend" },
135
- [tokenType.zerolend_lending]: { protocol: "ZeroLend" },
136
- [tokenType.zkswap]: { protocol: "ZKSwap" },
137
- [tokenType.rfx]: { protocol: "RFX" },
138
- [tokenType.woofi]: {
139
- protocol: "Woofi",
140
- },
141
- [tokenType.ironcladStaking]: {
142
- protocol: "Ironclad",
143
- },
144
- [tokenType.maverickBoostedPosition]: {
145
- protocol: "Maverick",
146
- },
147
- [tokenType.zkSwapThreePool]: {
148
- protocol: "ZKSwap",
149
- },
150
- [tokenType.maha]: {
151
- protocol: "Maha",
152
- },
153
- [tokenType.tempest]: {
154
- protocol: "Tempest",
155
- },
156
- [tokenType.pendleYT]: {
157
- protocol: "Pendle",
158
- },
159
- [tokenType.pancakeswap]: {
160
- protocol: "PancakeSwap V2",
161
- },
162
- [tokenType.tempestStaking]: {
163
- protocol: "Tempest",
164
- },
165
- [tokenType.holdstation]: {
166
- protocol: "HoldStation",
167
- },
168
- [tokenType.staking]: {
169
- protocol: "Staking",
170
- },
171
- [tokenType.noLinkVault]: {
172
- protocol: "NoLinkVault",
173
- },
174
- [tokenType.cpmmGamma]: {
175
- protocol: "GammaSwap",
176
- },
177
- [tokenType.crosscurve]: {
178
- protocol: "CrossCurve",
179
- },
180
- [tokenType.curveNPool]: {
181
- protocol: "Curve",
182
- },
183
- [tokenType.vicuna]: { protocol: "Vicuna" },
184
- [tokenType.traderJoe]: { protocol: "Trader Joe" },
185
- [tokenType.avalon_lending]: { protocol: "Avalon" },
186
- [tokenType.avalon_borrowing]: { protocol: "Avalon" },
187
- [tokenType.satlayer]: { protocol: "Satlayer" },
188
- [tokenType.veda]: { protocol: "Veda" },
189
- [tokenType.superlend_borrowing]: { protocol: "Superlend" },
190
- [tokenType.superlend_lending]: { protocol: "Superlend" },
191
- [tokenType.cian]: { protocol: "Cian" },
192
- [tokenType.concrete]: { protocol: "Concrete" },
193
- [tokenType.lendle_borrowing]: { protocol: "Lendle" },
194
- [tokenType.lendle_lending]: { protocol: "Lendle" },
195
- [tokenType.takotako_borrowing]: { protocol: "TakoTako" },
196
- [tokenType.takotako_lending]: { protocol: "TakoTako" },
197
- [tokenType.equalizer_gauge]: { protocol: "Equalizer" },
198
- [tokenType.vicuna_lending]: { protocol: "Vicuna" },
199
- [tokenType.vicuna_borrowing]: { protocol: "Vicuna" },
89
+ [tokenType.aave_borrowing]: { protocol: "Aave", action: OpportunityAction.BORROW },
90
+ [tokenType.aave_lending]: { protocol: "Aave", action: OpportunityAction.LEND },
91
+ [tokenType.aerodrome]: { protocol: "Aerodrome V2", action: OpportunityAction.POOL },
92
+ [tokenType.akron]: { protocol: "Akron V2", action: OpportunityAction.POOL },
93
+ [tokenType.aura]: { protocol: "Aura", action: OpportunityAction.POOL },
94
+ [tokenType.balancerGauge]: { protocol: "Balancer Gauge", action: OpportunityAction.POOL },
95
+ [tokenType.balancerPool]: { protocol: "Balancer Pool", action: OpportunityAction.POOL },
96
+ [tokenType.baseswap]: { protocol: "Baseswap V2", action: OpportunityAction.HOLD },
97
+ [tokenType.beefy]: { protocol: "Moo Velodrome V2", action: OpportunityAction.POOL },
98
+ [tokenType.compound]: { protocol: "Compound", action: OpportunityAction.LEND },
99
+ [tokenType.curve]: { protocol: "Curve", action: OpportunityAction.POOL },
100
+ [tokenType.curve_2]: { protocol: "Curve", action: OpportunityAction.POOL },
101
+ [tokenType.dragonswap]: { protocol: "Dragonswap V2", action: OpportunityAction.POOL },
102
+ [tokenType.enzyme]: { protocol: "Enzyme", action: OpportunityAction.HOLD },
103
+ [tokenType.euler_borrow]: { protocol: "Euler V2", action: OpportunityAction.BORROW },
104
+ [tokenType.euler_lend]: { protocol: "Euler V2", action: OpportunityAction.LEND },
105
+ [tokenType.fenix]: { protocol: "Fenix V2", action: OpportunityAction.HOLD },
106
+ [tokenType.filament]: { protocol: "Filament", action: OpportunityAction.HOLD },
107
+ [tokenType.fluid]: { protocol: "Fluid", action: OpportunityAction.LEND },
108
+ [tokenType.fraxlend]: { protocol: "Fraxlend", action: OpportunityAction.LEND },
109
+ [tokenType.gearbox]: { protocol: "Gearbox", action: OpportunityAction.LEND },
110
+ [tokenType.ionic]: { protocol: "Ionic", action: OpportunityAction.LEND },
111
+ [tokenType.ironclad_borrowing]: { protocol: "Ironclad", action: OpportunityAction.HOLD },
112
+ [tokenType.ironclad_lending]: { protocol: "Ironclad", action: OpportunityAction.HOLD },
113
+ [tokenType.koi]: { protocol: "Koi", action: OpportunityAction.POOL },
114
+ [tokenType.layerbank]: { protocol: "Layerbank", action: OpportunityAction.LEND },
115
+ [tokenType.metamorpho]: { protocol: "Metamorpho", action: OpportunityAction.HOLD },
116
+ [tokenType.moonwell]: { protocol: "Moonwell", action: OpportunityAction.LEND },
117
+ [tokenType.pendle]: { protocol: "Pendle", action: OpportunityAction.HOLD },
118
+ [tokenType.poolside]: { protocol: "Poolside", action: OpportunityAction.POOL },
119
+ [tokenType.ra]: { protocol: "Ra", action: OpportunityAction.HOLD },
120
+ [tokenType.radiant_borrow]: { protocol: "Radiant", action: OpportunityAction.BORROW },
121
+ [tokenType.radiant_lend]: { protocol: "Radiant", action: OpportunityAction.LEND },
122
+ [tokenType.reactor_fusion]: { protocol: "Reactor Fusion", action: OpportunityAction.LEND },
123
+ [tokenType.silostaking]: { protocol: "Silo Staking", action: OpportunityAction.LEND },
124
+ [tokenType.splice]: { protocol: "Splice", action: OpportunityAction.HOLD },
125
+ [tokenType.sturdy_aggregator]: { protocol: "Sturdy", action: OpportunityAction.LEND },
126
+ [tokenType.sturdy_silo]: { protocol: "Sturdy", action: OpportunityAction.LEND },
127
+ [tokenType.syncswap]: { protocol: "SyncSwap", action: OpportunityAction.POOL },
128
+ [tokenType.toros]: { protocol: "Toros", action: OpportunityAction.HOLD },
129
+ [tokenType.uniswapv2]: { protocol: "Uniswap V2", action: OpportunityAction.POOL },
130
+ [tokenType.velodrome]: { protocol: "Velodrome V2", action: OpportunityAction.POOL },
131
+ [tokenType.venus]: { protocol: "Venus", action: OpportunityAction.LEND },
132
+ [tokenType.unknown]: { protocol: "Unknown", action: OpportunityAction.HOLD },
133
+ [tokenType.yei_borrowing]: { protocol: "Yei Finance", action: OpportunityAction.HOLD },
134
+ [tokenType.yei_lending]: { protocol: "Yei Finance", action: OpportunityAction.HOLD },
135
+ [tokenType.zerolend_borrowing]: { protocol: "ZeroLend", action: OpportunityAction.BORROW },
136
+ [tokenType.zerolend_lending]: { protocol: "ZeroLend", action: OpportunityAction.LEND },
137
+ [tokenType.zkswap]: { protocol: "ZKSwap", action: OpportunityAction.POOL },
138
+ [tokenType.rfx]: { protocol: "RFX", action: OpportunityAction.POOL },
139
+ [tokenType.woofi]: { protocol: "Woofi", action: OpportunityAction.LEND },
140
+ [tokenType.ironcladStaking]: { protocol: "Ironclad", action: OpportunityAction.HOLD },
141
+ [tokenType.maverickBoostedPosition]: { protocol: "Maverick", action: OpportunityAction.POOL },
142
+ [tokenType.zkSwapThreePool]: { protocol: "ZKSwap", action: OpportunityAction.POOL },
143
+ [tokenType.maha]: { protocol: "Maha", action: OpportunityAction.HOLD },
144
+ [tokenType.tempest]: { protocol: "Tempest", action: OpportunityAction.POOL },
145
+ [tokenType.pendleYT]: { protocol: "Pendle", action: OpportunityAction.HOLD },
146
+ [tokenType.pancakeswap]: { protocol: "PancakeSwap V2", action: OpportunityAction.POOL },
147
+ [tokenType.tempestStaking]: { protocol: "Tempest", action: OpportunityAction.HOLD },
148
+ [tokenType.holdstation]: { protocol: "HoldStation", action: OpportunityAction.HOLD },
149
+ [tokenType.staking]: { protocol: "Staking", action: OpportunityAction.HOLD },
150
+ [tokenType.noLinkVault]: { protocol: "NoLinkVault", action: OpportunityAction.HOLD },
151
+ [tokenType.cpmmGamma]: { protocol: "GammaSwap", action: OpportunityAction.HOLD },
152
+ [tokenType.crosscurve]: { protocol: "CrossCurve", action: OpportunityAction.POOL },
153
+ [tokenType.curveNPool]: { protocol: "Curve", action: OpportunityAction.POOL },
154
+ [tokenType.vicuna]: { protocol: "Vicuna", action: OpportunityAction.HOLD },
155
+ [tokenType.traderJoe]: { protocol: "Trader Joe", action: OpportunityAction.HOLD },
156
+ [tokenType.avalon_lending]: { protocol: "Avalon", action: OpportunityAction.HOLD },
157
+ [tokenType.avalon_borrowing]: { protocol: "Avalon", action: OpportunityAction.HOLD },
158
+ [tokenType.satlayer]: { protocol: "Satlayer", action: OpportunityAction.HOLD },
159
+ [tokenType.veda]: { protocol: "Veda", action: OpportunityAction.HOLD },
160
+ [tokenType.superlend_borrowing]: { protocol: "Superlend", action: OpportunityAction.BORROW },
161
+ [tokenType.superlend_lending]: { protocol: "Superlend", action: OpportunityAction.LEND },
162
+ [tokenType.cian]: { protocol: "Cian", action: OpportunityAction.HOLD },
163
+ [tokenType.concrete]: { protocol: "Concrete", action: OpportunityAction.HOLD },
164
+ [tokenType.lendle_borrowing]: { protocol: "Lendle", action: OpportunityAction.BORROW },
165
+ [tokenType.lendle_lending]: { protocol: "Lendle", action: OpportunityAction.LEND },
166
+ [tokenType.takotako_borrowing]: { protocol: "TakoTako", action: OpportunityAction.BORROW },
167
+ [tokenType.takotako_lending]: { protocol: "TakoTako", action: OpportunityAction.LEND },
168
+ [tokenType.equalizer_gauge]: { protocol: "Equalizer", action: OpportunityAction.HOLD },
169
+ [tokenType.vicuna_lending]: { protocol: "Vicuna", action: OpportunityAction.LEND },
170
+ [tokenType.vicuna_borrowing]: { protocol: "Vicuna", action: OpportunityAction.BORROW },
200
171
  };
@@ -1,22 +1,8 @@
1
- import { type MerklChainId } from "@sdk";
1
+ import { type EulerVaultType } from "@sdk";
2
2
  export declare enum LoggedEntityType {
3
3
  EULER = "EULER_VAULT",
4
4
  UNISWAP_V4 = "UNISWAP_V4"
5
5
  }
6
- export type EulerVaultType = {
7
- address: string;
8
- asset: string;
9
- chainId: MerklChainId;
10
- debtTokenAddress: string;
11
- name: string;
12
- fetchedAtBlock: number;
13
- collaterals: {
14
- address: string;
15
- borrowLTV: string;
16
- nameCollateral: string;
17
- symbolCollateral: string;
18
- symbolUnderlying: string;
19
- }[];
20
- };
21
6
  export declare function getEulerV2Vaults(): Promise<EulerVaultType[]>;
22
7
  export declare const getEulerV2VaultsWithCache: () => Promise<EulerVaultType[]>;
8
+ export declare function updateEulerVaultsCollatInDatabase(): Promise<void>;
@@ -5,6 +5,7 @@ import { apiDbClient } from "../../../utils/prisma";
5
5
  import { providers } from "../../../utils/providers";
6
6
  import { ChainInteractionService, ERC20Interface, EULER_ADDRESSES, EulerEVKInterface, EulerVaultLensInterface, EulerVault__factory, NETWORK_LABELS, eulerChainIds, getContractCreationBlock, } from "@sdk";
7
7
  import { getAddress } from "ethers/lib/utils";
8
+ import _ from "lodash";
8
9
  import { fetchEulerVaultName } from "../campaignTypes/ERC20SubTypes/helpers/eulerVaultNames";
9
10
  import { safeFetchLogs } from "./fetchLogs";
10
11
  export var LoggedEntityType;
@@ -12,6 +13,79 @@ export var LoggedEntityType;
12
13
  LoggedEntityType["EULER"] = "EULER_VAULT";
13
14
  LoggedEntityType["UNISWAP_V4"] = "UNISWAP_V4";
14
15
  })(LoggedEntityType || (LoggedEntityType = {}));
16
+ async function computeCollatListAndReturnVaults(chainId, vaults) {
17
+ let vaultsPerChain = [];
18
+ /** Extra calls batch to get the collateral addresses */
19
+ const resCollat = await batchMulticallCallWithRetry(chainId, {
20
+ calls: vaults
21
+ .map(vault => vault.address)
22
+ .map(vaultAddress => {
23
+ return {
24
+ allowFailure: true,
25
+ callData: EulerVaultLensInterface.encodeFunctionData("getRecognizedCollateralsLTVInfo", [vaultAddress]),
26
+ target: EULER_ADDRESSES[chainId].VAULT_LENS,
27
+ };
28
+ }),
29
+ });
30
+ const callsCollatUnderlying = [];
31
+ const callsCollatUnderlyingSymbol = [];
32
+ for (const [index, vault] of vaults.entries()) {
33
+ const collatArray = EulerVaultLensInterface.decodeFunctionResult("getRecognizedCollateralsLTVInfo", resCollat[index].returnData)[0];
34
+ for (const collat of collatArray) {
35
+ if (!!vault.collaterals &&
36
+ vault.collaterals.map(c => c.address.toLowerCase()).includes(collat.collateral.toLowerCase()))
37
+ continue;
38
+ log.info(`🦭 found new collateral ${collat.collateral} for vault ${vault.address} (${NETWORK_LABELS[chainId]})`);
39
+ callsCollatUnderlying.push({
40
+ allowFailure: true,
41
+ callData: EulerEVKInterface.encodeFunctionData("asset"),
42
+ target: collat.collateral,
43
+ }, {
44
+ allowFailure: true,
45
+ callData: EulerEVKInterface.encodeFunctionData("symbol"),
46
+ target: collat.collateral,
47
+ });
48
+ }
49
+ }
50
+ const resCollatUnderlying = await batchMulticallCallWithRetry(chainId, {
51
+ calls: callsCollatUnderlying,
52
+ });
53
+ for (let i = 0; i < resCollatUnderlying.length; i = i + 2) {
54
+ const underlyingToken = EulerEVKInterface.decodeFunctionResult("asset", resCollatUnderlying[i].returnData)[0];
55
+ callsCollatUnderlyingSymbol.push({
56
+ allowFailure: true,
57
+ callData: ERC20Interface.encodeFunctionData("symbol"),
58
+ target: underlyingToken,
59
+ });
60
+ }
61
+ const resCollatUnderlyingSymbol = await batchMulticallCallWithRetry(chainId, {
62
+ calls: callsCollatUnderlyingSymbol,
63
+ });
64
+ vaultsPerChain = vaultsPerChain.concat((await Promise.all(vaults.map(async (vault, index) => {
65
+ const collatArray = EulerVaultLensInterface.decodeFunctionResult("getRecognizedCollateralsLTVInfo", resCollat[index].returnData)[0];
66
+ if (!vault.collaterals)
67
+ vault.collaterals = [];
68
+ let offset = 0;
69
+ for (const [_index, collat] of collatArray.entries()) {
70
+ // _ Check whether the collat was already registered
71
+ if (!!vault.collaterals &&
72
+ vault.collaterals.map(c => c.address.toLowerCase()).includes(collat.collateral.toLowerCase())) {
73
+ offset += 1;
74
+ continue;
75
+ }
76
+ const symbolUnderlying = ERC20Interface.decodeFunctionResult("symbol", resCollatUnderlyingSymbol[_index - offset].returnData)[0];
77
+ vault.collaterals.push({
78
+ address: collat.collateral,
79
+ symbolCollateral: EulerEVKInterface.decodeFunctionResult("symbol", resCollatUnderlying[2 * (_index - offset) + 1].returnData)[0],
80
+ symbolUnderlying,
81
+ borrowLTV: collat.borrowLTV.toString(),
82
+ nameCollateral: (await fetchEulerVaultName(collat.collateral, chainId)) ?? symbolUnderlying,
83
+ });
84
+ }
85
+ return { ...vault };
86
+ }))));
87
+ return vaultsPerChain;
88
+ }
15
89
  export async function getEulerV2Vaults() {
16
90
  let vaults = [];
17
91
  // 0_ Fetch all euler vaults from database
@@ -53,61 +127,7 @@ export async function getEulerV2Vaults() {
53
127
  };
54
128
  }));
55
129
  log.local(`fetched ${decodedVaults.length} vaults(s) on ${NETWORK_LABELS[chainId]} between blocks ${fromBlock} and ${toBlock}`);
56
- /** Extra calls batch to get the collateral addresses */
57
- const resCollat = await batchMulticallCallWithRetry(chainId, {
58
- calls: decodedVaults.map(vault => {
59
- return {
60
- allowFailure: true,
61
- callData: EulerVaultLensInterface.encodeFunctionData("getRecognizedCollateralsLTVInfo", [vault.address]),
62
- target: EULER_ADDRESSES[chainId].VAULT_LENS,
63
- };
64
- }),
65
- });
66
- const callsCollatUnderlying = [];
67
- const callsCollatUnderlyingSymbol = [];
68
- for (const [index, _] of decodedVaults.entries()) {
69
- const collatArray = EulerVaultLensInterface.decodeFunctionResult("getRecognizedCollateralsLTVInfo", resCollat[index].returnData)[0];
70
- for (const collat of collatArray) {
71
- callsCollatUnderlying.push({
72
- allowFailure: true,
73
- callData: EulerEVKInterface.encodeFunctionData("asset"),
74
- target: collat.collateral,
75
- }, {
76
- allowFailure: true,
77
- callData: EulerEVKInterface.encodeFunctionData("symbol"),
78
- target: collat.collateral,
79
- });
80
- }
81
- }
82
- const resCollatUnderlying = await batchMulticallCallWithRetry(chainId, {
83
- calls: callsCollatUnderlying,
84
- });
85
- for (let i = 0; i < resCollatUnderlying.length; i = i + 2) {
86
- const underlyingToken = EulerEVKInterface.decodeFunctionResult("asset", resCollatUnderlying[i].returnData)[0];
87
- callsCollatUnderlyingSymbol.push({
88
- allowFailure: true,
89
- callData: ERC20Interface.encodeFunctionData("symbol"),
90
- target: underlyingToken,
91
- });
92
- }
93
- const resCollatUnderlyingSymbol = await batchMulticallCallWithRetry(chainId, {
94
- calls: callsCollatUnderlyingSymbol,
95
- });
96
- vaultsPerChain = vaultsPerChain.concat((await Promise.all(decodedVaults.map(async (decodedVault, index) => {
97
- const collatArray = EulerVaultLensInterface.decodeFunctionResult("getRecognizedCollateralsLTVInfo", resCollat[index].returnData)[0];
98
- const collaterals = [];
99
- for (const [_index, collat] of collatArray.entries()) {
100
- const symbolUnderlying = ERC20Interface.decodeFunctionResult("symbol", resCollatUnderlyingSymbol[_index].returnData)[0];
101
- collaterals.push({
102
- address: collat.collateral,
103
- symbolCollateral: EulerEVKInterface.decodeFunctionResult("symbol", resCollatUnderlying[2 * _index + 1].returnData)[0],
104
- symbolUnderlying,
105
- borrowLTV: collat.borrowLTV.toString(),
106
- nameCollateral: (await fetchEulerVaultName(collat.collateral, chainId)) ?? symbolUnderlying,
107
- });
108
- }
109
- return { ...decodedVault, collaterals };
110
- }))));
130
+ vaultsPerChain = await computeCollatListAndReturnVaults(chainId, decodedVaults);
111
131
  return vaultsPerChain;
112
132
  }
113
133
  catch (e) {
@@ -140,8 +160,7 @@ export async function getEulerV2Vaults() {
140
160
  throw new Error("Error while saving vaults to API database (`Logged` table)");
141
161
  }
142
162
  }
143
- log.info("✅ successfully fetched vaults on Euler V2");
144
- // FIXME _ Merge previoulsy stored vaults with newly fetched ones
163
+ log.info("✅ successfully fetched new vaults on Euler V2");
145
164
  if (storedVaults.length > 0) {
146
165
  vaults = vaults.concat(storedVaults.map(v => v.entityData));
147
166
  }
@@ -149,3 +168,42 @@ export async function getEulerV2Vaults() {
149
168
  return vaults;
150
169
  }
151
170
  export const getEulerV2VaultsWithCache = async () => await Redis.getOrSet("EulerV2Vaults", getEulerV2Vaults);
171
+ export async function updateEulerVaultsCollatInDatabase() {
172
+ // 0_ Fetch all euler vaults from database
173
+ const vaults = await apiDbClient.logged.findMany({
174
+ where: { type: LoggedEntityType.EULER },
175
+ });
176
+ const clonedVaults = _.cloneDeep(vaults);
177
+ let toUpdateVaults = [];
178
+ // 1_ Return all vaults already stored with their collateral updated
179
+ const res = await Promise.all(eulerChainIds.map(async (chainId) => computeCollatListAndReturnVaults(chainId, clonedVaults.filter(entity => entity.chainId === chainId).map(entity => entity.entityData))));
180
+ for (const resPerChain of res) {
181
+ if (!!resPerChain && resPerChain.length > 0) {
182
+ toUpdateVaults = toUpdateVaults.concat(resPerChain.filter(updatedVault => {
183
+ return (updatedVault.collaterals.length >
184
+ vaults.find(vault => vault.address?.toLowerCase() === updatedVault.address.toLowerCase())
185
+ ?.entityData?.collaterals.length);
186
+ }));
187
+ }
188
+ }
189
+ // 2_ Update the API database
190
+ if (toUpdateVaults.length > 0) {
191
+ try {
192
+ for (const vault of toUpdateVaults) {
193
+ await apiDbClient.logged.updateMany({
194
+ where: {
195
+ address: vault.address,
196
+ chainId: vault.chainId,
197
+ },
198
+ data: {
199
+ entityData: vault,
200
+ },
201
+ });
202
+ }
203
+ log.info(`✅ successfully updated ${toUpdateVaults.length} vault(s) collaterals in API database ('Logged' table)`);
204
+ }
205
+ catch {
206
+ throw new Error("Error while updating vaults to API database (`Logged` table)");
207
+ }
208
+ }
209
+ }
@@ -2,7 +2,7 @@ import type { UploadOptions } from "./bucket.model";
2
2
  export declare class BucketService {
3
3
  #private;
4
4
  defaultUploadOptions: UploadOptions<unknown>;
5
- constructor(bucket: string);
5
+ constructor(bucket: string, projectId: string);
6
6
  pushArray<T>(filename: string, arr: T[], options?: UploadOptions<T>): Promise<number>;
7
7
  push(filename: string, text: string, options?: Omit<UploadOptions<never>, "transform">): Promise<number>;
8
8
  pullArray<T>(filename: string, callback: (elem: string) => T, separator?: string): Promise<T[]>;
@@ -17,14 +17,14 @@ export class BucketService {
17
17
  separator: "\n",
18
18
  };
19
19
  // ─── Constructor ─────────────────────────────────────────────────────
20
- constructor(bucket) {
20
+ constructor(bucket, projectId) {
21
21
  this.#s3Client = new S3Client({
22
22
  accessKeyId: process.env.GCS_ACCESS_ID,
23
23
  secretAccessKey: process.env.GCS_SECRET,
24
24
  endpoint: process.env.GCS_ENDPOINT,
25
25
  bucket,
26
26
  });
27
- this.#gcsBucket = new Storage().bucket(bucket);
27
+ this.#gcsBucket = new Storage({ projectId }).bucket(bucket);
28
28
  this.#encoder = new TextEncoder();
29
29
  this.#decoder = new TextDecoder();
30
30
  }
@@ -52,7 +52,7 @@ export class BucketService {
52
52
  data = gzipSync(data);
53
53
  // ─── ReadableStream Initialization From Blob ─────────────────
54
54
  const blob = new Blob([data]);
55
- const stream = blob.stream(50 * 1024 * 1024);
55
+ const stream = blob.stream();
56
56
  const reader = stream.getReader();
57
57
  // ─── Start Writing Data To Bucket ────────────────────────────
58
58
  if (options.overwrite && (await file.exists()))
@@ -74,7 +74,7 @@ export class BucketService {
74
74
  if (options.compression)
75
75
  await this.#gcsBucket.file(filename).setMetadata({ contentEncoding: "gzip" });
76
76
  if (options.isPublic)
77
- await this.#gcsBucket.makePublic();
77
+ await this.#gcsBucket.file(filename).makePublic();
78
78
  // ─── Return The Number Of Bytes Written ──────────────────────
79
79
  return bytes;
80
80
  }
@@ -92,7 +92,7 @@ export class BucketService {
92
92
  type: options.type,
93
93
  });
94
94
  const blob = new Blob([data]);
95
- const stream = blob.stream(50 * 1024 * 1024);
95
+ const stream = blob.stream();
96
96
  const reader = stream.getReader();
97
97
  if (options.overwrite && (await file.exists()))
98
98
  await file.delete();
@@ -114,7 +114,7 @@ export class BucketService {
114
114
  if (options.compression)
115
115
  await this.#gcsBucket.file(filename).setMetadata({ contentEncoding: "gzip" });
116
116
  if (options.isPublic)
117
- await this.#gcsBucket.makePublic();
117
+ await this.#gcsBucket.file(filename).makePublic();
118
118
  // ─── Return The Number Of Bytes Written ──────────────────────
119
119
  return bytes;
120
120
  }
@@ -18,7 +18,7 @@ export const getErc20Metadata = async (computeChainId, distributionChainId, camp
18
18
  campaignParameters: params,
19
19
  },
20
20
  ]);
21
- action = "HOLD"; // In case the protocol doesn't exist, initialize it to HOLD
21
+ action = dynamicData?.typeInfo?.action;
22
22
  name = dynamicData?.typeInfo?.cardName;
23
23
  mainProtocolId = dynamicData?.typeInfo?.protocol?.toLowerCase().replace(" ", "");
24
24
  const protocol = (await ProtocolService.findMany({ id: mainProtocolId }))?.[0];