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