@curvefi/llamalend-api 2.0.22 → 2.0.24

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,138 @@
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
+ import { extractDecimals } from "../../constants/utils.js";
18
+ export const fetchMintMarketsByAPI = (llamalend) => __awaiter(void 0, void 0, void 0, function* () {
19
+ if (llamalend.chainId !== 1)
20
+ return;
21
+ const data = yield _getCrvUsdMarketsData();
22
+ const existingControllers = new Set(Object.values(llamalend.constants.LLAMMAS).map((l) => l.controller_address));
23
+ const newMarkets = data.filter((m) => !existingControllers.has(m.address.toLowerCase()));
24
+ if (newMarkets.length === 0)
25
+ return;
26
+ const N1 = Object.keys(llamalend.constants.LLAMMAS).length;
27
+ const controllers = newMarkets.map((m) => m.address.toLowerCase());
28
+ const amms = newMarkets.map((m) => m.llamma.toLowerCase());
29
+ const collaterals = newMarkets.map((m) => m.collateral_token.address.toLowerCase());
30
+ for (const collateral of collaterals)
31
+ llamalend.setContract(collateral, ERC20ABI);
32
+ for (const amm of amms)
33
+ llamalend.setContract(amm, llammaABI);
34
+ for (const controller of controllers)
35
+ llamalend.setContract(controller, controllerABI);
36
+ for (let i = 0; i < newMarkets.length; i++) {
37
+ const market = newMarkets[i];
38
+ const collateral_address = collaterals[i];
39
+ const is_eth = collateral_address === llamalend.constants.WETH;
40
+ const collateral_symbol = market.collateral_token.symbol;
41
+ const monetary_policy_address = market.monetary_policy_address.toLowerCase();
42
+ llamalend.setContract(monetary_policy_address, MonetaryPolicy2ABI);
43
+ const _llammaId = is_eth ? "eth" : collateral_symbol.toLowerCase();
44
+ let llammaId = _llammaId;
45
+ let j = 2;
46
+ while (llammaId in llamalend.constants.LLAMMAS)
47
+ llammaId = _llammaId + j++;
48
+ llamalend.constants.LLAMMAS[llammaId] = {
49
+ amm_address: amms[i],
50
+ controller_address: controllers[i],
51
+ monetary_policy_address,
52
+ collateral_address: is_eth ? "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" : collateral_address,
53
+ leverage_zap: llamalend.constants.ALIASES.leverage_zap,
54
+ deleverage_zap: "0x0000000000000000000000000000000000000000",
55
+ collateral_symbol: is_eth ? "ETH" : collateral_symbol,
56
+ collateral_decimals: market.collateral_token.decimals,
57
+ min_bands: 4,
58
+ max_bands: 50,
59
+ default_bands: 10,
60
+ A: market.amm_a,
61
+ monetary_policy_abi: MonetaryPolicy2ABI,
62
+ is_deleverage_supported: true,
63
+ index: N1 + i,
64
+ };
65
+ }
66
+ llamalend.constants.DECIMALS = Object.assign(Object.assign({}, llamalend.constants.DECIMALS), extractDecimals(llamalend.constants.LLAMMAS));
67
+ });
68
+ export const fetchMintMarketsByBlockchain = (llamalend) => __awaiter(void 0, void 0, void 0, function* () {
69
+ if (llamalend.chainId !== 1)
70
+ return;
71
+ llamalend.setContract(llamalend.constants.FACTORY, FactoryABI);
72
+ const factoryContract = llamalend.contracts[llamalend.constants.FACTORY].contract;
73
+ const factoryMulticallContract = llamalend.contracts[llamalend.constants.FACTORY].multicallContract;
74
+ const N1 = Object.keys(llamalend.constants.LLAMMAS).length;
75
+ const N2 = yield factoryContract.n_collaterals(llamalend.constantOptions);
76
+ let calls = [];
77
+ for (let i = N1; i < N2; i++) {
78
+ calls.push(factoryMulticallContract.collaterals(i), factoryMulticallContract.amms(i), factoryMulticallContract.controllers(i));
79
+ }
80
+ const res = (yield llamalend.multicallProvider.all(calls)).map((c) => c.toLowerCase());
81
+ const collaterals = res.filter((a, i) => i % 3 == 0);
82
+ const amms = res.filter((a, i) => i % 3 == 1);
83
+ const controllers = res.filter((a, i) => i % 3 == 2);
84
+ if (collaterals.length === 0)
85
+ return;
86
+ for (const collateral of collaterals)
87
+ llamalend.setContract(collateral, ERC20ABI);
88
+ calls = [];
89
+ for (const collateral of collaterals) {
90
+ calls.push(llamalend.contracts[collateral].multicallContract.symbol(), llamalend.contracts[collateral].multicallContract.decimals());
91
+ }
92
+ const collateralData = (yield llamalend.multicallProvider.all(calls)).map((x) => {
93
+ if (typeof x === "string")
94
+ return x.toLowerCase();
95
+ return x;
96
+ });
97
+ calls = [];
98
+ for (const amm of amms) {
99
+ llamalend.setContract(amm, llammaABI);
100
+ calls.push(llamalend.contracts[amm].multicallContract.A());
101
+ }
102
+ const AParams = (yield llamalend.multicallProvider.all(calls)).map((x) => Number(x));
103
+ for (let i = 0; i < collaterals.length; i++) {
104
+ const is_eth = collaterals[i] === llamalend.constants.WETH;
105
+ const [collateral_symbol, collateral_decimals] = collateralData.splice(0, 2);
106
+ if (i >= collaterals.length - 3) {
107
+ llamalend.setContract(controllers[i], controllerV2ABI);
108
+ }
109
+ else {
110
+ llamalend.setContract(controllers[i], controllerABI);
111
+ }
112
+ const monetary_policy_address = (yield llamalend.contracts[controllers[i]].contract.monetary_policy(llamalend.constantOptions)).toLowerCase();
113
+ llamalend.setContract(monetary_policy_address, MonetaryPolicy2ABI);
114
+ const _llammaId = is_eth ? "eth" : collateral_symbol.toLowerCase();
115
+ let llammaId = _llammaId;
116
+ let j = 2;
117
+ while (llammaId in llamalend.constants.LLAMMAS)
118
+ llammaId = _llammaId + j++;
119
+ llamalend.constants.LLAMMAS[llammaId] = {
120
+ amm_address: amms[i],
121
+ controller_address: controllers[i],
122
+ monetary_policy_address,
123
+ collateral_address: is_eth ? "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" : collaterals[i],
124
+ leverage_zap: llamalend.constants.ALIASES.leverage_zap,
125
+ deleverage_zap: "0x0000000000000000000000000000000000000000",
126
+ collateral_symbol: is_eth ? "ETH" : collateral_symbol,
127
+ collateral_decimals,
128
+ min_bands: 4,
129
+ max_bands: 50,
130
+ default_bands: 10,
131
+ A: AParams[i],
132
+ monetary_policy_abi: MonetaryPolicy2ABI,
133
+ is_deleverage_supported: true,
134
+ index: N1 + i,
135
+ };
136
+ }
137
+ llamalend.constants.DECIMALS = Object.assign(Object.assign({}, llamalend.constants.DECIMALS), extractDecimals(llamalend.constants.LLAMMAS));
138
+ });
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.24",
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,35 @@ 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";
56
- import {extractDecimals} from "./constants/utils.js";
50
+ import {_getMarketsData, _getCrvUsdMarketsData} from "./external-api.js";
57
51
  import {MintMarketTemplate} from "./mintMarkets";
