@curvefi/llamalend-api 1.0.3 → 1.0.6
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.
- package/.github/workflows/lint.yml +2 -2
- package/.github/workflows/publish.yml +11 -7
- package/eslint.config.mjs +87 -0
- package/lib/cache/index.js +18 -19
- package/lib/constants/L2Networks.js +1 -1
- package/lib/constants/abis/crvUSD/controller_v2.json +979 -0
- package/lib/constants/aliases.js +34 -34
- package/lib/constants/coins.js +16 -16
- package/lib/constants/llammas.js +1 -1
- package/lib/constants/utils.js +8 -10
- package/lib/external-api.d.ts +8 -6
- package/lib/external-api.js +136 -397
- package/lib/index.d.ts +9 -10
- package/lib/index.js +46 -81
- package/lib/interfaces.d.ts +2 -20
- package/lib/lendMarkets/LendMarketTemplate.js +2438 -4419
- package/lib/lendMarkets/lendMarketConstructor.js +2 -2
- package/lib/llamalend.js +511 -696
- package/lib/mintMarkets/MintMarketTemplate.js +1469 -2799
- package/lib/mintMarkets/mintMarketConstructor.js +1 -1
- package/lib/st-crvUSD.js +172 -488
- package/lib/utils.d.ts +2 -2
- package/lib/utils.js +318 -548
- package/package.json +21 -16
- package/src/cache/index.ts +1 -0
- package/src/constants/abis/crvUSD/controller_v2.json +979 -0
- package/src/constants/aliases.ts +7 -7
- package/src/external-api.ts +25 -148
- package/src/interfaces.ts +2 -21
- package/src/lendMarkets/LendMarketTemplate.ts +31 -6
- package/src/llamalend.ts +36 -6
- package/src/mintMarkets/MintMarketTemplate.ts +2 -2
- package/src/utils.ts +8 -8
- package/tsconfig.json +1 -1
- package/.eslintrc.json +0 -40
package/src/constants/aliases.ts
CHANGED
|
@@ -125,17 +125,17 @@ export const ALIASES_FRAXTAL = lowerCaseValues({
|
|
|
125
125
|
"crv": "0x331B9182088e2A7d6D3Fe4742AbA1fB231aEcc56",
|
|
126
126
|
"one_way_factory": "0xf3c9bdAB17B7016fBE3B77D17b1602A7db93ac66",
|
|
127
127
|
"gauge_controller": "0x0000000000000000000000000000000000000000", // <--- TODO CHANGE
|
|
128
|
-
"
|
|
128
|
+
"gauge_factory_old": "0xeF672bD94913CB6f1d2812a6e18c1fFdEd8eFf5c",
|
|
129
|
+
"gauge_factory": "0x0b8d6b6cefc7aa1c2852442e518443b1b22e1c52",
|
|
129
130
|
"leverage_zap": "0x37c5ab57AF7100Bdc9B668d766e193CCbF6614FD", // odos
|
|
130
131
|
"leverage_markets_start_id": "0",
|
|
131
132
|
});
|
|
132
133
|
|
|
133
134
|
export const ALIASES_SONIC = lowerCaseValues({
|
|
134
|
-
"crv": "
|
|
135
|
-
"one_way_factory": "
|
|
135
|
+
"crv": "0x5Af79133999f7908953E94b7A5CF367740Ebee35",
|
|
136
|
+
"one_way_factory": "0x30d1859dad5a52ae03b6e259d1b48c4b12933993",
|
|
136
137
|
"gauge_controller": "0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB",
|
|
137
|
-
"gauge_factory": "
|
|
138
|
-
|
|
139
|
-
"
|
|
140
|
-
"leverage_markets_start_id": "9",
|
|
138
|
+
"gauge_factory": "0xf3A431008396df8A8b2DF492C913706BDB0874ef",
|
|
139
|
+
"leverage_zap": "0x5552b631e2aD801fAa129Aacf4B701071cC9D1f7", // odos
|
|
140
|
+
"leverage_markets_start_id": "0",
|
|
141
141
|
});
|
package/src/external-api.ts
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { ethers } from "ethers";
|
|
1
|
+
import {ethers} from "ethers";
|
|
3
2
|
import memoize from "memoizee";
|
|
4
|
-
import
|
|
5
|
-
import { llamalend } from "./llamalend.js";
|
|
3
|
+
import {llamalend} from "./llamalend.js";
|
|
6
4
|
import {
|
|
5
|
+
IDict,
|
|
7
6
|
IExtendedPoolDataFromApi,
|
|
7
|
+
IMarketData,
|
|
8
8
|
INetworkName,
|
|
9
9
|
IPoolFactory,
|
|
10
|
-
I1inchSwapData,
|
|
11
|
-
IDict,
|
|
12
|
-
IMarketData,
|
|
13
10
|
IQuoteOdos,
|
|
14
11
|
} from "./interfaces";
|
|
15
12
|
|
|
16
13
|
|
|
17
14
|
const _getPoolsFromApi = memoize(
|
|
18
15
|
async (network: INetworkName, poolFactory: IPoolFactory ): Promise<IExtendedPoolDataFromApi> => {
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
return
|
|
16
|
+
const response = await fetch(`https://api.curve.fi/api/getPools/${network}/${poolFactory}`);
|
|
17
|
+
const { data } = await response.json() as { data?: IExtendedPoolDataFromApi, success: boolean };
|
|
18
|
+
return data ?? { poolData: [], tvl: 0, tvlAll: 0 };
|
|
22
19
|
},
|
|
23
20
|
{
|
|
24
21
|
promise: true,
|
|
@@ -117,14 +114,16 @@ export const _getUsdPricesFromApi = async (): Promise<IDict<number>> => {
|
|
|
117
114
|
return priceDictByMaxTvl
|
|
118
115
|
}
|
|
119
116
|
|
|
117
|
+
type UserCollateral = { total_deposit_precise: string, total_deposit_from_user: number, total_deposit_usd_value: number }
|
|
120
118
|
export const _getUserCollateral = memoize(
|
|
121
|
-
async (network: INetworkName, controller: string, user: string): Promise<
|
|
119
|
+
async (network: INetworkName, controller: string, user: string): Promise<UserCollateral> => {
|
|
122
120
|
const url = `https://prices.curve.fi/v1/lending/collateral_events/${network}/${controller}/${user}`;
|
|
123
|
-
const response = await
|
|
121
|
+
const response = await fetch(url);
|
|
122
|
+
const data = await response.json() as UserCollateral;
|
|
124
123
|
return {
|
|
125
|
-
total_deposit_precise:
|
|
126
|
-
total_deposit_from_user:
|
|
127
|
-
total_deposit_usd_value:
|
|
124
|
+
total_deposit_precise: data.total_deposit_precise,
|
|
125
|
+
total_deposit_from_user: data.total_deposit_from_user,
|
|
126
|
+
total_deposit_usd_value: data.total_deposit_usd_value,
|
|
128
127
|
}
|
|
129
128
|
},
|
|
130
129
|
{
|
|
@@ -136,8 +135,9 @@ export const _getUserCollateral = memoize(
|
|
|
136
135
|
export const _getUserCollateralCrvUsd = memoize(
|
|
137
136
|
async (network: INetworkName, controller: string, user: string): Promise<string> => {
|
|
138
137
|
const url = `https://prices.curve.fi/v1/crvusd/collateral_events/${network}/${controller}/${user}`;
|
|
139
|
-
const response = await
|
|
140
|
-
|
|
138
|
+
const response = await fetch(url);
|
|
139
|
+
const { total_deposit } = await response.json() as { total_deposit: string };
|
|
140
|
+
return total_deposit;
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
143
|
promise: true,
|
|
@@ -148,16 +148,11 @@ export const _getUserCollateralCrvUsd = memoize(
|
|
|
148
148
|
export const _getMarketsData = memoize(
|
|
149
149
|
async (network: INetworkName): Promise<IMarketData> => {
|
|
150
150
|
const url = `https://api.curve.fi/api/getLendingVaults/${network}/oneway`;
|
|
151
|
-
const response = await
|
|
152
|
-
url,
|
|
153
|
-
{
|
|
154
|
-
headers: {"accept": "application/json"},
|
|
155
|
-
validateStatus: () => true,
|
|
156
|
-
});
|
|
151
|
+
const response = await fetch(url, { headers: {"accept": "application/json"} });
|
|
157
152
|
if (response.status !== 200) {
|
|
158
153
|
throw Error(`Fetch error: ${response.status} ${response.statusText}`);
|
|
159
154
|
}
|
|
160
|
-
return response.
|
|
155
|
+
return await response.json() as IMarketData;
|
|
161
156
|
},
|
|
162
157
|
{
|
|
163
158
|
promise: true,
|
|
@@ -177,17 +172,12 @@ export const _getQuoteOdos = async (fromToken: string, toToken: string, _amount:
|
|
|
177
172
|
`&to_address=${ethers.getAddress(toToken)}&amount=${_amount.toString()}&slippage=${slippage}&pathVizImage=${pathVizImage}` +
|
|
178
173
|
`&caller_address=${ethers.getAddress(llamalend.constants.ALIASES.leverage_zap)}&blacklist=${ethers.getAddress(blacklist)}`;
|
|
179
174
|
|
|
180
|
-
const response = await
|
|
181
|
-
url,
|
|
182
|
-
{
|
|
183
|
-
headers: {"accept": "application/json"},
|
|
184
|
-
validateStatus: () => true,
|
|
185
|
-
});
|
|
175
|
+
const response = await fetch(url, { headers: {"accept": "application/json"} });
|
|
186
176
|
if (response.status !== 200) {
|
|
187
177
|
throw Error(`Odos quote error - ${response.status} ${response.statusText}`);
|
|
188
178
|
}
|
|
189
|
-
|
|
190
|
-
return { ...
|
|
179
|
+
const data = await response.json() as Omit<IQuoteOdos, 'slippage'>;
|
|
180
|
+
return { ...data, slippage };
|
|
191
181
|
}
|
|
192
182
|
|
|
193
183
|
export const _getExpectedOdos = async (fromToken: string, toToken: string, _amount: bigint, blacklist: string) => {
|
|
@@ -198,125 +188,12 @@ export const _assembleTxOdos = memoize(
|
|
|
198
188
|
async (pathId: string): Promise<string> => {
|
|
199
189
|
const url = `https://prices.curve.fi/odos/assemble?user=${ethers.getAddress(llamalend.constants.ALIASES.leverage_zap)}&path_id=${pathId}`;
|
|
200
190
|
|
|
201
|
-
const response = await
|
|
202
|
-
url,
|
|
203
|
-
{
|
|
204
|
-
headers: {'Content-Type': 'application/json'},
|
|
205
|
-
validateStatus: () => true,
|
|
206
|
-
});
|
|
191
|
+
const response = await fetch(url, { headers: {'Content-Type': 'application/json'} });
|
|
207
192
|
if (response.status !== 200) {
|
|
208
193
|
throw Error(`Odos assemble error - ${response.status} ${response.statusText}`);
|
|
209
194
|
}
|
|
210
|
-
|
|
211
|
-
return
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
promise: true,
|
|
215
|
-
maxAge: 10 * 1000, // 10s
|
|
216
|
-
}
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
export const _getSpotPriceOdos = memoize(
|
|
220
|
-
async (fromToken: string, toToken: string): Promise<string | undefined> => {
|
|
221
|
-
fromToken = ethers.getAddress(fromToken);
|
|
222
|
-
toToken = ethers.getAddress(toToken);
|
|
223
|
-
const url = `https://prices.curve.fi/odos/prices?chain_id=${llamalend.chainId}&tokens=${fromToken},${toToken}`;
|
|
224
|
-
const response = await axios.get(
|
|
225
|
-
url,
|
|
226
|
-
{
|
|
227
|
-
headers: {"accept": "application/json"},
|
|
228
|
-
validateStatus: () => true,
|
|
229
|
-
});
|
|
230
|
-
if (response.status !== 200) {
|
|
231
|
-
throw Error(`Odos spot prices error - ${response.status} ${response.statusText}`);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const pricesFromOdos = response.data.tokenPrices;
|
|
235
|
-
const pricesFromApi: IDict<string> = {};
|
|
236
|
-
for (const coin of [fromToken, toToken]) {
|
|
237
|
-
if (pricesFromOdos[coin] !== 0) continue;
|
|
238
|
-
const _pricesFromApi = await _getUsdPricesFromApi();
|
|
239
|
-
pricesFromApi[coin] = String(_pricesFromApi[coin] || 0);
|
|
240
|
-
}
|
|
241
|
-
const prices = { ...pricesFromOdos, ...pricesFromApi };
|
|
242
|
-
if (BigNumber(prices[fromToken]).eq(0) || BigNumber(prices[toToken]).eq( 0)) return undefined;
|
|
243
|
-
|
|
244
|
-
return (new BigNumber(prices[toToken])).div(prices[fromToken]).toString()
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
promise: true,
|
|
248
|
-
maxAge: 10 * 1000, // 10s
|
|
249
|
-
}
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
// --- 1INCH ---
|
|
253
|
-
|
|
254
|
-
export const _getExpected1inch = memoize(
|
|
255
|
-
async (fromToken: string, toToken: string, _amount: bigint): Promise<string> => {
|
|
256
|
-
if (_amount === BigInt(0)) return "0.0";
|
|
257
|
-
const url = `https://prices.curve.fi/1inch/swap/v6.0/${llamalend.chainId}/quote?src=${fromToken}&dst=${toToken}&amount=${_amount}&excludedProtocols=${llamalend.constants.EXCLUDED_PROTOCOLS_1INCH}&includeTokensInfo=true&includeProtocols=true`;
|
|
258
|
-
const response = await axios.get(
|
|
259
|
-
url,
|
|
260
|
-
{
|
|
261
|
-
headers: {"accept": "application/json"},
|
|
262
|
-
validateStatus: () => true,
|
|
263
|
-
});
|
|
264
|
-
if (response.status !== 200) {
|
|
265
|
-
throw Error(`1inch error: ${response.status} ${response.statusText}`);
|
|
266
|
-
}
|
|
267
|
-
return response.data.dstAmount;
|
|
268
|
-
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
promise: true,
|
|
272
|
-
maxAge: 10 * 1000, // 10s
|
|
273
|
-
}
|
|
274
|
-
)
|
|
275
|
-
|
|
276
|
-
export const _getSwapData1inch = memoize(
|
|
277
|
-
async (fromToken: string, toToken: string, _amount: bigint, slippage: number): Promise<I1inchSwapData> => {
|
|
278
|
-
if (_amount === BigInt(0)) throw Error("Amount must be > 0");
|
|
279
|
-
const url = `https://prices.curve.fi/1inch/swap/v6.0/${llamalend.chainId}/swap?src=${fromToken}&dst=${toToken}&amount=${_amount}&from_=${llamalend.constants.ALIASES.leverage_zap}&slippage=${slippage}&excludedProtocols=${llamalend.constants.EXCLUDED_PROTOCOLS_1INCH}&includeTokensInfo=true&includeProtocols=true&disableEstimate=true`;
|
|
280
|
-
const response = await axios.get(
|
|
281
|
-
url,
|
|
282
|
-
{
|
|
283
|
-
headers: {"accept": "application/json"},
|
|
284
|
-
validateStatus: () => true,
|
|
285
|
-
});
|
|
286
|
-
if (response.status !== 200) {
|
|
287
|
-
throw Error(`1inch error: ${response.status} ${response.statusText}`);
|
|
288
|
-
}
|
|
289
|
-
return response.data;
|
|
290
|
-
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
promise: true,
|
|
294
|
-
maxAge: 10 * 1000, // 10s
|
|
295
|
-
}
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
export const _getSpotPrice1inch = memoize(
|
|
299
|
-
async (fromToken: string, toToken: string): Promise<string | undefined> => {
|
|
300
|
-
const url = `https://prices.curve.fi/1inch/price/v1.1/${llamalend.chainId}?tokens=${fromToken},${toToken}¤cy=USD`;
|
|
301
|
-
const response = await axios.get(
|
|
302
|
-
url,
|
|
303
|
-
{
|
|
304
|
-
headers: {"accept": "application/json"},
|
|
305
|
-
validateStatus: () => true,
|
|
306
|
-
});
|
|
307
|
-
if (response.status !== 200) {
|
|
308
|
-
throw Error(`1inch error: ${response.status} ${response.statusText}`);
|
|
309
|
-
}
|
|
310
|
-
const pricesFromApi: IDict<string> = {};
|
|
311
|
-
for (const coin in response.data) {
|
|
312
|
-
if (response.data[coin] !== "0") continue;
|
|
313
|
-
const _pricesFromApi = await _getUsdPricesFromApi();
|
|
314
|
-
pricesFromApi[coin] = String(_pricesFromApi[coin] || 0);
|
|
315
|
-
}
|
|
316
|
-
const prices = { ...response.data, ...pricesFromApi };
|
|
317
|
-
if (prices[fromToken] === '0' || prices[toToken] === '0') return undefined;
|
|
318
|
-
|
|
319
|
-
return (new BigNumber(prices[toToken])).div(prices[fromToken]).toString()
|
|
195
|
+
const { transaction } = await response.json() as { transaction: { data: string } };
|
|
196
|
+
return transaction.data;
|
|
320
197
|
},
|
|
321
198
|
{
|
|
322
199
|
promise: true,
|
package/src/interfaces.ts
CHANGED
|
@@ -5,8 +5,8 @@ export interface IDict<T> {
|
|
|
5
5
|
[index: string]: T,
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
export type INetworkName = "ethereum" | "optimism" | "bsc" | "xdai" | "polygon" | "x-layer" | "fantom" | "fraxtal" | "zksync" | "moonbeam" | "kava" | "mantle" | "base" | "arbitrum" | "celo" | "avalanche" | "aurora";
|
|
9
|
-
export type IChainId = 1 | 10 | 56 | 100 | 137 | 196 | 250 | 252 | 324 | 1284 | 2222 | 5000 | 8453 | 42161 | 42220 | 43114 | 1313161554;
|
|
8
|
+
export type INetworkName = "ethereum" | "optimism" | "bsc" | "xdai" | "polygon" | 'sonic' | "x-layer" | "fantom" | "fraxtal" | "zksync" | "moonbeam" | "kava" | "mantle" | "base" | "arbitrum" | "celo" | "avalanche" | "aurora";
|
|
9
|
+
export type IChainId = 1 | 10 | 56 | 100 | 137 | 146 | 196 | 250 | 252 | 324 | 1284 | 2222 | 5000 | 8453 | 42161 | 42220 | 43114 | 1313161554;
|
|
10
10
|
export type IPoolFactory = "main" | "crypto" | "factory" | "factory-crvusd" | "factory-crypto" | "factory-twocrypto" | "factory-tricrypto" | "factory-stable-ng";
|
|
11
11
|
export interface ICurveContract {
|
|
12
12
|
contract: Contract,
|
|
@@ -123,25 +123,6 @@ export interface IReward {
|
|
|
123
123
|
apy: number
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
export type T1inchRouteStep = {
|
|
127
|
-
name: string,
|
|
128
|
-
part: number,
|
|
129
|
-
fromTokenAddress: string,
|
|
130
|
-
toTokenAddress: string,
|
|
131
|
-
}[]
|
|
132
|
-
|
|
133
|
-
export interface I1inchRoute {
|
|
134
|
-
part: number,
|
|
135
|
-
hops: T1inchRouteStep[],
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export interface I1inchSwapData {
|
|
139
|
-
tx: { data: string },
|
|
140
|
-
dstAmount: string,
|
|
141
|
-
protocols: I1inchRoute[],
|
|
142
|
-
slippage: number,
|
|
143
|
-
}
|
|
144
|
-
|
|
145
126
|
interface Rates {
|
|
146
127
|
borrowApr: number;
|
|
147
128
|
borrowApy: number;
|
|
@@ -700,7 +700,7 @@ export class LendMarketTemplate {
|
|
|
700
700
|
return [baseApyBN.times(100).toNumber(), boostedApyBN.times(100).toNumber()]
|
|
701
701
|
}
|
|
702
702
|
|
|
703
|
-
private async vaultCrvApr(
|
|
703
|
+
private async vaultCrvApr(): Promise<[baseApy: number, boostedApy: number]> {
|
|
704
704
|
if (this.vaultRewardsOnly()) throw Error(`${this.name} has Rewards-Only Gauge. Use stats.rewardsApy instead`);
|
|
705
705
|
|
|
706
706
|
// const isDisabledChain = [1313161554].includes(llamalend.chainId); // Disable Aurora
|
|
@@ -723,7 +723,32 @@ export class LendMarketTemplate {
|
|
|
723
723
|
|
|
724
724
|
private async _vaultClaimCrv(estimateGas: boolean): Promise<string | TGas> {
|
|
725
725
|
if (this.vaultRewardsOnly()) throw Error(`${this.name} has Rewards-Only Gauge. Use claimRewards instead`);
|
|
726
|
-
|
|
726
|
+
|
|
727
|
+
let isOldFactory = false;
|
|
728
|
+
let contract;
|
|
729
|
+
|
|
730
|
+
if (llamalend.chainId !== 1) {
|
|
731
|
+
if (llamalend.constants.ALIASES.gauge_factory_old && llamalend.constants.ALIASES.gauge_factory_old !== llamalend.constants.ZERO_ADDRESS) {
|
|
732
|
+
const oldFactoryContract = llamalend.contracts[llamalend.constants.ALIASES.gauge_factory_old].contract;
|
|
733
|
+
const lpToken = await llamalend.contracts[this.addresses.gauge].contract.lp_token();
|
|
734
|
+
const gaugeAddress = await oldFactoryContract.get_gauge_from_lp_token(lpToken);
|
|
735
|
+
|
|
736
|
+
isOldFactory = gaugeAddress.toLowerCase() === this.addresses.gauge.toLowerCase();
|
|
737
|
+
|
|
738
|
+
if (isOldFactory) {
|
|
739
|
+
contract = oldFactoryContract;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
if (!isOldFactory) {
|
|
745
|
+
contract = llamalend.contracts[llamalend.constants.ALIASES.minter].contract
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
if(!contract) {
|
|
749
|
+
throw Error(`${this.name} couldn't match gauge factory`);
|
|
750
|
+
}
|
|
751
|
+
|
|
727
752
|
const gas = await contract.mint.estimateGas(this.addresses.gauge, llamalend.constantOptions);
|
|
728
753
|
if (estimateGas) return smartNumber(gas);
|
|
729
754
|
|
|
@@ -740,7 +765,7 @@ export class LendMarketTemplate {
|
|
|
740
765
|
return await this._vaultClaimCrv(false) as string;
|
|
741
766
|
}
|
|
742
767
|
|
|
743
|
-
private vaultRewardTokens = memoize(async (
|
|
768
|
+
private vaultRewardTokens = memoize(async (): Promise<{token: string, symbol: string, decimals: number}[]> => {
|
|
744
769
|
if (this.addresses.gauge === llamalend.constants.ZERO_ADDRESS) return []
|
|
745
770
|
|
|
746
771
|
// if (useApi) {
|
|
@@ -803,7 +828,7 @@ export class LendMarketTemplate {
|
|
|
803
828
|
// }
|
|
804
829
|
|
|
805
830
|
const apy: IReward[] = [];
|
|
806
|
-
const rewardTokens = await this.vaultRewardTokens(
|
|
831
|
+
const rewardTokens = await this.vaultRewardTokens();
|
|
807
832
|
for (const rewardToken of rewardTokens) {
|
|
808
833
|
const gaugeContract = llamalend.contracts[this.addresses.gauge].multicallContract;
|
|
809
834
|
const lpTokenContract = llamalend.contracts[this.addresses.vault].multicallContract;
|
|
@@ -1838,7 +1863,7 @@ export class LendMarketTemplate {
|
|
|
1838
1863
|
|
|
1839
1864
|
const _debt = parseUnits(debt);
|
|
1840
1865
|
const contract = llamalend.contracts[this.addresses.controller].contract;
|
|
1841
|
-
const [
|
|
1866
|
+
const [, n1] = await this.userBands(address);
|
|
1842
1867
|
const { borrowed } = await this.userState(address);
|
|
1843
1868
|
const n = (BN(borrowed).gt(0)) ? MAX_ACTIVE_BAND : n1 - 1; // In liquidation mode it doesn't matter if active band moves
|
|
1844
1869
|
const gas = await contract.repay.estimateGas(_debt, address, n, llamalend.constantOptions);
|
|
@@ -2834,7 +2859,7 @@ export class LendMarketTemplate {
|
|
|
2834
2859
|
try {
|
|
2835
2860
|
_n1 = await llamalend.contracts[this.addresses.controller].contract.calculate_debt_n1(_stateCollateral - _stateRepayCollateral, _stateDebt - _repayExpected, _N);
|
|
2836
2861
|
_n2 = _n1 + (_N - BigInt(1));
|
|
2837
|
-
} catch
|
|
2862
|
+
} catch {
|
|
2838
2863
|
console.log("Full repayment");
|
|
2839
2864
|
}
|
|
2840
2865
|
|
package/src/llamalend.ts
CHANGED
|
@@ -32,6 +32,7 @@ import gasOracleBlobABI from './constants/abis/gas_oracle_optimism_blob.json' as
|
|
|
32
32
|
// crvUSD ABIs
|
|
33
33
|
import llammaABI from "./constants/abis/crvUSD/llamma.json" assert { type: 'json'};
|
|
34
34
|
import controllerABI from "./constants/abis/crvUSD/controller.json" assert { type: 'json'};
|
|
35
|
+
import controllerV2ABI from "./constants/abis/crvUSD/controller_v2.json";
|
|
35
36
|
import PegKeeper from "./constants/abis/crvUSD/PegKeeper.json" assert { type: 'json'};
|
|
36
37
|
import FactoryABI from "./constants/abis/crvUSD/Factory.json" assert { type: 'json'};
|
|
37
38
|
import MonetaryPolicy2ABI from "./constants/abis/crvUSD/MonetaryPolicy2.json" assert { type: 'json'};
|
|
@@ -287,7 +288,7 @@ class Llamalend implements ILlamalend {
|
|
|
287
288
|
} else if (!providerSettings.url?.startsWith("https://rpc.gnosischain.com")) {
|
|
288
289
|
try {
|
|
289
290
|
this.signer = await this.provider.getSigner();
|
|
290
|
-
} catch
|
|
291
|
+
} catch {
|
|
291
292
|
this.signer = null;
|
|
292
293
|
}
|
|
293
294
|
}
|
|
@@ -334,7 +335,7 @@ class Llamalend implements ILlamalend {
|
|
|
334
335
|
if (this.signer) {
|
|
335
336
|
try {
|
|
336
337
|
this.signerAddress = await this.signer.getAddress();
|
|
337
|
-
} catch
|
|
338
|
+
} catch {
|
|
338
339
|
this.signer = null;
|
|
339
340
|
}
|
|
340
341
|
} else {
|
|
@@ -352,8 +353,18 @@ class Llamalend implements ILlamalend {
|
|
|
352
353
|
this.setContract(this.constants.ALIASES.minter, MinterABI);
|
|
353
354
|
this.setContract(this.constants.ALIASES.gauge_factory, GaugeFactoryMainnetABI);
|
|
354
355
|
} else {
|
|
355
|
-
this.constants.ALIASES.
|
|
356
|
-
|
|
356
|
+
if(this.constants.ALIASES.gauge_factory_old && this.constants.ALIASES.gauge_factory_old !== this.constants.ZERO_ADDRESS) {
|
|
357
|
+
// set old gauge factory
|
|
358
|
+
this.constants.ALIASES.minter_old = this.constants.ALIASES.gauge_factory_old;
|
|
359
|
+
this.setContract(this.constants.ALIASES.gauge_factory_old, GaugeFactorySidechainABI);
|
|
360
|
+
|
|
361
|
+
// set new gauge factory
|
|
362
|
+
this.constants.ALIASES.minter = this.constants.ALIASES.gauge_factory;
|
|
363
|
+
this.setContract(this.constants.ALIASES.gauge_factory, GaugeFactorySidechainABI);
|
|
364
|
+
} else {
|
|
365
|
+
this.constants.ALIASES.minter = this.constants.ALIASES.gauge_factory;
|
|
366
|
+
this.setContract(this.constants.ALIASES.gauge_factory, GaugeFactorySidechainABI);
|
|
367
|
+
}
|
|
357
368
|
}
|
|
358
369
|
|
|
359
370
|
// crvUSD contracts
|
|
@@ -415,10 +426,29 @@ class Llamalend implements ILlamalend {
|
|
|
415
426
|
return x;
|
|
416
427
|
});
|
|
417
428
|
|
|
429
|
+
calls = [];
|
|
430
|
+
|
|
431
|
+
for(const amm of amms) {
|
|
432
|
+
this.setContract(amm, llammaABI);
|
|
433
|
+
calls.push(
|
|
434
|
+
this.contracts[amm].multicallContract.A()
|
|
435
|
+
)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const AParams = (await this.multicallProvider.all(calls)).map((x) => {
|
|
439
|
+
return Number(x)
|
|
440
|
+
});
|
|
441
|
+
|
|
418
442
|
for (let i = 0; i < collaterals.length; i++) {
|
|
419
443
|
const is_eth = collaterals[i] === this.constants.WETH;
|
|
420
444
|
const [collateral_symbol, collateral_decimals] = res.splice(0, 2) as [string, number];
|
|
421
|
-
|
|
445
|
+
|
|
446
|
+
if (i >= collaterals.length - 3) {
|
|
447
|
+
this.setContract(controllers[i], controllerV2ABI);
|
|
448
|
+
} else {
|
|
449
|
+
this.setContract(controllers[i], controllerABI);
|
|
450
|
+
}
|
|
451
|
+
|
|
422
452
|
this.setContract(controllers[i], controllerABI);
|
|
423
453
|
const monetary_policy_address = (await this.contracts[controllers[i]].contract.monetary_policy(this.constantOptions)).toLowerCase();
|
|
424
454
|
this.setContract(monetary_policy_address, MonetaryPolicy2ABI);
|
|
@@ -438,7 +468,7 @@ class Llamalend implements ILlamalend {
|
|
|
438
468
|
min_bands: 4,
|
|
439
469
|
max_bands: 50,
|
|
440
470
|
default_bands: 10,
|
|
441
|
-
A:
|
|
471
|
+
A: AParams[i],
|
|
442
472
|
monetary_policy_abi: MonetaryPolicy2ABI,
|
|
443
473
|
}
|
|
444
474
|
}
|
|
@@ -1057,7 +1057,7 @@ export class MintMarketTemplate {
|
|
|
1057
1057
|
|
|
1058
1058
|
const _debt = parseUnits(debt);
|
|
1059
1059
|
const contract = llamalend.contracts[this.controller].contract;
|
|
1060
|
-
const [
|
|
1060
|
+
const [, n1] = await this.userBands(address);
|
|
1061
1061
|
const { stablecoin } = await this.userState(address);
|
|
1062
1062
|
const n = (BN(stablecoin).gt(0)) ? MAX_ACTIVE_BAND : n1 - 1; // In liquidation mode it doesn't matter if active band moves
|
|
1063
1063
|
const gas = await contract.repay.estimateGas(_debt, address, n, isEth(this.collateral), llamalend.constantOptions);
|
|
@@ -1693,7 +1693,7 @@ export class MintMarketTemplate {
|
|
|
1693
1693
|
try {
|
|
1694
1694
|
_n1 = await llamalend.contracts[this.deleverageZap].contract.calculate_debt_n1(_collateral, routeIdx, address);
|
|
1695
1695
|
_n2 = _n1 + BigInt(N - 1);
|
|
1696
|
-
} catch
|
|
1696
|
+
} catch {
|
|
1697
1697
|
console.log("Full repayment");
|
|
1698
1698
|
}
|
|
1699
1699
|
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import axios from "axios";
|
|
2
1
|
import { ethers, BigNumberish, Numeric } from "ethers";
|
|
3
2
|
import { Call } from "@curvefi/ethcall";
|
|
4
3
|
import BigNumber from 'bignumber.js';
|
|
@@ -295,7 +294,7 @@ export const _getUsdRate = async (assetId: string): Promise<number> => {
|
|
|
295
294
|
56: "binance-smart-chain",
|
|
296
295
|
100: 'xdai',
|
|
297
296
|
137: 'polygon-pos',
|
|
298
|
-
|
|
297
|
+
146: 'sonic',
|
|
299
298
|
196: 'x-layer',
|
|
300
299
|
250: 'fantom',
|
|
301
300
|
252: 'fraxtal',
|
|
@@ -316,7 +315,7 @@ export const _getUsdRate = async (assetId: string): Promise<number> => {
|
|
|
316
315
|
56: 'binancecoin',
|
|
317
316
|
100: 'xdai',
|
|
318
317
|
137: 'matic-network',
|
|
319
|
-
|
|
318
|
+
146: 'sonic-3',
|
|
320
319
|
196: 'okb',
|
|
321
320
|
250: 'fantom',
|
|
322
321
|
252: 'frax-ether',
|
|
@@ -359,10 +358,11 @@ export const _getUsdRate = async (assetId: string): Promise<number> => {
|
|
|
359
358
|
const url = [nativeTokenName, 'ethereum', 'bitcoin', 'link', 'curve-dao-token', 'stasis-eurs'].includes(assetId.toLowerCase()) ?
|
|
360
359
|
`https://api.coingecko.com/api/v3/simple/price?ids=${assetId}&vs_currencies=usd` :
|
|
361
360
|
`https://api.coingecko.com/api/v3/simple/token_price/${chainName}?contract_addresses=${assetId}&vs_currencies=usd`
|
|
362
|
-
const response = await
|
|
361
|
+
const response = await fetch(url);
|
|
362
|
+
const data = await response.json() as Record<string, { usd: number }>;
|
|
363
363
|
try {
|
|
364
|
-
_usdRatesCache[assetId] = {'rate':
|
|
365
|
-
} catch
|
|
364
|
+
_usdRatesCache[assetId] = {'rate': data[assetId]['usd'] ?? 0, 'time': Date.now()};
|
|
365
|
+
} catch { // TODO pay attention!
|
|
366
366
|
_usdRatesCache[assetId] = {'rate': 0, 'time': Date.now()};
|
|
367
367
|
}
|
|
368
368
|
}
|
|
@@ -457,8 +457,8 @@ export const getLsdApy = memoize(async(name: 'wstETH' | 'sfrxETH'): Promise<{
|
|
|
457
457
|
baseApy: number,
|
|
458
458
|
apyMean30d: number,
|
|
459
459
|
}> => {
|
|
460
|
-
const response = await
|
|
461
|
-
const {data} = response as { data: { chain: string, project: string, symbol: string, apy: number, apyBase: number, apyMean30d: number }[] };
|
|
460
|
+
const response = await fetch('https://yields.llama.fi/pools');
|
|
461
|
+
const {data} = await response.json() as { data: { chain: string, project: string, symbol: string, apy: number, apyBase: number, apyMean30d: number }[] };
|
|
462
462
|
|
|
463
463
|
const params = {
|
|
464
464
|
'wstETH': {
|
package/tsconfig.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/* Basic Options */
|
|
6
6
|
// "incremental": true, /* Enable incremental compilation */
|
|
7
|
-
"target": "
|
|
7
|
+
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
|
8
8
|
"module": "ESNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
|
9
9
|
"lib": ["ES2020"], /* Specify library files to be included in the compilation. */
|
|
10
10
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
package/.eslintrc.json
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"browser": true,
|
|
4
|
-
"es6": true
|
|
5
|
-
},
|
|
6
|
-
"extends": "eslint:recommended",
|
|
7
|
-
"parser": "vue-eslint-parser",
|
|
8
|
-
"parserOptions": {
|
|
9
|
-
"parser": "babel-eslint",
|
|
10
|
-
"sourceType": "module",
|
|
11
|
-
"allowImportExportEverywhere": false
|
|
12
|
-
},
|
|
13
|
-
"rules": {
|
|
14
|
-
"func-names": 0,
|
|
15
|
-
"no-nested-ternary": 0,
|
|
16
|
-
"max-len": 0,
|
|
17
|
-
"arrow-parens": ["error", "always"],
|
|
18
|
-
"no-underscore-dangle": 0,
|
|
19
|
-
"comma-dangle": ["error", {
|
|
20
|
-
"arrays": "always-multiline",
|
|
21
|
-
"objects": "always-multiline",
|
|
22
|
-
"imports": "always-multiline",
|
|
23
|
-
"exports": "always-multiline",
|
|
24
|
-
"functions": "never"
|
|
25
|
-
}],
|
|
26
|
-
"no-use-before-define": ["error", "nofunc"],
|
|
27
|
-
"no-empty": ["error", { "allowEmptyCatch": true }],
|
|
28
|
-
"no-mixed-operators": ["error", { "allowSamePrecedence": true }],
|
|
29
|
-
"indent": ["error", 4, { "flatTernaryExpressions": true, "SwitchCase": 1 }]
|
|
30
|
-
},
|
|
31
|
-
"overrides": [{
|
|
32
|
-
"files": ["**/*.ts"],
|
|
33
|
-
"parser": "@typescript-eslint/parser",
|
|
34
|
-
"plugins": ["@typescript-eslint"],
|
|
35
|
-
"extends": ["plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended"],
|
|
36
|
-
"rules": {
|
|
37
|
-
"@typescript-eslint/ban-ts-comment": "off"
|
|
38
|
-
}
|
|
39
|
-
}]
|
|
40
|
-
}
|