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