@curvefi/api 2.31.0 → 2.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/lib/boosting.js +137 -402
  2. package/lib/constants/abis/stable_calc.json +151 -0
  3. package/lib/constants/abis/wbeth/swap.json +1086 -0
  4. package/lib/constants/aliases.d.ts +11 -11
  5. package/lib/constants/aliases.js +23 -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 +7 -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 +21 -27
  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 +272 -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 +22 -28
  38. package/lib/constants/pools/xdai.d.ts +2 -4
  39. package/lib/constants/pools/xdai.js +24 -30
  40. package/lib/constants/utils.d.ts +1 -1
  41. package/lib/constants/utils.js +20 -29
  42. package/lib/curve.d.ts +9 -7
  43. package/lib/curve.js +399 -615
  44. package/lib/external-api.d.ts +1 -1
  45. package/lib/external-api.js +47 -140
  46. package/lib/factory/common.js +6 -10
  47. package/lib/factory/constants-crypto.js +48 -54
  48. package/lib/factory/constants.js +274 -280
  49. package/lib/factory/deploy.d.ts +8 -8
  50. package/lib/factory/deploy.js +177 -347
  51. package/lib/factory/factory-api.js +195 -278
  52. package/lib/factory/factory-crypto.js +170 -323
  53. package/lib/factory/factory.js +195 -350
  54. package/lib/index.d.ts +24 -25
  55. package/lib/index.js +87 -143
  56. package/lib/interfaces.d.ts +6 -11
  57. package/lib/interfaces.js +1 -2
  58. package/lib/pools/PoolTemplate.js +1478 -2931
  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 -112
  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 +144 -417
  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 -1
  70. package/lib/pools/mixins/poolBalancesMixin.js +25 -105
  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 -1
  76. package/lib/pools/mixins/withdrawExpectedMixins.js +26 -110
  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 +123 -390
  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 +124 -390
  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 +77 -101
  95. package/lib/pools/utils.js +299 -500
  96. package/lib/router.d.ts +2 -2
  97. package/lib/router.js +221 -689
  98. package/lib/utils.d.ts +9 -9
  99. package/lib/utils.js +377 -731
  100. package/package.json +9 -8
package/lib/router.js CHANGED
@@ -1,710 +1,242 @@
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; });
72
- // Steps <= 4
73
- if (routePoolIds.length >= 4)
74
- return { route: [], minTvl: Infinity, totalTvl: 0 };
75
- // Exclude such cases as cvxeth -> tricrypto2 -> tricrypto2 -> susd
76
- if (routePoolIds.includes(poolId))
77
- return { route: [], minTvl: Infinity, totalTvl: 0 };
78
- 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),
80
- minTvl: Math.min(tvl, routeTvl.minTvl),
81
- totalTvl: routeTvl.totalTvl + tvl,
82
- };
83
- };
84
- // 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)
90
- return false;
91
- }
92
- return true;
93
- });
94
- };
95
- // 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];
100
- if (step.poolId == 'avaxcrypto' && step.swapType == 4 && (step.i === 3 || step.j === 3))
101
- return false;
102
- }
103
- return true;
104
- });
105
- };
106
- var MAX_ROUTES_FOR_ONE_COIN = 3;
107
- var filterRoutes = function (routes, inputCoinAddress, sortFn) {
108
- // TODO REMOVE IT!!!
109
- if (curve_1.curve.chainId === 137)
110
- routes = filterMaticFactory83Route(routes);
111
- if (curve_1.curve.chainId === 43114)
112
- routes = filterAvax(routes);
113
- 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;
119
- }) // Route duplications
120
- .sort(sortFn).slice(0, MAX_ROUTES_FOR_ONE_COIN);
121
- };
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; };
124
- // 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
- });
335
- };
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; })];
358
- }
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, "-->");
1
+ import axios from "axios";
2
+ import memoize from "memoizee";
3
+ import { findAllRoutes } from "@curvefi/router";
4
+ import { ethers } from "ethers";
5
+ import { curve } from "./curve.js";
6
+ import { _getCoinAddresses, _getCoinDecimals, _getUsdRate, ensureAllowance, ensureAllowanceEstimateGas, fromBN, hasAllowance, isEth, toBN, BN, parseUnits, _cutZeros, ETH_ADDRESS, _get_small_x, _get_price_impact, } from "./utils.js";
7
+ import { getPool } from "./pools/index.js";
8
+ import { _getAmplificationCoefficientsFromApi } from "./pools/utils.js";
9
+ const _getRouteKey = (route, inputCoinAddress, outputCoinAddress) => {
10
+ const sortedCoins = [inputCoinAddress, outputCoinAddress].sort();
11
+ let key = `${sortedCoins[0]}-->`;
12
+ for (const routeStep of route) {
13
+ key += `${routeStep.poolId}-->`;
367
14
  }
368
15
  key += sortedCoins[1];
369
16
  return key;
370
17
  };
