@merkl/api 0.20.2 → 0.20.4

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.
@@ -4,5 +4,4 @@ export declare enum LoggedEntityType {
4
4
  UNISWAP_V4 = "UNISWAP_V4"
5
5
  }
6
6
  export declare function getEulerV2Vaults(): Promise<EulerVaultType[]>;
7
- export declare const getEulerV2VaultsWithCache: () => Promise<EulerVaultType[]>;
8
7
  export declare function updateEulerVaultsCollatInDatabase(): Promise<void>;
@@ -1,7 +1,6 @@
1
- import { Redis } from "@/cache";
2
1
  import { fetchEulerVaultName } from "@/engine/erc20SubTypeProcessors/helpers/eulerVaultNames";
3
2
  import { batchMulticallCallWithRetry } from "@/utils/generic";
4
- import { log } from "@/utils/logger";
3
+ import { log, logger } from "@/utils/logger";
5
4
  import { providers } from "@/utils/providers";
6
5
  import { apiDbClient } from "@db";
7
6
  import { ChainInteractionService, ERC20Interface, EULER_ADDRESSES, EulerEVKInterface, EulerVaultLensInterface, EulerVault__factory, NETWORK_LABELS, eulerChainIds, getContractCreationBlock, } from "@sdk";
@@ -27,59 +26,93 @@ async function computeCollatListAndReturnVaults(chainId, vaults) {
27
26
  };
28
27
  }),
29
28
  });
