@curvefi/api 2.8.8 → 2.10.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/router.js CHANGED
@@ -59,7 +59,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
59
59
  return (mod && mod.__esModule) ? mod : { "default": mod };
60
60
  };
61
61
  Object.defineProperty(exports, "__esModule", { value: true });
62
- exports.swap = exports.swapEstimateGas = exports.swapApprove = exports.swapApproveEstimateGas = exports.swapIsApproved = exports.swapPriceImpact = exports.swapExpected = exports.getBestRouteAndOutput = exports._findAllRoutes = void 0;
62
+ exports.swap = exports.swapEstimateGas = exports.swapApprove = exports.swapApproveEstimateGas = exports.swapIsApproved = exports.swapPriceImpact = exports.swapExpected = exports.getBestRouteAndOutput = exports._findAllRoutes = exports._findAllRoutesTvl = exports._findAllRoutesTheShorterTheBetter = exports.NATIVE_TOKENS = exports.NATIVE_TOKEN_ADDRESS = void 0;
63
63
  var axios_1 = __importDefault(require("axios"));
64
64
  var memoizee_1 = __importDefault(require("memoizee"));
65
65
  var bignumber_js_1 = __importDefault(require("bignumber.js"));
@@ -67,15 +67,53 @@ var ethers_1 = require("ethers");
67
67
  var curve_1 = require("./curve");
68
68
  var utils_1 = require("./utils");
69
69
  var pools_1 = require("./pools");
70
- // TODO make working or remove
71
- var IMBALANCED_POOLS = [];
70
+ // TODO Move to another place
71
+ exports.NATIVE_TOKEN_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
72
+ exports.NATIVE_TOKENS = {
73
+ 1: {
74
+ symbol: 'ETH',
75
+ wrappedSymbol: 'WETH',
76
+ wrappedAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'.toLowerCase(),
77
+ },
78
+ 10: {
79
+ symbol: 'ETH',
80
+ wrappedSymbol: 'WETH',
81
+ wrappedAddress: '0x4200000000000000000000000000000000000006'.toLowerCase(),
82
+ },
83
+ 100: {
84
+ symbol: 'XDAi',
85
+ wrappedSymbol: 'WXDAI',
86
+ wrappedAddress: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'.toLowerCase(),
87
+ },
88
+ 137: {
89
+ symbol: 'MATIC',
90
+ wrappedSymbol: 'WMATIC',
91
+ wrappedAddress: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270'.toLowerCase(),
92
+ },
93
+ 250: {
94
+ symbol: 'FTM',
95
+ wrappedSymbol: 'WFTM',
96
+ wrappedAddress: '0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83'.toLowerCase(),
97
+ },
98
+ 1284: {
99
+ symbol: 'GLMR',
100
+ wrappedSymbol: 'WGLMR',
101
+ wrappedAddress: '0xAcc15dC74880C9944775448304B263D191c6077F'.toLowerCase(),
102
+ },
103
+ 42161: {
104
+ symbol: 'ETH',
105
+ wrappedSymbol: 'WETH',
106
+ wrappedAddress: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1'.toLowerCase(),
107
+ },
108
+ };
109
+ var MAX_ROUTES_FOR_ONE_COIN = 3;
72
110
  // Inspired by Dijkstra's algorithm