371
- var _getExchangeMultipleArgs = function (route) {
372
- var _route = [];
18
+ const _getExchangeMultipleArgs = (route) => {
19
+ let _route = [];
373
20
  if (route.length > 0)
374
21
  _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];
22
+ let _swapParams = [];
23
+ let _factorySwapAddresses = [];
24
+ for (const routeStep of route) {
379
25
  _route.push(routeStep.poolAddress, routeStep.outputCoinAddress);
380
26
  _swapParams.push([routeStep.i, routeStep.j, routeStep.swapType]);
381
27
  _factorySwapAddresses.push(routeStep.swapAddress);
382
28
  }
383
- _route = _route.concat(Array(9 - _route.length).fill(ethers_1.ethers.constants.AddressZero));
29
+ _route = _route.concat(Array(9 - _route.length).fill(curve.constants.ZERO_ADDRESS));
384
30
  _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 };
31
+ _factorySwapAddresses = _factorySwapAddresses.concat(Array(4 - _factorySwapAddresses.length).fill(curve.constants.ZERO_ADDRESS));
32
+ return { _route, _swapParams, _factorySwapAddresses };
387
33
  };
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*/];
34
+ const _estimatedGasForDifferentRoutesCache = {};
35
+ const _estimateGasForDifferentRoutes = async (routes, inputCoinAddress, outputCoinAddress, _amount) => {
36
+ inputCoinAddress = inputCoinAddress.toLowerCase();
37
+ outputCoinAddress = outputCoinAddress.toLowerCase();
38
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
39
+ const gasPromises = [];
40
+ const value = isEth(inputCoinAddress) ? _amount : 0n;
41
+ for (const route of routes) {
42
+ const routeKey = _getRouteKey(route, inputCoinAddress, outputCoinAddress);
43
+ let gasPromise;
44
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(route);
45
+ if ((_estimatedGasForDifferentRoutesCache[routeKey]?.time || 0) + 3600000 < Date.now()) {
46
+ gasPromise = contract.exchange_multiple.estimateGas(_route, _swapParams, _amount, 0, _factorySwapAddresses, { ...curve.constantOptions, value });
47
+ }
48
+ else {
49
+ gasPromise = Promise.resolve(_estimatedGasForDifferentRoutesCache[routeKey].gas);
50
+ }
51
+ gasPromises.push(gasPromise);
52
+ }
53
+ try {
54
+ const _gasAmounts = await Promise.all(gasPromises);
55
+ routes.forEach((route, i) => {
56
+ const routeKey = _getRouteKey(route, inputCoinAddress, outputCoinAddress);
57
+ _estimatedGasForDifferentRoutesCache[routeKey] = { 'gas': _gasAmounts[i], 'time': Date.now() };
58
+ });
59
+ return _gasAmounts.map((_g) => Number(curve.formatUnits(_g, 0)));
60
+ }
61
+ catch (err) { // No allowance
62
+ return routes.map(() => 0);
63
+ }
64
+ };
65
+ const _getBestRoute = memoize(async (inputCoinAddress, outputCoinAddress, amount) => {
66
+ const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
67
+ const _amount = parseUnits(amount, inputCoinDecimals);
68
+ if (_amount === 0n)
69
+ return [];
70
+ const pools = {
71
+ ...curve.constants.POOLS_DATA,
72
+ ...curve.constants.FACTORY_POOLS_DATA,
73
+ ...curve.constants.CRYPTO_FACTORY_POOLS_DATA,
74
+ };
75
+ const ADict = await _getAmplificationCoefficientsFromApi();
76
+ const tvlDict = {};
77
+ const poolIds = Object.keys(pools);
78
+ for (let i = 0; i < poolIds.length; i++) {
79
+ tvlDict[poolIds[i]] = Number(await (getPool(poolIds[i])).stats.totalLiquidity());
80
+ }
81
+ const routesRaw = (findAllRoutes(inputCoinAddress, outputCoinAddress, pools, ADict, curve.chainId, curve.constants.NATIVE_TOKEN, tvlDict)).map((route) => ({ route, _output: 0n, outputUsd: 0, txCostUsd: 0 }));
82
+ const routes = [];
83
+ try {
84
+ const calls = [];
85
+ const multicallContract = curve.contracts[curve.constants.ALIASES.registry_exchange].multicallContract;
86
+ for (const r of routesRaw) {
87
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(r.route);
88
+ calls.push(multicallContract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses));
89
+ }
90
+ const _outputAmounts = await curve.multicallProvider.all(calls);
91
+ for (let i = 0; i < _outputAmounts.length; i++) {
92
+ routesRaw[i]._output = _outputAmounts[i];
93
+ routes.push(routesRaw[i]);
428
94
  }
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];
95
+ }
96
+ catch (err) {
97
+ const promises = [];
98
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
99
+ for (const r of routesRaw) {
100
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(r.route);
101
+ promises.push(contract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses, curve.constantOptions));
102
+ }
103
+ const res = await Promise.allSettled(promises);
104
+ for (let i = 0; i < res.length; i++) {
105
+ if (res[i].status === 'rejected') {
106
+ console.log(`Route ${(routesRaw[i].route.map((s) => s.poolId)).join(" --> ")} is unavailable`);
107
+ continue;
108
+ }
109
+ routesRaw[i]._output = res[i].value;
110
+ routes.push(routesRaw[i]);
512
111
  }
