@curvefi/llamalend-api 2.0.4 → 2.0.5

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.
@@ -143,6 +143,42 @@ This document tracks feature support across market versions.
143
143
  | ammBalances() | ✅ | ✅ | ✅ | ✅ | ✅ |
144
144
  | capAndAvailable() | ✅ | ✅ | ❌ | ✅ | ❌ |
145
145
 
146
+ ### Update for `capAndAvailable` method
147
+
148
+ Previously the `capAndAvailable` method returned:
149
+
150
+ ```ts
151
+ {
152
+ cap: string
153
+ available: string
154
+ }
155
+ ```
156
+
157
+ Now it returns:
158
+
159
+ ```ts
160
+ {
161
+ totalAssets: string
162
+ borrowCap: string
163
+ available: string
164
+ availableForBorrow: string
165
+ }
166
+ ```
167
+
168
+ #### Important clarification
169
+
170
+ Previously the value called **`cap`** was incorrectly named.
171
+
172
+ On the frontend, the value that we now return as **`totalAssets`** corresponds to what was previously treated as **`cap`**.
173
+
174
+ #### Summary
175
+
176
+ - `totalAssets` → total assets deposited in the vault (what was previously used as `cap` on the frontend)
177
+ - `borrowCap` → maximum total debt allowed by the controller (LLv2 only; `Infinity` for LLv1)
178
+ - `available` → balance of borrowed token available in the controller
179
+ - `availableForBorrow` → effective amount available to borrow: `min(available, borrowCap - totalDebt)`
180
+
181
+
146
182
  ## Stats Module (`market.stats`) new methods
147
183
  | Method | v1 | v2 | Same logic | Same params | Same type |
148
184
  |--------|----|----|-----------------|----------------------|-----------------------|
@@ -186,6 +186,7 @@ export interface IMarketDataAPI {
186
186
  totalSupplied: Total;
187
187
  borrowed: Total;
188
188
  availableToBorrow: Total;
189
+ borrowCap: Total;
189
190
  lendingVaultUrls: LendingVaultUrls;
190
191
  usdTotal: number;
191
192
  ammBalances: AmmBalances;
@@ -81,7 +81,7 @@ export class LendMarketTemplate {
81
81
  adminPercentage: stats.statsAdminPercentage.bind(stats),
82
82
  };
83
83
  this.wallet = {
84
- balances: wallet.balances.bind(this),
84
+ balances: wallet.balances.bind(wallet),
85
85
  };
86
86
  this.prices = {
87
87
  A: prices.A.bind(prices),
@@ -43,8 +43,10 @@ export interface IStatsV1 {
43
43
  collateral: string;
44
44
  }>;
45
45
  capAndAvailable: (isGetter?: boolean, useAPI?: boolean) => Promise<{
46
- cap: string;
46
+ borrowCap: string;
47
47
  available: string;
48
+ totalAssets: string;
49
+ availableForBorrow: string;
48
50
  }>;
49
51
  adminPercentage: () => Promise<string>;
50
52
  }
@@ -43,8 +43,10 @@ export interface IStatsV2 {
43
43
  collateral: string;
44
44
  }>;
45
45
  capAndAvailable: (isGetter?: boolean, useAPI?: boolean) => Promise<{
46
- cap: string;
46
+ borrowCap: string;
47
47
  available: string;
48
+ totalAssets: string;
49
+ availableForBorrow: string;
48
50
  }>;
49
51
  adminPercentage: () => Promise<string>;
50
52
  }
@@ -1,12 +1,15 @@
1
1
  import memoize from "memoizee";
2
- import { TAmount } from "../../../interfaces";
2
+ import { TAmount, IMarketDataAPI } from "../../../interfaces";
3
3
  import type { LendMarketTemplate } from "../../LendMarketTemplate";
4
4
  import { Llamalend } from "../../../llamalend";