30
- const callsCollatUnderlying = [];
31
- const callsCollatUnderlyingSymbol = [];
29
+ const callsToCollat = [];
30
+ const callsToCollatUnderlying = [];
31
+ // To keep track of all collat data
32
+ const collateralDataArray = [];
33
+ let k = 0;
32
34
  for (const [index, vault] of vaults.entries()) {
33
35
  const collatArray = EulerVaultLensInterface.decodeFunctionResult("getRecognizedCollateralsLTVInfo", resCollat[index].returnData)[0];
34
36
  for (const collat of collatArray) {
37
+ // FIXME
35
38
  if (!!vault.collaterals &&
36
- vault.collaterals.map(c => c.address.toLowerCase()).includes(collat.collateral.toLowerCase()))
39
+ vault.collaterals.map(c => c.address.toLowerCase()).includes(collat.collateral.toLowerCase())) {
37
40
  continue;
41
+ }
38
42
  log.info(`🦭 found new collateral ${collat.collateral} for vault ${vault.address} (${NETWORK_LABELS[chainId]})`);
39
- callsCollatUnderlying.push({
43
+ collateralDataArray.push({ vaultAddress: vault.address, address: collat.collateral, callsToCollatIndex: k });
44
+ k++;
45
+ callsToCollat.push({
40
46
  allowFailure: true,
41
- callData: EulerEVKInterface.encodeFunctionData("asset"),
47
+ callData: EulerEVKInterface.encodeFunctionData("symbol"),
42
48
  target: collat.collateral,
43
49
  }, {
44
50
  allowFailure: true,
45
- callData: EulerEVKInterface.encodeFunctionData("symbol"),
51
+ callData: EulerEVKInterface.encodeFunctionData("asset"),
46
52
  target: collat.collateral,
47
53
  });
48
54
  }
49
55
  }
50
- const resCollatUnderlying = await batchMulticallCallWithRetry(chainId, {
51
- calls: callsCollatUnderlying,
56
+ const resCallsToCollat = await batchMulticallCallWithRetry(chainId, {
57
+ calls: callsToCollat,
52
58
  });
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
+ let j = 0;
60
+ for (let i = 0; i < resCallsToCollat.length; i = i + 2) {
61
+ const collatData = collateralDataArray.find(collat => collat.callsToCollatIndex === i / 2);
62
+ try {
63
+ // 1_ Collat symbol
64
+ const symbolCollateral = EulerEVKInterface.decodeFunctionResult("symbol", resCallsToCollat[i].returnData)[0];
65
+ collatData.symbolCollateral = symbolCollateral;
66
+ // 2_ Underlying asset => warning it can be undefined and throw an error
67
+ const underlyingToken = EulerEVKInterface.decodeFunctionResult("asset", resCallsToCollat[i + 1].returnData)[0];
68
+ callsToCollatUnderlying.push({
69
+ allowFailure: true,
70
+ callData: ERC20Interface.encodeFunctionData("symbol"),
71
+ target: underlyingToken,
72
+ });
73
+ collatData.callsToCollatUnderlyingIndex = j;
74
+ j++;
75
+ }
76
+ catch {
77
+ logger.warn(`🦭 error while decoding underlying token address for collat ${JSON.stringify(collatData)}`);
78
+ }
79
+ }
80
+ let resCallsToCollatUnderlying;
81
+ if (callsToCollatUnderlying.length > 0) {
82
+ resCallsToCollatUnderlying = await batchMulticallCallWithRetry(chainId, {
83
+ calls: callsToCollatUnderlying,
59
84
  });
60
85
  }
61
- const resCollatUnderlyingSymbol = await batchMulticallCallWithRetry(chainId, {
62
- calls: callsCollatUnderlyingSymbol,
63
- });
64
86
  vaultsPerChain = vaultsPerChain.concat((await Promise.all(vaults.map(async (vault, index) => {
65
87
  const collatArray = EulerVaultLensInterface.decodeFunctionResult("getRecognizedCollateralsLTVInfo", resCollat[index].returnData)[0];
66
88
  if (!vault.collaterals)
67
89
  vault.collaterals = [];
68
- let offset = 0;
69
90
  for (const [_index, collat] of collatArray.entries()) {
70
91
  // _ Check whether the collat was already registered
71
92
  if (!!vault.collaterals &&
72
93
  vault.collaterals.map(c => c.address.toLowerCase()).includes(collat.collateral.toLowerCase())) {
73
- offset += 1;
74
94
  continue;
75
95
  }
76
- const symbolUnderlying = ERC20Interface.decodeFunctionResult("symbol", resCollatUnderlyingSymbol[_index - offset].returnData)[0];
96
+ const collatData = collateralDataArray.find(c => c.vaultAddress?.toLowerCase() === vault.address?.toLowerCase() && c.address === collat.collateral);
97
+ if (!collatData || collatData.address !== collat.collateral) {
98
+ logger.warn(`🦭 issue when fetching data for collat ${collat.collateral} on vault ${vault.address}`);
99
+ console.log(collatData, collat.collateral);
100
+ process.exit(1);
101
+ }
102
+ // Collateral symbol
103
+ const symbolCollateral = collatData.symbolCollateral ?? "Unknown";
104
+ // Collat underlying symbol
105
+ let symbolUnderlying = "Unknown";
106
+ try {
107
+ symbolUnderlying = ERC20Interface.decodeFunctionResult("symbol", resCallsToCollatUnderlying[collatData.callsToCollatUnderlyingIndex ?? -1].returnData)[0];
108
+ }
109
+ catch { }
77
110
  vault.collaterals.push({
78
111
  address: collat.collateral,
79
- symbolCollateral: EulerEVKInterface.decodeFunctionResult("symbol", resCollatUnderlying[2 * (_index - offset) + 1].returnData)[0],
80
- symbolUnderlying,
112
+ symbolCollateral: symbolCollateral,
113
+ symbolUnderlying: symbolUnderlying,
81
114
  borrowLTV: collat.borrowLTV.toString(),
82
- nameCollateral: (await fetchEulerVaultName(collat.collateral, chainId)) ?? symbolUnderlying,
115
+ nameCollateral: (await fetchEulerVaultName(collat.collateral, chainId)) ?? symbolCollateral,
83
116
  });
84
117
  }
85
118
  return { ...vault };
@@ -113,20 +146,26 @@ export async function getEulerV2Vaults() {
113
146
  }
114
147
  const logs = await safeFetchLogs(chainId, [EulerEVKInterface.getEventTopic("EVaultCreated")], [], fromBlock, toBlock);
115
148
  const decodedVaults = await Promise.all(logs.map(async (log) => {
116
- const aux = EulerEVKInterface.decodeEventLog("EVaultCreated", log.data, log.topics);
117
- const name = (await EulerVault__factory.connect(log.address, providers[chainId]).name()).split(" ");
118
- const vaultName = (await fetchEulerVaultName(getAddress(log.address), chainId)) ?? name[name.length - 1];
119
- /** Respect the previous typing */
120
- return {
121
- address: log.address.toString(),
122
- asset: aux[1].toString(),
123
- fetchedAtBlock: Number(log.blockNumber),
124
- chainId: chainId,
125
- debtTokenAddress: aux[2].toString(),
126
- name: vaultName,
127
- };
149
+ try {
150
+ const aux = EulerEVKInterface.decodeEventLog("EVaultCreated", log.data, log.topics);
151
+ const name = (await EulerVault__factory.connect(log.address, providers[chainId]).name()).split(" ");
152
+ const vaultName = (await fetchEulerVaultName(getAddress(log.address), chainId)) ?? name[name.length - 1];
153
+ /** Respect the previous typing */
154
+ return {
155
+ address: log.address.toString(),
156
+ asset: aux[1].toString(),
157
+ fetchedAtBlock: Number(log.blockNumber),
158
+ chainId: chainId,
159
+ debtTokenAddress: aux[2].toString(),
160
+ name: vaultName,
161
+ };
162
+ }
163
+ catch {
164
+ logger.warn(`issue when fetching data on ${NETWORK_LABELS[chainId]} for vault ${log.address}`);
165
+ process.exit(1);
166
+ }
128
167
  }));
129
- log.local(`fetched ${decodedVaults.length} vaults(s) on ${NETWORK_LABELS[chainId]} between blocks ${fromBlock} and ${toBlock}`);
168
+ log.info(`fetched ${decodedVaults.length} vaults(s) on ${NETWORK_LABELS[chainId]} between blocks ${fromBlock} and ${toBlock}`);
130
169
  vaultsPerChain = await computeCollatListAndReturnVaults(chainId, decodedVaults);
131
170
  return vaultsPerChain;
132
171
  }
@@ -160,14 +199,12 @@ export async function getEulerV2Vaults() {
160
199
  throw new Error("Error while saving vaults to API database (`Logged` table)");
161
200
  }
162
201
  }
163
- log.info("✅ successfully fetched new vaults on Euler V2");
164
202
  if (storedVaults.length > 0) {
165
203
  vaults = vaults.concat(storedVaults.map(v => v.entityData));
166
204
  }
167
205
  log.info("👋 exiting getEulerV2Vaults");
168
206
  return vaults;
169
207
  }
170
- export const getEulerV2VaultsWithCache = async () => await Redis.getOrSet("EulerV2Vaults", getEulerV2Vaults);
171
208
  export async function updateEulerVaultsCollatInDatabase() {
172
209
  // 0_ Fetch all euler vaults from database
173
210
  const vaults = await apiDbClient.logged.findMany({
@@ -1,4 +1,5 @@
1
1
  import { generateCardName } from "@/utils/generateCardName";
2
+ import { log } from "@/utils/logger";
2
3
  import { BN2Number } from "@sdk";
3
4
  import { GenericProcessor } from "../GenericProcessor";
4
5
  import { fetchEulerVaultName } from "../helpers/eulerVaultNames";
@@ -18,8 +19,12 @@ export class EulerLendProcessor extends GenericProcessor {
18
19
  async processingRound5(index, type, typeInfo, calls, campaign, pricer) {
19
20
  const { whitelistedSupplyTargetToken, totalSupply, blacklistedSupply } = this.handleWhiteListBlacklistRound5(typeInfo, campaign);
20
21
  const symbolAsset = campaign.campaignParameters.symbolAsset;
21
- const decimalsAsset = Number(campaign.campaignParameters.decimalsAsset);
22
+ let decimalsAsset = Number(campaign.campaignParameters.decimalsAsset) ?? 18;
22
23
  const priceAsset = (await pricer.get({ symbol: symbolAsset })) ?? 1;
24
+ if (Number.isNaN(decimalsAsset)) {
25
+ log.warn(`decimalsAsset is NaN for ${symbolAsset} on campaign ${campaign.campaignId}`);
26
+ decimalsAsset = 18;
27
+ }
23
28
  const totalAssets = BN2Number(typeInfo.totalAssets, decimalsAsset);
24
29
  typeInfo.symbolUnderlyingToken = symbolAsset;
25
30
  let cardName = generateCardName(type, typeInfo, campaign);