58
52
  import {LendMarketTemplate} from "./lendMarkets";
59
53
  import {fetchOneWayMarketsByBlockchain, fetchOneWayMarketsByAPI} from "./lendMarkets/fetch/fetchLendMarkets.js";
54
+ import {fetchMintMarketsByBlockchain, fetchMintMarketsByAPI} from "./mintMarkets/fetch/fetchMintMarkets.js";
55
+
56
+ const memoizeByAddress = <T, Args extends unknown[]>(
57
+ factory: (address: string, abi: any, ...args: Args) => T
58
+ ): () => (address: string, abi: any, ...args: Args) => T => {
59
+ return () => {
60
+ const cache: Record<string, T> = {};
61
+ return (address: string, abi: any, ...args: Args): T => {
62
+ if (address in cache) {
63
+ return cache[address];
64
+ }
65
+ const result = factory(address, abi, ...args);
66
+ cache[address] = result;
67
+ return result;
68
+ };
69
+ };
70
+ };
71
+
72
+ const memoizedContract = memoizeByAddress(
73
+ (address, abi, provider: BrowserProvider | JsonRpcProvider | Signer) => new Contract(address, abi, provider)
74
+ );
75
+
76
+ const memoizedMulticallContract = memoizeByAddress(
77
+ (address, abi) => new MulticallContract(address, abi)
78
+ );
60
79
 
