@curvefi/api 2.19.2 → 2.20.1

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/README.md CHANGED
@@ -17,10 +17,10 @@ import curve from "@curvefi/api";
17
17
  await curve.init('JsonRpc', {}, {}); // In this case JsonRpc url, privateKey, fee data and chainId will be specified automatically
18
18
 
19
19
  // 2. Infura
20
- curve.init("Infura", { network: "homestead", apiKey: <INFURA_KEY> }, { chainId: 1 });
20
+ await curve.init("Infura", { network: "homestead", apiKey: <INFURA_KEY> }, { chainId: 1 });
21
21
 
22
22
  // 3. Web3 provider
23
- curve.init('Web3', { externalProvider: <WEB3_PROVIDER> }, { chainId: 1 });
23
+ await curve.init('Web3', { externalProvider: <WEB3_PROVIDER> }, { chainId: 1 });
24
24
 
25
25
  // Fetch factory pools
26
26
  await curve.fetchFactoryPools();
@@ -964,12 +964,14 @@ import curve from "@curvefi/api";
964
964
 
965
965
  (async () => {
966
966
  await curve.init('JsonRpc', {}, { gasPrice: 0, maxFeePerGas: 0, maxPriorityFeePerGas: 0 });
967
+ await curve.fetchFactoryPools();
968
+ await curve.getCryptoFactoryPoolList();
967
969
 
968
970
  await curve.getBalances(['DAI', 'CRV']);
969
971
  // [ '9900.0', '100049.744832225238317557' ]
970
972
 
971
973
  const { route, output } = await curve.router.getBestRouteAndOutput('DAI', 'CRV', '1000');
972
- // OR await curve.router.getBestPoolAndOutput('0x6B175474E89094C44Da98b954EedeAC495271d0F', '0xD533a949740bb3306d119CC777fa900bA034cd52', '1000');
974
+ // OR await curve.router.getBestRouteAndOutput('0x6B175474E89094C44Da98b954EedeAC495271d0F', '0xD533a949740bb3306d119CC777fa900bA034cd52', '1000');
973
975
  const expected = await curve.router.expected('DAI', 'CRV', '1000');
974
976
  // OR await curve.router.expected('0x6B175474E89094C44Da98b954EedeAC495271d0F', '0xD533a949740bb3306d119CC777fa900bA034cd52', '1000');
975
977
  const priceImpact = await curve.router.priceImpact('DAI', 'CRV', '1000');
@@ -133,6 +133,7 @@ export interface IRouteStep {
133
133
  export interface IRoute_ {
134
134
  steps: IRouteStep[];
135
135
  minTvl: number;
136
+ totalTvl: number;
136
137
  }
137
138
  export interface IRoute {
138
139
  steps: IRouteStep[];
@@ -2714,7 +2714,7 @@ var PoolTemplate = /** @class */ (function () {
2714
2714
  case 2:
2715
2715
  _smallOutput = _d.sent();
2716
2716
  priceImpactBN = (0, utils_1._get_price_impact)(_amount, _output, _smallAmount, _smallOutput, inputCoinDecimals, outputCoinDecimals);
2717
- return [2 /*return*/, Number((0, utils_1._cutZeros)(priceImpactBN.toFixed(4)).replace('-', ''))];
2717
+ return [2 /*return*/, Number((0, utils_1._cutZeros)(priceImpactBN.toFixed(4)))];
2718
2718
  }
2719
2719
  });
2720
2720
  });
@@ -2825,7 +2825,7 @@ var PoolTemplate = /** @class */ (function () {
2825
2825
  case 2:
2826
2826
  _smallOutput = _d.sent();
2827
2827
  priceImpactBN = (0, utils_1._get_price_impact)(_amount, _output, _smallAmount, _smallOutput, inputCoinDecimals, outputCoinDecimals);
2828
- return [2 /*return*/, Number((0, utils_1._cutZeros)(priceImpactBN.toFixed(4)).replace('-', ''))];
2828
+ return [2 /*return*/, Number((0, utils_1._cutZeros)(priceImpactBN.toFixed(4)))];
2829
2829
  }
2830
2830
  });
2831
2831
  });
package/lib/router.js CHANGED
@@ -67,10 +67,10 @@ var curve_1 = require("./curve");
67
67
  var utils_1 = require("./utils");
68
68
  var pools_1 = require("./pools");
69
69
  var utils_2 = require("./pools/utils");
70
- var MAX_ROUTES_FOR_ONE_COIN = 3;
70
+ // --------------------------- LEGACY ROUTER ---------------------------
71
71
  // Inspired by Dijkstra's algorithm
