@curvefi/api 2.31.0 → 2.31.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.
Files changed (97) hide show
  1. package/lib/boosting.js +137 -402
  2. package/lib/constants/aliases.d.ts +11 -11
  3. package/lib/constants/aliases.js +12 -15
  4. package/lib/constants/coins/arbitrum.js +6 -9
  5. package/lib/constants/coins/aurora.js +6 -9
  6. package/lib/constants/coins/avalanche.js +7 -10
  7. package/lib/constants/coins/celo.js +6 -9
  8. package/lib/constants/coins/ethereum.js +10 -13
  9. package/lib/constants/coins/fantom.js +8 -11
  10. package/lib/constants/coins/kava.js +6 -9
  11. package/lib/constants/coins/moonbeam.js +6 -9
  12. package/lib/constants/coins/optimism.js +6 -9
  13. package/lib/constants/coins/polygon.js +7 -10
  14. package/lib/constants/coins/xdai.js +6 -9
  15. package/lib/constants/pools/arbitrum.d.ts +2 -4
  16. package/lib/constants/pools/arbitrum.js +22 -28
  17. package/lib/constants/pools/aurora.d.ts +2 -4
  18. package/lib/constants/pools/aurora.js +6 -12
  19. package/lib/constants/pools/avalanche.d.ts +2 -4
  20. package/lib/constants/pools/avalanche.js +21 -27
  21. package/lib/constants/pools/celo.d.ts +2 -4
  22. package/lib/constants/pools/celo.js +2 -5
  23. package/lib/constants/pools/ethereum.js +247 -253
  24. package/lib/constants/pools/fantom.d.ts +2 -4
  25. package/lib/constants/pools/fantom.js +28 -34
  26. package/lib/constants/pools/index.d.ts +11 -11
  27. package/lib/constants/pools/index.js +12 -25
  28. package/lib/constants/pools/kava.d.ts +2 -4
  29. package/lib/constants/pools/kava.js +2 -5
  30. package/lib/constants/pools/moonbeam.d.ts +2 -4
  31. package/lib/constants/pools/moonbeam.js +6 -12
  32. package/lib/constants/pools/optimism.d.ts +2 -4
  33. package/lib/constants/pools/optimism.js +9 -15
  34. package/lib/constants/pools/polygon.d.ts +2 -4
  35. package/lib/constants/pools/polygon.js +22 -28
  36. package/lib/constants/pools/xdai.d.ts +2 -4
  37. package/lib/constants/pools/xdai.js +24 -30
  38. package/lib/constants/utils.js +20 -29
  39. package/lib/curve.d.ts +9 -7
  40. package/lib/curve.js +397 -615
  41. package/lib/external-api.d.ts +1 -1
  42. package/lib/external-api.js +47 -140
  43. package/lib/factory/common.js +6 -10
  44. package/lib/factory/constants-crypto.js +48 -54
  45. package/lib/factory/constants.js +274 -280
  46. package/lib/factory/deploy.d.ts +8 -8
  47. package/lib/factory/deploy.js +177 -347
  48. package/lib/factory/factory-api.js +195 -278
  49. package/lib/factory/factory-crypto.js +170 -323
  50. package/lib/factory/factory.js +195 -350
  51. package/lib/index.d.ts +24 -25
  52. package/lib/index.js +87 -143
  53. package/lib/interfaces.d.ts +5 -5
  54. package/lib/interfaces.js +1 -2
  55. package/lib/pools/PoolTemplate.js +1516 -2929
  56. package/lib/pools/index.d.ts +2 -2
  57. package/lib/pools/index.js +3 -7
  58. package/lib/pools/mixins/common.d.ts +3 -4
  59. package/lib/pools/mixins/common.js +23 -112
  60. package/lib/pools/mixins/depositBalancedAmountsMixins.d.ts +1 -1
  61. package/lib/pools/mixins/depositBalancedAmountsMixins.js +50 -139
  62. package/lib/pools/mixins/depositMixins.d.ts +1 -1
  63. package/lib/pools/mixins/depositMixins.js +144 -417
  64. package/lib/pools/mixins/depositWrappedMixins.d.ts +1 -1
  65. package/lib/pools/mixins/depositWrappedMixins.js +72 -227
  66. package/lib/pools/mixins/poolBalancesMixin.d.ts +1 -1
  67. package/lib/pools/mixins/poolBalancesMixin.js +25 -105
  68. package/lib/pools/mixins/swapMixins.d.ts +1 -1
  69. package/lib/pools/mixins/swapMixins.js +127 -353
  70. package/lib/pools/mixins/swapWrappedMixins.d.ts +1 -1
  71. package/lib/pools/mixins/swapWrappedMixins.js +90 -276
  72. package/lib/pools/mixins/withdrawExpectedMixins.d.ts +1 -1
  73. package/lib/pools/mixins/withdrawExpectedMixins.js +26 -110
  74. package/lib/pools/mixins/withdrawImbalanceMixins.d.ts +1 -1
  75. package/lib/pools/mixins/withdrawImbalanceMixins.js +99 -321
  76. package/lib/pools/mixins/withdrawImbalanceWrappedMixins.d.ts +1 -1
  77. package/lib/pools/mixins/withdrawImbalanceWrappedMixins.js +53 -192
  78. package/lib/pools/mixins/withdrawMixins.d.ts +1 -1
  79. package/lib/pools/mixins/withdrawMixins.js +123 -390
  80. package/lib/pools/mixins/withdrawOneCoinExpectedMixins.d.ts +1 -1
  81. package/lib/pools/mixins/withdrawOneCoinExpectedMixins.js +17 -92
  82. package/lib/pools/mixins/withdrawOneCoinMixins.d.ts +1 -1
  83. package/lib/pools/mixins/withdrawOneCoinMixins.js +124 -390
  84. package/lib/pools/mixins/withdrawOneCoinWrappedExpectedMixins.d.ts +1 -1
  85. package/lib/pools/mixins/withdrawOneCoinWrappedExpectedMixins.js +9 -66
  86. package/lib/pools/mixins/withdrawOneCoinWrappedMixins.d.ts +1 -1
  87. package/lib/pools/mixins/withdrawOneCoinWrappedMixins.js +55 -190
  88. package/lib/pools/mixins/withdrawWrappedMixins.d.ts +1 -1
  89. package/lib/pools/mixins/withdrawWrappedMixins.js +52 -191
  90. package/lib/pools/poolConstructor.d.ts +1 -1
  91. package/lib/pools/poolConstructor.js +77 -101
  92. package/lib/pools/utils.js +298 -500
  93. package/lib/router.d.ts +2 -2
  94. package/lib/router.js +390 -653
  95. package/lib/utils.d.ts +9 -9
  96. package/lib/utils.js +377 -731
  97. package/package.json +8 -8
package/lib/router.js CHANGED
@@ -1,74 +1,12 @@
1
- "use strict";
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
- return new (P || (P = Promise))(function (resolve, reject) {
16
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
- step((generator = generator.apply(thisArg, _arguments || [])).next());
20
- });
21
- };
22
- var __generator = (this && this.__generator) || function (thisArg, body) {
23
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
- function verb(n) { return function (v) { return step([n, v]); }; }
26
- function step(op) {
27
- if (f) throw new TypeError("Generator is already executing.");
28
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
- if (y = 0, t) op = [op[0] & 2, t.value];
31
- switch (op[0]) {
32
- case 0: case 1: t = op; break;
33
- case 4: _.label++; return { value: op[1], done: false };
34
- case 5: _.label++; y = op[1]; op = [0]; continue;
35
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
- default:
37
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
- if (t[2]) _.ops.pop();
42
- _.trys.pop(); continue;
43
- }
44
- op = body.call(thisArg, _);
45
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
- }
48
- };
49
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
50
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
51
- if (ar || !(i in from)) {
52
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
53
- ar[i] = from[i];
54
- }
55
- }
56
- return to.concat(ar || Array.prototype.slice.call(from));
57
- };
58
- var __importDefault = (this && this.__importDefault) || function (mod) {
59
- return (mod && mod.__esModule) ? mod : { "default": mod };
60
- };
61
- Object.defineProperty(exports, "__esModule", { value: true });
62
- exports.getSwappedAmount = exports.swap = exports.swapEstimateGas = exports.swapApprove = exports.swapApproveEstimateGas = exports.swapIsApproved = exports.swapPriceImpact = exports.swapExpected = exports.getBestRouteAndOutput = void 0;
63
- var axios_1 = __importDefault(require("axios"));
64
- var memoizee_1 = __importDefault(require("memoizee"));
65
- var ethers_1 = require("ethers");
66
- var curve_1 = require("./curve");
67
- var utils_1 = require("./utils");
68
- var pools_1 = require("./pools");
69
- var utils_2 = require("./pools/utils");
70
- var getNewRoute = function (routeTvl, poolId, poolAddress, inputCoinAddress, outputCoinAddress, i, j, swapType, swapAddress, tvl) {
71
- var routePoolIds = routeTvl.route.map(function (s) { return s.poolId; });
1
+ import axios from "axios";
2
+ import memoize from "memoizee";
3
+ import { ethers } from "ethers";
4
+ import { curve } from "./curve.js";
5
+ 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
+ import { getPool } from "./pools/index.js";
7
+ 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);
72
10
  // Steps <= 4
