@curvefi/api 2.31.1 → 2.32.0
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/constants/abis/stable_calc.json +151 -0
- package/lib/constants/abis/wbeth/swap.json +1086 -0
- package/lib/constants/aliases.js +11 -0
- package/lib/constants/pools/ethereum.js +25 -0
- package/lib/constants/utils.d.ts +1 -1
- package/lib/curve.js +2 -0
- package/lib/interfaces.d.ts +1 -6
- package/lib/pools/PoolTemplate.js +18 -58
- package/lib/pools/mixins/swapMixins.js +4 -4
- package/lib/pools/utils.js +2 -1
- package/lib/router.js +13 -218
- package/package.json +2 -1
package/lib/router.js
CHANGED
|
@@ -1,226 +1,11 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import memoize from "memoizee";
|
|
3
|
+
import { findAllRoutes } from "@curvefi/router";
|
|
3
4
|
import { ethers } from "ethers";
|
|
4
5
|
import { curve } from "./curve.js";
|
|
5
6
|
import { _getCoinAddresses, _getCoinDecimals, _getUsdRate, ensureAllowance, ensureAllowanceEstimateGas, fromBN, hasAllowance, isEth, toBN, BN, parseUnits, _cutZeros, ETH_ADDRESS, _get_small_x, _get_price_impact, } from "./utils.js";
|
|
6
7
|
import { getPool } from "./pools/index.js";
|
|
7
8
|
import { _getAmplificationCoefficientsFromApi } from "./pools/utils.js";
|
|
8
|
-
const getNewRoute = (routeTvl, poolId, poolAddress, inputCoinAddress, outputCoinAddress, i, j, swapType, swapAddress, tvl) => {
|
|
9
|
-
const routePoolIds = routeTvl.route.map((s) => s.poolId);
|
|
10
|
-
// Steps <= 4
|
|
11
|
-
if (routePoolIds.length >= 4)
|
|
12
|
-
return { route: [], minTvl: Infinity, totalTvl: 0 };
|
|
13
|
-
// Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
|
|
14
|
-
if (routePoolIds.includes(poolId))
|
|
15
|
-
return { route: [], minTvl: Infinity, totalTvl: 0 };
|
|
16
|
-
return {
|
|
17
|
-
route: [...routeTvl.route, { poolId, poolAddress, inputCoinAddress, outputCoinAddress, i, j, swapType, swapAddress }],
|
|
18
|
-
minTvl: Math.min(tvl, routeTvl.minTvl),
|
|
19
|
-
totalTvl: routeTvl.totalTvl + tvl,
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
// TODO REMOVE IT!!!
|
|
23
|
-
const filterMaticFactory83Route = (routes) => {
|
|
24
|
-
return routes.filter((r) => {
|
|
25
|
-
for (const step of r.route) {
|
|
26
|
-
if (step.poolId === "factory-crypto-83" && step.inputCoinAddress === curve.constants.NATIVE_TOKEN.address)
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
return true;
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
|
-
// TODO REMOVE IT!!!
|
|
33
|
-
const filterAvax = (routes) => {
|
|
34
|
-
return routes.filter((r) => {
|
|
35
|
-
for (const step of r.route) {
|
|
36
|
-
if (step.poolId == 'avaxcrypto' && step.swapType == 4 && (step.i === 3 || step.j === 3))
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
return true;
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
const MAX_ROUTES_FOR_ONE_COIN = 3;
|
|
43
|
-
const filterRoutes = (routes, inputCoinAddress, sortFn) => {
|
|
44
|
-
// TODO REMOVE IT!!!
|
|
45
|
-
if (curve.chainId === 137)
|
|
46
|
-
routes = filterMaticFactory83Route(routes);
|
|
47
|
-
if (curve.chainId === 43114)
|
|
48
|
-
routes = filterAvax(routes);
|
|
49
|
-
return routes
|
|
50
|
-
.filter((r) => r.route.length > 0)
|
|
51
|
-
.filter((r) => r.route[0].inputCoinAddress === inputCoinAddress) // Truncated routes
|
|
52
|
-
.filter((r, i, _routes) => {
|
|
53
|
-
const routesByPoolIds = _routes.map((r) => r.route.map((s) => s.poolId).toString());
|
|
54
|
-
return routesByPoolIds.indexOf(r.route.map((s) => s.poolId).toString()) === i;
|
|
55
|
-
}) // Route duplications
|
|
56
|
-
.sort(sortFn).slice(0, MAX_ROUTES_FOR_ONE_COIN);
|
|
57
|
-
};
|
|
58
|
-
const sortByTvl = (a, b) => b.minTvl - a.minTvl || b.totalTvl - a.totalTvl || a.route.length - b.route.length;
|
|
59
|
-
const sortByLength = (a, b) => a.route.length - b.route.length || b.minTvl - a.minTvl || b.totalTvl - a.totalTvl;
|
|
60
|
-
// Inspired by Dijkstra's algorithm
|
|
61
|
-
const _findAllRoutes = async (inputCoinAddress, outputCoinAddress) => {
|
|
62
|
-
inputCoinAddress = inputCoinAddress.toLowerCase();
|
|
63
|
-
outputCoinAddress = outputCoinAddress.toLowerCase();
|
|
64
|
-
const ALL_POOLS = Object.entries({
|
|
65
|
-
...curve.constants.POOLS_DATA,
|
|
66
|
-
...curve.constants.FACTORY_POOLS_DATA,
|
|
67
|
-
...curve.constants.CRYPTO_FACTORY_POOLS_DATA,
|
|
68
|
-
});
|
|
69
|
-
const amplificationCoefficientDict = await _getAmplificationCoefficientsFromApi();
|
|
70
|
-
// Coins we are searching routes for on the current step
|
|
71
|
-
let curCoins = [inputCoinAddress];
|
|
72
|
-
// Coins we will search routes for on the next step
|
|
73
|
-
let nextCoins = new Set();
|
|
74
|
-
// Routes for all coins found
|
|
75
|
-
const routesByTvl = {
|
|
76
|
-
[inputCoinAddress]: [{ route: [], minTvl: Infinity, totalTvl: 0 }],
|
|
77
|
-
};
|
|
78
|
-
const routesByLength = {
|
|
79
|
-
[inputCoinAddress]: [{ route: [], minTvl: Infinity, totalTvl: 0 }],
|
|
80
|
-
};
|
|
81
|
-
// No more than 4 steps (swaps)
|
|
82
|
-
for (let step = 0; step < 4; step++) {
|
|
83
|
-
for (const inCoin of curCoins) {
|
|
84
|
-
if (curve.chainId !== 42220 && [curve.constants.NATIVE_TOKEN.address, curve.constants.NATIVE_TOKEN.wrappedAddress].includes(inCoin)) { // Exclude Celo
|
|
85
|
-
const outCoin = inCoin === curve.constants.NATIVE_TOKEN.address ? curve.constants.NATIVE_TOKEN.wrappedAddress : curve.constants.NATIVE_TOKEN.address;
|
|
86
|
-
const newRoutesByTvl = routesByTvl[inCoin].map((route) => getNewRoute(route, "wrapper", curve.constants.NATIVE_TOKEN.wrappedAddress, inCoin, outCoin, 0, 0, 15, curve.constants.ZERO_ADDRESS, Infinity));
|
|
87
|
-
const newRoutesByLength = routesByLength[inCoin].map((route) => getNewRoute(route, "wrapper", curve.constants.NATIVE_TOKEN.wrappedAddress, inCoin, outCoin, 0, 0, 15, curve.constants.ZERO_ADDRESS, Infinity));
|
|
88
|
-
routesByTvl[outCoin] = [...(routesByTvl[outCoin] ?? []), ...newRoutesByTvl];
|
|
89
|
-
routesByTvl[outCoin] = filterRoutes(routesByTvl[outCoin], inputCoinAddress, sortByTvl);
|
|
90
|
-
routesByLength[outCoin] = [...(routesByLength[outCoin] ?? []), ...newRoutesByLength];
|
|
91
|
-
routesByLength[outCoin] = filterRoutes(routesByLength[outCoin], inputCoinAddress, sortByLength);
|
|
92
|
-
nextCoins.add(outCoin);
|
|
93
|
-
}
|
|
94
|
-
for (const [poolId, poolData] of ALL_POOLS) {
|
|
95
|
-
const wrapped_coin_addresses = poolData.wrapped_coin_addresses.map((a) => a.toLowerCase());
|
|
96
|
-
const underlying_coin_addresses = poolData.underlying_coin_addresses.map((a) => a.toLowerCase());
|
|
97
|
-
const base_pool = poolData.is_meta ? curve.constants.POOLS_DATA[poolData.base_pool] : null;
|
|
98
|
-
const meta_coin_addresses = base_pool ? base_pool.underlying_coin_addresses.map((a) => a.toLowerCase()) : [];
|
|
99
|
-
const token_address = poolData.token_address.toLowerCase();
|
|
100
|
-
const is_aave_like_lending = poolData.is_lending && wrapped_coin_addresses.length === 3 && !poolData.deposit_address;
|
|
101
|
-
const tvlMultiplier = poolData.is_crypto ? 1 : (amplificationCoefficientDict[poolData.swap_address] ?? 1);
|
|
102
|
-
const inCoinIndexes = {
|
|
103
|
-
wrapped_coin: wrapped_coin_addresses.indexOf(inCoin),
|
|
104
|
-
underlying_coin: underlying_coin_addresses.indexOf(inCoin),
|
|
105
|
-
meta_coin: meta_coin_addresses ? meta_coin_addresses.indexOf(inCoin) : -1,
|
|
106
|
-
};
|
|
107
|
-
// Skip pools which don't contain inCoin
|
|
108
|
-
if (inCoinIndexes.wrapped_coin === -1 && inCoinIndexes.underlying_coin === -1 && inCoinIndexes.meta_coin === -1 && inCoin !== token_address)
|
|
109
|
-
continue;
|
|
110
|
-
const tvl = Number(await (getPool(poolId)).stats.totalLiquidity()) * tvlMultiplier;
|
|
111
|
-
// Skip empty pools
|
|
112
|
-
if (tvl === 0)
|
|
113
|
-
continue;
|
|
114
|
-
let poolAddress = poolData.is_fake ? poolData.deposit_address : poolData.swap_address;
|
|
115
|
-
const coin_addresses = (is_aave_like_lending || poolData.is_fake) ? underlying_coin_addresses : wrapped_coin_addresses;
|
|
116
|
-
// LP -> wrapped coin (underlying for lending or fake pool) "swaps" (actually remove_liquidity_one_coin)
|
|
117
|
-
if (coin_addresses.length < 6 && inCoin === token_address) {
|
|
118
|
-
for (let j = 0; j < coin_addresses.length; j++) {
|
|
119
|
-
// Looking for outputCoinAddress only on the final step
|
|
120
|
-
if (step === 3 && coin_addresses[j] !== outputCoinAddress)
|
|
121
|
-
continue;
|
|
122
|
-
// Exclude such cases as cvxeth -> tricrypto2 -> tusd -> susd or cvxeth -> tricrypto2 -> susd -> susd
|
|
123
|
-
const outputCoinIdx = coin_addresses.indexOf(outputCoinAddress);
|
|
124
|
-
if (outputCoinIdx >= 0 && j !== outputCoinIdx)
|
|
125
|
-
continue;
|
|
126
|
-
const swapType = poolData.is_crypto ? 14 : is_aave_like_lending ? 13 : 12;
|
|
127
|
-
const newRoutesByTvl = routesByTvl[inCoin].map((route) => getNewRoute(route, poolId, poolAddress, inCoin, coin_addresses[j], 0, j, swapType, curve.constants.ZERO_ADDRESS, tvl));
|
|
128
|
-
const newRoutesByLength = routesByLength[inCoin].map((route) => getNewRoute(route, poolId, poolAddress, inCoin, coin_addresses[j], 0, j, swapType, curve.constants.ZERO_ADDRESS, tvl));
|
|
129
|
-
routesByTvl[coin_addresses[j]] = [...(routesByTvl[coin_addresses[j]] ?? []), ...newRoutesByTvl];
|
|
130
|
-
routesByTvl[coin_addresses[j]] = filterRoutes(routesByTvl[coin_addresses[j]], inputCoinAddress, sortByTvl);
|
|
131
|
-
routesByLength[coin_addresses[j]] = [...(routesByLength[coin_addresses[j]] ?? []), ...newRoutesByLength];
|
|
132
|
-
routesByLength[coin_addresses[j]] = filterRoutes(routesByLength[coin_addresses[j]], inputCoinAddress, sortByLength);
|
|
133
|
-
nextCoins.add(coin_addresses[j]);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// Wrapped coin (underlying for lending or fake pool) -> LP "swaps" (actually add_liquidity)
|
|
137
|
-
const inCoinIndex = (is_aave_like_lending || poolData.is_fake) ? inCoinIndexes.underlying_coin : inCoinIndexes.wrapped_coin;
|
|
138
|
-
if (coin_addresses.length < 6 && inCoinIndex >= 0) {
|
|
139
|
-
// Looking for outputCoinAddress only on the final step
|
|
140
|
-
if (!(step === 3 && token_address !== outputCoinAddress)) {
|
|
141
|
-
const swapType = is_aave_like_lending ? 9
|
|
142
|
-
: coin_addresses.length === 2 ? 7
|
|
143
|
-
: coin_addresses.length === 3 ? 8
|
|
144
|
-
: coin_addresses.length === 4 ? 10 : 11;
|
|
145
|
-
const newRoutesByTvl = routesByTvl[inCoin].map((route) => getNewRoute(route, poolId, poolAddress, inCoin, token_address, coin_addresses.indexOf(inCoin), 0, swapType, curve.constants.ZERO_ADDRESS, tvl));
|
|
146
|
-
const newRoutesByLength = routesByLength[inCoin].map((route) => getNewRoute(route, poolId, poolAddress, inCoin, token_address, coin_addresses.indexOf(inCoin), 0, swapType, curve.constants.ZERO_ADDRESS, tvl));
|
|
147
|
-
routesByTvl[token_address] = [...(routesByTvl[token_address] ?? []), ...newRoutesByTvl];
|
|
148
|
-
routesByTvl[token_address] = filterRoutes(routesByTvl[token_address], inputCoinAddress, sortByTvl);
|
|
149
|
-
routesByLength[token_address] = [...(routesByLength[token_address] ?? []), ...newRoutesByLength];
|
|
150
|
-
routesByLength[token_address] = filterRoutes(routesByLength[token_address], inputCoinAddress, sortByLength);
|
|
151
|
-
nextCoins.add(token_address);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// Wrapped swaps
|
|
155
|
-
if (inCoinIndexes.wrapped_coin >= 0 && !poolData.is_fake) {
|
|
156
|
-
for (let j = 0; j < wrapped_coin_addresses.length; j++) {
|
|
157
|
-
if (j === inCoinIndexes.wrapped_coin)
|
|
158
|
-
continue;
|
|
159
|
-
// Native swaps spend less gas
|
|
160
|
-
// TODO uncomment
|
|
161
|
-
// if (wrapped_coin_addresses[j] !== outputCoinAddress && wrapped_coin_addresses[j] === curve.constants.NATIVE_TOKEN.wrappedAddress) continue;
|
|
162
|
-
// Looking for outputCoinAddress only on the final step
|
|
163
|
-
if (step === 3 && wrapped_coin_addresses[j] !== outputCoinAddress)
|
|
164
|
-
continue;
|
|
165
|
-
// Exclude such cases as cvxeth -> tricrypto2 -> tusd -> susd or cvxeth -> tricrypto2 -> susd -> susd
|
|
166
|
-
const outputCoinIdx = wrapped_coin_addresses.indexOf(outputCoinAddress);
|
|
167
|
-
if (outputCoinIdx >= 0 && j !== outputCoinIdx)
|
|
168
|
-
continue;
|
|
169
|
-
const swapType = poolData.is_crypto ? 3 : 1;
|
|
170
|
-
const newRoutesByTvl = routesByTvl[inCoin].map((route) => getNewRoute(route, poolId, poolData.swap_address, inCoin, wrapped_coin_addresses[j], inCoinIndexes.wrapped_coin, j, swapType, curve.constants.ZERO_ADDRESS, tvl));
|
|
171
|
-
const newRoutesByLength = routesByLength[inCoin].map((route) => getNewRoute(route, poolId, poolData.swap_address, inCoin, wrapped_coin_addresses[j], inCoinIndexes.wrapped_coin, j, swapType, curve.constants.ZERO_ADDRESS, tvl));
|
|
172
|
-
routesByTvl[wrapped_coin_addresses[j]] = [...(routesByTvl[wrapped_coin_addresses[j]] ?? []), ...newRoutesByTvl];
|
|
173
|
-
routesByTvl[wrapped_coin_addresses[j]] = filterRoutes(routesByTvl[wrapped_coin_addresses[j]], inputCoinAddress, sortByTvl);
|
|
174
|
-
routesByLength[wrapped_coin_addresses[j]] = [...(routesByLength[wrapped_coin_addresses[j]] ?? []), ...newRoutesByLength];
|
|
175
|
-
routesByLength[wrapped_coin_addresses[j]] = filterRoutes(routesByLength[wrapped_coin_addresses[j]], inputCoinAddress, sortByLength);
|
|
176
|
-
nextCoins.add(wrapped_coin_addresses[j]);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
// Only for underlying swaps
|
|
180
|
-
poolAddress = (poolData.is_crypto && poolData.is_meta) || (base_pool?.is_lending && poolData.is_factory) ?
|
|
181
|
-
poolData.deposit_address : poolData.swap_address;
|
|
182
|
-
// Underlying swaps
|
|
183
|
-
if (!poolData.is_plain && inCoinIndexes.underlying_coin >= 0) {
|
|
184
|
-
for (let j = 0; j < underlying_coin_addresses.length; j++) {
|
|
185
|
-
if (j === inCoinIndexes.underlying_coin)
|
|
186
|
-
continue;
|
|
187
|
-
// Don't swap metacoins since they can be swapped directly in base pool
|
|
188
|
-
if (inCoinIndexes.meta_coin >= 0 && meta_coin_addresses.includes(underlying_coin_addresses[j]))
|
|
189
|
-
continue;
|
|
190
|
-
// Looking for outputCoinAddress only on the final step
|
|
191
|
-
if (step === 3 && underlying_coin_addresses[j] !== outputCoinAddress)
|
|
192
|
-
continue;
|
|
193
|
-
// Exclude such cases as cvxeth -> tricrypto2 -> tusd -> susd or cvxeth -> tricrypto2 -> susd -> susd
|
|
194
|
-
const outputCoinIdx = underlying_coin_addresses.indexOf(outputCoinAddress);
|
|
195
|
-
if (outputCoinIdx >= 0 && j !== outputCoinIdx)
|
|
196
|
-
continue;
|
|
197
|
-
// Skip empty pools
|
|
198
|
-
const tvl = Number(await (getPool(poolId)).stats.totalLiquidity());
|
|
199
|
-
if (tvl === 0)
|
|
200
|
-
continue;
|
|
201
|
-
const hasEth = (inCoin === curve.constants.NATIVE_TOKEN.address || underlying_coin_addresses[j] === curve.constants.NATIVE_TOKEN.address);
|
|
202
|
-
const swapType = (poolData.is_crypto && poolData.is_meta && poolData.is_factory) ? 6
|
|
203
|
-
: (base_pool?.is_lending && poolData.is_factory) ? 5
|
|
204
|
-
: hasEth && poolId !== 'avaxcrypto' ? 3
|
|
205
|
-
: poolData.is_crypto ? 4
|
|
206
|
-
: 2;
|
|
207
|
-
const newRoutesByTvl = routesByTvl[inCoin].map((route) => getNewRoute(route, poolId, poolAddress, inCoin, underlying_coin_addresses[j], inCoinIndexes.underlying_coin, j, swapType, (swapType === 5 || swapType === 6) ? poolData.swap_address : curve.constants.ZERO_ADDRESS, tvl));
|
|
208
|
-
const newRoutesByLength = routesByLength[inCoin].map((route) => getNewRoute(route, poolId, poolAddress, inCoin, underlying_coin_addresses[j], inCoinIndexes.underlying_coin, j, swapType, (swapType === 5 || swapType === 6) ? poolData.swap_address : curve.constants.ZERO_ADDRESS, tvl));
|
|
209
|
-
routesByTvl[underlying_coin_addresses[j]] = [...(routesByTvl[underlying_coin_addresses[j]] ?? []), ...newRoutesByTvl];
|
|
210
|
-
routesByTvl[underlying_coin_addresses[j]] = filterRoutes(routesByTvl[underlying_coin_addresses[j]], inputCoinAddress, sortByTvl);
|
|
211
|
-
routesByLength[underlying_coin_addresses[j]] = [...(routesByLength[underlying_coin_addresses[j]] ?? []), ...newRoutesByLength];
|
|
212
|
-
routesByLength[underlying_coin_addresses[j]] = filterRoutes(routesByLength[underlying_coin_addresses[j]], inputCoinAddress, sortByLength);
|
|
213
|
-
nextCoins.add(underlying_coin_addresses[j]);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
curCoins = Array.from(nextCoins);
|
|
219
|
-
nextCoins = new Set();
|
|
220
|
-
}
|
|
221
|
-
const routes = [...(routesByTvl[outputCoinAddress] ?? []), ...(routesByLength[outputCoinAddress] ?? [])];
|
|
222
|
-
return routes.map((r) => r.route);
|
|
223
|
-
};
|
|
224
9
|
const _getRouteKey = (route, inputCoinAddress, outputCoinAddress) => {
|
|
225
10
|
const sortedCoins = [inputCoinAddress, outputCoinAddress].sort();
|
|
226
11
|
let key = `${sortedCoins[0]}-->`;
|
|
@@ -282,7 +67,18 @@ const _getBestRoute = memoize(async (inputCoinAddress, outputCoinAddress, amount
|
|
|
282
67
|
const _amount = parseUnits(amount, inputCoinDecimals);
|
|
283
68
|
if (_amount === 0n)
|
|
284
69
|
return [];
|
|
285
|
-
const
|
|
70
|
+
const pools = {
|
|
71
|
+
...curve.constants.POOLS_DATA,
|
|
72
|
+
...curve.constants.FACTORY_POOLS_DATA,
|
|
73
|
+
...curve.constants.CRYPTO_FACTORY_POOLS_DATA,
|
|
74
|
+
};
|
|
75
|
+
const ADict = await _getAmplificationCoefficientsFromApi();
|
|
76
|
+
const tvlDict = {};
|
|
77
|
+
const poolIds = Object.keys(pools);
|
|
78
|
+
for (let i = 0; i < poolIds.length; i++) {
|
|
79
|
+
tvlDict[poolIds[i]] = Number(await (getPool(poolIds[i])).stats.totalLiquidity());
|
|
80
|
+
}
|
|
81
|
+
const routesRaw = (findAllRoutes(inputCoinAddress, outputCoinAddress, pools, ADict, curve.chainId, curve.constants.NATIVE_TOKEN, tvlDict)).map((route) => ({ route, _output: 0n, outputUsd: 0, txCostUsd: 0 }));
|
|
286
82
|
const routes = [];
|
|
287
83
|
try {
|
|
288
84
|
const calls = [];
|
|
@@ -304,7 +100,6 @@ const _getBestRoute = memoize(async (inputCoinAddress, outputCoinAddress, amount
|
|
|
304
100
|
const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(r.route);
|
|
305
101
|
promises.push(contract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses, curve.constantOptions));
|
|
306
102
|
}
|
|
307
|
-
// @ts-ignore
|
|
308
103
|
const res = await Promise.allSettled(promises);
|
|
309
104
|
for (let i = 0; i < res.length; i++) {
|
|
310
105
|
if (res[i].status === 'rejected') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@curvefi/api",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.32.0",
|
|
4
4
|
"description": "JavaScript library for curve.fi",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"author": "Macket",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"vue-eslint-parser": "^7.6.0"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"@curvefi/router": "^0.1.0",
|
|
35
36
|
"axios": "^0.21.1",
|
|
36
37
|
"bignumber.js": "^9.0.1",
|
|
37
38
|
"ethcall": "^6.0.0",
|