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