73
11
  if (routePoolIds.length >= 4)
74
12
  return { route: [], minTvl: Infinity, totalTvl: 0 };
@@ -76,635 +14,434 @@ var getNewRoute = function (routeTvl, poolId, poolAddress, inputCoinAddress, out
76
14
  if (routePoolIds.includes(poolId))
77
15
  return { route: [], minTvl: Infinity, totalTvl: 0 };
78
16
  return {
79
- route: __spreadArray(__spreadArray([], routeTvl.route, true), [{ poolId: poolId, poolAddress: poolAddress, inputCoinAddress: inputCoinAddress, outputCoinAddress: outputCoinAddress, i: i, j: j, swapType: swapType, swapAddress: swapAddress }], false),
17
+ route: [...routeTvl.route, { poolId, poolAddress, inputCoinAddress, outputCoinAddress, i, j, swapType, swapAddress }],
80
18
  minTvl: Math.min(tvl, routeTvl.minTvl),
81
19
  totalTvl: routeTvl.totalTvl + tvl,
82
20
  };
83
21
  };
84
22
  // TODO REMOVE IT!!!
85
- var filterMaticFactory83Route = function (routes) {
86
- return routes.filter(function (r) {
87
- for (var _i = 0, _a = r.route; _i < _a.length; _i++) {
88
- var step = _a[_i];
89
- if (step.poolId === "factory-crypto-83" && step.inputCoinAddress === curve_1.curve.constants.NATIVE_TOKEN.address)
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)
90
27
  return false;
91
28
  }
92
29
  return true;
93
30
  });
94
31
  };
95
32
  // TODO REMOVE IT!!!
