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