5
5
  export declare class StatsBaseModule {
6
6
  protected market: LendMarketTemplate;
7
7
  protected llamalend: Llamalend;
8
8
  constructor(market: LendMarketTemplate);
9
+ protected _fetchMarketDataFromAPI(): Promise<IMarketDataAPI>;
9
10
  protected _fetchAdminPercentage: () => Promise<bigint>;
11
+ protected _fetchAdminFee: () => Promise<bigint>;
12
+ protected _getAdminFeesXY(isGetter: boolean): Promise<[bigint, bigint]>;
10
13
  private _getRate;
11
14
  private _getFutureRate;
12
15
  statsParameters: (() => Promise<{
@@ -63,9 +66,23 @@ export declare class StatsBaseModule {
63
66
  borrowed: string;
64
67
  collateral: string;
65
68
  }>;
69
+ protected _statsCapAndAvailableFromAPI(): Promise<{
70
+ borrowCap: string;
71
+ available: string;
72
+ totalAssets: string;
73
+ availableForBorrow: string;
74
+ }>;
75
+ protected _statsCapAndAvailableOnChain(isGetter: boolean): Promise<{
76
+ borrowCap: string;
77
+ available: string;
78
+ totalAssets: string;
79
+ availableForBorrow: string;
80
+ }>;
66
81
  statsCapAndAvailable(isGetter?: boolean, useAPI?: boolean): Promise<{
67
- cap: string;
82
+ borrowCap: string;
68
83
  available: string;
84
+ totalAssets: string;
85
+ availableForBorrow: string;
69
86
  }>;
70
87
  statsAdminPercentage: () => Promise<string>;
71
88
  }
@@ -18,6 +18,9 @@ export class StatsBaseModule {
18
18
  this._fetchAdminPercentage = () => __awaiter(this, void 0, void 0, function* () {
19
19
  return BigInt(0);
20
20
  });
21
+ this._fetchAdminFee = () => __awaiter(this, void 0, void 0, function* () {
22
+ return this.llamalend.contracts[this.market.addresses.amm].contract.admin_fee(this.llamalend.constantOptions);
23
+ });
21
24
  this._getRate = (...args_1) => __awaiter(this, [...args_1], void 0, function* (isGetter = true) {
22
25
  if (isGetter) {
23
26
  const _rate = cacheStats.get(cacheKey(this.market.addresses.amm, 'rate'));
@@ -44,15 +47,16 @@ export class StatsBaseModule {
44
47
  this.statsParameters = memoize(() => __awaiter(this, void 0, void 0, function* () {
45
48
  const llammaContract = this.llamalend.contracts[this.market.addresses.amm].multicallContract;
46
49
  const controllerContract = this.llamalend.contracts[this.market.addresses.controller].multicallContract;
47
- const calls = [
48
- llammaContract.fee(),
49
- llammaContract.admin_fee(), // TODO: removed
50
- controllerContract.liquidation_discount(),
51
- controllerContract.loan_discount(),
52
- llammaContract.get_base_price(),
53
- llammaContract.A(),
54
- ];
55
- const [_fee, _admin_fee, _liquidation_discount, _loan_discount, _base_price, _A] = yield this.llamalend.multicallProvider.all(calls);
50
+ const [[_fee, _liquidation_discount, _loan_discount, _base_price, _A], _admin_fee] = yield Promise.all([
51
+ this.llamalend.multicallProvider.all([
52
+ llammaContract.fee(),
53
+ controllerContract.liquidation_discount(),
54
+ controllerContract.loan_discount(),
55
+ llammaContract.get_base_price(),
56
+ llammaContract.A(),
57
+ ]),
58
+ this._fetchAdminFee(),
59
+ ]);
56
60
  const A = formatUnits(_A, 0);
57
61
  const base_price = formatUnits(_base_price);
58
62
  const [fee, admin_fee, liquidation_discount, loan_discount] = [_fee, _admin_fee, _liquidation_discount, _loan_discount]
@@ -81,7 +85,7 @@ export class StatsBaseModule {
81
85
  });
82
86
  this.statsAmmBalances = (...args_1) => __awaiter(this, [...args_1], void 0, function* (isGetter = true, useAPI = false) {
83
87
  if (useAPI) {
84
- const market = yield fetchMarketDataByVault(this.llamalend.constants.NETWORK_NAME, this.market.addresses.vault, _getMarketsData);
88
+ const market = yield this._fetchMarketDataFromAPI();
85
89
  return {
86
90
  borrowed: market.ammBalances.ammBalanceBorrowed.toString(),
87
91
  collateral: market.ammBalances.ammBalanceCollateral.toString(),
@@ -90,27 +94,23 @@ export class StatsBaseModule {
90
94
  else {
91
95
  const borrowedContract = this.llamalend.contracts[this.market.addresses.borrowed_token].multicallContract;
92
96
  const collateralContract = this.llamalend.contracts[this.market.addresses.collateral_token].multicallContract;
93
- const ammContract = this.llamalend.contracts[this.market.addresses.amm].multicallContract;
94
- let _balance_x, _fee_x, _balance_y, _fee_y; // TODO: fees are always 0
97
+ let _balance_x, _balance_y;
98
+ let _fee_x, _fee_y;
95
99
  if (isGetter) {
96
- [_balance_x, _fee_x, _balance_y, _fee_y] = [
97
- cacheStats.get(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.amm)),
98
- cacheStats.get(cacheKey(this.market.addresses.amm, 'admin_fees_x')),
99
- cacheStats.get(cacheKey(this.market.addresses.collateral_token, 'balanceOf', this.market.addresses.amm)),
100
- cacheStats.get(cacheKey(this.market.addresses.amm, 'admin_fees_y')),
101
- ];
100
+ _balance_x = cacheStats.get(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.amm));
101
+ _balance_y = cacheStats.get(cacheKey(this.market.addresses.collateral_token, 'balanceOf', this.market.addresses.amm));
102
+ [_fee_x, _fee_y] = yield this._getAdminFeesXY(true);
102
103
  }
103
104
  else {
104
- [_balance_x, _fee_x, _balance_y, _fee_y] = yield this.llamalend.multicallProvider.all([
105
- borrowedContract.balanceOf(this.market.addresses.amm),
106
- ammContract.admin_fees_x(),
107
- collateralContract.balanceOf(this.market.addresses.amm),
108
- ammContract.admin_fees_y(),
109
- ]);
105
+ [[_balance_x, _balance_y], [_fee_x, _fee_y]] = (yield Promise.all([
106
+ this.llamalend.multicallProvider.all([
107
+ borrowedContract.balanceOf(this.market.addresses.amm),
108
+ collateralContract.balanceOf(this.market.addresses.amm),
109
+ ]),
110
+ this._getAdminFeesXY(false),
111
+ ]));
110
112
  cacheStats.set(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.amm), _balance_x);
111
- cacheStats.set(cacheKey(this.market.addresses.amm, 'admin_fees_x'), _fee_x);
112
113
  cacheStats.set(cacheKey(this.market.addresses.collateral_token, 'balanceOf', this.market.addresses.amm), _balance_y);
113
- cacheStats.set(cacheKey(this.market.addresses.amm, 'admin_fees_y'), _fee_y);
114
114
  }
115
115
  return {
116
116
  borrowed: toBN(_balance_x, this.market.borrowed_token.decimals).minus(toBN(_fee_x, this.market.borrowed_token.decimals)).toString(),
@@ -125,10 +125,33 @@ export class StatsBaseModule {
125
125
  this.market = market;
126
126
  this.llamalend = market.getLlamalend();
127
127
  }
128
+ _fetchMarketDataFromAPI() {
129
+ return __awaiter(this, void 0, void 0, function* () {
130
+ return fetchMarketDataByVault(this.llamalend.constants.NETWORK_NAME, this.market.addresses.vault, _getMarketsData);
131
+ });
132
+ }
133
+ _getAdminFeesXY(isGetter) {
134
+ return __awaiter(this, void 0, void 0, function* () {
135
+ if (isGetter) {
136
+ return [
137
+ cacheStats.get(cacheKey(this.market.addresses.amm, 'admin_fees_x')),
138
+ cacheStats.get(cacheKey(this.market.addresses.amm, 'admin_fees_y')),
139
+ ];
140
+ }
141
+ const ammContract = this.llamalend.contracts[this.market.addresses.amm].multicallContract;
142
+ const [_fee_x, _fee_y] = yield this.llamalend.multicallProvider.all([
143
+ ammContract.admin_fees_x(),
144
+ ammContract.admin_fees_y(),
145
+ ]);
146
+ cacheStats.set(cacheKey(this.market.addresses.amm, 'admin_fees_x'), _fee_x);
147
+ cacheStats.set(cacheKey(this.market.addresses.amm, 'admin_fees_y'), _fee_y);
148
+ return [_fee_x, _fee_y];
149
+ });
150
+ }
128
151
  statsRates() {
129
152
  return __awaiter(this, arguments, void 0, function* (isGetter = true, useAPI = false) {
130
153
  if (useAPI) {
131
- const market = yield fetchMarketDataByVault(this.llamalend.constants.NETWORK_NAME, this.market.addresses.vault, _getMarketsData);
154
+ const market = yield this._fetchMarketDataFromAPI();
132
155
  return {
133
156
  borrowApr: (market.rates.borrowApr * 100).toString(),
134
157
  lendApr: (market.rates.lendApr * 100).toString(),
@@ -138,9 +161,9 @@ export class StatsBaseModule {
138
161
  }
139
162
  else {
140
163
  const _rate = yield this._getRate(isGetter);
141
- const debt = yield this.statsTotalDebt(isGetter);
142
- const { cap } = Number(debt) > 0 ? yield this.statsCapAndAvailable(isGetter) : { cap: "0" };
143
- return computeRatesFromRate(_rate, debt, cap);
164
+ const debt = yield this.statsTotalDebt(isGetter, false);
165
+ const { totalAssets } = Number(debt) > 0 ? yield this.statsCapAndAvailable(isGetter, false) : { totalAssets: "0" };
166
+ return computeRatesFromRate(_rate, debt, totalAssets);
144
167
  }
145
168
  });
146
169
  }
@@ -150,7 +173,7 @@ export class StatsBaseModule {
150
173
  const _dDebt = parseUnits(dDebt, this.market.borrowed_token.decimals);
151
174
  const _rate = yield this._getFutureRate(_dReserves, _dDebt);
152
175
  const debt = Number(yield this.statsTotalDebt()) + Number(dDebt);
153
- const cap = Number((yield this.statsCapAndAvailable(true, useAPI)).cap) + Number(dReserves);
176
+ const cap = Number((yield this.statsCapAndAvailable(true, useAPI)).totalAssets) + Number(dReserves);
154
177
  return computeRatesFromRate(_rate, debt, cap);
155
178
  });
156
179
  }
@@ -158,14 +181,13 @@ export class StatsBaseModule {
158
181
  return __awaiter(this, void 0, void 0, function* () {
159
182
  const borrowedContract = this.llamalend.contracts[this.market.borrowed_token.address].multicallContract;
160
183
  const collateralContract = this.llamalend.contracts[this.market.collateral_token.address].multicallContract;
161
- const ammContract = this.llamalend.contracts[this.market.addresses.amm].multicallContract;
162
- const calls = [
163
- borrowedContract.balanceOf(this.market.addresses.amm),
164
- collateralContract.balanceOf(this.market.addresses.amm),
165
- ammContract.admin_fees_x(), // TODO: always 0
166
- ammContract.admin_fees_y(), // TODO: always 0
167
- ];
168
- const [_borrowedBalance, _collateralBalance, _borrowedAdminFees, _collateralAdminFees] = yield this.llamalend.multicallProvider.all(calls);
184
+ const [[_borrowedBalance, _collateralBalance], [_borrowedAdminFees, _collateralAdminFees]] = yield Promise.all([
185
+ this.llamalend.multicallProvider.all([
186
+ borrowedContract.balanceOf(this.market.addresses.amm),
187
+ collateralContract.balanceOf(this.market.addresses.amm),
188
+ ]),
189
+ this._getAdminFeesXY(false),
190
+ ]);
169
191
  return [
170
192
  formatUnits(_borrowedBalance - _borrowedAdminFees, this.market.borrowed_token.decimals),
171
193
  formatUnits(_collateralBalance - _collateralAdminFees, this.market.collateral_token.decimals),
@@ -209,7 +231,7 @@ export class StatsBaseModule {
209
231
  statsTotalDebt() {
210
232
  return __awaiter(this, arguments, void 0, function* (isGetter = true, useAPI = true) {
211
233
  if (useAPI) {
212
- const market = yield fetchMarketDataByVault(this.llamalend.constants.NETWORK_NAME, this.market.addresses.vault, _getMarketsData);
234
+ const market = yield this._fetchMarketDataFromAPI();
213
235
  return market.borrowed.total.toString();
214
236
  }
215
237
  else {
@@ -225,38 +247,48 @@ export class StatsBaseModule {
225
247
  }
226
248
  });
227
249
  }
228
- statsCapAndAvailable() {
229
- return __awaiter(this, arguments, void 0, function* (isGetter = true, useAPI = false) {
230
- if (useAPI) {
231
- const market = yield fetchMarketDataByVault(this.llamalend.constants.NETWORK_NAME, this.market.addresses.vault, _getMarketsData);
232
- return {
233
- cap: market.totalSupplied.total.toString(),
234
- available: market.availableToBorrow.total.toString(),
235
- };
250
+ _statsCapAndAvailableFromAPI() {
251
+ return __awaiter(this, void 0, void 0, function* () {
252
+ const market = yield this._fetchMarketDataFromAPI();
253
+ return {
254
+ totalAssets: market.totalSupplied.total.toString(),
255
+ borrowCap: Infinity.toString(),
256
+ available: market.availableToBorrow.total.toString(),
257
+ availableForBorrow: market.availableToBorrow.total.toString(),
258
+ };
259
+ });
260
+ }
261
+ _statsCapAndAvailableOnChain(isGetter) {
262
+ return __awaiter(this, void 0, void 0, function* () {
263
+ const vaultContract = this.llamalend.contracts[this.market.addresses.vault].multicallContract;
264
+ const borrowedContract = this.llamalend.contracts[this.market.addresses.borrowed_token].multicallContract;
265
+ let _cap, _available;
266
+ if (isGetter) {
267
+ _cap = cacheStats.get(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller));
268
+ _available = cacheStats.get(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.controller));
236
269
  }
237
270
  else {
238
- const vaultContract = this.llamalend.contracts[this.market.addresses.vault].multicallContract;
239
- const borrowedContract = this.llamalend.contracts[this.market.addresses.borrowed_token].multicallContract;
240
- let _cap, _available;
241
- if (isGetter) { // TODO: should call controller.available_balance() instead of borrowed_token.balanceOf(controller)
242
- _cap = cacheStats.get(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller));
243
- _available = cacheStats.get(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.controller));
244
- }
245
- else {
246
- [_cap, _available] = yield this.llamalend.multicallProvider.all([
247
- vaultContract.totalAssets(this.market.addresses.controller),
248
- borrowedContract.balanceOf(this.market.addresses.controller),
249
- ]);
250
- cacheStats.set(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller), _cap);
251
- cacheStats.set(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.controller), _available);
252
- }
253
- return {
254
- cap: this.llamalend.formatUnits(_cap, this.market.borrowed_token.decimals),
255
- available: this.llamalend.formatUnits(_available, this.market.borrowed_token.decimals),
256
- };
257
- // cap -> totalAssets
258
- // add cap: controller.borrow_cap() // Display
271
+ [_cap, _available] = yield this.llamalend.multicallProvider.all([
272
+ vaultContract.totalAssets(this.market.addresses.controller),
273
+ borrowedContract.balanceOf(this.market.addresses.controller),
274
+ ]);
275
+ cacheStats.set(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller), _cap);
276
+ cacheStats.set(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.controller), _available);
259
277
  }
278
+ const available = this.llamalend.formatUnits(_available, this.market.borrowed_token.decimals);
279
+ return {
280
+ totalAssets: this.llamalend.formatUnits(_cap, this.market.borrowed_token.decimals),
281
+ borrowCap: Infinity.toString(),
282
+ available,
283
+ availableForBorrow: available,
284
+ };
285
+ });
286
+ }
287
+ statsCapAndAvailable() {
288
+ return __awaiter(this, arguments, void 0, function* (isGetter = true, useAPI = false) {
289
+ if (useAPI)
290
+ return this._statsCapAndAvailableFromAPI();
291
+ return this._statsCapAndAvailableOnChain(isGetter);
260
292
  });
261
293
  }
262
294
  }
@@ -415,9 +415,9 @@ export class VaultModule {
415
415
  }
416
416
  vaultTotalLiquidity() {
417
417
  return __awaiter(this, arguments, void 0, function* (useAPI = true) {
418
- const { cap } = yield this.market.stats.capAndAvailable(true, useAPI);
418
+ const { totalAssets } = yield this.market.stats.capAndAvailable(true, useAPI);
419
419
  const price = yield _getUsdRate.call(this.llamalend, this.market.addresses.borrowed_token);
420
- return BN(cap).times(price).toFixed(6);
420
+ return BN(totalAssets).times(price).toFixed(6);
421
421
  });
422
422
  }
423
423
  vaultCrvApr() {
@@ -2,4 +2,18 @@ import memoize from "memoizee";
2
2
  import { StatsBaseModule } from "../common/statsBase.js";
3
3
  export declare class StatsV2Module extends StatsBaseModule {
4
4
  protected _fetchAdminPercentage: (() => Promise<bigint>) & memoize.Memoized<() => Promise<bigint>>;
5
+ protected _fetchAdminFee: () => Promise<bigint>;
6
+ protected _getAdminFeesXY: () => Promise<[bigint, bigint]>;
7
+ protected _statsCapAndAvailableFromAPI(): Promise<{
8
+ totalAssets: string;
9
+ borrowCap: string;
10
+ available: string;
11
+ availableForBorrow: string;
12
+ }>;
13
+ protected _statsCapAndAvailableOnChain(isGetter: boolean): Promise<{
14
+ borrowCap: string;
15
+ available: string;
16
+ totalAssets: string;
17
+ availableForBorrow: string;
18
+ }>;
5
19
  }
@@ -9,6 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import memoize from "memoizee";
11
11
  import { StatsBaseModule } from "../common/statsBase.js";
12
+ import { cacheKey, cacheStats } from "../../../cache";
13
+ import BigNumber from "bignumber.js";
14
+ import { BN } from "../../../utils";
12
15
  export class StatsV2Module extends StatsBaseModule {
13
16
  constructor() {
14
17
  super(...arguments);
@@ -18,5 +21,49 @@ export class StatsV2Module extends StatsBaseModule {
18
21
  promise: true,
19
22
  maxAge: 30 * 60 * 1000, // 30m
20
23
  });
24
+ this._fetchAdminFee = () => __awaiter(this, void 0, void 0, function* () { return BigInt(0); });
25
+ this._getAdminFeesXY = () => __awaiter(this, void 0, void 0, function* () { return [BigInt(0), BigInt(0)]; });
26
+ }
27
+ _statsCapAndAvailableFromAPI() {
28
+ return __awaiter(this, void 0, void 0, function* () {
29
+ const market = yield this._fetchMarketDataFromAPI();
30
+ return {
31
+ totalAssets: market.totalSupplied.total.toString(),
32
+ borrowCap: market.borrowCap.total.toString(),
33
+ available: market.availableToBorrow.total.toString(),
34
+ availableForBorrow: market.availableToBorrow.total.toString(),
35
+ };
36
+ });
37
+ }
38
+ _statsCapAndAvailableOnChain(isGetter) {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ const vaultContract = this.llamalend.contracts[this.market.addresses.vault].multicallContract;
41
+ const controllerContract = this.llamalend.contracts[this.market.addresses.controller].multicallContract;
42
+ let _cap, _available, _totalAssets, _totalDebt;
43
+ if (isGetter) {
44
+ _totalAssets = cacheStats.get(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller));
45
+ _cap = cacheStats.get(cacheKey(this.market.addresses.controller, 'borrow_cap'));
46
+ _available = cacheStats.get(cacheKey(this.market.addresses.controller, 'available_balance'));
47
+ _totalDebt = cacheStats.get(cacheKey(this.market.addresses.controller, 'total_debt'));
48
+ }
49
+ else {
50
+ [_totalAssets, _available, _cap, _totalDebt] = yield this.llamalend.multicallProvider.all([
51
+ vaultContract.totalAssets(this.market.addresses.controller),
52
+ controllerContract.available_balance(),
53
+ controllerContract.borrow_cap(),
54
+ controllerContract.total_debt(),
55
+ ]);
56
+ cacheStats.set(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller), _totalAssets);
57
+ cacheStats.set(cacheKey(this.market.addresses.controller, 'borrow_cap'), _cap);
58
+ cacheStats.set(cacheKey(this.market.addresses.controller, 'available_balance'), _available);
59
+ cacheStats.set(cacheKey(this.market.addresses.controller, 'total_debt'), _totalDebt);
60
+ }
61
+ const totalAssets = this.llamalend.formatUnits(_totalAssets, this.market.borrowed_token.decimals);
62
+ const borrowCap = this.llamalend.formatUnits(_cap, this.market.borrowed_token.decimals);
63
+ const available = this.llamalend.formatUnits(_available, this.market.borrowed_token.decimals);
64
+ const totalDebt = this.llamalend.formatUnits(_totalDebt, this.market.borrowed_token.decimals);
65
+ const availableForBorrow = BigNumber.min(BN(available), BN(borrowCap).minus(BN(totalDebt))).toFixed();
66
+ return { totalAssets, borrowCap, available, availableForBorrow };
67
+ });
21
68
  }
22
69
  }
@@ -18,8 +18,10 @@ export const computeRatesFromRate = (_rate, debt, cap) => {
18
18
  const expFactor = Math.pow(Math.E, annualFactor.toNumber());
19
19
  const borrowApr = annualFactor.times(100).toString();
20
20
  const borrowApy = String((expFactor - 1) * 100);
21
- const lendApr = annualFactor.times(debt).div(cap).times(100).toString();
22
- const lendApy = BN(debt).times(expFactor).minus(debt).div(cap).times(100).toString();
21
+ const lendAprRaw = annualFactor.times(debt).div(cap).times(100);
22
+ const lendApr = lendAprRaw.isNaN() ? "0" : lendAprRaw.toString();
23
+ const lendApyRaw = BN(debt).times(expFactor).minus(debt).div(cap).times(100);
24
+ const lendApy = lendApyRaw.isNaN() ? "0" : lendApyRaw.toString();
23
25
  return { borrowApr, lendApr, borrowApy, lendApy };
24
26
  };
25
27
  export const fetchMarketDataByVault = (networkName, vaultAddress, getData) => __awaiter(void 0, void 0, void 0, function* () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curvefi/llamalend-api",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "description": "JavaScript library for Curve Lending",
5
5
  "main": "lib/index.js",
6
6
  "author": "Macket",
package/src/interfaces.ts CHANGED
@@ -193,6 +193,7 @@ export interface IMarketDataAPI {
193
193
  totalSupplied: Total;
194
194
  borrowed: Total;
195
195
  availableToBorrow: Total;
196
+ borrowCap: Total;
196
197
  lendingVaultUrls: LendingVaultUrls;
197
198
  usdTotal: number;
198
199
  ammBalances: AmmBalances;
@@ -180,7 +180,7 @@ export class LendMarketTemplate<V extends 'v1' | 'v2' = 'v1' | 'v2'> {
180
180
  } as StatsForVersion<V>
181
181
 
182
182
  this.wallet = {
183
- balances: wallet.balances.bind(this),
183
+ balances: wallet.balances.bind(wallet),
184
184
  }
185
185
 
186
186
  this.prices = {
@@ -17,6 +17,6 @@ export interface IStatsV1 {
17
17
  bandsBalances: () => Promise<{ [index: number]: { borrowed: string, collateral: string } }>,
18
18
  totalDebt: (isGetter?: boolean, useAPI?: boolean) => Promise<string>,
19
19
  ammBalances: (isGetter?: boolean, useAPI?: boolean) => Promise<{ borrowed: string, collateral: string }>,
20
- capAndAvailable: (isGetter?: boolean, useAPI?: boolean) => Promise<{ cap: string, available: string }>,
20
+ capAndAvailable: (isGetter?: boolean, useAPI?: boolean) => Promise<{ borrowCap: string, available: string, totalAssets: string, availableForBorrow: string }>,
21
21
  adminPercentage: () => Promise<string>,
22
22
  }
@@ -17,6 +17,6 @@ export interface IStatsV2 {
17
17
  bandsBalances: () => Promise<{ [index: number]: { borrowed: string, collateral: string } }>,
18
18
  totalDebt: (isGetter?: boolean, useAPI?: boolean) => Promise<string>,
19
19
  ammBalances: (isGetter?: boolean, useAPI?: boolean) => Promise<{ borrowed: string, collateral: string }>,
20
- capAndAvailable: (isGetter?: boolean, useAPI?: boolean) => Promise<{ cap: string, available: string }>,
20
+ capAndAvailable: (isGetter?: boolean, useAPI?: boolean) => Promise<{ borrowCap: string, available: string, totalAssets: string, availableForBorrow: string }>,
21
21
  adminPercentage: () => Promise<string>,
22
22
  }
@@ -1,5 +1,5 @@
1
1
  import memoize from "memoizee";
2
- import {TAmount} from "../../../interfaces";
2
+ import {TAmount, IMarketDataAPI} from "../../../interfaces";
3
3
  import type { LendMarketTemplate } from "../../LendMarketTemplate";
4
4
  import {
5
5
  parseUnits,
@@ -22,10 +22,39 @@ export class StatsBaseModule {
22
22
  this.llamalend = market.getLlamalend();
23
23
  }
24
24
 
25
+ protected async _fetchMarketDataFromAPI(): Promise<IMarketDataAPI> {
26
+ return fetchMarketDataByVault(
27
+ this.llamalend.constants.NETWORK_NAME,
28
+ this.market.addresses.vault,
29
+ _getMarketsData
30
+ );
31
+ }
32
+
25
33
  protected _fetchAdminPercentage = async (): Promise<bigint> => {
26
34
  return BigInt(0)
27
35
  }
28
36
 
37
+ protected _fetchAdminFee = async (): Promise<bigint> => {
38
+ return this.llamalend.contracts[this.market.addresses.amm].contract.admin_fee(this.llamalend.constantOptions);
39
+ }
40
+
41
+ protected async _getAdminFeesXY(isGetter: boolean): Promise<[bigint, bigint]> {
42
+ if(isGetter) {
43
+ return [
44
+ cacheStats.get(cacheKey(this.market.addresses.amm, 'admin_fees_x')),
45
+ cacheStats.get(cacheKey(this.market.addresses.amm, 'admin_fees_y')),
46
+ ];
47
+ }
48
+ const ammContract = this.llamalend.contracts[this.market.addresses.amm].multicallContract;
49
+ const [_fee_x, _fee_y] = await this.llamalend.multicallProvider.all([
50
+ ammContract.admin_fees_x(),
51
+ ammContract.admin_fees_y(),
52
+ ]) as [bigint, bigint];
53
+ cacheStats.set(cacheKey(this.market.addresses.amm, 'admin_fees_x'), _fee_x);
54
+ cacheStats.set(cacheKey(this.market.addresses.amm, 'admin_fees_y'), _fee_y);
55
+ return [_fee_x, _fee_y];
56
+ }
57
+
29
58
  private _getRate = async (isGetter = true): Promise<bigint> => {
30
59
  if (isGetter) {
31
60
  const _rate: bigint = cacheStats.get(cacheKey(this.market.addresses.amm, 'rate'));
@@ -61,16 +90,17 @@ export class StatsBaseModule {
61
90
  const llammaContract = this.llamalend.contracts[this.market.addresses.amm].multicallContract;
62
91
  const controllerContract = this.llamalend.contracts[this.market.addresses.controller].multicallContract;
63
92
 
64
- const calls = [
65
- llammaContract.fee(),
66
- llammaContract.admin_fee(), // TODO: removed
67
- controllerContract.liquidation_discount(),
68
- controllerContract.loan_discount(),
69
- llammaContract.get_base_price(),
70
- llammaContract.A(),
71
- ]
93
+ const [[_fee, _liquidation_discount, _loan_discount, _base_price, _A], _admin_fee] = await Promise.all([
94
+ this.llamalend.multicallProvider.all([
95
+ llammaContract.fee(),
96
+ controllerContract.liquidation_discount(),
97
+ controllerContract.loan_discount(),
98
+ llammaContract.get_base_price(),
99
+ llammaContract.A(),
100
+ ]),
101
+ this._fetchAdminFee(),
102
+ ]) as [bigint[], bigint];
72
103
 
73
- const [_fee, _admin_fee, _liquidation_discount, _loan_discount, _base_price, _A]: bigint[] = await this.llamalend.multicallProvider.all(calls) as bigint[];
74
104
  const A = formatUnits(_A, 0)
75
105
  const base_price = formatUnits(_base_price)
76
106
  const [fee, admin_fee, liquidation_discount, loan_discount] = [_fee, _admin_fee, _liquidation_discount, _loan_discount]
@@ -84,11 +114,7 @@ export class StatsBaseModule {
84
114
 
85
115
  public async statsRates(isGetter = true, useAPI = false): Promise<{borrowApr: string, lendApr: string, borrowApy: string, lendApy: string}> {
86
116
  if(useAPI) {
87
- const market = await fetchMarketDataByVault(
88
- this.llamalend.constants.NETWORK_NAME,
89
- this.market.addresses.vault,
90
- _getMarketsData
91
- );
117
+ const market = await this._fetchMarketDataFromAPI();
92
118
  return {
93
119
  borrowApr: (market.rates.borrowApr * 100).toString(),
94
120
  lendApr: (market.rates.lendApr * 100).toString(),
@@ -97,9 +123,9 @@ export class StatsBaseModule {
97
123
  };
98
124
  } else {
99
125
  const _rate = await this._getRate(isGetter);
100
- const debt = await this.statsTotalDebt(isGetter);
101
- const { cap } = Number(debt) > 0 ? await this.statsCapAndAvailable(isGetter) : { cap: "0" };
102
- return computeRatesFromRate(_rate, debt, cap);
126
+ const debt = await this.statsTotalDebt(isGetter, false);
127
+ const { totalAssets } = Number(debt) > 0 ? await this.statsCapAndAvailable(isGetter, false) : { totalAssets: "0" };
128
+ return computeRatesFromRate(_rate, debt, totalAssets);
103
129
  }
104
130
  }
105
131
 
@@ -108,21 +134,21 @@ export class StatsBaseModule {
108
134
  const _dDebt = parseUnits(dDebt, this.market.borrowed_token.decimals);
109
135
  const _rate = await this._getFutureRate(_dReserves, _dDebt);
110
136
  const debt = Number(await this.statsTotalDebt()) + Number(dDebt);
111
- const cap = Number((await this.statsCapAndAvailable(true, useAPI)).cap) + Number(dReserves);
137
+ const cap = Number((await this.statsCapAndAvailable(true, useAPI)).totalAssets) + Number(dReserves);
112
138
  return computeRatesFromRate(_rate, debt, cap);
113
139
  }
114
140
 
115
141
  public async statsBalances(): Promise<[string, string]> {
116
142
  const borrowedContract = this.llamalend.contracts[this.market.borrowed_token.address].multicallContract;
117
143
  const collateralContract = this.llamalend.contracts[this.market.collateral_token.address].multicallContract;
118
- const ammContract = this.llamalend.contracts[this.market.addresses.amm].multicallContract;
119
- const calls = [
120
- borrowedContract.balanceOf(this.market.addresses.amm),
121
- collateralContract.balanceOf(this.market.addresses.amm),
122
- ammContract.admin_fees_x(), // TODO: always 0
123
- ammContract.admin_fees_y(), // TODO: always 0
124
- ]
125
- const [_borrowedBalance, _collateralBalance, _borrowedAdminFees, _collateralAdminFees]: bigint[] = await this.llamalend.multicallProvider.all(calls);
144
+
145
+ const [[_borrowedBalance, _collateralBalance], [_borrowedAdminFees, _collateralAdminFees]] = await Promise.all([
146
+ this.llamalend.multicallProvider.all([
147
+ borrowedContract.balanceOf(this.market.addresses.amm),
148
+ collateralContract.balanceOf(this.market.addresses.amm),
149
+ ]),
150
+ this._getAdminFeesXY(false),
151
+ ]) as [bigint[], [bigint, bigint]];
126
152
 
127
153
  return [
128
154
  formatUnits(_borrowedBalance - _borrowedAdminFees, this.market.borrowed_token.decimals),
@@ -188,11 +214,7 @@ export class StatsBaseModule {
188
214
 
189
215
  public async statsTotalDebt(isGetter = true, useAPI = true): Promise<string> {
190
216
  if(useAPI) {
191
- const market = await fetchMarketDataByVault(
192
- this.llamalend.constants.NETWORK_NAME,
193
- this.market.addresses.vault,
194
- _getMarketsData
195
- );
217
+ const market = await this._fetchMarketDataFromAPI();
196
218
  return market.borrowed.total.toString();
197
219
  } else {
198
220
  let _debt;
@@ -209,11 +231,7 @@ export class StatsBaseModule {
209
231
 
210
232
  public statsAmmBalances = async (isGetter = true, useAPI = false): Promise<{ borrowed: string, collateral: string }> => {
211
233
  if(useAPI) {
212
- const market = await fetchMarketDataByVault(
213
- this.llamalend.constants.NETWORK_NAME,
214
- this.market.addresses.vault,
215
- _getMarketsData
216
- );
234
+ const market = await this._fetchMarketDataFromAPI();
217
235
  return {
218
236
  borrowed: market.ammBalances.ammBalanceBorrowed.toString(),
219
237
  collateral: market.ammBalances.ammBalanceCollateral.toString(),
@@ -221,27 +239,24 @@ export class StatsBaseModule {
221
239
  } else {
222
240
  const borrowedContract = this.llamalend.contracts[this.market.addresses.borrowed_token].multicallContract;
223
241
  const collateralContract = this.llamalend.contracts[this.market.addresses.collateral_token].multicallContract;
224
- const ammContract = this.llamalend.contracts[this.market.addresses.amm].multicallContract;
225
242
 
226
- let _balance_x, _fee_x, _balance_y, _fee_y; // TODO: fees are always 0
243
+ let _balance_x: bigint, _balance_y: bigint;
244
+ let _fee_x: bigint, _fee_y: bigint;
245
+
227
246
  if(isGetter) {
228
- [_balance_x, _fee_x, _balance_y, _fee_y] = [
229
- cacheStats.get(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.amm)),
230
- cacheStats.get(cacheKey(this.market.addresses.amm, 'admin_fees_x')),
231
- cacheStats.get(cacheKey(this.market.addresses.collateral_token, 'balanceOf', this.market.addresses.amm)),
232
- cacheStats.get(cacheKey(this.market.addresses.amm, 'admin_fees_y')),
233
- ]
247
+ _balance_x = cacheStats.get(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.amm));
248
+ _balance_y = cacheStats.get(cacheKey(this.market.addresses.collateral_token, 'balanceOf', this.market.addresses.amm));
249
+ [_fee_x, _fee_y] = await this._getAdminFeesXY(true);
234
250
  } else {
235
- [_balance_x, _fee_x, _balance_y, _fee_y] = await this.llamalend.multicallProvider.all([
236
- borrowedContract.balanceOf(this.market.addresses.amm),
237
- ammContract.admin_fees_x(),
238
- collateralContract.balanceOf(this.market.addresses.amm),
239
- ammContract.admin_fees_y(),
240
- ]);
251
+ [[_balance_x, _balance_y], [_fee_x, _fee_y]] = await Promise.all([
252
+ this.llamalend.multicallProvider.all([
253
+ borrowedContract.balanceOf(this.market.addresses.amm),
254
+ collateralContract.balanceOf(this.market.addresses.amm),
255
+ ]),
256
+ this._getAdminFeesXY(false),
257
+ ]) as [[bigint, bigint], [bigint, bigint]];
241
258
  cacheStats.set(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.amm), _balance_x);
242
- cacheStats.set(cacheKey(this.market.addresses.amm, 'admin_fees_x'), _fee_x);
243
259
  cacheStats.set(cacheKey(this.market.addresses.collateral_token, 'balanceOf', this.market.addresses.amm), _balance_y);
244
- cacheStats.set(cacheKey(this.market.addresses.amm, 'admin_fees_y'), _fee_y);
245
260
  }
246
261
 
247
262
  return {
@@ -251,43 +266,47 @@ export class StatsBaseModule {
251
266
  }
252
267
  }
253
268
 
254
- public async statsCapAndAvailable(isGetter = true, useAPI = false): Promise<{ cap: string, available: string }> {
255
- if(useAPI) {
256
- const market = await fetchMarketDataByVault(
257
- this.llamalend.constants.NETWORK_NAME,
258
- this.market.addresses.vault,
259
- _getMarketsData
260
- );
261
- return {
262
- cap: market.totalSupplied.total.toString(),
263
- available: market.availableToBorrow.total.toString(),
264
- };
265
- } else {
266
- const vaultContract = this.llamalend.contracts[this.market.addresses.vault].multicallContract;
267
- const borrowedContract = this.llamalend.contracts[this.market.addresses.borrowed_token].multicallContract;
269
+ protected async _statsCapAndAvailableFromAPI(): Promise<{ borrowCap: string, available: string, totalAssets: string, availableForBorrow: string }> {
270
+ const market = await this._fetchMarketDataFromAPI();
271
+ return {
272
+ totalAssets: market.totalSupplied.total.toString(),
273
+ borrowCap: Infinity.toString(),
274
+ available: market.availableToBorrow.total.toString(),
275
+ availableForBorrow: market.availableToBorrow.total.toString(),
276
+ };
277
+ }
268
278
 
269
- let _cap, _available;
270
- if(isGetter) { // TODO: should call controller.available_balance() instead of borrowed_token.balanceOf(controller)
271
- _cap = cacheStats.get(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller));
272
- _available = cacheStats.get(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.controller));
273
- } else {
274
- [_cap, _available] =await this.llamalend.multicallProvider.all([
275
- vaultContract.totalAssets(this.market.addresses.controller),
276
- borrowedContract.balanceOf(this.market.addresses.controller),
277
- ]);
278
- cacheStats.set(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller), _cap);
279
- cacheStats.set(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.controller), _available);
280
- }
279
+ protected async _statsCapAndAvailableOnChain(isGetter: boolean): Promise<{ borrowCap: string, available: string, totalAssets: string, availableForBorrow: string }> {
280
+ const vaultContract = this.llamalend.contracts[this.market.addresses.vault].multicallContract;
281
+ const borrowedContract = this.llamalend.contracts[this.market.addresses.borrowed_token].multicallContract;
281
282
 
282
- return {
283
- cap: this.llamalend.formatUnits(_cap, this.market.borrowed_token.decimals),
284
- available: this.llamalend.formatUnits(_available, this.market.borrowed_token.decimals),
285
- }
286
- // cap -> totalAssets
287
- // add cap: controller.borrow_cap() // Display
283
+ let _cap, _available;
284
+ if(isGetter) {
285
+ _cap = cacheStats.get(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller));
286
+ _available = cacheStats.get(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.controller));
287
+ } else {
288
+ [_cap, _available] = await this.llamalend.multicallProvider.all([
289
+ vaultContract.totalAssets(this.market.addresses.controller),
290
+ borrowedContract.balanceOf(this.market.addresses.controller),
291
+ ]);
292
+ cacheStats.set(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller), _cap);
293
+ cacheStats.set(cacheKey(this.market.addresses.borrowed_token, 'balanceOf', this.market.addresses.controller), _available);
294
+ }
295
+
296
+ const available = this.llamalend.formatUnits(_available, this.market.borrowed_token.decimals);
297
+ return {
298
+ totalAssets: this.llamalend.formatUnits(_cap, this.market.borrowed_token.decimals),
299
+ borrowCap: Infinity.toString(),
300
+ available,
301
+ availableForBorrow: available,
288
302
  }
289
303
  }
290
304
 
305
+ public async statsCapAndAvailable(isGetter = true, useAPI = false): Promise<{ borrowCap: string, available: string, totalAssets: string, availableForBorrow: string }> {
306
+ if(useAPI) return this._statsCapAndAvailableFromAPI();
307
+ return this._statsCapAndAvailableOnChain(isGetter);
308
+ }
309
+
291
310
  public statsAdminPercentage = async (): Promise<string> => {
292
311
  const _adminPercentage = await this._fetchAdminPercentage();
293
312
  return formatUnits(_adminPercentage * BigInt(100));
@@ -289,10 +289,10 @@ export class VaultModule {
289
289
  }
290
290
 
291
291
  public async vaultTotalLiquidity(useAPI = true): Promise<string> {
292
- const { cap } = await this.market.stats.capAndAvailable(true, useAPI);
292
+ const { totalAssets } = await this.market.stats.capAndAvailable(true, useAPI);
293
293
  const price = await _getUsdRate.call(this.llamalend, this.market.addresses.borrowed_token);
294
294
 
295
- return BN(cap).times(price).toFixed(6)
295
+ return BN(totalAssets).times(price).toFixed(6)
296
296
  }
297
297
 
298
298
  private _calcCrvApr = async (futureWorkingSupplyBN: BigNumber | null = null): Promise<[baseApy: number, boostedApy: number]> => {
@@ -1,5 +1,8 @@
1
1
  import memoize from "memoizee";
2
2
  import { StatsBaseModule } from "../common/statsBase.js";
3
+ import {cacheKey, cacheStats} from "../../../cache";
4
+ import BigNumber from "bignumber.js";
5
+ import {BN} from "../../../utils";
3
6
 
4
7
  export class StatsV2Module extends StatsBaseModule {
5
8
  protected _fetchAdminPercentage = memoize(async (): Promise<bigint> => {
@@ -8,4 +11,51 @@ export class StatsV2Module extends StatsBaseModule {
8
11
  promise: true,
9
12
  maxAge: 30 * 60 * 1000, // 30m
10
13
  });
14
+
15
+ protected _fetchAdminFee = async (): Promise<bigint> => BigInt(0);
16
+
17
+ protected _getAdminFeesXY = async (): Promise<[bigint, bigint]> => [BigInt(0), BigInt(0)];
18
+
19
+ protected async _statsCapAndAvailableFromAPI() {
20
+ const market = await this._fetchMarketDataFromAPI();
21
+ return {
22
+ totalAssets: market.totalSupplied.total.toString(),
23
+ borrowCap: market.borrowCap.total.toString(),
24
+ available: market.availableToBorrow.total.toString(),
25
+ availableForBorrow: market.availableToBorrow.total.toString(),
26
+ };
27
+ }
28
+
29
+ protected async _statsCapAndAvailableOnChain(isGetter: boolean): Promise<{ borrowCap: string, available: string, totalAssets: string, availableForBorrow: string }> {
30
+ const vaultContract = this.llamalend.contracts[this.market.addresses.vault].multicallContract;
31
+ const controllerContract = this.llamalend.contracts[this.market.addresses.controller].multicallContract;
32
+
33
+ let _cap: bigint, _available: bigint, _totalAssets: bigint, _totalDebt: bigint;
34
+ if(isGetter) {
35
+ _totalAssets = cacheStats.get(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller));
36
+ _cap = cacheStats.get(cacheKey(this.market.addresses.controller, 'borrow_cap'));
37
+ _available = cacheStats.get(cacheKey(this.market.addresses.controller, 'available_balance'));
38
+ _totalDebt = cacheStats.get(cacheKey(this.market.addresses.controller, 'total_debt'));
39
+ } else {
40
+ [_totalAssets, _available, _cap, _totalDebt] = await this.llamalend.multicallProvider.all([
41
+ vaultContract.totalAssets(this.market.addresses.controller),
42
+ controllerContract.available_balance(),
43
+ controllerContract.borrow_cap(),
44
+ controllerContract.total_debt(),
45
+ ]);
46
+
47
+ cacheStats.set(cacheKey(this.market.addresses.vault, 'totalAssets', this.market.addresses.controller), _totalAssets);
48
+ cacheStats.set(cacheKey(this.market.addresses.controller, 'borrow_cap'), _cap);
49
+ cacheStats.set(cacheKey(this.market.addresses.controller, 'available_balance'), _available);
50
+ cacheStats.set(cacheKey(this.market.addresses.controller, 'total_debt'), _totalDebt);
51
+ }
52
+
53
+ const totalAssets = this.llamalend.formatUnits(_totalAssets, this.market.borrowed_token.decimals);
54
+ const borrowCap = this.llamalend.formatUnits(_cap, this.market.borrowed_token.decimals);
55
+ const available = this.llamalend.formatUnits(_available, this.market.borrowed_token.decimals);
56
+ const totalDebt = this.llamalend.formatUnits(_totalDebt, this.market.borrowed_token.decimals);
57
+ const availableForBorrow = BigNumber.min(BN(available), BN(borrowCap).minus(BN(totalDebt))).toFixed();
58
+
59
+ return { totalAssets, borrowCap, available, availableForBorrow }
60
+ }
11
61
  }
@@ -24,8 +24,10 @@ export const computeRatesFromRate = (
24
24
  const borrowApr = annualFactor.times(100).toString();
25
25
  const borrowApy = String((expFactor - 1) * 100);
26
26
 
27
- const lendApr = annualFactor.times(debt).div(cap).times(100).toString();
28
- const lendApy = BN(debt).times(expFactor).minus(debt).div(cap).times(100).toString();
27
+ const lendAprRaw = annualFactor.times(debt).div(cap).times(100);
28
+ const lendApr = lendAprRaw.isNaN() ? "0" : lendAprRaw.toString();
29
+ const lendApyRaw = BN(debt).times(expFactor).minus(debt).div(cap).times(100);
30
+ const lendApy = lendApyRaw.isNaN() ? "0" : lendApyRaw.toString();
29
31
 
30
32
  return { borrowApr, lendApr, borrowApy, lendApy };
31
33
  }