96
- var filterAvax = function (routes) {
97
- return routes.filter(function (r) {
98
- for (var _i = 0, _a = r.route; _i < _a.length; _i++) {
99
- var step = _a[_i];
33
+ const filterAvax = (routes) => {
34
+ return routes.filter((r) => {
35
+ for (const step of r.route) {
100
36
  if (step.poolId == 'avaxcrypto' && step.swapType == 4 && (step.i === 3 || step.j === 3))
101
37
  return false;
102
38
  }
103
39
  return true;
104
40
  });
105
41
  };
106
- var MAX_ROUTES_FOR_ONE_COIN = 3;
107
- var filterRoutes = function (routes, inputCoinAddress, sortFn) {
42
+ const MAX_ROUTES_FOR_ONE_COIN = 3;
43
+ const filterRoutes = (routes, inputCoinAddress, sortFn) => {
108
44
  // TODO REMOVE IT!!!
109
- if (curve_1.curve.chainId === 137)
45
+ if (curve.chainId === 137)
110
46
  routes = filterMaticFactory83Route(routes);
111
- if (curve_1.curve.chainId === 43114)
47
+ if (curve.chainId === 43114)
112
48
  routes = filterAvax(routes);
113
49
  return routes
114
- .filter(function (r) { return r.route.length > 0; })
115
- .filter(function (r) { return r.route[0].inputCoinAddress === inputCoinAddress; }) // Truncated routes
116
- .filter(function (r, i, _routes) {
117
- var routesByPoolIds = _routes.map(function (r) { return r.route.map(function (s) { return s.poolId; }).toString(); });
118
- return routesByPoolIds.indexOf(r.route.map(function (s) { return s.poolId; }).toString()) === i;
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;
119
55
  }) // Route duplications
120
56
  .sort(sortFn).slice(0, MAX_ROUTES_FOR_ONE_COIN);
121
57
  };
122
- var sortByTvl = function (a, b) { return b.minTvl - a.minTvl || b.totalTvl - a.totalTvl || a.route.length - b.route.length; };
123
- var sortByLength = function (a, b) { return a.route.length - b.route.length || b.minTvl - a.minTvl || b.totalTvl - a.totalTvl; };
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;
124
60
  // Inspired by Dijkstra's algorithm
125
- var _findAllRoutes = function (inputCoinAddress, outputCoinAddress) { return __awaiter(void 0, void 0, void 0, function () {
126
- var ALL_POOLS, amplificationCoefficientDict, curCoins, nextCoins, routesByTvl, routesByLength, step, _loop_1, _i, curCoins_1, inCoin, routes;
127
- var _a, _b;
128
- var _c, _d, _e, _f, _h, _j, _k, _l, _m, _o, _p, _q, _r;
129
- return __generator(this, function (_s) {
130
- switch (_s.label) {
131
- case 0:
132
- inputCoinAddress = inputCoinAddress.toLowerCase();
133
- outputCoinAddress = outputCoinAddress.toLowerCase();
134
- 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));
135
- return [4 /*yield*/, (0, utils_2._getAmplificationCoefficientsFromApi)()];
136
- case 1:
137
- amplificationCoefficientDict = _s.sent();
138
- curCoins = [inputCoinAddress];
139
- nextCoins = new Set();
140
- routesByTvl = (_a = {},
141
- _a[inputCoinAddress] = [{ route: [], minTvl: Infinity, totalTvl: 0 }],
142
- _a);
143
- routesByLength = (_b = {},
144
- _b[inputCoinAddress] = [{ route: [], minTvl: Infinity, totalTvl: 0 }],
145
- _b);
146
- step = 0;
147
- _s.label = 2;
148
- case 2:
149
- if (!(step < 4)) return [3 /*break*/, 8];
150
- _loop_1 = function (inCoin) {
151
- var outCoin_1, newRoutesByTvl, newRoutesByLength, _loop_2, _t, ALL_POOLS_1, _u, poolId, poolData;
152
- return __generator(this, function (_v) {
153
- switch (_v.label) {
154
- case 0:
155
- if (curve_1.curve.chainId !== 42220 && [curve_1.curve.constants.NATIVE_TOKEN.address, curve_1.curve.constants.NATIVE_TOKEN.wrappedAddress].includes(inCoin)) { // Exclude Celo
156
- outCoin_1 = inCoin === curve_1.curve.constants.NATIVE_TOKEN.address ? curve_1.curve.constants.NATIVE_TOKEN.wrappedAddress : curve_1.curve.constants.NATIVE_TOKEN.address;
157
- newRoutesByTvl = routesByTvl[inCoin].map(function (route) { return getNewRoute(route, "wrapper", curve_1.curve.constants.NATIVE_TOKEN.wrappedAddress, inCoin, outCoin_1, 0, 0, 15, ethers_1.ethers.constants.AddressZero, Infinity); });
158
- newRoutesByLength = routesByLength[inCoin].map(function (route) { return getNewRoute(route, "wrapper", curve_1.curve.constants.NATIVE_TOKEN.wrappedAddress, inCoin, outCoin_1, 0, 0, 15, ethers_1.ethers.constants.AddressZero, Infinity); });
159
- routesByTvl[outCoin_1] = __spreadArray(__spreadArray([], ((_c = routesByTvl[outCoin_1]) !== null && _c !== void 0 ? _c : []), true), newRoutesByTvl, true);
160
- routesByTvl[outCoin_1] = filterRoutes(routesByTvl[outCoin_1], inputCoinAddress, sortByTvl);
161
- routesByLength[outCoin_1] = __spreadArray(__spreadArray([], ((_d = routesByLength[outCoin_1]) !== null && _d !== void 0 ? _d : []), true), newRoutesByLength, true);
162
- routesByLength[outCoin_1] = filterRoutes(routesByLength[outCoin_1], inputCoinAddress, sortByLength);
163
- nextCoins.add(outCoin_1);
164
- }
165
- _loop_2 = function (poolId, poolData) {
166
- var wrapped_coin_addresses, underlying_coin_addresses, base_pool, meta_coin_addresses, token_address, is_aave_like_lending, tvlMultiplier, inCoinIndexes, tvl, _w, poolAddress, coin_addresses, _loop_3, j, inCoinIndex, swapType_1, newRoutesByTvl, newRoutesByLength, _loop_4, j, _loop_5, j;
167
- return __generator(this, function (_x) {
168
- switch (_x.label) {
169
- case 0:
170
- wrapped_coin_addresses = poolData.wrapped_coin_addresses.map(function (a) { return a.toLowerCase(); });
171
- underlying_coin_addresses = poolData.underlying_coin_addresses.map(function (a) { return a.toLowerCase(); });
172
- base_pool = poolData.is_meta ? curve_1.curve.constants.POOLS_DATA[poolData.base_pool] : null;
173
- meta_coin_addresses = base_pool ? base_pool.underlying_coin_addresses.map(function (a) { return a.toLowerCase(); }) : [];
174
- token_address = poolData.token_address.toLowerCase();
175
- is_aave_like_lending = poolData.is_lending && wrapped_coin_addresses.length === 3 && !poolData.deposit_address;
176
- tvlMultiplier = poolData.is_crypto ? 1 : ((_e = amplificationCoefficientDict[poolData.swap_address]) !== null && _e !== void 0 ? _e : 1);
177
- inCoinIndexes = {
178
- wrapped_coin: wrapped_coin_addresses.indexOf(inCoin),
179
- underlying_coin: underlying_coin_addresses.indexOf(inCoin),
180
- meta_coin: meta_coin_addresses ? meta_coin_addresses.indexOf(inCoin) : -1,
181
- };
182
- // Skip pools which don't contain inCoin
183
- if (inCoinIndexes.wrapped_coin === -1 && inCoinIndexes.underlying_coin === -1 && inCoinIndexes.meta_coin === -1 && inCoin !== token_address)
184
- return [2 /*return*/, "continue"];
185
- _w = Number;
186
- return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
187
- case 1:
188
- tvl = _w.apply(void 0, [_x.sent()]) * tvlMultiplier;
189
- // Skip empty pools
190
- if (tvl === 0)
191
- return [2 /*return*/, "continue"];
192
- poolAddress = poolData.is_fake ? poolData.deposit_address : poolData.swap_address;
193
- coin_addresses = (is_aave_like_lending || poolData.is_fake) ? underlying_coin_addresses : wrapped_coin_addresses;
194
- // LP -> wrapped coin (underlying for lending or fake pool) "swaps" (actually remove_liquidity_one_coin)
195
- if (coin_addresses.length < 6 && inCoin === token_address) {
196
- _loop_3 = function (j) {
197
- // Looking for outputCoinAddress only on the final step
198
- if (step === 3 && coin_addresses[j] !== outputCoinAddress)
199
- return "continue";
200
- // Exclude such cases as cvxeth -> tricrypto2 -> tusd -> susd or cvxeth -> tricrypto2 -> susd -> susd
201
- var outputCoinIdx = coin_addresses.indexOf(outputCoinAddress);
202
- if (outputCoinIdx >= 0 && j !== outputCoinIdx)
203
- return "continue";
204
- var swapType = poolData.is_crypto ? 14 : is_aave_like_lending ? 13 : 12;
205
- var newRoutesByTvl = routesByTvl[inCoin].map(function (route) { return getNewRoute(route, poolId, poolAddress, inCoin, coin_addresses[j], 0, j, swapType, ethers_1.ethers.constants.AddressZero, tvl); });
206
- var newRoutesByLength = routesByLength[inCoin].map(function (route) { return getNewRoute(route, poolId, poolAddress, inCoin, coin_addresses[j], 0, j, swapType, ethers_1.ethers.constants.AddressZero, tvl); });
207
- routesByTvl[coin_addresses[j]] = __spreadArray(__spreadArray([], ((_f = routesByTvl[coin_addresses[j]]) !== null && _f !== void 0 ? _f : []), true), newRoutesByTvl, true);
208
- routesByTvl[coin_addresses[j]] = filterRoutes(routesByTvl[coin_addresses[j]], inputCoinAddress, sortByTvl);
209
- routesByLength[coin_addresses[j]] = __spreadArray(__spreadArray([], ((_h = routesByLength[coin_addresses[j]]) !== null && _h !== void 0 ? _h : []), true), newRoutesByLength, true);
210
- routesByLength[coin_addresses[j]] = filterRoutes(routesByLength[coin_addresses[j]], inputCoinAddress, sortByLength);
211
- nextCoins.add(coin_addresses[j]);
212
- };
213
- for (j = 0; j < coin_addresses.length; j++) {
214
- _loop_3(j);
215
- }
216
- }
217
- inCoinIndex = (is_aave_like_lending || poolData.is_fake) ? inCoinIndexes.underlying_coin : inCoinIndexes.wrapped_coin;
218
- if (coin_addresses.length < 6 && inCoinIndex >= 0) {
219
- // Looking for outputCoinAddress only on the final step
220
- if (!(step === 3 && token_address !== outputCoinAddress)) {
221
- swapType_1 = is_aave_like_lending ? 9
222
- : coin_addresses.length === 2 ? 7
223
- : coin_addresses.length === 3 ? 8
224
- : coin_addresses.length === 4 ? 10 : 11;
225
- newRoutesByTvl = routesByTvl[inCoin].map(function (route) { return getNewRoute(route, poolId, poolAddress, inCoin, token_address, coin_addresses.indexOf(inCoin), 0, swapType_1, ethers_1.ethers.constants.AddressZero, tvl); });
226
- newRoutesByLength = routesByLength[inCoin].map(function (route) { return getNewRoute(route, poolId, poolAddress, inCoin, token_address, coin_addresses.indexOf(inCoin), 0, swapType_1, ethers_1.ethers.constants.AddressZero, tvl); });
227
- routesByTvl[token_address] = __spreadArray(__spreadArray([], ((_j = routesByTvl[token_address]) !== null && _j !== void 0 ? _j : []), true), newRoutesByTvl, true);
228
- routesByTvl[token_address] = filterRoutes(routesByTvl[token_address], inputCoinAddress, sortByTvl);
229
- routesByLength[token_address] = __spreadArray(__spreadArray([], ((_k = routesByLength[token_address]) !== null && _k !== void 0 ? _k : []), true), newRoutesByLength, true);
230
- routesByLength[token_address] = filterRoutes(routesByLength[token_address], inputCoinAddress, sortByLength);
231
- nextCoins.add(token_address);
232
- }
233
- }
234
- // Wrapped swaps
235
- if (inCoinIndexes.wrapped_coin >= 0 && !poolData.is_fake) {
236
- _loop_4 = function (j) {
237
- if (j === inCoinIndexes.wrapped_coin)
238
- return "continue";
239
- // Native swaps spend less gas
240
- // TODO uncomment
241
- // if (wrapped_coin_addresses[j] !== outputCoinAddress && wrapped_coin_addresses[j] === curve.constants.NATIVE_TOKEN.wrappedAddress) continue;
242
- // Looking for outputCoinAddress only on the final step
243
- if (step === 3 && wrapped_coin_addresses[j] !== outputCoinAddress)
244
- return "continue";
245
- // Exclude such cases as cvxeth -> tricrypto2 -> tusd -> susd or cvxeth -> tricrypto2 -> susd -> susd
246
- var outputCoinIdx = wrapped_coin_addresses.indexOf(outputCoinAddress);
247
- if (outputCoinIdx >= 0 && j !== outputCoinIdx)
248
- return "continue";
249
- var swapType = poolData.is_crypto ? 3 : 1;
250
- 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); });
251
- 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); });
252
- routesByTvl[wrapped_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_l = routesByTvl[wrapped_coin_addresses[j]]) !== null && _l !== void 0 ? _l : []), true), newRoutesByTvl, true);
253
- routesByTvl[wrapped_coin_addresses[j]] = filterRoutes(routesByTvl[wrapped_coin_addresses[j]], inputCoinAddress, sortByTvl);
254
- routesByLength[wrapped_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_m = routesByLength[wrapped_coin_addresses[j]]) !== null && _m !== void 0 ? _m : []), true), newRoutesByLength, true);
255
- routesByLength[wrapped_coin_addresses[j]] = filterRoutes(routesByLength[wrapped_coin_addresses[j]], inputCoinAddress, sortByLength);
256
- nextCoins.add(wrapped_coin_addresses[j]);
257
- };
258
- for (j = 0; j < wrapped_coin_addresses.length; j++) {
259
- _loop_4(j);
260
- }
261
- }
262
- // Only for underlying swaps
263
- poolAddress = (poolData.is_crypto && poolData.is_meta) || ((base_pool === null || base_pool === void 0 ? void 0 : base_pool.is_lending) && poolData.is_factory) ?
264
- poolData.deposit_address : poolData.swap_address;
265
- if (!(!poolData.is_plain && inCoinIndexes.underlying_coin >= 0)) return [3 /*break*/, 5];
266
- _loop_5 = function (j) {
267
- var outputCoinIdx, tvl_1, _y, hasEth, swapType, newRoutesByTvl, newRoutesByLength;
268
- return __generator(this, function (_z) {
269
- switch (_z.label) {
270
- case 0:
271
- if (j === inCoinIndexes.underlying_coin)
272
- return [2 /*return*/, "continue"];
273
- // Don't swap metacoins since they can be swapped directly in base pool
274
- if (inCoinIndexes.meta_coin >= 0 && meta_coin_addresses.includes(underlying_coin_addresses[j]))
275
- return [2 /*return*/, "continue"];
276
- // Looking for outputCoinAddress only on the final step
277
- if (step === 3 && underlying_coin_addresses[j] !== outputCoinAddress)
278
- return [2 /*return*/, "continue"];
279
- outputCoinIdx = underlying_coin_addresses.indexOf(outputCoinAddress);
280
- if (outputCoinIdx >= 0 && j !== outputCoinIdx)
281
- return [2 /*return*/, "continue"];
282
- _y = Number;
283
- return [4 /*yield*/, ((0, pools_1.getPool)(poolId)).stats.totalLiquidity()];
284
- case 1:
285
- tvl_1 = _y.apply(void 0, [_z.sent()]);
286
- if (tvl_1 === 0)
287
- return [2 /*return*/, "continue"];
288
- hasEth = (inCoin === curve_1.curve.constants.NATIVE_TOKEN.address || underlying_coin_addresses[j] === curve_1.curve.constants.NATIVE_TOKEN.address);
289
- swapType = (poolData.is_crypto && poolData.is_meta && poolData.is_factory) ? 6
290
- : ((base_pool === null || base_pool === void 0 ? void 0 : base_pool.is_lending) && poolData.is_factory) ? 5
291
- : hasEth && poolId !== 'avaxcrypto' ? 3
292
- : poolData.is_crypto ? 4
293
- : 2;
294
- 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); });
295
- 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); });
296
- routesByTvl[underlying_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_o = routesByTvl[underlying_coin_addresses[j]]) !== null && _o !== void 0 ? _o : []), true), newRoutesByTvl, true);
297
- routesByTvl[underlying_coin_addresses[j]] = filterRoutes(routesByTvl[underlying_coin_addresses[j]], inputCoinAddress, sortByTvl);
298
- routesByLength[underlying_coin_addresses[j]] = __spreadArray(__spreadArray([], ((_p = routesByLength[underlying_coin_addresses[j]]) !== null && _p !== void 0 ? _p : []), true), newRoutesByLength, true);
299
- routesByLength[underlying_coin_addresses[j]] = filterRoutes(routesByLength[underlying_coin_addresses[j]], inputCoinAddress, sortByLength);
300
- nextCoins.add(underlying_coin_addresses[j]);
301
- return [2 /*return*/];
302
- }
303
- });
304
- };
305
- j = 0;
306
- _x.label = 2;
307
- case 2:
308
- if (!(j < underlying_coin_addresses.length)) return [3 /*break*/, 5];
309
- return [5 /*yield**/, _loop_5(j)];
310
- case 3:
311
- _x.sent();
312
- _x.label = 4;
313
- case 4:
314
- j++;
315
- return [3 /*break*/, 2];
316
- case 5: return [2 /*return*/];
317
- }
318
- });
319
- };
320
- _t = 0, ALL_POOLS_1 = ALL_POOLS;
321
- _v.label = 1;
322
- case 1:
323
- if (!(_t < ALL_POOLS_1.length)) return [3 /*break*/, 4];
324
- _u = ALL_POOLS_1[_t], poolId = _u[0], poolData = _u[1];
325
- return [5 /*yield**/, _loop_2(poolId, poolData)];
326
- case 2:
327
- _v.sent();
328
- _v.label = 3;
329
- case 3:
330
- _t++;
331
- return [3 /*break*/, 1];
332
- case 4: return [2 /*return*/];
333
- }
334
- });
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,
335
106
  };
