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