73
- var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __awaiter(void 0, void 0, void 0, function () {
74
- 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, swapType, _o, _p, inCoinRoute, j, tvl, _q, swapType, _r, _s, inCoinRoute, tvl, _t, swapType, _u, _v, inCoinRoute;
75
- var _w;
76
- var _x, _y, _z, _0, _1, _2, _3, _4;
77
- return __generator(this, function (_5) {
78
- switch (_5.label) {
111
+ var _findAllRoutesTheShorterTheBetter = function (inputCoinAddress, outputCoinAddress) { return __awaiter(void 0, void 0, void 0, function () {
112
+ 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;
113
+ var _q;
114
+ var _r, _s, _t, _u, _v, _w;
115
+ return __generator(this, function (_x) {
116
+ switch (_x.label) {
79
117
  case 0:
80
118
  inputCoinAddress = inputCoinAddress.toLowerCase();
81
119
  outputCoinAddress = outputCoinAddress.toLowerCase();
@@ -90,35 +128,35 @@ var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __a
90
128
  markedCoins = [];
91
129
  curCoins = [inputCoinAddress];
92
130
  nextCoins = new Set();
93
- routes = (_w = {},
94
- _w[inputCoinAddress] = [[]],
95
- _w);
131
+ routes = (_q = {},
132
+ _q[inputCoinAddress] = [[]],
133
+ _q);
96
134
  step = 0;
97
- _5.label = 1;
135
+ _x.label = 1;
98
136
  case 1:
99
- if (!(step < 4)) return [3 /*break*/, 21];
137
+ if (!(step < 4)) return [3 /*break*/, 15];
100
138
  _a = 0, curCoins_1 = curCoins;
101
- _5.label = 2;
139
+ _x.label = 2;
102
140
  case 2:
103
- if (!(_a < curCoins_1.length)) return [3 /*break*/, 19];
141
+ if (!(_a < curCoins_1.length)) return [3 /*break*/, 13];
104
142
  inCoin = curCoins_1[_a];
105
143
  _b = 0, ALL_POOLS_2 = ALL_POOLS;
106
- _5.label = 3;
144
+ _x.label = 3;
107
145
  case 3:
108
- if (!(_b < ALL_POOLS_2.length)) return [3 /*break*/, 18];
146
+ if (!(_b < ALL_POOLS_2.length)) return [3 /*break*/, 12];
109
147
  _c = ALL_POOLS_2[_b], poolId = _c[0], poolData = _c[1];
110
148
  wrapped_coin_addresses = poolData.wrapped_coin_addresses.map(function (a) { return a.toLowerCase(); });
111
149
  underlying_coin_addresses = poolData.underlying_coin_addresses.map(function (a) { return a.toLowerCase(); });
112
150
  base_pool = poolData.is_meta ? curve_1.curve.constants.POOLS_DATA[poolData.base_pool] : null;
113
151
  meta_coin_addresses = base_pool ? base_pool.underlying_coin_addresses.map(function (a) { return a.toLowerCase(); }) : [];
114
152
  token_address = poolData.token_address.toLowerCase();
115
- is_lending = (_x = poolData.is_lending) !== null && _x !== void 0 ? _x : false;
153
+ is_lending = (_r = poolData.is_lending) !== null && _r !== void 0 ? _r : false;
116
154
  inCoinIndexes = {
117
155
  wrapped_coin: wrapped_coin_addresses.indexOf(inCoin),
118
156
  underlying_coin: underlying_coin_addresses.indexOf(inCoin),
119
157
  meta_coin: meta_coin_addresses ? meta_coin_addresses.indexOf(inCoin) : -1,
120
158
  };
121
- // Find all LP -> underlying coin "swaps" (actually remove_liquidity_one_coin)
159
+ // LP -> underlying coin "swaps" (actually remove_liquidity_one_coin)
122
160
  if (basePoolIds.includes(poolId) && inCoin === token_address) {
123
161
  for (j = 0; j < underlying_coin_addresses.length; j++) {
124
162
  // If this coin already marked or will be marked on the current step, no need to consider it on the next step
@@ -130,10 +168,11 @@ var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __a
130
168
  swapType = poolId === 'aave' ? 10 : 9;
131
169
  for (_d = 0, _e = routes[inCoin]; _d < _e.length; _d++) {
132
170
  inCoinRoute = _e[_d];
133
- routes[underlying_coin_addresses[j]] = ((_y = routes[underlying_coin_addresses[j]]) !== null && _y !== void 0 ? _y : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
171
+ routes[underlying_coin_addresses[j]] = ((_s = routes[underlying_coin_addresses[j]]) !== null && _s !== void 0 ? _s : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
134
172
  {
135
173
  poolId: poolId,
136
174
  poolAddress: poolData.swap_address,
175
+ inputCoinAddress: inCoin,
137
176
  outputCoinAddress: underlying_coin_addresses[j],
138
177
  i: 0,
139
178
  j: j,
@@ -145,21 +184,22 @@ var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __a
145
184
  nextCoins.add(underlying_coin_addresses[j]);
146
185
  }
147
186
  }
148
- // Find all underlying coin -> LP "swaps" (actually add_liquidity)
187
+ // Underlying coin -> LP "swaps" (actually add_liquidity)
149
188
  if (basePoolIds.includes(poolId) && underlying_coin_addresses.includes(inCoin)) {
150
189
  // If this coin already marked or will be marked on the current step, no need to consider it on the next step
151
190
  if (markedCoins.includes(token_address) || curCoins.includes(token_address))
152
- return [3 /*break*/, 17];
191
+ return [3 /*break*/, 11];
153
192
  // Looking for outputCoinAddress only on the final step
154
193
  if (step === 3 && token_address !== outputCoinAddress)
155
- return [3 /*break*/, 17];
194
+ return [3 /*break*/, 11];
156
195
  swapType = is_lending ? 8 : underlying_coin_addresses.length === 2 ? 6 : 7;
157
196
  for (_f = 0, _h = routes[inCoin]; _f < _h.length; _f++) {
158
197
  inCoinRoute = _h[_f];
159
- routes[token_address] = ((_z = routes[token_address]) !== null && _z !== void 0 ? _z : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
198
+ routes[token_address] = ((_t = routes[token_address]) !== null && _t !== void 0 ? _t : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
160
199
  {
161
200
  poolId: poolId,
162
201
  poolAddress: poolData.swap_address,
202
+ inputCoinAddress: inCoin,
163
203
  outputCoinAddress: token_address,
164
204
  i: underlying_coin_addresses.indexOf(inCoin),
165
205
  j: 0,
@@ -172,34 +212,35 @@ var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __a
172
212
  }
173
213
  // No input coin in this pool --> skip
174
214
  if (inCoinIndexes.wrapped_coin === -1 && inCoinIndexes.underlying_coin === -1 && inCoinIndexes.meta_coin === -1)
175
- return [3 /*break*/, 17];
215
+ return [3 /*break*/, 11];
176
216
  if (!(inCoinIndexes.wrapped_coin >= 0 && !poolData.is_fake)) return [3 /*break*/, 7];
177
217
  j = 0;
178
- _5.label = 4;
218
+ _x.label = 4;
179
219
  case 4:
180
220
  if (!(j < wrapped_coin_addresses.length)) return [3 /*break*/, 7];
181
221
  // If this coin already marked or will be marked on the current step, no need to consider it on the next step
182
222
  if (markedCoins.includes(wrapped_coin_addresses[j]) || curCoins.includes(wrapped_coin_addresses[j]))
183
223
  return [3 /*break*/, 6];
224
+ // Native swaps spend less gas
225
+ if (wrapped_coin_addresses[j] !== outputCoinAddress && wrapped_coin_addresses[j] === exports.NATIVE_TOKENS[curve_1.curve.chainId].wrappedAddress)
226
+ return [3 /*break*/, 6];
184
227
  // Looking for outputCoinAddress only on the final step
185
228
  if (step === 3 && wrapped_coin_addresses[j] !== outputCoinAddress)
186
229
  return [3 /*break*/, 6];
187
230
  _j = Number;
188
231
  return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
189
232
  case 5:
190
- tvl = _j.apply(void 0, [_5.sent()]);
233
+ tvl = _j.apply(void 0, [_x.sent()]);
191
234
  if (tvl === 0)
192
235
  return [3 /*break*/, 6];
193
- // Skip imbalanced pools
194
- if (IMBALANCED_POOLS.includes(poolId))
195
- return [3 /*break*/, 6];
196
236
  swapType = poolData.is_crypto ? 3 : 1;
197
237
  for (_k = 0, _l = routes[inCoin]; _k < _l.length; _k++) {
198
238
  inCoinRoute = _l[_k];
199
- routes[wrapped_coin_addresses[j]] = ((_0 = routes[wrapped_coin_addresses[j]]) !== null && _0 !== void 0 ? _0 : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
239
+ routes[wrapped_coin_addresses[j]] = ((_u = routes[wrapped_coin_addresses[j]]) !== null && _u !== void 0 ? _u : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
200
240
  {
201
241
  poolId: poolId,
202
242
  poolAddress: poolData.swap_address,
243
+ inputCoinAddress: inCoin,
203
244
  outputCoinAddress: wrapped_coin_addresses[j],
204
245
  i: inCoinIndexes.wrapped_coin,
205
246
  j: j,
@@ -209,16 +250,16 @@ var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __a
209
250
  ], false)]);
210
251
  }
211
252
  nextCoins.add(wrapped_coin_addresses[j]);
212
- _5.label = 6;
253
+ _x.label = 6;
213
254
  case 6:
214
255
  j++;
215
256
  return [3 /*break*/, 4];
216
257
  case 7:
217
- poolAddress = (poolData.is_crypto && poolData.is_meta) || (base_pool && base_pool.is_meta && poolData.is_factory) ?
258
+ poolAddress = (poolData.is_crypto && poolData.is_meta) || ((base_pool === null || base_pool === void 0 ? void 0 : base_pool.is_lending) && poolData.is_factory) ?
218
259
  poolData.deposit_address : poolData.swap_address;
219
260
  if (!(!poolData.is_plain && inCoinIndexes.underlying_coin >= 0)) return [3 /*break*/, 11];
220
261
  j = 0;
221
- _5.label = 8;
262
+ _x.label = 8;
222
263
  case 8:
223
264
  if (!(j < underlying_coin_addresses.length)) return [3 /*break*/, 11];
224
265
  // Don't swap metacoins since they can be swapped directly in base pool
@@ -233,19 +274,18 @@ var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __a
233
274
  _m = Number;
234
275
  return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
235
276
  case 9:
236
- tvl = _m.apply(void 0, [_5.sent()]);
277
+ tvl = _m.apply(void 0, [_x.sent()]);
237
278
  if (tvl === 0)
238
279
  return [3 /*break*/, 10];
239
- // Skip imbalanced pools
240
- if (IMBALANCED_POOLS.includes(poolId))
241
- return [3 /*break*/, 10];
242
- swapType = poolData.is_crypto && (poolData.is_fake || poolData.is_meta) ? 4 : poolData.is_crypto ? 3 : 2;
280
+ hasEth = (inCoin === exports.NATIVE_TOKEN_ADDRESS || underlying_coin_addresses[j] === exports.NATIVE_TOKEN_ADDRESS);
281
+ swapType = ((base_pool === null || base_pool === void 0 ? void 0 : base_pool.is_lending) && poolData.is_factory) ? 5 : hasEth ? 3 : poolData.is_crypto ? 4 : 2;
243
282
  for (_o = 0, _p = routes[inCoin]; _o < _p.length; _o++) {
244
283
  inCoinRoute = _p[_o];
245
- routes[underlying_coin_addresses[j]] = ((_1 = routes[underlying_coin_addresses[j]]) !== null && _1 !== void 0 ? _1 : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
284
+ routes[underlying_coin_addresses[j]] = ((_v = routes[underlying_coin_addresses[j]]) !== null && _v !== void 0 ? _v : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
246
285
  {
247
286
  poolId: poolId,
248
287
  poolAddress: poolAddress,
288
+ inputCoinAddress: inCoin,
249
289
  outputCoinAddress: underlying_coin_addresses[j],
250
290
  i: inCoinIndexes.underlying_coin,
251
291
  j: j,
@@ -255,103 +295,393 @@ var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __a
255
295
  ], false)]);
256
296
  }
257
297
  nextCoins.add(underlying_coin_addresses[j]);
258
- _5.label = 10;
298
+ _x.label = 10;
259
299
  case 10:
260
300
  j++;
261
301
  return [3 /*break*/, 8];
262
302
  case 11:
263
- if (!(inCoinIndexes.wrapped_coin === 0 && meta_coin_addresses.length > 0 && !poolData.is_fake)) return [3 /*break*/, 15];
264
- j = 0;
265
- _5.label = 12;
266
- case 12:
267
- if (!(j < meta_coin_addresses.length)) return [3 /*break*/, 15];
268
- // If this coin already marked or will be marked on the current step, no need to consider it on the next step
269
- if (markedCoins.includes(meta_coin_addresses[j]) || curCoins.includes(meta_coin_addresses[j]))
270
- return [3 /*break*/, 14];
271
- // Looking for outputCoinAddress only on the final step
272
- if (step === 3 && meta_coin_addresses[j] !== outputCoinAddress)
273
- return [3 /*break*/, 14];
274
- _q = Number;
275
- return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
276
- case 13:
277
- tvl = _q.apply(void 0, [_5.sent()]);
278
- if (tvl === 0)
279
- return [3 /*break*/, 14];
280
- // Skip imbalanced pools
281
- if (IMBALANCED_POOLS.includes(poolId))
282
- return [3 /*break*/, 14];
283
- swapType = (base_pool && base_pool.is_meta && poolData.is_factory) ? 5 : poolData.is_crypto ? 4 : 2;
284
- for (_r = 0, _s = routes[inCoin]; _r < _s.length; _r++) {
285
- inCoinRoute = _s[_r];
286
- routes[meta_coin_addresses[j]] = ((_2 = routes[meta_coin_addresses[j]]) !== null && _2 !== void 0 ? _2 : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
287
- {
288
- poolId: poolId,
289
- poolAddress: poolAddress,
290
- outputCoinAddress: meta_coin_addresses[j],
291
- i: inCoinIndexes.wrapped_coin,
292
- j: j + 1,
293
- swapType: swapType,
294
- swapAddress: swapType === 5 ? poolData.swap_address : ethers_1.ethers.constants.AddressZero,
295
- },
296
- ], false)]);
297
- }
298
- nextCoins.add(meta_coin_addresses[j]);
299
- _5.label = 14;
300
- case 14:
301
- j++;
302
- return [3 /*break*/, 12];
303
- case 15:
304
- if (!(inCoinIndexes.meta_coin >= 0 && !poolData.is_fake)) return [3 /*break*/, 17];
305
- // If this coin already marked or will be marked on the current step, no need to consider it on the next step
306
- if (markedCoins.includes(wrapped_coin_addresses[0]) || curCoins.includes(wrapped_coin_addresses[0]))
307
- return [3 /*break*/, 17];
308
- // Looking for outputCoinAddress only on the final step
309
- if (step === 3 && wrapped_coin_addresses[0] !== outputCoinAddress)
310
- return [3 /*break*/, 17];
311
- _t = Number;
312
- return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
313
- case 16:
314
- tvl = _t.apply(void 0, [_5.sent()]);
315
- if (tvl === 0)
316
- return [3 /*break*/, 17];
317
- // Skip imbalanced pools
318
- if (IMBALANCED_POOLS.includes(poolId))
319
- return [3 /*break*/, 17];
320
- swapType = (base_pool && base_pool.is_meta && poolData.is_factory) ? 5 : poolData.is_crypto ? 4 : 2;
321
- for (_u = 0, _v = routes[inCoin]; _u < _v.length; _u++) {
322
- inCoinRoute = _v[_u];
323
- routes[wrapped_coin_addresses[0]] = ((_3 = routes[wrapped_coin_addresses[0]]) !== null && _3 !== void 0 ? _3 : []).concat([__spreadArray(__spreadArray([], inCoinRoute, true), [
324
- {
325
- poolId: poolId,
326
- poolAddress: poolAddress,
327
- outputCoinAddress: wrapped_coin_addresses[0],
328
- i: inCoinIndexes.meta_coin + 1,
329
- j: 0,
330
- swapType: swapType,
331
- swapAddress: swapType === 5 ? poolData.swap_address : ethers_1.ethers.constants.AddressZero,
332
- },
333
- ], false)]);
334
- nextCoins.add(wrapped_coin_addresses[0]);
335
- }
336
- _5.label = 17;
337
- case 17:
338
303
  _b++;
339
304
  return [3 /*break*/, 3];
340
- case 18:
305
+ case 12:
341
306
  _a++;
342
307
  return [3 /*break*/, 2];
343
- case 19:
308
+ case 13:
344
309
  // If target output coin is reached, search is finished. Assumption: the shorter route, the better.
345
310
  if (outputCoinAddress in routes)
346
- return [3 /*break*/, 21];
311
+ return [3 /*break*/, 15];
347
312
  markedCoins.push.apply(markedCoins, curCoins);
348
313
  curCoins = Array.from(nextCoins);
349
314
  nextCoins = new Set();
350
- _5.label = 20;
351
- case 20:
315
+ _x.label = 14;
316
+ case 14:
317
+ step++;
318
+ return [3 /*break*/, 1];
319
+ case 15: return [2 /*return*/, (_w = routes[outputCoinAddress]) !== null && _w !== void 0 ? _w : []];
320
+ }
321
+ });
322
+ }); };
323
+ exports._findAllRoutesTheShorterTheBetter = _findAllRoutesTheShorterTheBetter;
324
+ // Inspired by Dijkstra's algorithm
325
+ var _findAllRoutesTvl = function (inputCoinAddress, outputCoinAddress) { return __awaiter(void 0, void 0, void 0, function () {
326
+ var ALL_POOLS, basePoolsSet, _i, ALL_POOLS_3, pool, basePoolIds, curCoins, nextCoins, routes, step, _loop_1, _a, curCoins_2, inCoin;
327
+ var _b;
328
+ var _c, _d, _e, _f, _h;
329
+ return __generator(this, function (_j) {
330
+ switch (_j.label) {
331
+ case 0:
332
+ inputCoinAddress = inputCoinAddress.toLowerCase();
333
+ outputCoinAddress = outputCoinAddress.toLowerCase();
334
+ 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));
335
+ basePoolsSet = new Set();
336
+ for (_i = 0, ALL_POOLS_3 = ALL_POOLS; _i < ALL_POOLS_3.length; _i++) {
337
+ pool = ALL_POOLS_3[_i];
338
+ if (pool[1].base_pool)
339
+ basePoolsSet.add(pool[1].base_pool);
340
+ }
341
+ basePoolIds = Array.from(basePoolsSet);
342
+ curCoins = [inputCoinAddress];
343
+ nextCoins = new Set();
344
+ routes = (_b = {},
345
+ _b[inputCoinAddress] = [{ steps: [], minTvl: Infinity }],
346
+ _b);
347
+ step = 0;
348
+ _j.label = 1;
349
+ case 1:
350
+ if (!(step < 4)) return [3 /*break*/, 7];
351
+ _loop_1 = function (inCoin) {
352
+ var _loop_2, _k, ALL_POOLS_4, _l, poolId, poolData;
353
+ return __generator(this, function (_m) {
354
+ switch (_m.label) {
355
+ case 0:
356
+ _loop_2 = function (poolId, poolData) {
357
+ var wrapped_coin_addresses, underlying_coin_addresses, base_pool, meta_coin_addresses, token_address, is_lending, inCoinIndexes, _loop_3, j, tvl_1, _o, swapType_1, newRoutes, routesByPoolIds_1, _loop_4, j, poolAddress, _loop_5, j;
358
+ return __generator(this, function (_p) {
359
+ switch (_p.label) {
360
+ case 0:
361
+ wrapped_coin_addresses = poolData.wrapped_coin_addresses.map(function (a) { return a.toLowerCase(); });
362
+ underlying_coin_addresses = poolData.underlying_coin_addresses.map(function (a) { return a.toLowerCase(); });
363
+ base_pool = poolData.is_meta ? curve_1.curve.constants.POOLS_DATA[poolData.base_pool] : null;
364
+ meta_coin_addresses = base_pool ? base_pool.underlying_coin_addresses.map(function (a) { return a.toLowerCase(); }) : [];
365
+ token_address = poolData.token_address.toLowerCase();
366
+ is_lending = (_c = poolData.is_lending) !== null && _c !== void 0 ? _c : false;
367
+ inCoinIndexes = {
368
+ wrapped_coin: wrapped_coin_addresses.indexOf(inCoin),
369
+ underlying_coin: underlying_coin_addresses.indexOf(inCoin),
370
+ meta_coin: meta_coin_addresses ? meta_coin_addresses.indexOf(inCoin) : -1,
371
+ };
372
+ // No input coin in this pool --> skip
373
+ if (inCoinIndexes.wrapped_coin === -1 && inCoinIndexes.underlying_coin === -1 && inCoinIndexes.meta_coin === -1 && inCoin !== token_address)
374
+ return [2 /*return*/, "continue"];
375
+ if (!(basePoolIds.includes(poolId) && inCoin === token_address)) return [3 /*break*/, 4];
376
+ _loop_3 = function (j) {
377
+ var outputCoinIdx, tvl, _q, swapType, newRoutes, routesByPoolIds;
378
+ return __generator(this, function (_r) {
379
+ switch (_r.label) {
380
+ case 0:
381
+ // Looking for outputCoinAddress only on the final step
382
+ if (step === 3 && underlying_coin_addresses[j] !== outputCoinAddress)
383
+ return [2 /*return*/, "continue"];
384
+ outputCoinIdx = underlying_coin_addresses.indexOf(outputCoinAddress);
385
+ if (outputCoinIdx >= 0 && j !== outputCoinIdx)
386
+ return [2 /*return*/, "continue"];
387
+ _q = Number;
388
+ return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
389
+ case 1:
390
+ tvl = _q.apply(void 0, [_r.sent()]);
391
+ swapType = poolId === 'aave' ? 10 : 9;
392
+ newRoutes = routes[inCoin].map(function (route) {
393
+ var routePoolIds = route.steps.map(function (s) { return s.poolId; });
394
+ // Steps <= 4
395
+ if (routePoolIds.length >= 4)
396
+ return { steps: [], minTvl: -1 };
397
+ // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
398
+ if (routePoolIds.includes(poolId))
399
+ return { steps: [], minTvl: -1 };
400
+ return {
401
+ steps: __spreadArray(__spreadArray([], route.steps, true), [
402
+ {
403
+ poolId: poolId,
404
+ poolAddress: poolData.swap_address,
405
+ inputCoinAddress: inCoin,
406
+ outputCoinAddress: underlying_coin_addresses[j],
407
+ i: 0,
408
+ j: j,
409
+ swapType: swapType,
410
+ swapAddress: ethers_1.ethers.constants.AddressZero,
411
+ },
412
+ ], false),
413
+ minTvl: Math.min(tvl, route.minTvl),
414
+ };
415
+ });
416
+ routes[underlying_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_d = routes[underlying_coin_addresses[j]]) !== null && _d !== void 0 ? _d : []), true), newRoutes, true);
417
+ routesByPoolIds = routes[underlying_coin_addresses[j]].map(function (r) { return r.steps.map(function (s) { return s.poolId; }).toString(); });
418
+ routes[underlying_coin_addresses[j]] = routes[underlying_coin_addresses[j]]
419
+ .filter(function (r) { return r.steps.length > 0; })
420
+ .filter(function (r) { return r.steps[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
421
+ .filter(function (r, i) { return routesByPoolIds.indexOf(r.steps.map(function (s) { return s.poolId; }).toString()) === i; }) // Route duplications
422
+ .sort(function (a, b) { return b.minTvl - a.minTvl || a.steps.length - b.steps.length; }).slice(0, MAX_ROUTES_FOR_ONE_COIN);
423
+ nextCoins.add(underlying_coin_addresses[j]);
424
+ return [2 /*return*/];
425
+ }
426
+ });
427
+ };
428
+ j = 0;
429
+ _p.label = 1;
430
+ case 1:
431
+ if (!(j < underlying_coin_addresses.length)) return [3 /*break*/, 4];
432
+ return [5 /*yield**/, _loop_3(j)];
433
+ case 2:
434
+ _p.sent();
435
+ _p.label = 3;
436
+ case 3:
437
+ j++;
438
+ return [3 /*break*/, 1];
439
+ case 4:
440
+ if (!(basePoolIds.includes(poolId) && inCoinIndexes.underlying_coin >= 0)) return [3 /*break*/, 6];
441
+ // Looking for outputCoinAddress only on the final step
442
+ if (step === 3 && token_address !== outputCoinAddress)
443
+ return [2 /*return*/, "continue"];
444
+ _o = Number;
445
+ return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
446
+ case 5:
447
+ tvl_1 = _o.apply(void 0, [_p.sent()]);
448
+ swapType_1 = is_lending ? 8 : underlying_coin_addresses.length === 2 ? 6 : 7;
449
+ newRoutes = routes[inCoin].map(function (route) {
450
+ var routePoolIds = route.steps.map(function (s) { return s.poolId; });
451
+ // Steps <= 4
452
+ if (routePoolIds.length >= 4)
453
+ return { steps: [], minTvl: -1 };
454
+ // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
455
+ if (routePoolIds.includes(poolId))
456
+ return { steps: [], minTvl: -1 };
457
+ return {
458
+ steps: __spreadArray(__spreadArray([], route.steps, true), [
459
+ {
460
+ poolId: poolId,
461
+ poolAddress: poolData.swap_address,
462
+ inputCoinAddress: inCoin,
463
+ outputCoinAddress: token_address,
464
+ i: underlying_coin_addresses.indexOf(inCoin),
465
+ j: 0,
466
+ swapType: swapType_1,
467
+ swapAddress: ethers_1.ethers.constants.AddressZero,
468
+ },
469
+ ], false),
470
+ minTvl: Math.min(tvl_1, route.minTvl),
471
+ };
472
+ });
473
+ routes[token_address] = __spreadArray(__spreadArray([], ((_e = routes[token_address]) !== null && _e !== void 0 ? _e : []), true), newRoutes, true);
474
+ routesByPoolIds_1 = routes[token_address].map(function (r) { return r.steps.map(function (s) { return s.poolId; }).toString(); });
475
+ routes[token_address] = routes[token_address]
476
+ .filter(function (r) { return r.steps.length > 0; })
477
+ .filter(function (r) { return r.steps[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
478
+ .filter(function (r, i) { return routesByPoolIds_1.indexOf(r.steps.map(function (s) { return s.poolId; }).toString()) === i; }) // Route duplications
479
+ .sort(function (a, b) { return b.minTvl - a.minTvl || a.steps.length - b.steps.length; }).slice(0, MAX_ROUTES_FOR_ONE_COIN);
480
+ nextCoins.add(token_address);
481
+ _p.label = 6;
482
+ case 6:
483
+ if (!(inCoinIndexes.wrapped_coin >= 0 && !poolData.is_fake)) return [3 /*break*/, 10];
484
+ _loop_4 = function (j) {
485
+ var outputCoinIdx, tvl, _s, swapType, newRoutes, routesByPoolIds;
486
+ return __generator(this, function (_t) {
487
+ switch (_t.label) {
488
+ case 0:
489
+ if (j === inCoinIndexes.wrapped_coin)
490
+ return [2 /*return*/, "continue"];
491
+ // Native swaps spend less gas
492
+ if (wrapped_coin_addresses[j] !== outputCoinAddress && wrapped_coin_addresses[j] === exports.NATIVE_TOKENS[curve_1.curve.chainId].wrappedAddress)
493
+ return [2 /*return*/, "continue"];
494
+ // Looking for outputCoinAddress only on the final step
495
+ if (step === 3 && wrapped_coin_addresses[j] !== outputCoinAddress)
496
+ return [2 /*return*/, "continue"];
497
+ outputCoinIdx = wrapped_coin_addresses.indexOf(outputCoinAddress);
498
+ if (outputCoinIdx >= 0 && j !== outputCoinIdx)
499
+ return [2 /*return*/, "continue"];
500
+ _s = Number;
501
+ return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
502
+ case 1:
503
+ tvl = _s.apply(void 0, [_t.sent()]);
504
+ // Skip empty pools
505
+ if (tvl === 0)
506
+ return [2 /*return*/, "continue"];
507
+ swapType = poolData.is_crypto ? 3 : 1;
508
+ newRoutes = routes[inCoin].map(function (route) {
509
+ var routePoolIds = route.steps.map(function (s) { return s.poolId; });
510
+ // Steps <= 4
511
+ if (routePoolIds.length >= 4)
512
+ return { steps: [], minTvl: -1 };
513
+ // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
514
+ if (routePoolIds.includes(poolId))
515
+ return { steps: [], minTvl: -1 };
516
+ return {
517
+ steps: __spreadArray(__spreadArray([], route.steps, true), [
518
+ {
519
+ poolId: poolId,
520
+ poolAddress: poolData.swap_address,
521
+ inputCoinAddress: inCoin,
522
+ outputCoinAddress: wrapped_coin_addresses[j],
523
+ i: inCoinIndexes.wrapped_coin,
524
+ j: j,
525
+ swapType: swapType,
526
+ swapAddress: ethers_1.ethers.constants.AddressZero,
527
+ },
528
+ ], false),
529
+ minTvl: Math.min(tvl, route.minTvl),
530
+ };
531
+ });
532
+ routes[wrapped_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_f = routes[wrapped_coin_addresses[j]]) !== null && _f !== void 0 ? _f : []), true), newRoutes, true);
533
+ routesByPoolIds = routes[wrapped_coin_addresses[j]].map(function (r) { return r.steps.map(function (s) { return s.poolId; }).toString(); });
534
+ routes[wrapped_coin_addresses[j]] = routes[wrapped_coin_addresses[j]]
535
+ .filter(function (r) { return r.steps.length > 0; })
536
+ .filter(function (r) { return r.steps[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
537
+ .filter(function (r, i) { return routesByPoolIds.indexOf(r.steps.map(function (s) { return s.poolId; }).toString()) === i; }) // Route duplications
538
+ .sort(function (a, b) { return b.minTvl - a.minTvl || a.steps.length - b.steps.length; }).slice(0, MAX_ROUTES_FOR_ONE_COIN);
539
+ nextCoins.add(wrapped_coin_addresses[j]);
540
+ return [2 /*return*/];
541
+ }
542
+ });
543
+ };
544
+ j = 0;
545
+ _p.label = 7;
546
+ case 7:
547
+ if (!(j < wrapped_coin_addresses.length)) return [3 /*break*/, 10];
548
+ return [5 /*yield**/, _loop_4(j)];
549
+ case 8:
550
+ _p.sent();
551
+ _p.label = 9;
552
+ case 9:
553
+ j++;
554
+ return [3 /*break*/, 7];
555
+ case 10:
556
+ poolAddress = (poolData.is_crypto && poolData.is_meta) || ((base_pool === null || base_pool === void 0 ? void 0 : base_pool.is_lending) && poolData.is_factory) ?
557
+ poolData.deposit_address : poolData.swap_address;
558
+ if (!(!poolData.is_plain && inCoinIndexes.underlying_coin >= 0)) return [3 /*break*/, 14];
559
+ _loop_5 = function (j) {
560
+ var outputCoinIdx, tvl, _u, hasEth, swapType, newRoutes, routesByPoolIds;
561
+ return __generator(this, function (_v) {
562
+ switch (_v.label) {
563
+ case 0:
564
+ if (j === inCoinIndexes.underlying_coin)
565
+ return [2 /*return*/, "continue"];
566
+ // Don't swap metacoins since they can be swapped directly in base pool
567
+ if (inCoinIndexes.meta_coin >= 0 && meta_coin_addresses.includes(underlying_coin_addresses[j]))
568
+ return [2 /*return*/, "continue"];
569
+ // Looking for outputCoinAddress only on the final step
570
+ if (step === 3 && underlying_coin_addresses[j] !== outputCoinAddress)
571
+ return [2 /*return*/, "continue"];
572
+ outputCoinIdx = underlying_coin_addresses.indexOf(outputCoinAddress);
573
+ if (outputCoinIdx >= 0 && j !== outputCoinIdx)
574
+ return [2 /*return*/, "continue"];
575
+ _u = Number;
576
+ return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
577
+ case 1:
578
+ tvl = _u.apply(void 0, [_v.sent()]);
579
+ if (tvl === 0)
580
+ return [2 /*return*/, "continue"];
581
+ hasEth = (inCoin === exports.NATIVE_TOKEN_ADDRESS || underlying_coin_addresses[j] === exports.NATIVE_TOKEN_ADDRESS);
582
+ swapType = ((base_pool === null || base_pool === void 0 ? void 0 : base_pool.is_lending) && poolData.is_factory) ? 5 : hasEth ? 3 : poolData.is_crypto ? 4 : 2;
583
+ newRoutes = routes[inCoin].map(function (route) {
584
+ var routePoolIds = route.steps.map(function (s) { return s.poolId; });
585
+ // Steps <= 4
586
+ if (routePoolIds.length >= 4)
587
+ return { steps: [], minTvl: -1 };
588
+ // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
589
+ if (routePoolIds.includes(poolId))
590
+ return { steps: [], minTvl: -1 };
591
+ return {
592
+ steps: __spreadArray(__spreadArray([], route.steps, true), [
593
+ {
594
+ poolId: poolId,
595
+ poolAddress: poolAddress,
596
+ inputCoinAddress: inCoin,
597
+ outputCoinAddress: underlying_coin_addresses[j],
598
+ i: inCoinIndexes.underlying_coin,
599
+ j: j,
600
+ swapType: swapType,
601
+ swapAddress: swapType === 5 ? poolData.swap_address : ethers_1.ethers.constants.AddressZero,
602
+ },
603
+ ], false),
604
+ minTvl: Math.min(tvl, route.minTvl),
605
+ };
606
+ });
607
+ routes[underlying_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_h = routes[underlying_coin_addresses[j]]) !== null && _h !== void 0 ? _h : []), true), newRoutes, true);
608
+ routesByPoolIds = routes[underlying_coin_addresses[j]].map(function (r) { return r.steps.map(function (s) { return s.poolId; }).toString(); });
609
+ routes[underlying_coin_addresses[j]] = routes[underlying_coin_addresses[j]]
610
+ .filter(function (r) { return r.steps.length > 0; })
611
+ .filter(function (r) { return r.steps[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
612
+ .filter(function (r, i) { return routesByPoolIds.indexOf(r.steps.map(function (s) { return s.poolId; }).toString()) === i; }) // Route duplications
613
+ .sort(function (a, b) { return b.minTvl - a.minTvl || a.steps.length - b.steps.length; }).slice(0, MAX_ROUTES_FOR_ONE_COIN);
614
+ nextCoins.add(underlying_coin_addresses[j]);
615
+ return [2 /*return*/];
616
+ }
617
+ });
618
+ };
619
+ j = 0;
620
+ _p.label = 11;
621
+ case 11:
622
+ if (!(j < underlying_coin_addresses.length)) return [3 /*break*/, 14];
623
+ return [5 /*yield**/, _loop_5(j)];
624
+ case 12:
625
+ _p.sent();
626
+ _p.label = 13;
627
+ case 13:
628
+ j++;
629
+ return [3 /*break*/, 11];
630
+ case 14: return [2 /*return*/];
631
+ }
632
+ });
633
+ };
634
+ _k = 0, ALL_POOLS_4 = ALL_POOLS;
635
+ _m.label = 1;
636
+ case 1:
637
+ if (!(_k < ALL_POOLS_4.length)) return [3 /*break*/, 4];
638
+ _l = ALL_POOLS_4[_k], poolId = _l[0], poolData = _l[1];
639
+ return [5 /*yield**/, _loop_2(poolId, poolData)];
640
+ case 2:
641
+ _m.sent();
642
+ _m.label = 3;
643
+ case 3:
644
+ _k++;
645
+ return [3 /*break*/, 1];
646
+ case 4: return [2 /*return*/];
647
+ }
648
+ });
649
+ };
650
+ _a = 0, curCoins_2 = curCoins;
651
+ _j.label = 2;
652
+ case 2:
653
+ if (!(_a < curCoins_2.length)) return [3 /*break*/, 5];
654
+ inCoin = curCoins_2[_a];
655
+ return [5 /*yield**/, _loop_1(inCoin)];
656
+ case 3:
657
+ _j.sent();
658
+ _j.label = 4;
659
+ case 4:
660
+ _a++;
661
+ return [3 /*break*/, 2];
662
+ case 5:
663
+ curCoins = Array.from(nextCoins);
664
+ nextCoins = new Set();
665
+ _j.label = 6;
666
+ case 6:
352
667
  step++;
353
668
  return [3 /*break*/, 1];
354
- case 21: return [2 /*return*/, (_4 = routes[outputCoinAddress]) !== null && _4 !== void 0 ? _4 : []];
669
+ case 7: return [2 /*return*/, routes[outputCoinAddress] ? routes[outputCoinAddress].map(function (r) { return r.steps; }) : []];
670
+ }
671
+ });
672
+ }); };
673
+ exports._findAllRoutesTvl = _findAllRoutesTvl;
674
+ var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __awaiter(void 0, void 0, void 0, function () {
675
+ var routes;
676
+ return __generator(this, function (_a) {
677
+ switch (_a.label) {
678
+ case 0: return [4 /*yield*/, (0, exports._findAllRoutesTvl)(inputCoinAddress, outputCoinAddress)];
679
+ case 1:
680
+ routes = _a.sent();
681
+ if (routes.length > 0)
682
+ return [2 /*return*/, routes];
683
+ return [4 /*yield*/, (0, exports._findAllRoutesTheShorterTheBetter)(inputCoinAddress, outputCoinAddress)];
684
+ case 2: return [2 /*return*/, _a.sent()];
355
685
  }
356
686
  });
357
687
  }); };