336
- _i = 0, curCoins_1 = curCoins;
337
- _s.label = 3;
338
- case 3:
339
- if (!(_i < curCoins_1.length)) return [3 /*break*/, 6];
340
- inCoin = curCoins_1[_i];
341
- return [5 /*yield**/, _loop_1(inCoin)];
342
- case 4:
343
- _s.sent();
344
- _s.label = 5;
345
- case 5:
346
- _i++;
347
- return [3 /*break*/, 3];
348
- case 6:
349
- curCoins = Array.from(nextCoins);
350
- nextCoins = new Set();
351
- _s.label = 7;
352
- case 7:
353
- step++;
354
- return [3 /*break*/, 2];
355
- case 8:
356
- routes = __spreadArray(__spreadArray([], ((_q = routesByTvl[outputCoinAddress]) !== null && _q !== void 0 ? _q : []), true), ((_r = routesByLength[outputCoinAddress]) !== null && _r !== void 0 ? _r : []), true);
357
- return [2 /*return*/, routes.map(function (r) { return r.route; })];
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
+ }
358
217
  }
359
- });
360
- }); };
361
- var _getRouteKey = function (route, inputCoinAddress, outputCoinAddress) {
362
- var sortedCoins = [inputCoinAddress, outputCoinAddress].sort();
363
- var key = "".concat(sortedCoins[0], "-->");
364
- for (var _i = 0, route_1 = route; _i < route_1.length; _i++) {
365
- var routeStep = route_1[_i];
366
- key += "".concat(routeStep.poolId, "-->");
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
+ const _getRouteKey = (route, inputCoinAddress, outputCoinAddress) => {
225
+ const sortedCoins = [inputCoinAddress, outputCoinAddress].sort();
226
+ let key = `${sortedCoins[0]}-->`;
227
+ for (const routeStep of route) {
228
+ key += `${routeStep.poolId}-->`;
367
229
  }
368
230
  key += sortedCoins[1];
369
231
  return key;
370
232
  };
371
- var _getExchangeMultipleArgs = function (route) {
372
- var _route = [];
233
+ const _getExchangeMultipleArgs = (route) => {
234
+ let _route = [];
373
235
  if (route.length > 0)
374
236
  _route.push(route[0].inputCoinAddress);
375
- var _swapParams = [];
376
- var _factorySwapAddresses = [];
377
- for (var _i = 0, route_2 = route; _i < route_2.length; _i++) {
378
- var routeStep = route_2[_i];
237
+ let _swapParams = [];
238
+ let _factorySwapAddresses = [];
239
+ for (const routeStep of route) {
379
240
  _route.push(routeStep.poolAddress, routeStep.outputCoinAddress);
380
241
  _swapParams.push([routeStep.i, routeStep.j, routeStep.swapType]);
381
242
  _factorySwapAddresses.push(routeStep.swapAddress);
382
243
  }
383
- _route = _route.concat(Array(9 - _route.length).fill(ethers_1.ethers.constants.AddressZero));
244
+ _route = _route.concat(Array(9 - _route.length).fill(curve.constants.ZERO_ADDRESS));
384
245
  _swapParams = _swapParams.concat(Array(4 - _swapParams.length).fill([0, 0, 0]));
385
- _factorySwapAddresses = _factorySwapAddresses.concat(Array(4 - _factorySwapAddresses.length).fill(ethers_1.ethers.constants.AddressZero));
386
- return { _route: _route, _swapParams: _swapParams, _factorySwapAddresses: _factorySwapAddresses };
246
+ _factorySwapAddresses = _factorySwapAddresses.concat(Array(4 - _factorySwapAddresses.length).fill(curve.constants.ZERO_ADDRESS));
247
+ return { _route, _swapParams, _factorySwapAddresses };
387
248
  };
388
- var _estimatedGasForDifferentRoutesCache = {};
389
- var _estimateGasForDifferentRoutes = function (routes, inputCoinAddress, outputCoinAddress, _amount) { return __awaiter(void 0, void 0, void 0, function () {
390
- var contract, gasPromises, value, _i, routes_1, route, routeKey, gasPromise, _a, _route, _swapParams, _factorySwapAddresses, _gasAmounts_1, err_1;
391
- var _b;
392
- return __generator(this, function (_c) {
393
- switch (_c.label) {
394
- case 0:
395
- inputCoinAddress = inputCoinAddress.toLowerCase();
396
- outputCoinAddress = outputCoinAddress.toLowerCase();
397
- contract = curve_1.curve.contracts[curve_1.curve.constants.ALIASES.registry_exchange].contract;
398
- gasPromises = [];
399
- value = (0, utils_1.isEth)(inputCoinAddress) ? _amount : ethers_1.ethers.BigNumber.from(0);
400
- for (_i = 0, routes_1 = routes; _i < routes_1.length; _i++) {
401
- route = routes_1[_i];
402
- routeKey = _getRouteKey(route, inputCoinAddress, outputCoinAddress);
403
- gasPromise = void 0;
404
- _a = _getExchangeMultipleArgs(route), _route = _a._route, _swapParams = _a._swapParams, _factorySwapAddresses = _a._factorySwapAddresses;
405
- if ((((_b = _estimatedGasForDifferentRoutesCache[routeKey]) === null || _b === void 0 ? void 0 : _b.time) || 0) + 3600000 < Date.now()) {
406
- gasPromise = contract.estimateGas.exchange_multiple(_route, _swapParams, _amount, 0, _factorySwapAddresses, __assign(__assign({}, curve_1.curve.constantOptions), { value: value }));
407
- }
408
- else {
409
- gasPromise = Promise.resolve(_estimatedGasForDifferentRoutesCache[routeKey].gas);
410
- }
411
- gasPromises.push(gasPromise);
412
- }
413
- _c.label = 1;
414
- case 1:
415
- _c.trys.push([1, 3, , 4]);
416
- return [4 /*yield*/, Promise.all(gasPromises)];
417
- case 2:
418
- _gasAmounts_1 = _c.sent();
419
- routes.forEach(function (route, i) {
420
- var routeKey = _getRouteKey(route, inputCoinAddress, outputCoinAddress);
421
- _estimatedGasForDifferentRoutesCache[routeKey] = { 'gas': _gasAmounts_1[i], 'time': Date.now() };
422
- });
423
- return [2 /*return*/, _gasAmounts_1.map(function (_g) { return Number(ethers_1.ethers.utils.formatUnits(_g, 0)); })];
424
- case 3:
425
- err_1 = _c.sent();
426
- return [2 /*return*/, routes.map(function () { return 0; })];
427
- case 4: return [2 /*return*/];
249
+ const _estimatedGasForDifferentRoutesCache = {};
250
+ const _estimateGasForDifferentRoutes = async (routes, inputCoinAddress, outputCoinAddress, _amount) => {
251
+ inputCoinAddress = inputCoinAddress.toLowerCase();
252
+ outputCoinAddress = outputCoinAddress.toLowerCase();
253
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
254
+ const gasPromises = [];
255
+ const value = isEth(inputCoinAddress) ? _amount : 0n;
256
+ for (const route of routes) {
257
+ const routeKey = _getRouteKey(route, inputCoinAddress, outputCoinAddress);
258
+ let gasPromise;
259
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(route);
260
+ if ((_estimatedGasForDifferentRoutesCache[routeKey]?.time || 0) + 3600000 < Date.now()) {
261
+ gasPromise = contract.exchange_multiple.estimateGas(_route, _swapParams, _amount, 0, _factorySwapAddresses, { ...curve.constantOptions, value });
428
262
  }
429
- });
430
- }); };
431
- var _getBestRoute = (0, memoizee_1.default)(function (inputCoinAddress, outputCoinAddress, amount) { return __awaiter(void 0, void 0, void 0, function () {
432
- var _a, inputCoinDecimals, outputCoinDecimals, _amount, routesRaw, routes, calls, multicallContract, _i, routesRaw_1, r, _b, _route, _swapParams, _factorySwapAddresses, _outputAmounts, i, err_2, promises, contract, _c, routesRaw_2, r, _d, _route, _swapParams, _factorySwapAddresses, res, i, _e, gasAmounts, outputCoinUsdRate, gasData, ethUsdRate, gasPrice, expectedAmounts, expectedAmountsUsd, txCostsUsd;
433
- return __generator(this, function (_f) {
434
- switch (_f.label) {
435
- case 0:
436
- _a = (0, utils_1._getCoinDecimals)(inputCoinAddress, outputCoinAddress), inputCoinDecimals = _a[0], outputCoinDecimals = _a[1];
437
- _amount = (0, utils_1.parseUnits)(amount, inputCoinDecimals);
438
- if (_amount.eq(0))
439
- return [2 /*return*/, []];
440
- return [4 /*yield*/, _findAllRoutes(inputCoinAddress, outputCoinAddress)];
441
- case 1:
442
- routesRaw = (_f.sent()).map(function (route) { return ({ route: route, _output: ethers_1.ethers.BigNumber.from(0), outputUsd: 0, txCostUsd: 0 }); });
443
- routes = [];
444
- _f.label = 2;
445
- case 2:
446
- _f.trys.push([2, 4, , 6]);
447
- calls = [];
448
- multicallContract = curve_1.curve.contracts[curve_1.curve.constants.ALIASES.registry_exchange].multicallContract;
449
- for (_i = 0, routesRaw_1 = routesRaw; _i < routesRaw_1.length; _i++) {
450
- r = routesRaw_1[_i];
451
- _b = _getExchangeMultipleArgs(r.route), _route = _b._route, _swapParams = _b._swapParams, _factorySwapAddresses = _b._factorySwapAddresses;
452
- calls.push(multicallContract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses));
453
- }
454
- return [4 /*yield*/, curve_1.curve.multicallProvider.all(calls)];
455
- case 3:
456
- _outputAmounts = _f.sent();
457
- for (i = 0; i < _outputAmounts.length; i++) {
458
- routesRaw[i]._output = _outputAmounts[i];
459
- routes.push(routesRaw[i]);
460
- }
461
- return [3 /*break*/, 6];
462
- case 4:
463
- err_2 = _f.sent();
464
- promises = [];
465
- contract = curve_1.curve.contracts[curve_1.curve.constants.ALIASES.registry_exchange].contract;
466
- for (_c = 0, routesRaw_2 = routesRaw; _c < routesRaw_2.length; _c++) {
467
- r = routesRaw_2[_c];
468
- _d = _getExchangeMultipleArgs(r.route), _route = _d._route, _swapParams = _d._swapParams, _factorySwapAddresses = _d._factorySwapAddresses;
469
- promises.push(contract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses, curve_1.curve.constantOptions));
470
- }
471
- return [4 /*yield*/, Promise.allSettled(promises)];
472
- case 5:
473
- res = _f.sent();
474
- for (i = 0; i < res.length; i++) {
475
- if (res[i].status === 'rejected') {
476
- console.log("Route ".concat((routesRaw[i].route.map(function (s) { return s.poolId; })).join(" --> "), " is unavailable"));
477
- continue;
478
- }
479
- routesRaw[i]._output = res[i].value;
480
- routes.push(routesRaw[i]);
481
- }
482
- return [3 /*break*/, 6];
483
- case 6:
484
- if (routes.length === 0)
485
- return [2 /*return*/, []];
486
- if (routes.length === 1)
487
- return [2 /*return*/, routes[0].route];
488
- return [4 /*yield*/, Promise.all([
489
- _estimateGasForDifferentRoutes(routes.map(function (r) { return r.route; }), inputCoinAddress, outputCoinAddress, _amount),
490
- (0, utils_1._getUsdRate)(outputCoinAddress),
491
- axios_1.default.get("https://api.curve.fi/api/getGas"),
492
- (0, utils_1._getUsdRate)(utils_1.ETH_ADDRESS),
493
- ])];
494
- case 7:
495
- _e = _f.sent(), gasAmounts = _e[0], outputCoinUsdRate = _e[1], gasData = _e[2], ethUsdRate = _e[3];
496
- gasPrice = gasData.data.data.gas.standard;
497
- expectedAmounts = (routes).map(function (route) { return Number(ethers_1.ethers.utils.formatUnits(route._output, outputCoinDecimals)); });
498
- expectedAmountsUsd = expectedAmounts.map(function (a) { return a * outputCoinUsdRate; });
499
- txCostsUsd = gasAmounts.map(function (a) { return ethUsdRate * a * gasPrice / 1e18; });
500
- routes.forEach(function (route, i) {
501
- route.outputUsd = expectedAmountsUsd[i];
502
- route.txCostUsd = txCostsUsd[i];
503
- });
504
- return [2 /*return*/, routes.reduce(function (route1, route2) {
505
- var diff = (route1.outputUsd - route1.txCostUsd) - (route2.outputUsd - route2.txCostUsd);
506
- if (diff > 0)
507
- return route1;
508
- if (diff === 0 && route1.route.length < route2.route.length)
509
- return route1;
510
- return route2;
511
- }).route];
263
+ else {
264
+ gasPromise = Promise.resolve(_estimatedGasForDifferentRoutesCache[routeKey].gas);
265
+ }
266
+ gasPromises.push(gasPromise);
267
+ }
268
+ try {
269
+ const _gasAmounts = await Promise.all(gasPromises);
270
+ routes.forEach((route, i) => {
271
+ const routeKey = _getRouteKey(route, inputCoinAddress, outputCoinAddress);
272
+ _estimatedGasForDifferentRoutesCache[routeKey] = { 'gas': _gasAmounts[i], 'time': Date.now() };
273
+ });
274
+ return _gasAmounts.map((_g) => Number(curve.formatUnits(_g, 0)));
275
+ }
276
+ catch (err) { // No allowance
277
+ return routes.map(() => 0);
278
+ }
279
+ };
280
+ const _getBestRoute = memoize(async (inputCoinAddress, outputCoinAddress, amount) => {
281
+ const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
282
+ const _amount = parseUnits(amount, inputCoinDecimals);
283
+ if (_amount === 0n)
284
+ return [];
285
+ const routesRaw = (await _findAllRoutes(inputCoinAddress, outputCoinAddress)).map((route) => ({ route, _output: 0n, outputUsd: 0, txCostUsd: 0 }));
286
+ const routes = [];
287
+ try {
288
+ const calls = [];
289
+ const multicallContract = curve.contracts[curve.constants.ALIASES.registry_exchange].multicallContract;
290
+ for (const r of routesRaw) {
291
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(r.route);
292
+ calls.push(multicallContract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses));
293
+ }
294
+ const _outputAmounts = await curve.multicallProvider.all(calls);
295
+ for (let i = 0; i < _outputAmounts.length; i++) {
296
+ routesRaw[i]._output = _outputAmounts[i];
297
+ routes.push(routesRaw[i]);
298
+ }
299
+ }
300
+ catch (err) {
301
+ const promises = [];
302
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
303
+ for (const r of routesRaw) {
304
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(r.route);
305
+ promises.push(contract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses, curve.constantOptions));
306
+ }
307
+ // @ts-ignore
308
+ const res = await Promise.allSettled(promises);
309
+ for (let i = 0; i < res.length; i++) {
310
+ if (res[i].status === 'rejected') {
311
+ console.log(`Route ${(routesRaw[i].route.map((s) => s.poolId)).join(" --> ")} is unavailable`);
312
+ continue;
313
+ }
314
+ routesRaw[i]._output = res[i].value;
315
+ routes.push(routesRaw[i]);
512
316
  }
317
+ }
318
+ if (routes.length === 0)
319
+ return [];
320
+ if (routes.length === 1)
321
+ return routes[0].route;
322
+ const [gasAmounts, outputCoinUsdRate, gasData, ethUsdRate] = await Promise.all([
323
+ _estimateGasForDifferentRoutes(routes.map((r) => r.route), inputCoinAddress, outputCoinAddress, _amount),
324
+ _getUsdRate(outputCoinAddress),
325
+ axios.get("https://api.curve.fi/api/getGas"),
326
+ _getUsdRate(ETH_ADDRESS),
327
+ ]);
328
+ const gasPrice = gasData.data.data.gas.standard;
329
+ const expectedAmounts = (routes).map((route) => Number(curve.formatUnits(route._output, outputCoinDecimals)));
330
+ const expectedAmountsUsd = expectedAmounts.map((a) => a * outputCoinUsdRate);
331
+ const txCostsUsd = gasAmounts.map((a) => ethUsdRate * a * gasPrice / 1e18);
332
+ routes.forEach((route, i) => {
333
+ route.outputUsd = expectedAmountsUsd[i];
334
+ route.txCostUsd = txCostsUsd[i];
513
335
  });
514
- }); }, {
336
+ return routes.reduce((route1, route2) => {
337
+ const diff = (route1.outputUsd - route1.txCostUsd) - (route2.outputUsd - route2.txCostUsd);
338
+ if (diff > 0)
339
+ return route1;
340
+ if (diff === 0 && route1.route.length < route2.route.length)
341
+ return route1;
342
+ return route2;
343
+ }).route;
344
+ }, {
515
345
  promise: true,
516
346
  maxAge: 5 * 60 * 1000, // 5m
517
347
  });
518
- var _getOutputForRoute = (0, memoizee_1.default)(function (route, _amount) { return __awaiter(void 0, void 0, void 0, function () {
519
- var contract, _a, _route, _swapParams, _factorySwapAddresses;
520
- return __generator(this, function (_b) {
521
- switch (_b.label) {
522
- case 0:
523
- contract = curve_1.curve.contracts[curve_1.curve.constants.ALIASES.registry_exchange].contract;
524
- _a = _getExchangeMultipleArgs(route), _route = _a._route, _swapParams = _a._swapParams, _factorySwapAddresses = _a._factorySwapAddresses;
525
- return [4 /*yield*/, contract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses, curve_1.curve.constantOptions)];
526
- case 1: return [2 /*return*/, _b.sent()];
527
- }
528
- });
529
- }); }, {
348
+ const _getOutputForRoute = memoize(async (route, _amount) => {
349
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
350
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(route);
351
+ return await contract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses, curve.constantOptions);
352
+ }, {
530
353
  promise: true,
531
354
  maxAge: 15 * 1000, // 15s
532
355
  });
533
- var getBestRouteAndOutput = function (inputCoin, outputCoin, amount) { return __awaiter(void 0, void 0, void 0, function () {
534
- var _a, inputCoinAddress, outputCoinAddress, _b, inputCoinDecimals, outputCoinDecimals, route, _output;
535
- return __generator(this, function (_c) {
536
- switch (_c.label) {
537
- case 0:
538
- _a = (0, utils_1._getCoinAddresses)(inputCoin, outputCoin), inputCoinAddress = _a[0], outputCoinAddress = _a[1];
539
- _b = (0, utils_1._getCoinDecimals)(inputCoinAddress, outputCoinAddress), inputCoinDecimals = _b[0], outputCoinDecimals = _b[1];
540
- return [4 /*yield*/, _getBestRoute(inputCoinAddress, outputCoinAddress, amount)];
541
- case 1:
542
- route = _c.sent();
543
- if (route.length === 0)
544
- return [2 /*return*/, { route: route, output: '0.0' }];
545
- return [4 /*yield*/, _getOutputForRoute(route, (0, utils_1.parseUnits)(amount, inputCoinDecimals))];
546
- case 2:
547
- _output = _c.sent();
548
- return [2 /*return*/, { route: route, output: ethers_1.ethers.utils.formatUnits(_output, outputCoinDecimals) }];
549
- }
550
- });
551
- }); };
552
- exports.getBestRouteAndOutput = getBestRouteAndOutput;
553
- var swapExpected = function (inputCoin, outputCoin, amount) { return __awaiter(void 0, void 0, void 0, function () {
554
- return __generator(this, function (_a) {
555
- switch (_a.label) {
556
- case 0: return [4 /*yield*/, (0, exports.getBestRouteAndOutput)(inputCoin, outputCoin, amount)];
557
- case 1: return [2 /*return*/, (_a.sent())['output']];
558
- }
559
- });
560
- }); };
561
- exports.swapExpected = swapExpected;
562
- var swapPriceImpact = function (inputCoin, outputCoin, amount) { return __awaiter(void 0, void 0, void 0, function () {
563
- var _a, inputCoinAddress, outputCoinAddress, _b, inputCoinDecimals, outputCoinDecimals, _c, route, output, _amount, _output, smallAmountIntBN, amountIntBN, contract, _smallAmount, _d, _route, _swapParams, _factorySwapAddresses, _smallOutput, e_1, priceImpactBN;
564
- return __generator(this, function (_e) {
565
- switch (_e.label) {
566
- case 0:
567
- _a = (0, utils_1._getCoinAddresses)(inputCoin, outputCoin), inputCoinAddress = _a[0], outputCoinAddress = _a[1];
568
- _b = (0, utils_1._getCoinDecimals)(inputCoinAddress, outputCoinAddress), inputCoinDecimals = _b[0], outputCoinDecimals = _b[1];
569
- return [4 /*yield*/, (0, exports.getBestRouteAndOutput)(inputCoinAddress, outputCoinAddress, amount)];
570
- case 1:
571
- _c = _e.sent(), route = _c.route, output = _c.output;
572
- _amount = (0, utils_1.parseUnits)(amount, inputCoinDecimals);
573
- _output = (0, utils_1.parseUnits)(output, outputCoinDecimals);
574
- smallAmountIntBN = (0, utils_1._get_small_x)(_amount, _output, inputCoinDecimals, outputCoinDecimals);
575
- amountIntBN = (0, utils_1.toBN)(_amount, 0);
576
- if (smallAmountIntBN.gte(amountIntBN))
577
- return [2 /*return*/, 0];
578
- contract = curve_1.curve.contracts[curve_1.curve.constants.ALIASES.registry_exchange].contract;
579
- _smallAmount = (0, utils_1.fromBN)(smallAmountIntBN.div(Math.pow(10, inputCoinDecimals)), inputCoinDecimals);
580
- _d = _getExchangeMultipleArgs(route), _route = _d._route, _swapParams = _d._swapParams, _factorySwapAddresses = _d._factorySwapAddresses;
581
- _e.label = 2;
582
- case 2:
583
- _e.trys.push([2, 4, , 6]);
584
- return [4 /*yield*/, contract.get_exchange_multiple_amount(_route, _swapParams, _smallAmount, _factorySwapAddresses, curve_1.curve.constantOptions)];
585
- case 3:
586
- _smallOutput = _e.sent();
587
- return [3 /*break*/, 6];
588
- case 4:
589
- e_1 = _e.sent();
590
- _smallAmount = ethers_1.ethers.utils.parseUnits("1", inputCoinDecimals); // Dirty hack
591
- return [4 /*yield*/, contract.get_exchange_multiple_amount(_route, _swapParams, _smallAmount, _factorySwapAddresses, curve_1.curve.constantOptions)];
592
- case 5:
593
- _smallOutput = _e.sent();
594
- return [3 /*break*/, 6];
595
- case 6:
596
- priceImpactBN = (0, utils_1._get_price_impact)(_amount, _output, _smallAmount, _smallOutput, inputCoinDecimals, outputCoinDecimals);
597
- return [2 /*return*/, Number((0, utils_1._cutZeros)(priceImpactBN.toFixed(4)))];
598
- }
599
- });
600
- }); };
601
- exports.swapPriceImpact = swapPriceImpact;
602
- var swapIsApproved = function (inputCoin, amount) { return __awaiter(void 0, void 0, void 0, function () {
603
- return __generator(this, function (_a) {
604
- switch (_a.label) {
605
- case 0: return [4 /*yield*/, (0, utils_1.hasAllowance)([inputCoin], [amount], curve_1.curve.signerAddress, curve_1.curve.constants.ALIASES.registry_exchange)];
606
- case 1: return [2 /*return*/, _a.sent()];
607
- }
608
- });
609
- }); };
610
- exports.swapIsApproved = swapIsApproved;
611
- var swapApproveEstimateGas = function (inputCoin, amount) { return __awaiter(void 0, void 0, void 0, function () {
612
- return __generator(this, function (_a) {
613
- switch (_a.label) {
614
- case 0: return [4 /*yield*/, (0, utils_1.ensureAllowanceEstimateGas)([inputCoin], [amount], curve_1.curve.constants.ALIASES.registry_exchange)];
615
- case 1: return [2 /*return*/, _a.sent()];
616
- }
617
- });
618
- }); };
619
- exports.swapApproveEstimateGas = swapApproveEstimateGas;
620
- var swapApprove = function (inputCoin, amount) { return __awaiter(void 0, void 0, void 0, function () {
621
- return __generator(this, function (_a) {
622
- switch (_a.label) {
623
- case 0: return [4 /*yield*/, (0, utils_1.ensureAllowance)([inputCoin], [amount], curve_1.curve.constants.ALIASES.registry_exchange)];
624
- case 1: return [2 /*return*/, _a.sent()];
625
- }
626
- });
627
- }); };
628
- exports.swapApprove = swapApprove;
629
- var swapEstimateGas = function (inputCoin, outputCoin, amount) { return __awaiter(void 0, void 0, void 0, function () {
630
- var _a, inputCoinAddress, outputCoinAddress, inputCoinDecimals, route, _amount, gas;
631
- return __generator(this, function (_b) {
632
- switch (_b.label) {
633
- case 0:
634
- _a = (0, utils_1._getCoinAddresses)(inputCoin, outputCoin), inputCoinAddress = _a[0], outputCoinAddress = _a[1];
635
- inputCoinDecimals = (0, utils_1._getCoinDecimals)(inputCoinAddress, outputCoinAddress)[0];
636
- return [4 /*yield*/, (0, exports.getBestRouteAndOutput)(inputCoinAddress, outputCoinAddress, amount)];
637
- case 1:
638
- route = (_b.sent()).route;
639
- if (route.length === 0)
640
- return [2 /*return*/, 0];
641
- _amount = (0, utils_1.parseUnits)(amount, inputCoinDecimals);
642
- return [4 /*yield*/, _estimateGasForDifferentRoutes([route], inputCoinAddress, outputCoinAddress, _amount)];
643
- case 2:
644
- gas = (_b.sent())[0];
645
- return [2 /*return*/, gas];
646
- }
647
- });
648
- }); };
649
- exports.swapEstimateGas = swapEstimateGas;
650
- var swap = function (inputCoin, outputCoin, amount, slippage) {
651
- if (slippage === void 0) { slippage = 0.5; }
652
- return __awaiter(void 0, void 0, void 0, function () {
653
- var _a, inputCoinAddress, outputCoinAddress, _b, inputCoinDecimals, outputCoinDecimals, _c, route, output, _d, _route, _swapParams, _factorySwapAddresses, _amount, minRecvAmountBN, _minRecvAmount, contract, value, gasLimit;
654
- return __generator(this, function (_e) {
655
- switch (_e.label) {
656
- case 0:
657
- _a = (0, utils_1._getCoinAddresses)(inputCoin, outputCoin), inputCoinAddress = _a[0], outputCoinAddress = _a[1];
658
- _b = (0, utils_1._getCoinDecimals)(inputCoinAddress, outputCoinAddress), inputCoinDecimals = _b[0], outputCoinDecimals = _b[1];
659
- return [4 /*yield*/, (0, exports.swapApprove)(inputCoin, amount)];
660
- case 1:
661
- _e.sent();
662
- return [4 /*yield*/, (0, exports.getBestRouteAndOutput)(inputCoinAddress, outputCoinAddress, amount)];
663
- case 2:
664
- _c = _e.sent(), route = _c.route, output = _c.output;
665
- if (route.length === 0) {
666
- throw new Error("This pair can't be exchanged");
667
- }
668
- _d = _getExchangeMultipleArgs(route), _route = _d._route, _swapParams = _d._swapParams, _factorySwapAddresses = _d._factorySwapAddresses;
669
- _amount = (0, utils_1.parseUnits)(amount, inputCoinDecimals);
670
- minRecvAmountBN = (0, utils_1.BN)(output).times(100 - slippage).div(100);
671
- _minRecvAmount = (0, utils_1.fromBN)(minRecvAmountBN, outputCoinDecimals);
672
- contract = curve_1.curve.contracts[curve_1.curve.constants.ALIASES.registry_exchange].contract;
673
- value = (0, utils_1.isEth)(inputCoinAddress) ? _amount : ethers_1.ethers.BigNumber.from(0);
674
- return [4 /*yield*/, curve_1.curve.updateFeeData()];
675
- case 3:
676
- _e.sent();
677
- return [4 /*yield*/, contract.estimateGas.exchange_multiple(_route, _swapParams, _amount, _minRecvAmount, _factorySwapAddresses, __assign(__assign({}, curve_1.curve.constantOptions), { value: value }))];
678
- case 4:
679
- gasLimit = (_e.sent()).mul(curve_1.curve.chainId === 1 ? 130 : 160).div(100);
680
- return [4 /*yield*/, contract.exchange_multiple(_route, _swapParams, _amount, _minRecvAmount, _factorySwapAddresses, __assign(__assign({}, curve_1.curve.options), { value: value, gasLimit: gasLimit }))];
681
- case 5: return [2 /*return*/, _e.sent()];
682
- }
683
- });
684
- });
356
+ export const getBestRouteAndOutput = async (inputCoin, outputCoin, amount) => {
357
+ const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin);
358
+ const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
359
+ const route = await _getBestRoute(inputCoinAddress, outputCoinAddress, amount); // 5 minutes cache
360
+ if (route.length === 0)
361
+ return { route, output: '0.0' };
362
+ const _output = await _getOutputForRoute(route, parseUnits(amount, inputCoinDecimals)); // 15 seconds cache, so we call it to get fresh output estimation
363
+ return { route, output: curve.formatUnits(_output, outputCoinDecimals) };
685
364
  };
686
- exports.swap = swap;
687
- var getSwappedAmount = function (tx, outputCoin) { return __awaiter(void 0, void 0, void 0, function () {
688
- var outputCoinAddress, outputCoinDecimals, txInfo, res, i;
689
- return __generator(this, function (_a) {
690
- switch (_a.label) {
691
- case 0:
692
- outputCoinAddress = (0, utils_1._getCoinAddresses)(outputCoin)[0];
693
- outputCoinDecimals = (0, utils_1._getCoinDecimals)(outputCoinAddress)[0];
694
- return [4 /*yield*/, tx.wait()];
695
- case 1:
696
- txInfo = _a.sent();
697
- for (i = 1; i <= txInfo.logs.length; i++) {
698
- try {
699
- res = ethers_1.ethers.utils.defaultAbiCoder.decode(['address[9]', 'uint256[3][4]', 'address[4]', 'uint256', 'uint256'], ethers_1.ethers.utils.hexDataSlice(txInfo.logs[txInfo.logs.length - i].data, 0));
700
- break;
701
- }
702
- catch (err) { }
703
- }
704
- if (res === undefined)
705
- return [2 /*return*/, '0'];
706
- return [2 /*return*/, ethers_1.ethers.utils.formatUnits(res[res.length - 1], outputCoinDecimals)];
365
+ export const swapExpected = async (inputCoin, outputCoin, amount) => {
366
+ return (await getBestRouteAndOutput(inputCoin, outputCoin, amount))['output'];
367
+ };
368
+ export const swapPriceImpact = async (inputCoin, outputCoin, amount) => {
369
+ const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin);
370
+ const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
371
+ const { route, output } = await getBestRouteAndOutput(inputCoinAddress, outputCoinAddress, amount);
372
+ const _amount = parseUnits(amount, inputCoinDecimals);
373
+ const _output = parseUnits(output, outputCoinDecimals);
374
+ const smallAmountIntBN = _get_small_x(_amount, _output, inputCoinDecimals, outputCoinDecimals);
375
+ const amountIntBN = toBN(_amount, 0);
376
+ if (smallAmountIntBN.gte(amountIntBN))
377
+ return 0;
378
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
379
+ let _smallAmount = fromBN(smallAmountIntBN.div(10 ** inputCoinDecimals), inputCoinDecimals);
380
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(route);
381
+ let _smallOutput;
382
+ try {
383
+ _smallOutput = await contract.get_exchange_multiple_amount(_route, _swapParams, _smallAmount, _factorySwapAddresses, curve.constantOptions);
384
+ }
385
+ catch (e) {
386
+ _smallAmount = curve.parseUnits("1", inputCoinDecimals); // Dirty hack
387
+ _smallOutput = await contract.get_exchange_multiple_amount(_route, _swapParams, _smallAmount, _factorySwapAddresses, curve.constantOptions);
388
+ }
389
+ const priceImpactBN = _get_price_impact(_amount, _output, _smallAmount, _smallOutput, inputCoinDecimals, outputCoinDecimals);
390
+ return Number(_cutZeros(priceImpactBN.toFixed(4)));
391
+ };
392
+ export const swapIsApproved = async (inputCoin, amount) => {
393
+ return await hasAllowance([inputCoin], [amount], curve.signerAddress, curve.constants.ALIASES.registry_exchange);
394
+ };
395
+ export const swapApproveEstimateGas = async (inputCoin, amount) => {
396
+ return await ensureAllowanceEstimateGas([inputCoin], [amount], curve.constants.ALIASES.registry_exchange);
397
+ };
398
+ export const swapApprove = async (inputCoin, amount) => {
399
+ return await ensureAllowance([inputCoin], [amount], curve.constants.ALIASES.registry_exchange);
400
+ };
401
+ export const swapEstimateGas = async (inputCoin, outputCoin, amount) => {
402
+ const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin);
403
+ const [inputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
404
+ const { route } = await getBestRouteAndOutput(inputCoinAddress, outputCoinAddress, amount);
405
+ if (route.length === 0)
406
+ return 0;
407
+ const _amount = parseUnits(amount, inputCoinDecimals);
408
+ const [gas] = await _estimateGasForDifferentRoutes([route], inputCoinAddress, outputCoinAddress, _amount);
409
+ return gas;
410
+ };
411
+ export const swap = async (inputCoin, outputCoin, amount, slippage = 0.5) => {
412
+ const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin);
413
+ const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
414
+ await swapApprove(inputCoin, amount);
415
+ const { route, output } = await getBestRouteAndOutput(inputCoinAddress, outputCoinAddress, amount);
416
+ if (route.length === 0) {
417
+ throw new Error("This pair can't be exchanged");
418
+ }
419
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(route);
420
+ const _amount = parseUnits(amount, inputCoinDecimals);
421
+ const minRecvAmountBN = BN(output).times(100 - slippage).div(100);
422
+ const _minRecvAmount = fromBN(minRecvAmountBN, outputCoinDecimals);
423
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
424
+ const value = isEth(inputCoinAddress) ? _amount : 0n;
425
+ await curve.updateFeeData();
426
+ const gasLimit = (await contract.exchange_multiple.estimateGas(_route, _swapParams, _amount, _minRecvAmount, _factorySwapAddresses, { ...curve.constantOptions, value })) * (curve.chainId === 1 ? 130n : 160n) / 100n;
427
+ return await contract.exchange_multiple(_route, _swapParams, _amount, _minRecvAmount, _factorySwapAddresses, { ...curve.options, value, gasLimit });
428
+ };
429
+ export const getSwappedAmount = async (tx, outputCoin) => {
430
+ const [outputCoinAddress] = _getCoinAddresses(outputCoin);
431
+ const [outputCoinDecimals] = _getCoinDecimals(outputCoinAddress);
432
+ const txInfo = await tx.wait();
433
+ if (txInfo === null)
434
+ return '0.0';
435
+ let res;
436
+ for (let i = 1; i <= txInfo.logs.length; i++) {
437
+ try {
438
+ const abiCoder = ethers.AbiCoder.defaultAbiCoder();
439
+ res = abiCoder.decode(['address[9]', 'uint256[3][4]', 'address[4]', 'uint256', 'uint256'], ethers.dataSlice(txInfo.logs[txInfo.logs.length - i].data, 0));
440
+ break;
707
441
  }
708
- });
709
- }); };
710
- exports.getSwappedAmount = getSwappedAmount;
442
+ catch (err) { }
443
+ }
444
+ if (res === undefined)
445
+ return '0.0';
446
+ return curve.formatUnits(res[res.length - 1], outputCoinDecimals);
447
+ };