@curvefi/llamalend-api 2.0.22 → 2.0.23

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.
@@ -0,0 +1,135 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { _getCrvUsdMarketsData } from "../../external-api.js";
11
+ import ERC20ABI from '../../constants/abis/ERC20.json' with { type: 'json' };
12
+ import llammaABI from "../../constants/abis/crvUSD/llamma.json" with { type: 'json' };
13
+ import controllerABI from "../../constants/abis/crvUSD/controller.json" with { type: 'json' };
14
+ import controllerV2ABI from "../../constants/abis/crvUSD/controller_v2.json";
15
+ import FactoryABI from "../../constants/abis/crvUSD/Factory.json" with { type: 'json' };
16
+ import MonetaryPolicy2ABI from "../../constants/abis/crvUSD/MonetaryPolicy2.json" with { type: 'json' };
17
+ export const fetchMintMarketsByAPI = (llamalend) => __awaiter(void 0, void 0, void 0, function* () {
18
+ if (llamalend.chainId !== 1)
19
+ return;
20
+ const data = yield _getCrvUsdMarketsData();
21
+ const existingControllers = new Set(Object.values(llamalend.constants.LLAMMAS).map((l) => l.controller_address));
22
+ const newMarkets = data.filter((m) => !existingControllers.has(m.address.toLowerCase()));
23
+ if (newMarkets.length === 0)
24
+ return;
25
+ const N1 = Object.keys(llamalend.constants.LLAMMAS).length;
26
+ const controllers = newMarkets.map((m) => m.address.toLowerCase());
27
+ const amms = newMarkets.map((m) => m.llamma.toLowerCase());
28
+ const collaterals = newMarkets.map((m) => m.collateral_token.address.toLowerCase());
29
+ for (const collateral of collaterals)
30
+ llamalend.setContract(collateral, ERC20ABI);
31
+ for (const amm of amms)
32
+ llamalend.setContract(amm, llammaABI);
33
+ for (const controller of controllers)
34
+ llamalend.setContract(controller, controllerABI);
35
+ for (let i = 0; i < newMarkets.length; i++) {
36
+ const market = newMarkets[i];
37
+ const collateral_address = collaterals[i];
38
+ const is_eth = collateral_address === llamalend.constants.WETH;
39
+ const collateral_symbol = market.collateral_token.symbol;
40
+ const monetary_policy_address = market.monetary_policy_address.toLowerCase();
41
+ llamalend.setContract(monetary_policy_address, MonetaryPolicy2ABI);
42
+ const _llammaId = is_eth ? "eth" : collateral_symbol.toLowerCase();
43
+ let llammaId = _llammaId;
44
+ let j = 2;
45
+ while (llammaId in llamalend.constants.LLAMMAS)
46
+ llammaId = _llammaId + j++;
47
+ llamalend.constants.LLAMMAS[llammaId] = {
48
+ amm_address: amms[i],
49
+ controller_address: controllers[i],
50
+ monetary_policy_address,
51
+ collateral_address: is_eth ? "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" : collateral_address,
52
+ leverage_zap: llamalend.constants.ALIASES.leverage_zap,
53
+ deleverage_zap: "0x0000000000000000000000000000000000000000",
54
+ collateral_symbol: is_eth ? "ETH" : collateral_symbol,
55
+ collateral_decimals: market.collateral_token.decimals,
56
+ min_bands: 4,
57
+ max_bands: 50,
58
+ default_bands: 10,
59
+ A: market.amm_a,
60
+ monetary_policy_abi: MonetaryPolicy2ABI,
61
+ is_deleverage_supported: true,
62
+ index: N1 + i,
63
+ };
64
+ }
65
+ });
66
+ export const fetchMintMarketsByBlockchain = (llamalend) => __awaiter(void 0, void 0, void 0, function* () {
67
+ if (llamalend.chainId !== 1)
68
+ return;
69
+ llamalend.setContract(llamalend.constants.FACTORY, FactoryABI);
70
+ const factoryContract = llamalend.contracts[llamalend.constants.FACTORY].contract;
71
+ const factoryMulticallContract = llamalend.contracts[llamalend.constants.FACTORY].multicallContract;
72
+ const N1 = Object.keys(llamalend.constants.LLAMMAS).length;
73
+ const N2 = yield factoryContract.n_collaterals(llamalend.constantOptions);
74
+ let calls = [];
75
+ for (let i = N1; i < N2; i++) {
76
+ calls.push(factoryMulticallContract.collaterals(i), factoryMulticallContract.amms(i), factoryMulticallContract.controllers(i));
77
+ }
78
+ const res = (yield llamalend.multicallProvider.all(calls)).map((c) => c.toLowerCase());
79
+ const collaterals = res.filter((a, i) => i % 3 == 0);
80
+ const amms = res.filter((a, i) => i % 3 == 1);
81
+ const controllers = res.filter((a, i) => i % 3 == 2);
82
+ if (collaterals.length === 0)
83
+ return;
84
+ for (const collateral of collaterals)
85
+ llamalend.setContract(collateral, ERC20ABI);
86
+ calls = [];
87
+ for (const collateral of collaterals) {
88
+ calls.push(llamalend.contracts[collateral].multicallContract.symbol(), llamalend.contracts[collateral].multicallContract.decimals());
89
+ }
90
+ const collateralData = (yield llamalend.multicallProvider.all(calls)).map((x) => {
91
+ if (typeof x === "string")
92
+ return x.toLowerCase();
93
+ return x;
94
+ });
95
+ calls = [];
96
+ for (const amm of amms) {
97
+ llamalend.setContract(amm, llammaABI);
98
+ calls.push(llamalend.contracts[amm].multicallContract.A());
99
+ }
100
+ const AParams = (yield llamalend.multicallProvider.all(calls)).map((x) => Number(x));
101
+ for (let i = 0; i < collaterals.length; i++) {
102
+ const is_eth = collaterals[i] === llamalend.constants.WETH;
103
+ const [collateral_symbol, collateral_decimals] = collateralData.splice(0, 2);
104
+ if (i >= collaterals.length - 3) {
105
+ llamalend.setContract(controllers[i], controllerV2ABI);
106
+ }
107
+ else {
108
+ llamalend.setContract(controllers[i], controllerABI);
109
+ }
110
+ const monetary_policy_address = (yield llamalend.contracts[controllers[i]].contract.monetary_policy(llamalend.constantOptions)).toLowerCase();
111
+ llamalend.setContract(monetary_policy_address, MonetaryPolicy2ABI);
112
+ const _llammaId = is_eth ? "eth" : collateral_symbol.toLowerCase();
113
+ let llammaId = _llammaId;
114
+ let j = 2;
115
+ while (llammaId in llamalend.constants.LLAMMAS)
116
+ llammaId = _llammaId + j++;
117
+ llamalend.constants.LLAMMAS[llammaId] = {
118
+ amm_address: amms[i],
119
+ controller_address: controllers[i],
120
+ monetary_policy_address,
121
+ collateral_address: is_eth ? "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" : collaterals[i],
122
+ leverage_zap: llamalend.constants.ALIASES.leverage_zap,
123
+ deleverage_zap: "0x0000000000000000000000000000000000000000",
124
+ collateral_symbol: is_eth ? "ETH" : collateral_symbol,
125
+ collateral_decimals,
126
+ min_bands: 4,
127
+ max_bands: 50,
128
+ default_bands: 10,
129
+ A: AParams[i],
130
+ monetary_policy_abi: MonetaryPolicy2ABI,
131
+ is_deleverage_supported: true,
132
+ index: N1 + i,
133
+ };
134
+ }
135
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curvefi/llamalend-api",
3
- "version": "2.0.22",
3
+ "version": "2.0.23",
4
4
  "description": "JavaScript library for Curve Lending",
5
5
  "main": "lib/index.js",
6
6
  "author": "Macket",
@@ -169,6 +169,34 @@ export const _getMarketsData = memoize(
169
169
  }
170
170
  )
171
171
 
172
+ export interface ICrvUsdMarketAPI {
173
+ address: string;
174
+ llamma: string;
175
+ amm_a: number;
176
+ monetary_policy_address: string;
177
+ collateral_token: {
178
+ symbol: string;
179
+ address: string;
180
+ decimals: number;
181
+ };
182
+ }
183
+
184
+ export const _getCrvUsdMarketsData = memoize(
185
+ async (): Promise<ICrvUsdMarketAPI[]> => {
186
+ const url = 'https://prices.curve.finance/v1/crvusd/markets/ethereum';
187
+ const response = await fetch(url, { headers: { "accept": "application/json" } });
188
+ if (response.status !== 200) {
189
+ throw Error(`Fetch error: ${response.status} ${response.statusText}`);
190
+ }
191
+ const { data } = await response.json() as { data: ICrvUsdMarketAPI[] };
192
+ return data;
193
+ },
194
+ {
195
+ promise: true,
196
+ maxAge: 10 * 1000, // 10s
197
+ }
198
+ )
199
+
172
200
  // --- ODOS ---
173
201
 
174
202
  export async function _getQuoteOdos(this: Llamalend, fromToken: string, toToken: string, _amount: bigint, blacklist: string, pathVizImage: boolean, slippage = 0.5): Promise<IQuoteOdos> {
@@ -214,18 +242,6 @@ export async function _assembleTxOdos(this: Llamalend, pathId: string): Promise<
214
242
  return _assembleTxOdosMemoized(this.constants.ALIASES.leverage_zap, pathId);
215
243
  }
216
244
 
217
- export const _getHiddenPools = memoize(
218
- async () => {
219
- const response = await fetch(`https://api.curve.finance/api/getHiddenPools`)
220
-
221
- return (await response.json() as any).data
222
- },
223
- {
224
- promise: true,
225
- maxAge: 5 * 60 * 1000, // 5m
226
- }
227
- )
228
-
229
245
  async function fetchJson(url: string): Promise<any> {
230
246
  const response = await fetch(url);
231
247
  return await response.json() ?? {};
package/src/index.ts CHANGED
@@ -86,12 +86,10 @@ export function createLlamalend() {
86
86
  getGasPriceFromL2: getGasPriceFromL2.bind(llamalend),
87
87
  getGasInfoForL2: getGasInfoForL2.bind(llamalend),
88
88
 
89
- // Core methods
90
- fetchStats: llamalend.fetchStats.bind(llamalend),
91
-
92
89
  // Market lists
93
90
  mintMarkets: {
94
91
  getMarketList: llamalend.getMintMarketList.bind(llamalend),
92
+ fetchMintMarkets: llamalend.fetchMintMarkets.bind(llamalend),
95
93
  },
96
94
  lendMarkets: {
97
95
  fetchMarkets: llamalend.fetchLendMarkets.bind(llamalend),
@@ -87,14 +87,6 @@ export const fetchOneWayMarketsByBlockchain = async (llamalend: Llamalend, versi
87
87
  }
88
88
 
89
89
  registerMarkets(llamalend, names, amms, controllers, borrowed_tokens, collateral_tokens, monetary_policies, vaults, gauges, COIN_DATA, version);
90
-
91
- if (version === 'v2') {
92
- llamalend.constants.ONE_WAY_MARKETS_V2 = await llamalend._filterHiddenMarkets(llamalend.constants.ONE_WAY_MARKETS_V2);
93
- } else {
94
- llamalend.constants.ONE_WAY_MARKETS = await llamalend._filterHiddenMarkets(llamalend.constants.ONE_WAY_MARKETS);
95
- }
96
-
97
- await llamalend.fetchStats(amms, controllers, vaults, borrowed_tokens, collateral_tokens, version);
98
90
  };
99
91
 
100
92
  export const fetchOneWayMarketsByAPI = async (llamalend: Llamalend, version: 'v1' | 'v2' = 'v1') => {
@@ -105,10 +97,4 @@ export const fetchOneWayMarketsByAPI = async (llamalend: Llamalend, version: 'v1
105
97
  }
106
98
 
107
99
  registerMarkets(llamalend, names, amms, controllers, borrowed_tokens, collateral_tokens, monetary_policies, vaults, gauges, COIN_DATA, version);
108
-
109
- if (version === 'v2') {
110
- llamalend.constants.ONE_WAY_MARKETS_V2 = await llamalend._filterHiddenMarkets(llamalend.constants.ONE_WAY_MARKETS_V2);
111
- } else {
112
- llamalend.constants.ONE_WAY_MARKETS = await llamalend._filterHiddenMarkets(llamalend.constants.ONE_WAY_MARKETS);
113
- }
114
100
  };
package/src/llamalend.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type TransactionRequest, ethers, Contract, Networkish, BigNumberish, Numeric, AbstractProvider } from "ethers";
1
+ import { type TransactionRequest, ethers, Contract, Networkish, BigNumberish, Numeric, AbstractProvider, BrowserProvider, Signer, JsonRpcProvider } from "ethers";
2
2
  import { Provider as MulticallProvider, Contract as MulticallContract, Call } from '@curvefi/ethcall';
3
3
  import {
4
4
  IChainId,
@@ -9,7 +9,6 @@ import {
9
9
  ICurveContract,
10
10
  IOneWayMarket,
11
11
  ICoin,
12
-
13
12
  } from "./interfaces.js";
14
13
  // OneWayMarket ABIs
15
14
  import OneWayLendingFactoryABI from "./constants/abis/OneWayLendingFactoryABI.json" with {type: 'json'};
@@ -26,10 +25,7 @@ import gasOracleBlobABI from './constants/abis/gas_oracle_optimism_blob.json' wi
26
25
  // crvUSD ABIs
27
26
  import llammaABI from "./constants/abis/crvUSD/llamma.json" with {type: 'json'};
28
27
  import controllerABI from "./constants/abis/crvUSD/controller.json" with {type: 'json'};
29
- import controllerV2ABI from "./constants/abis/crvUSD/controller_v2.json";
30
28
  import PegKeeper from "./constants/abis/crvUSD/PegKeeper.json" with {type: 'json'};
31
- import FactoryABI from "./constants/abis/crvUSD/Factory.json" with {type: 'json'};
32
- import MonetaryPolicy2ABI from "./constants/abis/crvUSD/MonetaryPolicy2.json" with {type: 'json'};
33
29
  import HealthCalculatorZapABI from "./constants/abis/crvUSD/HealthCalculatorZap.json" with {type: 'json'};
34
30
  import LeverageZapCrvUSDABI from "./constants/abis/crvUSD/LeverageZap.json" with {type: 'json'};
35
31
  import DeleverageZapABI from "./constants/abis/crvUSD/DeleverageZap.json" with {type: 'json'};
@@ -51,12 +47,36 @@ import {
51
47
  import {LLAMMAS} from "./constants/llammas.js";
52
48
  import {L2Networks} from "./constants/L2Networks.js";
53
49
  import {createCall, handleMultiCallResponse} from "./utils.js";
54
- import {cacheKey, cacheStats} from "./cache/index.js";
55
- import {_getMarketsData, _getHiddenPools} from "./external-api.js";
50
+ import {_getMarketsData, _getCrvUsdMarketsData} from "./external-api.js";
56
51
  import {extractDecimals} from "./constants/utils.js";
57
52
  import {MintMarketTemplate} from "./mintMarkets";
58
53
  import {LendMarketTemplate} from "./lendMarkets";
59
54
  import {fetchOneWayMarketsByBlockchain, fetchOneWayMarketsByAPI} from "./lendMarkets/fetch/fetchLendMarkets.js";
55
+ import {fetchMintMarketsByBlockchain, fetchMintMarketsByAPI} from "./mintMarkets/fetch/fetchMintMarkets.js";
56
+
57
+ const memoizeByAddress = <T, Args extends unknown[]>(
58
+ factory: (address: string, abi: any, ...args: Args) => T
59
+ ): () => (address: string, abi: any, ...args: Args) => T => {
60
+ return () => {
61
+ const cache: Record<string, T> = {};
62
+ return (address: string, abi: any, ...args: Args): T => {
63
+ if (address in cache) {
64
+ return cache[address];
65
+ }
66
+ const result = factory(address, abi, ...args);
67
+ cache[address] = result;
68
+ return result;
69
+ };
70
+ };
71
+ };
72
+
73
+ const memoizedContract = memoizeByAddress(
74
+ (address, abi, provider: BrowserProvider | JsonRpcProvider | Signer) => new Contract(address, abi, provider)
75
+ );
76
+
77
+ const memoizedMulticallContract = memoizeByAddress(
78
+ (address, abi) => new MulticallContract(address, abi)
79
+ );
60
80
 
61
81
  export const NETWORK_CONSTANTS: { [index: number]: any } = {
62
82
  1: {
@@ -190,52 +210,50 @@ class Llamalend implements ILlamalend {
190
210
  WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2".toLowerCase(),
191
211
  };
192
212
 
193
- // JsonRpc provider
213
+ let signerPromise: Promise<ethers.Signer | null>;
214
+
194
215
  if (providerType.toLowerCase() === 'JsonRpc'.toLowerCase()) {
195
216
  providerSettings = providerSettings as { url: string, privateKey: string, batchMaxCount? : number };
196
217
 
197
218
  let jsonRpcApiProviderOptions;
198
- if ( providerSettings.batchMaxCount ) {
199
- jsonRpcApiProviderOptions = {
200
- batchMaxCount: providerSettings.batchMaxCount,
201
- };
219
+ if (providerSettings.batchMaxCount) {
220
+ jsonRpcApiProviderOptions = { batchMaxCount: providerSettings.batchMaxCount };
202
221
  }
203
222
 
204
- if (providerSettings.url) {
205
- this.provider = new ethers.JsonRpcProvider(providerSettings.url, undefined, jsonRpcApiProviderOptions);
206
- } else {
207
- this.provider = new ethers.JsonRpcProvider('http://localhost:8545/', undefined, jsonRpcApiProviderOptions);
208
- }
223
+ this.provider = new ethers.JsonRpcProvider(
224
+ providerSettings.url || 'http://localhost:8545/',
225
+ undefined,
226
+ jsonRpcApiProviderOptions
227
+ );
209
228
 
210
229
  if (providerSettings.privateKey) {
211
- this.signer = new ethers.Wallet(providerSettings.privateKey, this.provider);
230
+ signerPromise = Promise.resolve(new ethers.Wallet(providerSettings.privateKey, this.provider));
212
231
  } else if (!providerSettings.url?.startsWith("https://rpc.gnosischain.com")) {
213
- try {
214
- this.signer = await this.provider.getSigner();
215
- } catch {
216
- this.signer = null;
217
- }
232
+ signerPromise = this.provider.getSigner().catch(() => null);
233
+ } else {
234
+ signerPromise = Promise.resolve(null);
218
235
  }
219
- // Web3 provider
220
236
  } else if (providerType.toLowerCase() === 'Web3'.toLowerCase()) {
221
237
  providerSettings = providerSettings as { externalProvider: ethers.Eip1193Provider };
222
238
  this.provider = new ethers.BrowserProvider(providerSettings.externalProvider);
223
- this.signer = await this.provider.getSigner();
224
- // Infura provider
239
+ signerPromise = this.provider.getSigner();
225
240
  } else if (providerType.toLowerCase() === 'Infura'.toLowerCase()) {
226
241
  providerSettings = providerSettings as { network?: Networkish, apiKey?: string };
227
242
  this.provider = new ethers.InfuraProvider(providerSettings.network, providerSettings.apiKey);
228
- this.signer = null;
229
- // Alchemy provider
243
+ signerPromise = Promise.resolve(null);
230
244
  } else if (providerType.toLowerCase() === 'Alchemy'.toLowerCase()) {
231
245
  providerSettings = providerSettings as { network?: Networkish, apiKey?: string };
232
246
  this.provider = new ethers.AlchemyProvider(providerSettings.network, providerSettings.apiKey);
233
- this.signer = null;
247
+ signerPromise = Promise.resolve(null);
234
248
  } else {
235
249
  throw Error('Wrong providerType');
236
250
  }
237
251
 
238
- const network = await this.provider.getNetwork();
252
+ const [signer, network] = await Promise.all([
253
+ signerPromise,
254
+ this.provider.getNetwork(),
255
+ ]);
256
+ this.signer = signer;
239
257
  this.chainId = Number(network.chainId) === 133 || Number(network.chainId) === 31337 ? 1 : Number(network.chainId) as IChainId;
240
258
  console.log("CURVE-LLAMALEND-JS IS CONNECTED TO NETWORK:", { name: network.name.toUpperCase(), chainId: Number(this.chainId) });
241
259
 
@@ -264,8 +282,6 @@ class Llamalend implements ILlamalend {
264
282
  }
265
283
 
266
284
  this.feeData = { gasPrice: options.gasPrice, maxFeePerGas: options.maxFeePerGas, maxPriorityFeePerGas: options.maxPriorityFeePerGas };
267
- await this.updateFeeData();
268
-
269
285
  // oneWayMarkets contracts
270
286
  this.setContract(this.constants.ALIASES['one_way_factory'], OneWayLendingFactoryABI);
271
287
  if(this.constants.ALIASES['one_way_factory_v2'] && this.constants.ALIASES['one_way_factory_v2'] !== this.constants.ZERO_ADDRESS) {
@@ -292,116 +308,6 @@ class Llamalend implements ILlamalend {
292
308
  }
293
309
  }
294
310
 
295
- // crvUSD contracts
296
- this.setContract(this.crvUsdAddress, ERC20ABI);
297
- if(this.chainId === 1) {
298
- this.setContract(this.constants.COINS.crvusd.toLowerCase(), ERC20ABI);
299
- for (const llamma of Object.values(this.constants.LLAMMAS)) {
300
- this.setContract(llamma.amm_address, llammaABI);
301
- this.setContract(llamma.controller_address, controllerABI);
302
- const monetary_policy_address = await this.contracts[llamma.controller_address].contract.monetary_policy(this.constantOptions);
303
- llamma.monetary_policy_address = monetary_policy_address.toLowerCase();
304
- this.setContract(llamma.monetary_policy_address, llamma.monetary_policy_abi);
305
- if (llamma.collateral_address === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") {
306
- this.setContract(this.constants.WETH, ERC20ABI);
307
- } else {
308
- this.setContract(llamma.collateral_address, ERC20ABI);
309
- }
310
- this.setContract(llamma.leverage_zap, LeverageZapCrvUSDABI);
311
- this.setContract(llamma.deleverage_zap, DeleverageZapABI);
312
- if (llamma.health_calculator_zap) this.setContract(llamma.health_calculator_zap, HealthCalculatorZapABI);
313
- }
314
- for (const pegKeeper of this.constants.PEG_KEEPERS) {
315
- this.setContract(pegKeeper, PegKeeper);
316
- }
317
- }
318
-
319
- // TODO Put it in a separate method
320
- // Fetch new llammas
321
- if(this.chainId === 1) {
322
- this.setContract(this.constants.FACTORY, FactoryABI);
323
- const factoryContract = this.contracts[this.constants.FACTORY].contract;
324
- const factoryMulticallContract = this.contracts[this.constants.FACTORY].multicallContract;
325
-
326
- const N1 = Object.keys(this.constants.LLAMMAS).length;
327
- const N2 = await factoryContract.n_collaterals(this.constantOptions);
328
- let calls = [];
329
- for (let i = N1; i < N2; i++) {
330
- calls.push(
331
- factoryMulticallContract.collaterals(i),
332
- factoryMulticallContract.amms(i),
333
- factoryMulticallContract.controllers(i)
334
- );
335
- }
336
- const res: string[] = (await this.multicallProvider.all(calls) as string[]).map((c) => c.toLowerCase());
337
- const collaterals = res.filter((a, i) => i % 3 == 0) as string[];
338
- const amms = res.filter((a, i) => i % 3 == 1) as string[];
339
- const controllers = res.filter((a, i) => i % 3 == 2) as string[];
340
-
341
- if (collaterals.length > 0) {
342
- for (const collateral of collaterals) this.setContract(collateral, ERC20ABI);
343
-
344
- calls = [];
345
- for (const collateral of collaterals) {
346
- calls.push(
347
- this.contracts[collateral].multicallContract.symbol(),
348
- this.contracts[collateral].multicallContract.decimals()
349
- )
350
- }
351
- const res = (await this.multicallProvider.all(calls)).map((x) => {
352
- if (typeof x === "string") return x.toLowerCase();
353
- return x;
354
- });
355
-
356
- calls = [];
357
-
358
- for(const amm of amms) {
359
- this.setContract(amm, llammaABI);
360
- calls.push(
361
- this.contracts[amm].multicallContract.A()
362
- )
363
- }
364
-
365
- const AParams = (await this.multicallProvider.all(calls)).map((x) => {
366
- return Number(x)
367
- });
368
-
369
- for (let i = 0; i < collaterals.length; i++) {
370
- const is_eth = collaterals[i] === this.constants.WETH;
371
- const [collateral_symbol, collateral_decimals] = res.splice(0, 2) as [string, number];
372
-
373
- if (i >= collaterals.length - 3) {
374
- this.setContract(controllers[i], controllerV2ABI);
375
- } else {
376
- this.setContract(controllers[i], controllerABI);
377
- }
378
-
379
- const monetary_policy_address = (await this.contracts[controllers[i]].contract.monetary_policy(this.constantOptions)).toLowerCase();
380
- this.setContract(monetary_policy_address, MonetaryPolicy2ABI);
381
- const _llammaId: string = is_eth ? "eth" : collateral_symbol.toLowerCase();
382
- let llammaId = _llammaId
383
- let j = 2;
384
- while (llammaId in this.constants.LLAMMAS) llammaId = _llammaId + j++;
385
- this.constants.LLAMMAS[llammaId] = {
386
- amm_address: amms[i],
387
- controller_address: controllers[i],
388
- monetary_policy_address,
389
- collateral_address: is_eth ? "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" : collaterals[i],
390
- leverage_zap: this.constants.ALIASES.leverage_zap,
391
- deleverage_zap: "0x0000000000000000000000000000000000000000",
392
- collateral_symbol: is_eth ? "ETH" : collateral_symbol,
393
- collateral_decimals,
394
- min_bands: 4,
395
- max_bands: 50,
396
- default_bands: 10,
397
- A: AParams[i],
398
- monetary_policy_abi: MonetaryPolicy2ABI,
399
- is_deleverage_supported: true,
400
- index: N1 + i,
401
- }
402
- }
403
- }
404
- }
405
311
 
406
312
  this.constants.DECIMALS = {
407
313
  ...extractDecimals(this.constants.LLAMMAS),
@@ -445,25 +351,85 @@ class Llamalend implements ILlamalend {
445
351
  AbstractProvider.prototype.estimateGas = AbstractProvider.prototype.originalEstimate as (_tx: TransactionRequest) => Promise<bigint>;
446
352
  }
447
353
  }
354
+
448
355
  }
449
356
 
450
- setContract(address: string, abi: any): void {
357
+ initContract = memoizedContract()
358
+ initMulticallContract = memoizedMulticallContract()
359
+
360
+ setContract(address: string | undefined, abi: any): void {
451
361
  if (address === this.constants.ZERO_ADDRESS || address === undefined) return;
452
- this.contracts[address] = {
453
- contract: new Contract(address, abi, this.signer || this.provider),
454
- multicallContract: new MulticallContract(address, abi),
455
- address: address,
456
- abi: abi,
362
+
363
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
364
+ const llamalendInstance = this;
365
+
366
+ const proxyHandler: ProxyHandler<any> = {
367
+ get: function(target: any, name: string) {
368
+ if(name === 'contract') {
369
+ return llamalendInstance.initContract(target['address'], target['abi'], llamalendInstance.signer || llamalendInstance.provider)
370
+ } else if(name === 'multicallContract') {
371
+ return llamalendInstance.initMulticallContract(target['address'], target['abi'])
372
+ } else {
373
+ return target[name];
374
+ }
375
+ },
457
376
  }
377
+
378
+ const coreContract = {
379
+ address,
380
+ abi,
381
+ }
382
+
383
+ this.contracts[address] = new Proxy(coreContract, proxyHandler)
458
384
  }
459
385
 
460
386
  setCustomFeeData(customFeeData: { gasPrice?: number, maxFeePerGas?: number, maxPriorityFeePerGas?: number }): void {
461
387
  this.feeData = { ...this.feeData, ...customFeeData };
462
388
  }
463
389
 
464
- async _filterHiddenMarkets(markets: IDict<IOneWayMarket>): Promise<IDict<IOneWayMarket>> {
465
- const hiddenMarkets = (await _getHiddenPools() as any)[this.constants.NETWORK_NAME] || [];
466
- return Object.fromEntries(Object.entries(markets).filter(([id]) => !hiddenMarkets.includes(id))) as IDict<IOneWayMarket>;
390
+ async _setupMintMarketContracts(useApi = true): Promise<void> {
391
+ this.setContract(this.crvUsdAddress, ERC20ABI);
392
+ if (this.chainId !== 1) return;
393
+
394
+ this.setContract(this.constants.COINS.crvusd.toLowerCase(), ERC20ABI);
395
+
396
+ const llammas = Object.values(this.constants.LLAMMAS);
397
+ for (const llamma of llammas) {
398
+ this.setContract(llamma.amm_address, llammaABI);
399
+ this.setContract(llamma.controller_address, controllerABI);
400
+ }
401
+
402
+ if (useApi) {
403
+ const apiData = await _getCrvUsdMarketsData();
404
+ const monetaryPolicyMap = new Map(
405
+ apiData.map((m) => [m.address.toLowerCase(), m.monetary_policy_address.toLowerCase()])
406
+ );
407
+ for (const llamma of llammas) {
408
+ const fresh = monetaryPolicyMap.get(llamma.controller_address);
409
+ if (fresh) llamma.monetary_policy_address = fresh;
410
+ }
411
+ } else {
412
+ const monetaryPolicies = (await this.multicallProvider.all(
413
+ llammas.map((l) => this.contracts[l.controller_address].multicallContract.monetary_policy())
414
+ ) as string[]).map((a) => a.toLowerCase());
415
+ llammas.forEach((llamma, i) => { llamma.monetary_policy_address = monetaryPolicies[i]; });
416
+ }
417
+
418
+ for (const llamma of llammas) {
419
+ this.setContract(llamma.monetary_policy_address, llamma.monetary_policy_abi);
420
+ if (llamma.collateral_address === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") {
421
+ this.setContract(this.constants.WETH, ERC20ABI);
422
+ } else {
423
+ this.setContract(llamma.collateral_address, ERC20ABI);
424
+ }
425
+ this.setContract(llamma.leverage_zap, LeverageZapCrvUSDABI);
426
+ this.setContract(llamma.deleverage_zap, DeleverageZapABI);
427
+ if (llamma.health_calculator_zap) this.setContract(llamma.health_calculator_zap, HealthCalculatorZapABI);
428
+ }
429
+
430
+ for (const pegKeeper of this.constants.PEG_KEEPERS) {
431
+ this.setContract(pegKeeper, PegKeeper);
432
+ }
467
433
  }
468
434
 
469
435
  getLendMarketList = () => Object.keys({...this.constants.ONE_WAY_MARKETS, ...this.constants.ONE_WAY_MARKETS_V2});
@@ -482,6 +448,13 @@ class Llamalend implements ILlamalend {
482
448
  }
483
449
  }
484
450
 
451
+ fetchMintMarkets = async ({ useApi = true }: { useApi?: boolean } = {}): Promise<void> => {
452
+ await Promise.all([
453
+ this._setupMintMarketContracts(useApi),
454
+ useApi ? fetchMintMarketsByAPI(this) : fetchMintMarketsByBlockchain(this),
455
+ ]);
456
+ }
457
+
485
458
  getCoins = async (collateral_tokens: string[], borrowed_tokens: string[], useApi = false): Promise<IDict<ICoin>> => {
486
459
  const coins = new Set([...collateral_tokens, ...borrowed_tokens]);
487
460
  const COINS_DATA: IDict<ICoin> = {};
@@ -539,54 +512,6 @@ class Llamalend implements ILlamalend {
539
512
  return COINS_DATA;
540
513
  }
541
514
 
542
-
543
- fetchStats = async (amms: string[], controllers: string[], vaults: string[], borrowed_tokens: string[], collateral_tokens: string[], version: 'v1' | 'v2' = 'v1') => {
544
- cacheStats.clear();
545
-
546
- const marketCount = controllers.length;
547
-
548
- const calls: Call[] = [];
549
-
550
- for (let i = 0; i < marketCount; i++) {
551
- calls.push(createCall(this.contracts[controllers[i]], 'total_debt', []));
552
- calls.push(createCall(this.contracts[vaults[i]], 'totalAssets', []));
553
- calls.push(createCall(this.contracts[borrowed_tokens[i]], 'balanceOf', [controllers[i]]));
554
- calls.push(createCall(this.contracts[amms[i]], 'rate', []));
555
- calls.push(createCall(this.contracts[borrowed_tokens[i]], 'balanceOf', [amms[i]]));
556
-
557
- if (version === 'v1') {
558
- calls.push(createCall(this.contracts[amms[i]], 'admin_fees_x', []));
559
- calls.push(createCall(this.contracts[amms[i]], 'admin_fees_y', []));
560
- }
561
-
562
- calls.push(createCall(this.contracts[collateral_tokens[i]], 'balanceOf', [amms[i]]));
563
- }
564
-
565
- const res = await this.multicallProvider.all(calls);
566
-
567
- for (let i = 0; i < marketCount; i++) {
568
- if (version === 'v1') {
569
- cacheStats.set(cacheKey(controllers[i], 'total_debt'), res[(i * 8) + 0]);
570
- cacheStats.set(cacheKey(vaults[i], 'totalAssets', controllers[i]), res[(i * 8) + 1]);
571
- cacheStats.set(cacheKey(borrowed_tokens[i], 'balanceOf', controllers[i]), res[(i * 8) + 2]);
572
- cacheStats.set(cacheKey(amms[i], 'rate'), res[(i * 8) + 3]);
573
- cacheStats.set(cacheKey(borrowed_tokens[i], 'balanceOf', amms[i]), res[(i * 8) + 4]);
574
- cacheStats.set(cacheKey(amms[i], 'admin_fees_x'), res[(i * 8) + 5]);
575
- cacheStats.set(cacheKey(amms[i], 'admin_fees_y'), res[(i * 8) + 6]);
576
- cacheStats.set(cacheKey(collateral_tokens[i], 'balanceOf', amms[i]), res[(i * 8) + 7]);
577
- } else {
578
- cacheStats.set(cacheKey(controllers[i], 'total_debt'), res[(i * 6) + 0]);
579
- cacheStats.set(cacheKey(vaults[i], 'totalAssets', controllers[i]), res[(i * 6) + 1]);
580
- cacheStats.set(cacheKey(borrowed_tokens[i], 'balanceOf', controllers[i]), res[(i * 6) + 2]);
581
- cacheStats.set(cacheKey(amms[i], 'rate'), res[(i * 6) + 3]);
582
- cacheStats.set(cacheKey(borrowed_tokens[i], 'balanceOf', amms[i]), res[(i * 6) + 4]);
583
- cacheStats.set(cacheKey(amms[i], 'admin_fees_x'), BigInt(0)); // Always 0 for v2
584
- cacheStats.set(cacheKey(amms[i], 'admin_fees_y'), BigInt(0)); // Always 0 for v2
585
- cacheStats.set(cacheKey(collateral_tokens[i], 'balanceOf', amms[i]), res[(i * 6) + 5]);
586
- }
587
- }
588
- };
589
-
590
515
  formatUnits(value: BigNumberish, unit?: string | Numeric): string {
591
516
  return ethers.formatUnits(value, unit);
592
517
  }