513
- });
514
- }); }, {
112
+ }
113
+ if (routes.length === 0)
114
+ return [];
115
+ if (routes.length === 1)
116
+ return routes[0].route;
117
+ const [gasAmounts, outputCoinUsdRate, gasData, ethUsdRate] = await Promise.all([
118
+ _estimateGasForDifferentRoutes(routes.map((r) => r.route), inputCoinAddress, outputCoinAddress, _amount),
119
+ _getUsdRate(outputCoinAddress),
120
+ axios.get("https://api.curve.fi/api/getGas"),
121
+ _getUsdRate(ETH_ADDRESS),
122
+ ]);
123
+ const gasPrice = gasData.data.data.gas.standard;
124
+ const expectedAmounts = (routes).map((route) => Number(curve.formatUnits(route._output, outputCoinDecimals)));
125
+ const expectedAmountsUsd = expectedAmounts.map((a) => a * outputCoinUsdRate);
126
+ const txCostsUsd = gasAmounts.map((a) => ethUsdRate * a * gasPrice / 1e18);
127
+ routes.forEach((route, i) => {
128
+ route.outputUsd = expectedAmountsUsd[i];
129
+ route.txCostUsd = txCostsUsd[i];
130
+ });
131
+ return routes.reduce((route1, route2) => {
132
+ const diff = (route1.outputUsd - route1.txCostUsd) - (route2.outputUsd - route2.txCostUsd);
133
+ if (diff > 0)
134
+ return route1;
135
+ if (diff === 0 && route1.route.length < route2.route.length)
136
+ return route1;
137
+ return route2;
138
+ }).route;
139
+ }, {
515
140
  promise: true,
516
141
  maxAge: 5 * 60 * 1000, // 5m
517
142
  });
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
- }); }, {
143
+ const _getOutputForRoute = memoize(async (route, _amount) => {
144
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
145
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(route);
146
+ return await contract.get_exchange_multiple_amount(_route, _swapParams, _amount, _factorySwapAddresses, curve.constantOptions);
147
+ }, {
530
148
  promise: true,
531
149
  maxAge: 15 * 1000, // 15s
532
150
  });
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
- });
151
+ export const getBestRouteAndOutput = async (inputCoin, outputCoin, amount) => {
152
+ const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin);
153
+ const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
154
+ const route = await _getBestRoute(inputCoinAddress, outputCoinAddress, amount); // 5 minutes cache
155
+ if (route.length === 0)
156
+ return { route, output: '0.0' };
157
+ const _output = await _getOutputForRoute(route, parseUnits(amount, inputCoinDecimals)); // 15 seconds cache, so we call it to get fresh output estimation
158
+ return { route, output: curve.formatUnits(_output, outputCoinDecimals) };
159
+ };
160
+ export const swapExpected = async (inputCoin, outputCoin, amount) => {
161
+ return (await getBestRouteAndOutput(inputCoin, outputCoin, amount))['output'];
162
+ };
163
+ export const swapPriceImpact = async (inputCoin, outputCoin, amount) => {
164
+ const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin);
165
+ const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
166
+ const { route, output } = await getBestRouteAndOutput(inputCoinAddress, outputCoinAddress, amount);
167
+ const _amount = parseUnits(amount, inputCoinDecimals);
168
+ const _output = parseUnits(output, outputCoinDecimals);
169
+ const smallAmountIntBN = _get_small_x(_amount, _output, inputCoinDecimals, outputCoinDecimals);
170
+ const amountIntBN = toBN(_amount, 0);
171
+ if (smallAmountIntBN.gte(amountIntBN))
172
+ return 0;
173
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
174
+ let _smallAmount = fromBN(smallAmountIntBN.div(10 ** inputCoinDecimals), inputCoinDecimals);
175
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(route);
176
+ let _smallOutput;
177
+ try {
178
+ _smallOutput = await contract.get_exchange_multiple_amount(_route, _swapParams, _smallAmount, _factorySwapAddresses, curve.constantOptions);
179
+ }
180
+ catch (e) {
181
+ _smallAmount = curve.parseUnits("1", inputCoinDecimals); // Dirty hack
182
+ _smallOutput = await contract.get_exchange_multiple_amount(_route, _swapParams, _smallAmount, _factorySwapAddresses, curve.constantOptions);
183
+ }
184
+ const priceImpactBN = _get_price_impact(_amount, _output, _smallAmount, _smallOutput, inputCoinDecimals, outputCoinDecimals);
185
+ return Number(_cutZeros(priceImpactBN.toFixed(4)));
186
+ };
187
+ export const swapIsApproved = async (inputCoin, amount) => {
188
+ return await hasAllowance([inputCoin], [amount], curve.signerAddress, curve.constants.ALIASES.registry_exchange);
189
+ };
190
+ export const swapApproveEstimateGas = async (inputCoin, amount) => {
191
+ return await ensureAllowanceEstimateGas([inputCoin], [amount], curve.constants.ALIASES.registry_exchange);
192
+ };
193
+ export const swapApprove = async (inputCoin, amount) => {
194
+ return await ensureAllowance([inputCoin], [amount], curve.constants.ALIASES.registry_exchange);
195
+ };
196
+ export const swapEstimateGas = async (inputCoin, outputCoin, amount) => {
197
+ const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin);
198
+ const [inputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
199
+ const { route } = await getBestRouteAndOutput(inputCoinAddress, outputCoinAddress, amount);
200
+ if (route.length === 0)
201
+ return 0;
202
+ const _amount = parseUnits(amount, inputCoinDecimals);
203
+ const [gas] = await _estimateGasForDifferentRoutes([route], inputCoinAddress, outputCoinAddress, _amount);
204
+ return gas;
205
+ };
206
+ export const swap = async (inputCoin, outputCoin, amount, slippage = 0.5) => {
207
+ const [inputCoinAddress, outputCoinAddress] = _getCoinAddresses(inputCoin, outputCoin);
208
+ const [inputCoinDecimals, outputCoinDecimals] = _getCoinDecimals(inputCoinAddress, outputCoinAddress);
209
+ await swapApprove(inputCoin, amount);
210
+ const { route, output } = await getBestRouteAndOutput(inputCoinAddress, outputCoinAddress, amount);
211
+ if (route.length === 0) {
212
+ throw new Error("This pair can't be exchanged");
213
+ }
214
+ const { _route, _swapParams, _factorySwapAddresses } = _getExchangeMultipleArgs(route);
215
+ const _amount = parseUnits(amount, inputCoinDecimals);
216
+ const minRecvAmountBN = BN(output).times(100 - slippage).div(100);
217
+ const _minRecvAmount = fromBN(minRecvAmountBN, outputCoinDecimals);
218
+ const contract = curve.contracts[curve.constants.ALIASES.registry_exchange].contract;
219
+ const value = isEth(inputCoinAddress) ? _amount : 0n;
220
+ await curve.updateFeeData();
221
+ const gasLimit = (await contract.exchange_multiple.estimateGas(_route, _swapParams, _amount, _minRecvAmount, _factorySwapAddresses, { ...curve.constantOptions, value })) * (curve.chainId === 1 ? 130n : 160n) / 100n;
222
+ return await contract.exchange_multiple(_route, _swapParams, _amount, _minRecvAmount, _factorySwapAddresses, { ...curve.options, value, gasLimit });
223
+ };
224
+ export const getSwappedAmount = async (tx, outputCoin) => {
225
+ const [outputCoinAddress] = _getCoinAddresses(outputCoin);
226
+ const [outputCoinDecimals] = _getCoinDecimals(outputCoinAddress);
227
+ const txInfo = await tx.wait();
228
+ if (txInfo === null)
229
+ return '0.0';
230
+ let res;
231
+ for (let i = 1; i <= txInfo.logs.length; i++) {
232
+ try {
233
+ const abiCoder = ethers.AbiCoder.defaultAbiCoder();
234
+ res = abiCoder.decode(['address[9]', 'uint256[3][4]', 'address[4]', 'uint256', 'uint256'], ethers.dataSlice(txInfo.logs[txInfo.logs.length - i].data, 0));
235
+ break;
236
+ }
237
+ catch (err) { }
238
+ }
239
+ if (res === undefined)
240
+ return '0.0';
241
+ return curve.formatUnits(res[res.length - 1], outputCoinDecimals);
685
242
  };
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)];
707
- }
708
- });
709
- }); };
710
- exports.getSwappedAmount = getSwappedAmount;