72
72
  var _findAllRoutesTheShorterTheBetter = function (inputCoinAddress, outputCoinAddress) { return __awaiter(void 0, void 0, void 0, function () {
73
- var ALL_POOLS, basePoolsSet, _i, ALL_POOLS_1, pool, basePoolIds, markedCoins, curCoins, nextCoins, routes, step, _a, curCoins_1, inCoin, _b, ALL_POOLS_2, _c, poolId, poolData, wrapped_coin_addresses, underlying_coin_addresses, base_pool, meta_coin_addresses, token_address, is_lending, inCoinIndexes, j, swapType, _d, _e, inCoinRoute, swapType, _f, _h, inCoinRoute, j, tvl, _j, swapType, _k, _l, inCoinRoute, poolAddress, j, tvl, _m, hasEth, swapType, _o, _p, inCoinRoute;
73
+ var ALL_POOLS, basePoolsSet, _i, ALL_POOLS_1, pool, basePoolIds, markedCoins, curCoins, nextCoins, routes, step, _a, curCoins_1, inCoin, _b, ALL_POOLS_2, _c, poolId, poolData, wrapped_coin_addresses, underlying_coin_addresses, base_pool, meta_coin_addresses, token_address, is_lending, inCoinIndexes, j, swapType, _d, _e, inCoinRoute, flag, swapType, _f, _h, inCoinRoute, j, tvl, _j, swapType, _k, _l, inCoinRoute, poolAddress, j, tvl, _m, hasEth, swapType, _o, _p, inCoinRoute;
74
74
  var _q;
75
75
  var _r, _s, _t, _u, _v, _w;
76
76
  return __generator(this, function (_x) {
@@ -147,29 +147,32 @@ var _findAllRoutesTheShorterTheBetter = function (inputCoinAddress, outputCoinAd
147
147
  }
148
148
  // Wrapped coin -> LP "swaps" (actually add_liquidity)
149
149
  if (basePoolIds.includes(poolId) && wrapped_coin_addresses.includes(inCoin)) {
150
+ flag = true;
150
151
  // If this coin already marked or will be marked on the current step, no need to consider it on the next step
151
152
  if (markedCoins.includes(token_address) || curCoins.includes(token_address))
152
- return [3 /*break*/, 11];
153
+ flag = false;
153
154
  // Looking for outputCoinAddress only on the final step
154
155
  if (step === 3 && token_address !== outputCoinAddress)
155
- return [3 /*break*/, 11];
156
- swapType = is_lending ? 9 : wrapped_coin_addresses.length === 2 ? 7 : 8;
157
- for (_f = 0, _h = routes[inCoin]; _f < _h.length; _f++) {
158
- inCoinRoute = _h[_f];
159
- routes[token_address] = ((_t = routes[token_address]) !== null && _t !== void 0 ? _t : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
160
- {
161
- poolId: poolId,
162
- poolAddress: poolData.swap_address,
163
- inputCoinAddress: inCoin,
164
- outputCoinAddress: token_address,
165
- i: wrapped_coin_addresses.indexOf(inCoin),
166
- j: 0,
167
- swapType: swapType,
168
- swapAddress: ethers_1.ethers.constants.AddressZero,
169
- },
170
- ], false)]);
156
+ flag = false;
157
+ if (flag) {
158
+ swapType = is_lending ? 9 : wrapped_coin_addresses.length === 2 ? 7 : 8;
159
+ for (_f = 0, _h = routes[inCoin]; _f < _h.length; _f++) {
160
+ inCoinRoute = _h[_f];
161
+ routes[token_address] = ((_t = routes[token_address]) !== null && _t !== void 0 ? _t : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
162
+ {
163
+ poolId: poolId,
164
+ poolAddress: poolData.swap_address,
165
+ inputCoinAddress: inCoin,
166
+ outputCoinAddress: token_address,
167
+ i: wrapped_coin_addresses.indexOf(inCoin),
168
+ j: 0,
169
+ swapType: swapType,
170
+ swapAddress: ethers_1.ethers.constants.AddressZero,
171
+ },
172
+ ], false)]);
173
+ }
174
+ nextCoins.add(token_address);
171
175
  }
172
- nextCoins.add(token_address);
173
176
  }
174
177
  // No input coin in this pool --> skip
175
178
  if (inCoinIndexes.wrapped_coin === -1 && inCoinIndexes.underlying_coin === -1 && inCoinIndexes.meta_coin === -1)
@@ -286,249 +289,169 @@ var _findAllRoutesTheShorterTheBetter = function (inputCoinAddress, outputCoinAd
286
289
  });
287
290
  }); };
288
291
  exports._findAllRoutesTheShorterTheBetter = _findAllRoutesTheShorterTheBetter;