61
80
  export const NETWORK_CONSTANTS: { [index: number]: any } = {
62
81
  1: {
@@ -190,52 +209,50 @@ class Llamalend implements ILlamalend {
190
209
  WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2".toLowerCase(),
191
210
  };
192
211
 
193
- // JsonRpc provider
212
+ let signerPromise: Promise<ethers.Signer | null>;
213
+
194
214
  if (providerType.toLowerCase() === 'JsonRpc'.toLowerCase()) {
195
215
  providerSettings = providerSettings as { url: string, privateKey: string, batchMaxCount? : number };
196
216
 
197
217
  let jsonRpcApiProviderOptions;
198
- if ( providerSettings.batchMaxCount ) {
199
- jsonRpcApiProviderOptions = {
200
- batchMaxCount: providerSettings.batchMaxCount,
201
- };
218
+ if (providerSettings.batchMaxCount) {
219
+ jsonRpcApiProviderOptions = { batchMaxCount: providerSettings.batchMaxCount };
202
220
  }
203
221
 
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
- }
222
+ this.provider = new ethers.JsonRpcProvider(
223
+ providerSettings.url || 'http://localhost:8545/',
224
+ undefined,
225
+ jsonRpcApiProviderOptions
226
+ );
209
227
 
210
228
  if (providerSettings.privateKey) {
211
- this.signer = new ethers.Wallet(providerSettings.privateKey, this.provider);
229
+ signerPromise = Promise.resolve(new ethers.Wallet(providerSettings.privateKey, this.provider));
212
230
  } 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
- }
231
+ signerPromise = this.provider.getSigner().catch(() => null);
232
+ } else {
233
+ signerPromise = Promise.resolve(null);
218
234
  }
219
- // Web3 provider
220
235
  } else if (providerType.toLowerCase() === 'Web3'.toLowerCase()) {
221
236
  providerSettings = providerSettings as { externalProvider: ethers.Eip1193Provider };
222
237
  this.provider = new ethers.BrowserProvider(providerSettings.externalProvider);
223
- this.signer = await this.provider.getSigner();
224
- // Infura provider
238
+ signerPromise = this.provider.getSigner();
225
239
  } else if (providerType.toLowerCase() === 'Infura'.toLowerCase()) {
226
240
  providerSettings = providerSettings as { network?: Networkish, apiKey?: string };
227
241
  this.provider = new ethers.InfuraProvider(providerSettings.network, providerSettings.apiKey);
228
- this.signer = null;
229
- // Alchemy provider
242
+ signerPromise = Promise.resolve(null);
230
243
  } else if (providerType.toLowerCase() === 'Alchemy'.toLowerCase()) {
231
244
  providerSettings = providerSettings as { network?: Networkish, apiKey?: string };
232
245
  this.provider = new ethers.AlchemyProvider(providerSettings.network, providerSettings.apiKey);
233
- this.signer = null;
246
+ signerPromise = Promise.resolve(null);
234
247
  } else {
235
248
  throw Error('Wrong providerType');
236
249
  }
237
250
 
238
- const network = await this.provider.getNetwork();
251
+ const [signer, network] = await Promise.all([
252
+ signerPromise,
253
+ this.provider.getNetwork(),
254
+ ]);
255
+ this.signer = signer;
239
256
  this.chainId = Number(network.chainId) === 133 || Number(network.chainId) === 31337 ? 1 : Number(network.chainId) as IChainId;
240
257
  console.log("CURVE-LLAMALEND-JS IS CONNECTED TO NETWORK:", { name: network.name.toUpperCase(), chainId: Number(this.chainId) });
241
258
 
@@ -264,8 +281,6 @@ class Llamalend implements ILlamalend {
264
281
  }
265
282
 
266
283
  this.feeData = { gasPrice: options.gasPrice, maxFeePerGas: options.maxFeePerGas, maxPriorityFeePerGas: options.maxPriorityFeePerGas };
267
- await this.updateFeeData();
268
-
269
284
  // oneWayMarkets contracts
270
285
  this.setContract(this.constants.ALIASES['one_way_factory'], OneWayLendingFactoryABI);
271
286
  if(this.constants.ALIASES['one_way_factory_v2'] && this.constants.ALIASES['one_way_factory_v2'] !== this.constants.ZERO_ADDRESS) {
@@ -292,119 +307,8 @@ class Llamalend implements ILlamalend {
292
307
  }
293
308
  }
294
309
 
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
310
 
406
311
  this.constants.DECIMALS = {
407
- ...extractDecimals(this.constants.LLAMMAS),
408
312
  [this.crvUsdAddress]: 18,
409
313
  [this.constants.ALIASES.crv]: 18,
410
314
  [this.constants.ALIASES.crvUSD]: 18,
@@ -445,25 +349,85 @@ class Llamalend implements ILlamalend {
445
349
  AbstractProvider.prototype.estimateGas = AbstractProvider.prototype.originalEstimate as (_tx: TransactionRequest) => Promise<bigint>;
446
350
  }
447
351
  }
352
+
448
353
  }
449
354
 