292
+ var getNewRoute = function (route, poolId, poolAddress, inputCoinAddress, outputCoinAddress, i, j, swapType, swapAddress, tvl) {
293
+ var routePoolIds = route.steps.map(function (s) { return s.poolId; });
294
+ // Steps <= 4
295
+ if (routePoolIds.length >= 4)
296
+ return { steps: [], minTvl: Infinity, totalTvl: 0 };
297
+ // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
298
+ if (routePoolIds.includes(poolId))
299
+ return { steps: [], minTvl: Infinity, totalTvl: 0 };
300
+ return {
301
+ steps: __spreadArray(__spreadArray([], route.steps, true), [{ poolId: poolId, poolAddress: poolAddress, inputCoinAddress: inputCoinAddress, outputCoinAddress: outputCoinAddress, i: i, j: j, swapType: swapType, swapAddress: swapAddress }], false),
302
+ minTvl: Math.min(tvl, route.minTvl),
303
+ totalTvl: route.totalTvl + tvl,
304
+ };
305
+ };
306
+ // --------------------------- MAIN ROUTER ---------------------------
307
+ var MAX_ROUTES_FOR_ONE_COIN = 3;
308
+ var filterRoutes = function (routes, inputCoinAddress, sortFn) {
309
+ var routesByPoolIds = routes.map(function (r) { return r.steps.map(function (s) { return s.poolId; }).toString(); });
310
+ return routes
311
+ .filter(function (r) { return r.steps.length > 0; })
312
+ .filter(function (r) { return r.steps[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
313
+ .filter(function (r, i) { return routesByPoolIds.indexOf(r.steps.map(function (s) { return s.poolId; }).toString()) === i; }) // Route duplications
314
+ .sort(sortFn).slice(0, MAX_ROUTES_FOR_ONE_COIN);
315
+ };
316
+ var sortByTvl = function (a, b) { return b.minTvl - a.minTvl || b.totalTvl - a.totalTvl || a.steps.length - b.steps.length; };
317
+ var sortByLength = function (a, b) { return a.steps.length - b.steps.length || b.minTvl - a.minTvl || b.totalTvl - a.totalTvl; };
289
318
  // Inspired by Dijkstra's algorithm
290
319
  var _findAllRoutesTvl = function (inputCoinAddress, outputCoinAddress) { return __awaiter(void 0, void 0, void 0, function () {
291
- var ALL_POOLS, amplificationCoefficientDict, basePoolsSet, _i, ALL_POOLS_3, pool, basePoolIds, curCoins, nextCoins, routes, step, _loop_1, _a, curCoins_2, inCoin;
292
- var _b;
293
- var _c, _d, _e, _f, _h, _j;
294
- return __generator(this, function (_k) {
295
- switch (_k.label) {
320
+ var ALL_POOLS, amplificationCoefficientDict, basePoolsSet, _i, ALL_POOLS_3, pool, basePoolIds, curCoins, nextCoins, routesByTvl, routesByLength, step, _loop_1, _a, curCoins_2, inCoin, routes;
321
+ var _b, _c;
322
+ var _d, _e, _f, _h, _j, _k, _l, _m, _o, _p, _q, _r;
323
+ return __generator(this, function (_s) {
324
+ switch (_s.label) {
296
325
  case 0:
297
326
  inputCoinAddress = inputCoinAddress.toLowerCase();
298
327
  outputCoinAddress = outputCoinAddress.toLowerCase();
299
328
  ALL_POOLS = Object.entries(__assign(__assign(__assign({}, curve_1.curve.constants.POOLS_DATA), curve_1.curve.constants.FACTORY_POOLS_DATA), curve_1.curve.constants.CRYPTO_FACTORY_POOLS_DATA));
300
329
  return [4 /*yield*/, (0, utils_2._getAmplificationCoefficientsFromApi)()];
301
330
  case 1:
302
- amplificationCoefficientDict = _k.sent();
331
+ amplificationCoefficientDict = _s.sent();
303
332
  basePoolsSet = new Set();
304
333
  for (_i = 0, ALL_POOLS_3 = ALL_POOLS; _i < ALL_POOLS_3.length; _i++) {
305
334
  pool = ALL_POOLS_3[_i];
306
- if (pool[1].base_pool)
307
- basePoolsSet.add(pool[1].base_pool);
335
+ if (pool[1].wrapped_coin_addresses.length < 4)
336
+ basePoolsSet.add(pool[0]);
308
337
  }
309
338
  basePoolIds = Array.from(basePoolsSet);
310
339
  curCoins = [inputCoinAddress];
311
340
  nextCoins = new Set();
312
- routes = (_b = {},
313
- _b[inputCoinAddress] = [{ steps: [], minTvl: Infinity }],
341
+ routesByTvl = (_b = {},
342
+ _b[inputCoinAddress] = [{ steps: [], minTvl: Infinity, totalTvl: 0 }],
314
343
  _b);
344
+ routesByLength = (_c = {},
345
+ _c[inputCoinAddress] = [{ steps: [], minTvl: Infinity, totalTvl: 0 }],
346
+ _c);
315
347
  step = 0;
316
- _k.label = 2;
348
+ _s.label = 2;
317
349
  case 2:
318
350
  if (!(step < 4)) return [3 /*break*/, 8];
319
351
  _loop_1 = function (inCoin) {
320
- var _loop_2, _l, ALL_POOLS_4, _m, poolId, poolData;
321
- return __generator(this, function (_o) {
322
- switch (_o.label) {
352
+ var _loop_2, _t, ALL_POOLS_4, _u, poolId, poolData;
353
+ return __generator(this, function (_v) {
354
+ switch (_v.label) {
323
355
  case 0:
324
356
  _loop_2 = function (poolId, poolData) {
325
- var wrapped_coin_addresses, underlying_coin_addresses, base_pool, meta_coin_addresses, token_address, is_lending, minTvlMultiplier, inCoinIndexes, _loop_3, j, tvl_1, _p, swapType_1, newRoutes, routesByPoolIds_1, _loop_4, j, poolAddress, _loop_5, j;
326
- return __generator(this, function (_q) {
327
- switch (_q.label) {
357
+ var wrapped_coin_addresses, underlying_coin_addresses, base_pool, meta_coin_addresses, token_address, is_lending, tvlMultiplier, inCoinIndexes, tvl, _w, _loop_3, j, swapType_1, newRoutesByTvl, newRoutesByLength, _loop_4, j, poolAddress, _loop_5, j;
358
+ return __generator(this, function (_x) {
359
+ switch (_x.label) {
328
360
  case 0:
329
361
  wrapped_coin_addresses = poolData.wrapped_coin_addresses.map(function (a) { return a.toLowerCase(); });
330
362
  underlying_coin_addresses = poolData.underlying_coin_addresses.map(function (a) { return a.toLowerCase(); });
331
363
  base_pool = poolData.is_meta ? curve_1.curve.constants.POOLS_DATA[poolData.base_pool] : null;
332
364
  meta_coin_addresses = base_pool ? base_pool.underlying_coin_addresses.map(function (a) { return a.toLowerCase(); }) : [];
333
365
  token_address = poolData.token_address.toLowerCase();
334
- is_lending = (_c = poolData.is_lending) !== null && _c !== void 0 ? _c : false;
335
- minTvlMultiplier = poolData.is_crypto ? 1 : ((_d = amplificationCoefficientDict[poolData.swap_address]) !== null && _d !== void 0 ? _d : 1);
366
+ is_lending = (_d = poolData.is_lending) !== null && _d !== void 0 ? _d : false;
367
+ tvlMultiplier = poolData.is_crypto ? 1 : ((_e = amplificationCoefficientDict[poolData.swap_address]) !== null && _e !== void 0 ? _e : 1);
336
368
  inCoinIndexes = {
337
369
  wrapped_coin: wrapped_coin_addresses.indexOf(inCoin),
338
370
  underlying_coin: underlying_coin_addresses.indexOf(inCoin),
339
371
  meta_coin: meta_coin_addresses ? meta_coin_addresses.indexOf(inCoin) : -1,
340
372
  };
341
- // No input coin in this pool --> skip
373
+ // Skip pools which don't contain inCoin
342
374
  if (inCoinIndexes.wrapped_coin === -1 && inCoinIndexes.underlying_coin === -1 && inCoinIndexes.meta_coin === -1 && inCoin !== token_address)
343
375
  return [2 /*return*/, "continue"];
344
- if (!(basePoolIds.includes(poolId) && inCoin === token_address)) return [3 /*break*/, 4];
345
- _loop_3 = function (j) {
346
- var outputCoinIdx, tvl, _r, swapType, newRoutes, routesByPoolIds;
347
- return __generator(this, function (_s) {
348
- switch (_s.label) {
349
- case 0:
350
- // Looking for outputCoinAddress only on the final step
351
- if (step === 3 && underlying_coin_addresses[j] !== outputCoinAddress)
352
- return [2 /*return*/, "continue"];
353
- outputCoinIdx = underlying_coin_addresses.indexOf(outputCoinAddress);
354
- if (outputCoinIdx >= 0 && j !== outputCoinIdx)
355
- return [2 /*return*/, "continue"];
356
- _r = Number;
357
- return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
358
- case 1:
359
- tvl = _r.apply(void 0, [_s.sent()]);
360
- swapType = poolId === 'aave' ? 11 : 10;
361
- newRoutes = routes[inCoin].map(function (route) {
362
- var routePoolIds = route.steps.map(function (s) { return s.poolId; });
363
- // Steps <= 4
364
- if (routePoolIds.length >= 4)
365
- return { steps: [], minTvl: -1 };
366
- // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
367
- if (routePoolIds.includes(poolId))
368
- return { steps: [], minTvl: -1 };
369
- return {
370
- steps: __spreadArray(__spreadArray([], route.steps, true), [
371
- {
372
- poolId: poolId,
373
- poolAddress: poolData.swap_address,
374
- inputCoinAddress: inCoin,
375
- outputCoinAddress: underlying_coin_addresses[j],
376
- i: 0,
377
- j: j,
378
- swapType: swapType,
379
- swapAddress: ethers_1.ethers.constants.AddressZero,
380
- },
381
- ], false),
382
- minTvl: Math.min(tvl, route.minTvl * minTvlMultiplier),
383
- };
384
- });
385
- routes[underlying_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_e = routes[underlying_coin_addresses[j]]) !== null && _e !== void 0 ? _e : []), true), newRoutes, true);
386
- routesByPoolIds = routes[underlying_coin_addresses[j]].map(function (r) { return r.steps.map(function (s) { return s.poolId; }).toString(); });
387
- routes[underlying_coin_addresses[j]] = routes[underlying_coin_addresses[j]]
388
- .filter(function (r) { return r.steps.length > 0; })
389
- .filter(function (r) { return r.steps[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
390
- .filter(function (r, i) { return routesByPoolIds.indexOf(r.steps.map(function (s) { return s.poolId; }).toString()) === i; }) // Route duplications
391
- .sort(function (a, b) { return b.minTvl - a.minTvl || a.steps.length - b.steps.length; }).slice(0, MAX_ROUTES_FOR_ONE_COIN);
392
- nextCoins.add(underlying_coin_addresses[j]);
393
- return [2 /*return*/];
394
- }
395
- });
396
- };
397
- j = 0;
398
- _q.label = 1;
376
+ _w = Number;
377
+ return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
399
378
  case 1:
400
- if (!(j < underlying_coin_addresses.length)) return [3 /*break*/, 4];
401
- return [5 /*yield**/, _loop_3(j)];
402
- case 2:
403
- _q.sent();
404
- _q.label = 3;
405
- case 3:
406
- j++;
407
- return [3 /*break*/, 1];
408
- case 4:
409
- if (!(basePoolIds.includes(poolId) && inCoinIndexes.underlying_coin >= 0)) return [3 /*break*/, 6];
410
- // Looking for outputCoinAddress only on the final step
411
- if (step === 3 && token_address !== outputCoinAddress)
379
+ tvl = _w.apply(void 0, [_x.sent()]) * tvlMultiplier;
380
+ // Skip empty pools
381
+ if (tvl === 0)
412
382
  return [2 /*return*/, "continue"];
413
- _p = Number;
414
- return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
415
- case 5:
416
- tvl_1 = _p.apply(void 0, [_q.sent()]);
417
- swapType_1 = is_lending ? 9 : underlying_coin_addresses.length === 2 ? 7 : 8;
418
- newRoutes = routes[inCoin].map(function (route) {
419
- var routePoolIds = route.steps.map(function (s) { return s.poolId; });
420
- // Steps <= 4
421
- if (routePoolIds.length >= 4)
422
- return { steps: [], minTvl: -1 };
423
- // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
424
- if (routePoolIds.includes(poolId))
425
- return { steps: [], minTvl: -1 };
426
- return {
427
- steps: __spreadArray(__spreadArray([], route.steps, true), [
428
- {
429
- poolId: poolId,
430
- poolAddress: poolData.swap_address,
431
- inputCoinAddress: inCoin,
432
- outputCoinAddress: token_address,
433
- i: underlying_coin_addresses.indexOf(inCoin),
434
- j: 0,
435
- swapType: swapType_1,
436
- swapAddress: ethers_1.ethers.constants.AddressZero,
437
- },
438
- ], false),
439
- minTvl: Math.min(tvl_1, route.minTvl * minTvlMultiplier),
383
+ // LP -> wrapped coin "swaps" (actually remove_liquidity_one_coin)
384
+ if (basePoolIds.includes(poolId) && inCoin === token_address) {
385
+ _loop_3 = function (j) {
386
+ // Looking for outputCoinAddress only on the final step
387
+ if (step === 3 && wrapped_coin_addresses[j] !== outputCoinAddress)
388
+ return "continue";
389
+ // Exclude such cases as cvxeth -> tricrypto2 -> tusd -> susd or cvxeth -> tricrypto2 -> susd -> susd
390
+ var outputCoinIdx = wrapped_coin_addresses.indexOf(outputCoinAddress);
391
+ if (outputCoinIdx >= 0 && j !== outputCoinIdx)
392
+ return "continue";
393
+ var swapType = poolId === 'aave' ? 11 : 10;
394
+ var newRoutesByTvl = routesByTvl[inCoin].map(function (route) { return getNewRoute(route, poolId, poolData.swap_address, inCoin, wrapped_coin_addresses[j], 0, j, swapType, ethers_1.ethers.constants.AddressZero, tvl); });
395
+ var newRoutesByLength = routesByLength[inCoin].map(function (route) { return getNewRoute(route, poolId, poolData.swap_address, inCoin, wrapped_coin_addresses[j], 0, j, swapType, ethers_1.ethers.constants.AddressZero, tvl); });
396
+ routesByTvl[wrapped_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_f = routesByTvl[wrapped_coin_addresses[j]]) !== null && _f !== void 0 ? _f : []), true), newRoutesByTvl, true);
397
+ routesByTvl[wrapped_coin_addresses[j]] = filterRoutes(routesByTvl[wrapped_coin_addresses[j]], inputCoinAddress, sortByTvl);
398
+ routesByLength[wrapped_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_h = routesByLength[wrapped_coin_addresses[j]]) !== null && _h !== void 0 ? _h : []), true), newRoutesByLength, true);
399
+ routesByLength[wrapped_coin_addresses[j]] = filterRoutes(routesByLength[wrapped_coin_addresses[j]], inputCoinAddress, sortByLength);
400
+ nextCoins.add(wrapped_coin_addresses[j]);
440
401
  };
441
- });
442
- routes[token_address] = __spreadArray(__spreadArray([], ((_f = routes[token_address]) !== null && _f !== void 0 ? _f : []), true), newRoutes, true);
443
- routesByPoolIds_1 = routes[token_address].map(function (r) { return r.steps.map(function (s) { return s.poolId; }).toString(); });
444
- routes[token_address] = routes[token_address]
445
- .filter(function (r) { return r.steps.length > 0; })
446
- .filter(function (r) { return r.steps[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
447
- .filter(function (r, i) { return routesByPoolIds_1.indexOf(r.steps.map(function (s) { return s.poolId; }).toString()) === i; }) // Route duplications
448
- .sort(function (a, b) { return b.minTvl - a.minTvl || a.steps.length - b.steps.length; }).slice(0, MAX_ROUTES_FOR_ONE_COIN);
449
- nextCoins.add(token_address);
450
- _q.label = 6;
451
- case 6:
452
- if (!(inCoinIndexes.wrapped_coin >= 0 && !poolData.is_fake)) return [3 /*break*/, 10];
453
- _loop_4 = function (j) {
454
- var outputCoinIdx, tvl, _t, swapType, newRoutes, routesByPoolIds;
455
- return __generator(this, function (_u) {
456
- switch (_u.label) {
457
- case 0:
458
- if (j === inCoinIndexes.wrapped_coin)
459
- return [2 /*return*/, "continue"];
460
- // Native swaps spend less gas
461
- if (wrapped_coin_addresses[j] !== outputCoinAddress && wrapped_coin_addresses[j] === curve_1.curve.constants.NATIVE_TOKEN.wrappedAddress)
462
- return [2 /*return*/, "continue"];
463
- // Looking for outputCoinAddress only on the final step
464
- if (step === 3 && wrapped_coin_addresses[j] !== outputCoinAddress)
465
- return [2 /*return*/, "continue"];
466
- outputCoinIdx = wrapped_coin_addresses.indexOf(outputCoinAddress);
467
- if (outputCoinIdx >= 0 && j !== outputCoinIdx)
468
- return [2 /*return*/, "continue"];
469
- _t = Number;
470
- return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
471
- case 1:
472
- tvl = _t.apply(void 0, [_u.sent()]);
473
- // Skip empty pools
474
- if (tvl === 0)
475
- return [2 /*return*/, "continue"];
476
- swapType = poolData.is_crypto ? 3 : 1;
477
- newRoutes = routes[inCoin].map(function (route) {
478
- var routePoolIds = route.steps.map(function (s) { return s.poolId; });
479
- // Steps <= 4
480
- if (routePoolIds.length >= 4)
481
- return { steps: [], minTvl: -1 };
482
- // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
483
- if (routePoolIds.includes(poolId))
484
- return { steps: [], minTvl: -1 };
485
- return {
486
- steps: __spreadArray(__spreadArray([], route.steps, true), [
487
- {
488
- poolId: poolId,
489
- poolAddress: poolData.swap_address,
490
- inputCoinAddress: inCoin,
491
- outputCoinAddress: wrapped_coin_addresses[j],
492
- i: inCoinIndexes.wrapped_coin,
493
- j: j,
494
- swapType: swapType,
495
- swapAddress: ethers_1.ethers.constants.AddressZero,
496
- },
497
- ], false),
498
- minTvl: Math.min(tvl, route.minTvl * minTvlMultiplier),
499
- };
500
- });
501
- routes[wrapped_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_h = routes[wrapped_coin_addresses[j]]) !== null && _h !== void 0 ? _h : []), true), newRoutes, true);
502
- routesByPoolIds = routes[wrapped_coin_addresses[j]].map(function (r) { return r.steps.map(function (s) { return s.poolId; }).toString(); });
503
- routes[wrapped_coin_addresses[j]] = routes[wrapped_coin_addresses[j]]
504
- .filter(function (r) { return r.steps.length > 0; })
505
- .filter(function (r) { return r.steps[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
506
- .filter(function (r, i) { return routesByPoolIds.indexOf(r.steps.map(function (s) { return s.poolId; }).toString()) === i; }) // Route duplications
507
- .sort(function (a, b) { return b.minTvl - a.minTvl || a.steps.length - b.steps.length; }).slice(0, MAX_ROUTES_FOR_ONE_COIN);
508
- nextCoins.add(wrapped_coin_addresses[j]);
509
- return [2 /*return*/];
510
- }
511
- });
512
- };
513
- j = 0;
514
- _q.label = 7;
515
- case 7:
516
- if (!(j < wrapped_coin_addresses.length)) return [3 /*break*/, 10];
517
- return [5 /*yield**/, _loop_4(j)];
518
- case 8:
519
- _q.sent();
520
- _q.label = 9;
521
- case 9:
522
- j++;
523
- return [3 /*break*/, 7];
524
- case 10:
402
+ for (j = 0; j < wrapped_coin_addresses.length; j++) {
403
+ _loop_3(j);
404
+ }
405
+ }
406
+ // Wrapped coin -> LP "swaps" (actually add_liquidity)
407
+ if (basePoolIds.includes(poolId) && inCoinIndexes.wrapped_coin >= 0) {
408
+ // Looking for outputCoinAddress only on the final step
409
+ if (!(step === 3 && token_address !== outputCoinAddress)) {
410
+ swapType_1 = is_lending ? 9 : wrapped_coin_addresses.length === 2 ? 7 : 8;
411
+ newRoutesByTvl = routesByTvl[inCoin].map(function (route) { return getNewRoute(route, poolId, poolData.swap_address, inCoin, token_address, wrapped_coin_addresses.indexOf(inCoin), 0, swapType_1, ethers_1.ethers.constants.AddressZero, tvl); });
412
+ newRoutesByLength = routesByLength[inCoin].map(function (route) { return getNewRoute(route, poolId, poolData.swap_address, inCoin, token_address, wrapped_coin_addresses.indexOf(inCoin), 0, swapType_1, ethers_1.ethers.constants.AddressZero, tvl); });
413
+ routesByTvl[token_address] = __spreadArray(__spreadArray([], ((_j = routesByTvl[token_address]) !== null && _j !== void 0 ? _j : []), true), newRoutesByTvl, true);
414
+ routesByTvl[token_address] = filterRoutes(routesByTvl[token_address], inputCoinAddress, sortByTvl);
415
+ routesByLength[token_address] = __spreadArray(__spreadArray([], ((_k = routesByLength[token_address]) !== null && _k !== void 0 ? _k : []), true), newRoutesByLength, true);
416
+ routesByLength[token_address] = filterRoutes(routesByLength[token_address], inputCoinAddress, sortByLength);
417
+ nextCoins.add(token_address);
418
+ }
419
+ }
420
+ // Wrapped swaps
421
+ if (inCoinIndexes.wrapped_coin >= 0 && !poolData.is_fake) {
422
+ _loop_4 = function (j) {
423
+ if (j === inCoinIndexes.wrapped_coin)
424
+ return "continue";
425
+ // Native swaps spend less gas
426
+ if (wrapped_coin_addresses[j] !== outputCoinAddress && wrapped_coin_addresses[j] === curve_1.curve.constants.NATIVE_TOKEN.wrappedAddress)
427
+ return "continue";
428
+ // Looking for outputCoinAddress only on the final step
429
+ if (step === 3 && wrapped_coin_addresses[j] !== outputCoinAddress)
430
+ return "continue";
431
+ // Exclude such cases as cvxeth -> tricrypto2 -> tusd -> susd or cvxeth -> tricrypto2 -> susd -> susd
432
+ var outputCoinIdx = wrapped_coin_addresses.indexOf(outputCoinAddress);
433
+ if (outputCoinIdx >= 0 && j !== outputCoinIdx)
434
+ return "continue";
435
+ var swapType = poolData.is_crypto ? 3 : 1;
436
+ var newRoutesByTvl = routesByTvl[inCoin].map(function (route) { return getNewRoute(route, poolId, poolData.swap_address, inCoin, wrapped_coin_addresses[j], inCoinIndexes.wrapped_coin, j, swapType, ethers_1.ethers.constants.AddressZero, tvl); });
437
+ var newRoutesByLength = routesByLength[inCoin].map(function (route) { return getNewRoute(route, poolId, poolData.swap_address, inCoin, wrapped_coin_addresses[j], inCoinIndexes.wrapped_coin, j, swapType, ethers_1.ethers.constants.AddressZero, tvl); });
438
+ routesByTvl[wrapped_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_l = routesByTvl[wrapped_coin_addresses[j]]) !== null && _l !== void 0 ? _l : []), true), newRoutesByTvl, true);
439
+ routesByTvl[wrapped_coin_addresses[j]] = filterRoutes(routesByTvl[wrapped_coin_addresses[j]], inputCoinAddress, sortByTvl);
440
+ routesByLength[wrapped_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_m = routesByLength[wrapped_coin_addresses[j]]) !== null && _m !== void 0 ? _m : []), true), newRoutesByLength, true);
441
+ routesByLength[wrapped_coin_addresses[j]] = filterRoutes(routesByLength[wrapped_coin_addresses[j]], inputCoinAddress, sortByLength);
442
+ nextCoins.add(wrapped_coin_addresses[j]);
443
+ };
444
+ for (j = 0; j < wrapped_coin_addresses.length; j++) {
445
+ _loop_4(j);
446
+ }
447
+ }
525
448
  poolAddress = (poolData.is_crypto && poolData.is_meta) || ((base_pool === null || base_pool === void 0 ? void 0 : base_pool.is_lending) && poolData.is_factory) ?
526
449
  poolData.deposit_address : poolData.swap_address;
527
- if (!(!poolData.is_plain && inCoinIndexes.underlying_coin >= 0)) return [3 /*break*/, 14];
450
+ if (!(!poolData.is_plain && inCoinIndexes.underlying_coin >= 0)) return [3 /*break*/, 5];
528
451
  _loop_5 = function (j) {
529
- var outputCoinIdx, tvl, _v, hasEth, swapType, newRoutes, routesByPoolIds;
530
- return __generator(this, function (_w) {
531
- switch (_w.label) {
452
+ var outputCoinIdx, tvl_1, _y, hasEth, swapType, newRoutesByTvl, newRoutesByLength;
453
+ return __generator(this, function (_z) {
454
+ switch (_z.label) {
532
455
  case 0:
533
456
  if (j === inCoinIndexes.underlying_coin)
534
457
  return [2 /*return*/, "continue"];
@@ -541,11 +464,11 @@ var _findAllRoutesTvl = function (inputCoinAddress, outputCoinAddress) { return
541
464
  outputCoinIdx = underlying_coin_addresses.indexOf(outputCoinAddress);
542
465
  if (outputCoinIdx >= 0 && j !== outputCoinIdx)
543
466
  return [2 /*return*/, "continue"];
544
- _v = Number;
467
+ _y = Number;
545
468
  return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
546
469
  case 1:
547
- tvl = _v.apply(void 0, [_w.sent()]);
548
- if (tvl === 0)
470
+ tvl_1 = _y.apply(void 0, [_z.sent()]);
471
+ if (tvl_1 === 0)
549
472
  return [2 /*return*/, "continue"];
550
473
  hasEth = (inCoin === curve_1.curve.constants.NATIVE_TOKEN.address || underlying_coin_addresses[j] === curve_1.curve.constants.NATIVE_TOKEN.address);
551
474
  swapType = (poolData.is_crypto && poolData.is_meta && poolData.is_factory) ? 6
@@ -553,93 +476,70 @@ var _findAllRoutesTvl = function (inputCoinAddress, outputCoinAddress) { return
553
476
  : hasEth ? 3
554
477
  : poolData.is_crypto ? 4
555
478
  : 2;
556
- newRoutes = routes[inCoin].map(function (route) {
557
- var routePoolIds = route.steps.map(function (s) { return s.poolId; });
558
- // Steps <= 4
559
- if (routePoolIds.length >= 4)
560
- return { steps: [], minTvl: -1 };
561
- // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
562
- if (routePoolIds.includes(poolId))
563
- return { steps: [], minTvl: -1 };
564
- return {
565
- steps: __spreadArray(__spreadArray([], route.steps, true), [
566
- {
567
- poolId: poolId,
568
- poolAddress: poolAddress,
569
- inputCoinAddress: inCoin,
570
- outputCoinAddress: underlying_coin_addresses[j],
571
- i: inCoinIndexes.underlying_coin,
572
- j: j,
573
- swapType: swapType,
574
- swapAddress: (swapType === 5 || swapType === 6) ? poolData.swap_address : ethers_1.ethers.constants.AddressZero,
575
- },
576
- ], false),
577
- minTvl: Math.min(tvl, route.minTvl * minTvlMultiplier),
578
- };
579
- });
580
- routes[underlying_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_j = routes[underlying_coin_addresses[j]]) !== null && _j !== void 0 ? _j : []), true), newRoutes, true);
581
- routesByPoolIds = routes[underlying_coin_addresses[j]].map(function (r) { return r.steps.map(function (s) { return s.poolId; }).toString(); });
582
- routes[underlying_coin_addresses[j]] = routes[underlying_coin_addresses[j]]
583
- .filter(function (r) { return r.steps.length > 0; })
584
- .filter(function (r) { return r.steps[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
585
- .filter(function (r, i) { return routesByPoolIds.indexOf(r.steps.map(function (s) { return s.poolId; }).toString()) === i; }) // Route duplications
586
- .sort(function (a, b) { return b.minTvl - a.minTvl || a.steps.length - b.steps.length; }).slice(0, MAX_ROUTES_FOR_ONE_COIN);
479
+ newRoutesByTvl = routesByTvl[inCoin].map(function (route) { return getNewRoute(route, poolId, poolAddress, inCoin, underlying_coin_addresses[j], inCoinIndexes.underlying_coin, j, swapType, (swapType === 5 || swapType === 6) ? poolData.swap_address : ethers_1.ethers.constants.AddressZero, tvl_1); });
480
+ newRoutesByLength = routesByLength[inCoin].map(function (route) { return getNewRoute(route, poolId, poolAddress, inCoin, underlying_coin_addresses[j], inCoinIndexes.underlying_coin, j, swapType, (swapType === 5 || swapType === 6) ? poolData.swap_address : ethers_1.ethers.constants.AddressZero, tvl_1); });
481
+ routesByTvl[underlying_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_o = routesByTvl[underlying_coin_addresses[j]]) !== null && _o !== void 0 ? _o : []), true), newRoutesByTvl, true);
482
+ routesByTvl[underlying_coin_addresses[j]] = filterRoutes(routesByTvl[underlying_coin_addresses[j]], inputCoinAddress, sortByTvl);
483
+ routesByLength[underlying_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_p = routesByLength[underlying_coin_addresses[j]]) !== null && _p !== void 0 ? _p : []), true), newRoutesByLength, true);
484
+ routesByLength[underlying_coin_addresses[j]] = filterRoutes(routesByLength[underlying_coin_addresses[j]], inputCoinAddress, sortByLength);
587
485
  nextCoins.add(underlying_coin_addresses[j]);
588
486
  return [2 /*return*/];
589
487
  }
590
488
  });
591
489
  };
592
490
  j = 0;
593
- _q.label = 11;
594
- case 11:
595
- if (!(j < underlying_coin_addresses.length)) return [3 /*break*/, 14];
491
+ _x.label = 2;
492
+ case 2:
493
+ if (!(j < underlying_coin_addresses.length)) return [3 /*break*/, 5];
596
494
  return [5 /*yield**/, _loop_5(j)];
597
- case 12:
598
- _q.sent();
599
- _q.label = 13;
600
- case 13:
495
+ case 3:
496
+ _x.sent();
497
+ _x.label = 4;
498
+ case 4:
601
499
  j++;
602
- return [3 /*break*/, 11];
603
- case 14: return [2 /*return*/];
500
+ return [3 /*break*/, 2];
501
+ case 5: return [2 /*return*/];
604
502
  }
605
503
  });
606
504
  };
607
- _l = 0, ALL_POOLS_4 = ALL_POOLS;
608
- _o.label = 1;
505
+ _t = 0, ALL_POOLS_4 = ALL_POOLS;
506
+ _v.label = 1;
609
507
  case 1:
610
- if (!(_l < ALL_POOLS_4.length)) return [3 /*break*/, 4];
611
- _m = ALL_POOLS_4[_l], poolId = _m[0], poolData = _m[1];
508
+ if (!(_t < ALL_POOLS_4.length)) return [3 /*break*/, 4];
509
+ _u = ALL_POOLS_4[_t], poolId = _u[0], poolData = _u[1];
612
510
  return [5 /*yield**/, _loop_2(poolId, poolData)];
613
511
  case 2:
614
- _o.sent();
615
- _o.label = 3;
512
+ _v.sent();
513
+ _v.label = 3;
616
514
  case 3:
617
- _l++;
515
+ _t++;
618
516
  return [3 /*break*/, 1];
619
517
  case 4: return [2 /*return*/];
620
518
  }
621
519
  });
622
520
  };
623
521
  _a = 0, curCoins_2 = curCoins;
624
- _k.label = 3;
522
+ _s.label = 3;
625
523
  case 3:
626
524
  if (!(_a < curCoins_2.length)) return [3 /*break*/, 6];
627
525
  inCoin = curCoins_2[_a];
628
526
  return [5 /*yield**/, _loop_1(inCoin)];
629
527
  case 4:
630
- _k.sent();
631
- _k.label = 5;
528
+ _s.sent();
529
+ _s.label = 5;
632
530
  case 5:
633
531
  _a++;
634
532
  return [3 /*break*/, 3];
635
533
  case 6:
636
534
  curCoins = Array.from(nextCoins);
637
535
  nextCoins = new Set();
638
- _k.label = 7;
536
+ _s.label = 7;
639
537
  case 7:
640
538
  step++;
641
539
  return [3 /*break*/, 2];
642
- case 8: return [2 /*return*/, routes[outputCoinAddress] ? routes[outputCoinAddress].map(function (r) { return r.steps; }) : []];
540
+ case 8:
541
+ routes = __spreadArray(__spreadArray([], ((_q = routesByTvl[outputCoinAddress]) !== null && _q !== void 0 ? _q : []), true), ((_r = routesByLength[outputCoinAddress]) !== null && _r !== void 0 ? _r : []), true);
542
+ return [2 /*return*/, routes.map(function (r) { return r.steps; })];
643
543
  }
644
544
  });
645
545
  }); };
@@ -865,7 +765,7 @@ var swapPriceImpact = function (inputCoin, outputCoin, amount) { return __awaite
865
765
  case 2:
866
766
  _smallOutput = _d.sent();
867
767
  priceImpactBN = (0, utils_1._get_price_impact)(_amount, _output, _smallAmount, _smallOutput, inputCoinDecimals, outputCoinDecimals);
868
- return [2 /*return*/, Number((0, utils_1._cutZeros)(priceImpactBN.toFixed(4)).replace('-', ''))];
768
+ return [2 /*return*/, Number((0, utils_1._cutZeros)(priceImpactBN.toFixed(4)))];
869
769
  }
870
770
  });
871
771
  }); };
package/lib/utils.js CHANGED
@@ -600,6 +600,8 @@ var _get_price_impact = function (_x, _y, _small_x, _small_y, x_decimals, y_deci
600
600
  var small_y_BN = (0, exports.toBN)(_small_y, y_decimals);
601
601
  var rateBN = y_BN.div(x_BN);
602
602
  var smallRateBN = small_y_BN.div(small_x_BN);
603
+ if (rateBN.gt(smallRateBN))
604
+ return (0, exports.BN)(0);
603
605
  return (0, exports.BN)(1).minus(rateBN.div(smallRateBN)).times(100);
604
606
  };
605
607
  exports._get_price_impact = _get_price_impact;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curvefi/api",
3
- "version": "2.19.2",
3
+ "version": "2.20.1",
4
4
  "description": "JavaScript library for curve.fi",
5
5
  "main": "lib/index.js",
6
6
  "author": "Macket",