450
- setContract(address: string, abi: any): void {
355
+ initContract = memoizedContract()
356
+ initMulticallContract = memoizedMulticallContract()
357
+
358
+ setContract(address: string | undefined, abi: any): void {
451
359
  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,
360
+
361
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
362
+ const llamalendInstance = this;
363
+
364
+ const proxyHandler: ProxyHandler<any> = {
365
+ get: function(target: any, name: string) {
366
+ if(name === 'contract') {
367
+ return llamalendInstance.initContract(target['address'], target['abi'], llamalendInstance.signer || llamalendInstance.provider)
368
+ } else if(name === 'multicallContract') {
369
+ return llamalendInstance.initMulticallContract(target['address'], target['abi'])
370
+ } else {
371
+ return target[name];
372
+ }
373
+ },
457
374
  }
375
+
376
+ const coreContract = {
377
+ address,
378
+ abi,
379
+ }
380
+
381
+ this.contracts[address] = new Proxy(coreContract, proxyHandler)
458
382
  }
459
383
 
460
384
  setCustomFeeData(customFeeData: { gasPrice?: number, maxFeePerGas?: number, maxPriorityFeePerGas?: number }): void {
461
385
  this.feeData = { ...this.feeData, ...customFeeData };
462
386
  }
463
387
 
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>;
388
+ async _setupMintMarketContracts(useApi = true): Promise<void> {
389
+ this.setContract(this.crvUsdAddress, ERC20ABI);
390
+ if (this.chainId !== 1) return;
391
+
392
+ this.setContract(this.constants.COINS.crvusd.toLowerCase(), ERC20ABI);
393
+
394
+ const llammas = Object.values(this.constants.LLAMMAS);
395
+ for (const llamma of llammas) {
396
+ this.setContract(llamma.amm_address, llammaABI);
397
+ this.setContract(llamma.controller_address, controllerABI);
398
+ }
399
+
400
+ if (useApi) {
401
+ const apiData = await _getCrvUsdMarketsData();
402
+ const monetaryPolicyMap = new Map(
403
+ apiData.map((m) => [m.address.toLowerCase(), m.monetary_policy_address.toLowerCase()])
404
+ );
405
+ for (const llamma of llammas) {
406
+ const fresh = monetaryPolicyMap.get(llamma.controller_address);
407
+ if (fresh) llamma.monetary_policy_address = fresh;
408
+ }
409
+ } else {
410
+ const monetaryPolicies = (await this.multicallProvider.all(
411
+ llammas.map((l) => this.contracts[l.controller_address].multicallContract.monetary_policy())
412
+ ) as string[]).map((a) => a.toLowerCase());
413
+ llammas.forEach((llamma, i) => { llamma.monetary_policy_address = monetaryPolicies[i]; });
414
+ }
415
+
416
+ for (const llamma of llammas) {
417
+ this.setContract(llamma.monetary_policy_address, llamma.monetary_policy_abi);
418
+ if (llamma.collateral_address === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") {
419
+ this.setContract(this.constants.WETH, ERC20ABI);
420
+ } else {
421
+ this.setContract(llamma.collateral_address, ERC20ABI);
422
+ }
423
+ this.setContract(llamma.leverage_zap, LeverageZapCrvUSDABI);
424
+ this.setContract(llamma.deleverage_zap, DeleverageZapABI);
425
+ if (llamma.health_calculator_zap) this.setContract(llamma.health_calculator_zap, HealthCalculatorZapABI);
426
+ }
427
+
428
+ for (const pegKeeper of this.constants.PEG_KEEPERS) {
429
+ this.setContract(pegKeeper, PegKeeper);
430
+ }
467
431
  }
468
432
 
469
433
  getLendMarketList = () => Object.keys({...this.constants.ONE_WAY_MARKETS, ...this.constants.ONE_WAY_MARKETS_V2});
@@ -482,6 +446,13 @@ class Llamalend implements ILlamalend {
482
446
  }
483
447
  }
484
448
 
449
+ fetchMintMarkets = async ({ useApi = true }: { useApi?: boolean } = {}): Promise<void> => {
450
+ await Promise.all([
451
+ this._setupMintMarketContracts(useApi),
452
+ useApi ? fetchMintMarketsByAPI(this) : fetchMintMarketsByBlockchain(this),
453
+ ]);
454
+ }
455
+
485
456
  getCoins = async (collateral_tokens: string[], borrowed_tokens: string[], useApi = false): Promise<IDict<ICoin>> => {
486
457
  const coins = new Set([...collateral_tokens, ...borrowed_tokens]);
487
458
  const COINS_DATA: IDict<ICoin> = {};
@@ -539,54 +510,6 @@ class Llamalend implements ILlamalend {
539
510
  return COINS_DATA;
540
511
  }
541
512
 
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
513
  formatUnits(value: BigNumberish, unit?: string | Numeric): string {
591
514
  return ethers.formatUnits(value, unit);
592
515
  }