@curvefi/api 2.62.0 → 2.63.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 +247 -645
- package/lib/constants/L2Networks.js +1 -1
- package/lib/constants/aliases.js +31 -31
- package/lib/constants/coins/arbitrum.js +5 -5
- package/lib/constants/coins/aurora.js +5 -5
- package/lib/constants/coins/avalanche.js +6 -6
- package/lib/constants/coins/base.js +5 -5
- package/lib/constants/coins/bsc.js +5 -5
- package/lib/constants/coins/celo.js +5 -5
- package/lib/constants/coins/ethereum.js +9 -9
- package/lib/constants/coins/fantom.js +7 -7
- package/lib/constants/coins/fraxtal.js +5 -5
- package/lib/constants/coins/kava.js +5 -5
- package/lib/constants/coins/mantle.js +5 -5
- package/lib/constants/coins/moonbeam.js +5 -5
- package/lib/constants/coins/optimism.js +5 -5
- package/lib/constants/coins/polygon.js +6 -6
- package/lib/constants/coins/xdai.js +5 -5
- package/lib/constants/coins/xlayer.js +5 -5
- package/lib/constants/coins/zksync.js +5 -5
- package/lib/constants/pools/arbitrum.js +1 -1
- package/lib/constants/pools/aurora.js +1 -1
- package/lib/constants/pools/avalanche.js +1 -1
- package/lib/constants/pools/base.js +1 -1
- package/lib/constants/pools/bsc.js +1 -1
- package/lib/constants/pools/celo.js +1 -1
- package/lib/constants/pools/ethereum.js +2 -2
- package/lib/constants/pools/fantom.js +1 -1
- package/lib/constants/pools/fraxtal.js +1 -1
- package/lib/constants/pools/kava.js +1 -1
- package/lib/constants/pools/mantle.js +1 -1
- package/lib/constants/pools/moonbeam.js +1 -1
- package/lib/constants/pools/optimism.js +1 -1
- package/lib/constants/pools/polygon.js +1 -1
- package/lib/constants/pools/xdai.js +1 -1
- package/lib/constants/pools/xlayer.js +1 -1
- package/lib/constants/pools/zksync.js +1 -1
- package/lib/constants/tricryptoDeployImplementations.js +3 -3
- package/lib/constants/utils.js +18 -19
- package/lib/constants/volumeNetworks.js +1 -1
- package/lib/curve.d.ts +3 -1
- package/lib/curve.js +534 -909
- package/lib/dao.js +351 -705
- package/lib/external-api.js +127 -256
- package/lib/factory/common.js +4 -4
- package/lib/factory/constants-crypto.js +33 -33
- package/lib/factory/constants.js +36 -46
- package/lib/factory/deploy.js +542 -907
- package/lib/factory/factory-api.js +205 -269
- package/lib/factory/factory-crypto.js +202 -342
- package/lib/factory/factory-tricrypto.js +164 -286
- package/lib/factory/factory-twocrypto.js +151 -269
- package/lib/factory/factory.js +245 -385
- package/lib/index.js +109 -198
- package/lib/interfaces.d.ts +1 -6
- package/lib/pools/PoolTemplate.js +1773 -3025
- package/lib/pools/gaugePool.js +112 -251
- package/lib/pools/mixins/common.js +22 -93
- package/lib/pools/mixins/depositBalancedAmountsMixins.js +52 -118
- package/lib/pools/mixins/depositMixins.js +160 -386
- package/lib/pools/mixins/depositWrappedMixins.js +79 -205
- package/lib/pools/mixins/poolBalancesMixin.js +24 -87
- package/lib/pools/mixins/swapMixins.js +139 -324
- package/lib/pools/mixins/swapWrappedMixins.js +111 -265
- package/lib/pools/mixins/withdrawExpectedMixins.js +27 -91
- package/lib/pools/mixins/withdrawImbalanceMixins.js +111 -293
- package/lib/pools/mixins/withdrawImbalanceWrappedMixins.js +58 -169
- package/lib/pools/mixins/withdrawMixins.js +139 -359
- package/lib/pools/mixins/withdrawOneCoinExpectedMixins.js +20 -75
- package/lib/pools/mixins/withdrawOneCoinMixins.js +140 -360
- package/lib/pools/mixins/withdrawOneCoinWrappedExpectedMixins.js +10 -51
- package/lib/pools/mixins/withdrawOneCoinWrappedMixins.js +60 -167
- package/lib/pools/mixins/withdrawWrappedMixins.js +57 -167
- package/lib/pools/poolConstructor.js +5 -25
- package/lib/pools/utils.js +301 -469
- package/lib/route-finder.worker.d.ts +9 -0
- package/lib/route-finder.worker.js +112 -0
- package/lib/route-graph.worker.d.ts +11 -0
- package/lib/route-graph.worker.js +334 -0
- package/lib/router.js +323 -912
- package/lib/utils.d.ts +5 -4
- package/lib/utils.js +539 -906
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IDict, IRoutePoolData, IRouteStep } from "./interfaces";
|
|
2
|
+
export type IRouterWorkerInput = {
|
|
3
|
+
inputCoinAddress: string;
|
|
4
|
+
outputCoinAddress: string;
|
|
5
|
+
routerGraph: IDict<IDict<IRouteStep[]>>;
|
|
6
|
+
poolData: IDict<IRoutePoolData>;
|
|
7
|
+
};
|
|
8
|
+
export declare function routeFinderWorker(): (({ inputCoinAddress, outputCoinAddress, routerGraph, poolData }: IRouterWorkerInput) => IRouteStep[][]) | undefined;
|
|
9
|
+
export declare const routeFinderWorkerCode: string;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
export function routeFinderWorker() {
|
|
2
|
+
const MAX_ROUTES_FOR_ONE_COIN = 5;
|
|
3
|
+
const MAX_DEPTH = 4;
|
|
4
|
+
const _removeDuplications = (routesA, routesB) => {
|
|
5
|
+
const routeToStr = (r) => r.route.map((s) => s.poolId).toString();
|
|
6
|
+
const routeIdsA = new Set(routesA.map(routeToStr));
|
|
7
|
+
return routesA.concat(routesB.filter((r) => !routeIdsA.has(routeToStr(r))));
|
|
8
|
+
};
|
|
9
|
+
const _sortByTvl = (a, b) => b.minTvl - a.minTvl || b.totalTvl - a.totalTvl || a.route.length - b.route.length;
|
|
10
|
+
const _sortByLength = (a, b) => a.route.length - b.route.length || b.minTvl - a.minTvl || b.totalTvl - a.totalTvl;
|
|
11
|
+
// 4 --> 6, 5 --> 7 not allowed
|
|
12
|
+
// 4 --> 7, 5 --> 6 allowed
|
|
13
|
+
const _handleSwapType = (swapType) => {
|
|
14
|
+
if (swapType === 6)
|
|
15
|
+
return "4";
|
|
16
|
+
if (swapType === 7)
|
|
17
|
+
return "5";
|
|
18
|
+
return swapType.toString();
|
|
19
|
+
};
|
|
20
|
+
/** Add step to route */
|
|
21
|
+
const _addStep = (route, step) => ({
|
|
22
|
+
route: route.route.concat(step),
|
|
23
|
+
minTvl: Math.min(step.tvl, route.minTvl),
|
|
24
|
+
totalTvl: route.totalTvl + step.tvl,
|
|
25
|
+
});
|
|
26
|
+
/** Check if item fits in a sorted-sized array */
|
|
27
|
+
function _fits(array, item, compareFn, maxSize) {
|
|
28
|
+
if (array.length < maxSize)
|
|
29
|
+
return true;
|
|
30
|
+
const last = array[array.length - 1];
|
|
31
|
+
return compareFn(item, last) < 0;
|
|
32
|
+
}
|
|
33
|
+
/** Add item to sorted-sized array */
|
|
34
|
+
function _sortedPush(array, item, compareFn, maxSize) {
|
|
35
|
+
if (!_fits(array, item, compareFn, maxSize))
|
|
36
|
+
return;
|
|
37
|
+
if (array.length === maxSize) {
|
|
38
|
+
array.pop();
|
|
39
|
+
}
|
|
40
|
+
const position = array.findIndex((existingItem) => compareFn(item, existingItem) < 0);
|
|
41
|
+
if (position === -1) {
|
|
42
|
+
array.push(item);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
array.splice(position, 0, item);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const _isVisitedCoin = (coinAddress, route) => route.route.find((r) => r.inputCoinAddress === coinAddress) !== undefined;
|
|
49
|
+
const _findPool = (route, poolId) => route.route.find((r) => r.poolId === poolId);
|
|
50
|
+
const findRoutes = ({ inputCoinAddress, outputCoinAddress, routerGraph, poolData }) => {
|
|
51
|
+
inputCoinAddress = inputCoinAddress.toLowerCase();
|
|
52
|
+
outputCoinAddress = outputCoinAddress.toLowerCase();
|
|
53
|
+
const routes = [{ route: [], minTvl: Infinity, totalTvl: 0 }];
|
|
54
|
+
const targetRoutesByTvl = [];
|
|
55
|
+
const targetRoutesByLength = [];
|
|
56
|
+
while (routes.length) {
|
|
57
|
+
const route = routes.pop();
|
|
58
|
+
const inCoin = route.route.length > 0 ? route.route[route.route.length - 1].outputCoinAddress : inputCoinAddress;
|
|
59
|
+
Object.entries(routerGraph[inCoin]).forEach((leaf) => {
|
|
60
|
+
const outCoin = leaf[0], steps = leaf[1];
|
|
61
|
+
if (_isVisitedCoin(outCoin, route))
|
|
62
|
+
return;
|
|
63
|
+
steps.forEach((step) => {
|
|
64
|
+
const pool = poolData[step.poolId];
|
|
65
|
+
const currentPoolInRoute = _findPool(route, step.poolId);
|
|
66
|
+
if (currentPoolInRoute) {
|
|
67
|
+
if (!(pool === null || pool === void 0 ? void 0 : pool.is_lending))
|
|
68
|
+
return;
|
|
69
|
+
// 4 --> 6, 5 --> 7 not allowed
|
|
70
|
+
// 4 --> 7, 5 --> 6 allowed
|
|
71
|
+
if (_handleSwapType(step.swapParams[2]) === _handleSwapType(currentPoolInRoute.swapParams[2])) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (step.outputCoinAddress === outputCoinAddress) {
|
|
76
|
+
const newRoute = _addStep(route, step);
|
|
77
|
+
_sortedPush(targetRoutesByTvl, newRoute, _sortByTvl, MAX_ROUTES_FOR_ONE_COIN);
|
|
78
|
+
_sortedPush(targetRoutesByLength, newRoute, _sortByLength, MAX_ROUTES_FOR_ONE_COIN);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if ((pool === null || pool === void 0 ? void 0 : pool.wrapped_coin_addresses.includes(outputCoinAddress)) || (pool === null || pool === void 0 ? void 0 : pool.underlying_coin_addresses.includes(outputCoinAddress))) {
|
|
82
|
+
// Exclude such cases as: cvxeth -> tricrypto2 -> tusd -> susd (cvxeth -> tricrypto2 -> tusd instead)
|
|
83
|
+
if (!(pool === null || pool === void 0 ? void 0 : pool.is_lending))
|
|
84
|
+
return;
|
|
85
|
+
// Exclude such cases as: aave -> aave -> 3pool (aave -> aave instead)
|
|
86
|
+
if (outCoin !== (pool === null || pool === void 0 ? void 0 : pool.token_address))
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (route.route.length < MAX_DEPTH) {
|
|
90
|
+
const newRoute = _addStep(route, step);
|
|
91
|
+
if (_fits(targetRoutesByTvl, newRoute, _sortByTvl, MAX_ROUTES_FOR_ONE_COIN) ||
|
|
92
|
+
_fits(targetRoutesByLength, newRoute, _sortByLength, MAX_ROUTES_FOR_ONE_COIN)) {
|
|
93
|
+
routes.push(newRoute); // try another step
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return _removeDuplications(targetRoutesByTvl, targetRoutesByLength).map((r) => r.route);
|
|
100
|
+
};
|
|
101
|
+
if (typeof addEventListener === 'undefined') {
|
|
102
|
+
return findRoutes; // for nodejs
|
|
103
|
+
}
|
|
104
|
+
addEventListener('message', (e) => {
|
|
105
|
+
const { type } = e.data;
|
|
106
|
+
if (type === 'findRoutes') {
|
|
107
|
+
postMessage({ type, result: findRoutes(e.data) });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
// this is a workaround to avoid importing web-worker in the main bundle (nextjs will try to inject invalid hot-reloading code)
|
|
112
|
+
export const routeFinderWorkerCode = `${routeFinderWorker.toString()}; ${routeFinderWorker.name}();`;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IChainId, IDict, IPoolData, IRouteStep } from "./interfaces";
|
|
2
|
+
import type { curve } from "./curve";
|
|
3
|
+
export type IRouteGraphInput = {
|
|
4
|
+
constants: typeof curve['constants'];
|
|
5
|
+
chainId: IChainId;
|
|
6
|
+
allPools: [string, IPoolData][];
|
|
7
|
+
amplificationCoefficientDict: IDict<number>;
|
|
8
|
+
poolTvlDict: IDict<number>;
|
|
9
|
+
};
|
|
10
|
+
export declare function routeGraphWorker(): (({ constants, chainId, allPools, amplificationCoefficientDict, poolTvlDict }: IRouteGraphInput) => IDict<IDict<IRouteStep[]>>) | undefined;
|
|
11
|
+
export declare const routeGraphWorkerCode: string;
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
export function routeGraphWorker() {
|
|
2
|
+
const GRAPH_MAX_EDGES = 3;
|
|
3
|
+
const SNX = {
|
|
4
|
+
10: {
|
|
5
|
+
swap: "0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4".toLowerCase(),
|
|
6
|
+
coins: [
|
|
7
|
+
"0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9",
|
|
8
|
+
"0xFBc4198702E81aE77c06D58f81b629BDf36f0a71",
|
|
9
|
+
"0xe405de8f52ba7559f9df3c368500b6e6ae6cee49",
|
|
10
|
+
"0x298b9b95708152ff6968aafd889c6586e9169f1d", // sBTC
|
|
11
|
+
].map((a) => a.toLowerCase()),
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
const createRouteGraph = ({ constants, chainId, allPools, amplificationCoefficientDict, poolTvlDict }) => {
|
|
15
|
+
var _a, _b, _c;
|
|
16
|
+
const routerGraph = {};
|
|
17
|
+
// ETH <-> WETH (exclude Celo)
|
|
18
|
+
if (chainId !== 42220) {
|
|
19
|
+
routerGraph[constants.NATIVE_TOKEN.address] = {};
|
|
20
|
+
routerGraph[constants.NATIVE_TOKEN.address][constants.NATIVE_TOKEN.wrappedAddress] = [{
|
|
21
|
+
poolId: "WETH wrapper",
|
|
22
|
+
swapAddress: constants.NATIVE_TOKEN.wrappedAddress,
|
|
23
|
+
inputCoinAddress: constants.NATIVE_TOKEN.address,
|
|
24
|
+
outputCoinAddress: constants.NATIVE_TOKEN.wrappedAddress,
|
|
25
|
+
swapParams: [0, 0, 8, 0, 0],
|
|
26
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
27
|
+
basePool: constants.ZERO_ADDRESS,
|
|
28
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
29
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
30
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
31
|
+
tvl: Infinity,
|
|
32
|
+
}];
|
|
33
|
+
routerGraph[constants.NATIVE_TOKEN.wrappedAddress] = {};
|
|
34
|
+
routerGraph[constants.NATIVE_TOKEN.wrappedAddress][constants.NATIVE_TOKEN.address] = [{
|
|
35
|
+
poolId: "WETH wrapper",
|
|
36
|
+
swapAddress: constants.NATIVE_TOKEN.wrappedAddress,
|
|
37
|
+
inputCoinAddress: constants.NATIVE_TOKEN.wrappedAddress,
|
|
38
|
+
outputCoinAddress: constants.NATIVE_TOKEN.address,
|
|
39
|
+
swapParams: [0, 0, 8, 0, 0],
|
|
40
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
41
|
+
basePool: constants.ZERO_ADDRESS,
|
|
42
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
43
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
44
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
45
|
+
tvl: Infinity,
|
|
46
|
+
}];
|
|
47
|
+
}
|
|
48
|
+
// ETH -> stETH, ETH -> frxETH, ETH -> wBETH (Ethereum only)
|
|
49
|
+
if (chainId == 1) {
|
|
50
|
+
for (const outCoin of ["stETH", "frxETH", "wBETH"]) {
|
|
51
|
+
routerGraph[constants.NATIVE_TOKEN.address][constants.COINS[outCoin.toLowerCase()]] = [{
|
|
52
|
+
poolId: outCoin + " minter",
|
|
53
|
+
swapAddress: outCoin === "frxETH" ? "0xbAFA44EFE7901E04E39Dad13167D089C559c1138".toLowerCase() : constants.COINS[outCoin.toLowerCase()],
|
|
54
|
+
inputCoinAddress: constants.NATIVE_TOKEN.address,
|
|
55
|
+
outputCoinAddress: constants.COINS[outCoin.toLowerCase()],
|
|
56
|
+
swapParams: [0, 0, 8, 0, 0],
|
|
57
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
58
|
+
basePool: constants.ZERO_ADDRESS,
|
|
59
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
60
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
61
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
62
|
+
tvl: Infinity,
|
|
63
|
+
}];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// stETH <-> wstETH (Ethereum only)
|
|
67
|
+
if (chainId === 1) {
|
|
68
|
+
routerGraph[constants.COINS.steth] = {};
|
|
69
|
+
routerGraph[constants.COINS.steth][constants.COINS.wsteth] = [{
|
|
70
|
+
poolId: "wstETH wrapper",
|
|
71
|
+
swapAddress: constants.COINS.wsteth,
|
|
72
|
+
inputCoinAddress: constants.COINS.steth,
|
|
73
|
+
outputCoinAddress: constants.COINS.wsteth,
|
|
74
|
+
swapParams: [0, 0, 8, 0, 0],
|
|
75
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
76
|
+
basePool: constants.ZERO_ADDRESS,
|
|
77
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
78
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
79
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
80
|
+
tvl: Infinity,
|
|
81
|
+
}];
|
|
82
|
+
routerGraph[constants.COINS.wsteth] = {};
|
|
83
|
+
routerGraph[constants.COINS.wsteth][constants.COINS.steth] = [{
|
|
84
|
+
poolId: "wstETH wrapper",
|
|
85
|
+
swapAddress: constants.COINS.wsteth,
|
|
86
|
+
inputCoinAddress: constants.COINS.wsteth,
|
|
87
|
+
outputCoinAddress: constants.COINS.steth,
|
|
88
|
+
swapParams: [0, 0, 8, 0, 0],
|
|
89
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
90
|
+
basePool: constants.ZERO_ADDRESS,
|
|
91
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
92
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
93
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
94
|
+
tvl: Infinity,
|
|
95
|
+
}];
|
|
96
|
+
}
|
|
97
|
+
// frxETH <-> sfrxETH (Ethereum only)
|
|
98
|
+
if (chainId === 1) {
|
|
99
|
+
routerGraph[constants.COINS.frxeth] = {};
|
|
100
|
+
routerGraph[constants.COINS.frxeth][constants.COINS.sfrxeth] = [{
|
|
101
|
+
poolId: "sfrxETH wrapper",
|
|
102
|
+
swapAddress: constants.COINS.sfrxeth,
|
|
103
|
+
inputCoinAddress: constants.COINS.frxeth,
|
|
104
|
+
outputCoinAddress: constants.COINS.sfrxeth,
|
|
105
|
+
swapParams: [0, 0, 8, 0, 0],
|
|
106
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
107
|
+
basePool: constants.ZERO_ADDRESS,
|
|
108
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
109
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
110
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
111
|
+
tvl: Infinity,
|
|
112
|
+
}];
|
|
113
|
+
routerGraph[constants.COINS.sfrxeth] = {};
|
|
114
|
+
routerGraph[constants.COINS.sfrxeth][constants.COINS.frxeth] = [{
|
|
115
|
+
poolId: "sfrxETH wrapper",
|
|
116
|
+
swapAddress: constants.COINS.sfrxeth,
|
|
117
|
+
inputCoinAddress: constants.COINS.sfrxeth,
|
|
118
|
+
outputCoinAddress: constants.COINS.frxeth,
|
|
119
|
+
swapParams: [0, 0, 8, 0, 0],
|
|
120
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
121
|
+
basePool: constants.ZERO_ADDRESS,
|
|
122
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
123
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
124
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
125
|
+
tvl: Infinity,
|
|
126
|
+
}];
|
|
127
|
+
}
|
|
128
|
+
// SNX swaps
|
|
129
|
+
if (chainId in SNX) {
|
|
130
|
+
// @ts-ignore
|
|
131
|
+
for (const inCoin of SNX[chainId].coins) {
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
for (const outCoin of SNX[chainId].coins) {
|
|
134
|
+
if (inCoin === outCoin)
|
|
135
|
+
continue;
|
|
136
|
+
if (!routerGraph[inCoin])
|
|
137
|
+
routerGraph[inCoin] = {};
|
|
138
|
+
routerGraph[inCoin][outCoin] = [{
|
|
139
|
+
poolId: "SNX exchanger",
|
|
140
|
+
// @ts-ignore
|
|
141
|
+
swapAddress: SNX[chainId].swap,
|
|
142
|
+
inputCoinAddress: inCoin,
|
|
143
|
+
outputCoinAddress: outCoin,
|
|
144
|
+
swapParams: [0, 0, 9, 0, 0],
|
|
145
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
146
|
+
basePool: constants.ZERO_ADDRESS,
|
|
147
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
148
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
149
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
150
|
+
tvl: Infinity,
|
|
151
|
+
}];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const start = Date.now();
|
|
156
|
+
for (const poolItem of allPools) {
|
|
157
|
+
const poolId = poolItem[0], poolData = poolItem[1];
|
|
158
|
+
const wrappedCoinAddresses = poolData.wrapped_coin_addresses.map((a) => a.toLowerCase());
|
|
159
|
+
const underlyingCoinAddresses = poolData.underlying_coin_addresses.map((a) => a.toLowerCase());
|
|
160
|
+
const poolAddress = poolData.swap_address.toLowerCase();
|
|
161
|
+
const tokenAddress = poolData.token_address.toLowerCase();
|
|
162
|
+
const isAaveLikeLending = poolData.is_lending && wrappedCoinAddresses.length === 3 && !poolData.deposit_address;
|
|
163
|
+
// pool_type: 1 - stable, 2 - twocrypto, 3 - tricrypto, 4 - llamma
|
|
164
|
+
// 10 - stable-ng, 20 - twocrypto-ng, 30 - tricrypto-ng
|
|
165
|
+
let poolType = poolData.is_llamma ? 4 : poolData.is_crypto ? Math.min(poolData.wrapped_coins.length, 3) : 1;
|
|
166
|
+
if (poolData.is_ng)
|
|
167
|
+
poolType *= 10;
|
|
168
|
+
const tvlMultiplier = poolData.is_crypto ? 1 : ((_a = amplificationCoefficientDict[poolData.swap_address]) !== null && _a !== void 0 ? _a : 1);
|
|
169
|
+
const basePool = poolData.is_meta ? Object.assign(Object.assign({}, constants.POOLS_DATA), constants.FACTORY_POOLS_DATA)[poolData.base_pool] : null;
|
|
170
|
+
const basePoolAddress = basePool ? basePool.swap_address.toLowerCase() : constants.ZERO_ADDRESS;
|
|
171
|
+
let baseTokenAddress = basePool ? basePool.token_address.toLowerCase() : constants.ZERO_ADDRESS;
|
|
172
|
+
const secondBasePool = basePool && basePool.base_pool ? Object.assign(Object.assign(Object.assign({}, constants.POOLS_DATA), constants.FACTORY_POOLS_DATA), constants.CRVUSD_FACTORY_POOLS_DATA)[basePool.base_pool] : null;
|
|
173
|
+
const secondBasePoolAddress = secondBasePool ? secondBasePool.swap_address.toLowerCase() : constants.ZERO_ADDRESS;
|
|
174
|
+
// for double meta underlying (crv/tricrypto, wmatic/tricrypto)
|
|
175
|
+
if (basePool && secondBasePoolAddress !== constants.ZERO_ADDRESS)
|
|
176
|
+
baseTokenAddress = (_b = basePool.deposit_address) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
177
|
+
const secondBaseTokenAddress = secondBasePool ? secondBasePool.token_address.toLowerCase() : constants.ZERO_ADDRESS;
|
|
178
|
+
const metaCoinAddresses = basePool ? basePool.underlying_coin_addresses.map((a) => a.toLowerCase()) : [];
|
|
179
|
+
let swapAddress = poolData.is_fake ? (_c = poolData.deposit_address) === null || _c === void 0 ? void 0 : _c.toLowerCase() : poolAddress;
|
|
180
|
+
const tvl = poolTvlDict[poolId] * tvlMultiplier;
|
|
181
|
+
// Skip empty pools
|
|
182
|
+
if (chainId === 1 && tvl < 1000)
|
|
183
|
+
continue;
|
|
184
|
+
if (chainId !== 1 && tvl < 100)
|
|
185
|
+
continue;
|
|
186
|
+
const excludedUnderlyingSwaps = (poolId === 'ib' && chainId === 1) ||
|
|
187
|
+
(poolId === 'geist' && chainId === 250) ||
|
|
188
|
+
(poolId === 'saave' && chainId === 1);
|
|
189
|
+
// Wrapped coin <-> LP "swaps" (actually add_liquidity/remove_liquidity_one_coin)
|
|
190
|
+
if (!poolData.is_fake && !poolData.is_llamma && wrappedCoinAddresses.length < 6) {
|
|
191
|
+
const coins = [tokenAddress].concat(wrappedCoinAddresses);
|
|
192
|
+
for (let k = 0; k < coins.length; k++) {
|
|
193
|
+
for (let l = 0; l < coins.length; l++) {
|
|
194
|
+
if (k > 0 && l > 0)
|
|
195
|
+
continue;
|
|
196
|
+
if (k == 0 && l == 0)
|
|
197
|
+
continue;
|
|
198
|
+
const i = Math.max(k - 1, 0);
|
|
199
|
+
const j = Math.max(l - 1, 0);
|
|
200
|
+
const swapType = k == 0 ? 6 : 4;
|
|
201
|
+
if (!routerGraph[coins[k]])
|
|
202
|
+
routerGraph[coins[k]] = {};
|
|
203
|
+
if (!routerGraph[coins[k]][coins[l]])
|
|
204
|
+
routerGraph[coins[k]][coins[l]] = [];
|
|
205
|
+
routerGraph[coins[k]][coins[l]].push({
|
|
206
|
+
poolId,
|
|
207
|
+
swapAddress,
|
|
208
|
+
inputCoinAddress: coins[k],
|
|
209
|
+
outputCoinAddress: coins[l],
|
|
210
|
+
swapParams: [i, j, swapType, poolType, wrappedCoinAddresses.length],
|
|
211
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
212
|
+
basePool: constants.ZERO_ADDRESS,
|
|
213
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
214
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
215
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
216
|
+
tvl,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Underlying coin <-> LP "swaps" (actually add_liquidity/remove_liquidity_one_coin)
|
|
222
|
+
if ((poolData.is_fake || isAaveLikeLending) && underlyingCoinAddresses.length < 6 && !excludedUnderlyingSwaps) {
|
|
223
|
+
const coins = [tokenAddress].concat(underlyingCoinAddresses);
|
|
224
|
+
for (let k = 0; k < coins.length; k++) {
|
|
225
|
+
for (let l = 0; l < coins.length; l++) {
|
|
226
|
+
if (k > 0 && l > 0)
|
|
227
|
+
continue;
|
|
228
|
+
if (k == 0 && l == 0)
|
|
229
|
+
continue;
|
|
230
|
+
const i = Math.max(k - 1, 0);
|
|
231
|
+
const j = Math.max(l - 1, 0);
|
|
232
|
+
let swapType = isAaveLikeLending ? 7 : 6;
|
|
233
|
+
if (k > 0)
|
|
234
|
+
swapType = isAaveLikeLending ? 5 : 4;
|
|
235
|
+
if (!routerGraph[coins[k]])
|
|
236
|
+
routerGraph[coins[k]] = {};
|
|
237
|
+
if (!routerGraph[coins[k]][coins[l]])
|
|
238
|
+
routerGraph[coins[k]][coins[l]] = [];
|
|
239
|
+
routerGraph[coins[k]][coins[l]].push({
|
|
240
|
+
poolId,
|
|
241
|
+
swapAddress,
|
|
242
|
+
inputCoinAddress: coins[k],
|
|
243
|
+
outputCoinAddress: coins[l],
|
|
244
|
+
swapParams: [i, j, swapType, poolType, underlyingCoinAddresses.length],
|
|
245
|
+
poolAddress: constants.ZERO_ADDRESS,
|
|
246
|
+
basePool: constants.ZERO_ADDRESS,
|
|
247
|
+
baseToken: constants.ZERO_ADDRESS,
|
|
248
|
+
secondBasePool: constants.ZERO_ADDRESS,
|
|
249
|
+
secondBaseToken: constants.ZERO_ADDRESS,
|
|
250
|
+
tvl,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// Wrapped swaps
|
|
256
|
+
if (!poolData.is_fake) {
|
|
257
|
+
for (let i = 0; i < wrappedCoinAddresses.length; i++) {
|
|
258
|
+
for (let j = 0; j < wrappedCoinAddresses.length; j++) {
|
|
259
|
+
if (i == j)
|
|
260
|
+
continue;
|
|
261
|
+
if (!routerGraph[wrappedCoinAddresses[i]])
|
|
262
|
+
routerGraph[wrappedCoinAddresses[i]] = {};
|
|
263
|
+
if (!routerGraph[wrappedCoinAddresses[i]][wrappedCoinAddresses[j]])
|
|
264
|
+
routerGraph[wrappedCoinAddresses[i]][wrappedCoinAddresses[j]] = [];
|
|
265
|
+
routerGraph[wrappedCoinAddresses[i]][wrappedCoinAddresses[j]] = routerGraph[wrappedCoinAddresses[i]][wrappedCoinAddresses[j]].concat({
|
|
266
|
+
poolId,
|
|
267
|
+
swapAddress,
|
|
268
|
+
inputCoinAddress: wrappedCoinAddresses[i],
|
|
269
|
+
outputCoinAddress: wrappedCoinAddresses[j],
|
|
270
|
+
swapParams: [i, j, 1, poolType, wrappedCoinAddresses.length],
|
|
271
|
+
poolAddress,
|
|
272
|
+
basePool: basePoolAddress,
|
|
273
|
+
baseToken: baseTokenAddress,
|
|
274
|
+
secondBasePool: secondBasePoolAddress,
|
|
275
|
+
secondBaseToken: secondBaseTokenAddress,
|
|
276
|
+
tvl,
|
|
277
|
+
}).sort((a, b) => b.tvl - a.tvl).slice(0, GRAPH_MAX_EDGES);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// Only for underlying swaps
|
|
282
|
+
swapAddress = (poolData.is_crypto && poolData.is_meta) || ((basePool === null || basePool === void 0 ? void 0 : basePool.is_lending) && poolData.is_factory) ?
|
|
283
|
+
poolData.deposit_address : poolData.swap_address;
|
|
284
|
+
// Underlying swaps
|
|
285
|
+
if (!poolData.is_plain && !excludedUnderlyingSwaps) {
|
|
286
|
+
for (let i = 0; i < underlyingCoinAddresses.length; i++) {
|
|
287
|
+
for (let j = 0; j < underlyingCoinAddresses.length; j++) {
|
|
288
|
+
if (i === j)
|
|
289
|
+
continue;
|
|
290
|
+
// Don't swap metacoins since they can be swapped directly in base pool
|
|
291
|
+
if (metaCoinAddresses.includes(underlyingCoinAddresses[i]) && metaCoinAddresses.includes(underlyingCoinAddresses[j]))
|
|
292
|
+
continue;
|
|
293
|
+
// avWBTC is frozen by Aave on Avalanche, deposits are not working
|
|
294
|
+
if (chainId === 43114 && poolId === "atricrypto" && i === 3)
|
|
295
|
+
continue;
|
|
296
|
+
const hasEth = underlyingCoinAddresses.includes(constants.NATIVE_TOKEN.address);
|
|
297
|
+
const swapType = (poolData.is_crypto && poolData.is_meta && poolData.is_factory) || ((basePool === null || basePool === void 0 ? void 0 : basePool.is_lending) && poolData.is_factory) ? 3
|
|
298
|
+
: hasEth && poolId !== 'avaxcrypto' ? 1 : 2;
|
|
299
|
+
if (!routerGraph[underlyingCoinAddresses[i]])
|
|
300
|
+
routerGraph[underlyingCoinAddresses[i]] = {};
|
|
301
|
+
if (!routerGraph[underlyingCoinAddresses[i]][underlyingCoinAddresses[j]])
|
|
302
|
+
routerGraph[underlyingCoinAddresses[i]][underlyingCoinAddresses[j]] = [];
|
|
303
|
+
routerGraph[underlyingCoinAddresses[i]][underlyingCoinAddresses[j]] = routerGraph[underlyingCoinAddresses[i]][underlyingCoinAddresses[j]].concat({
|
|
304
|
+
poolId,
|
|
305
|
+
swapAddress,
|
|
306
|
+
inputCoinAddress: underlyingCoinAddresses[i],
|
|
307
|
+
outputCoinAddress: underlyingCoinAddresses[j],
|
|
308
|
+
swapParams: [i, j, swapType, poolType, underlyingCoinAddresses.length],
|
|
309
|
+
poolAddress,
|
|
310
|
+
basePool: basePoolAddress,
|
|
311
|
+
baseToken: baseTokenAddress,
|
|
312
|
+
secondBasePool: secondBasePoolAddress,
|
|
313
|
+
secondBaseToken: secondBaseTokenAddress,
|
|
314
|
+
tvl,
|
|
315
|
+
}).sort((a, b) => b.tvl - a.tvl).slice(0, GRAPH_MAX_EDGES);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
console.log(`Read ${allPools.length} pools`, `${Date.now() - start}ms, routerGraph: ${Object.keys(routerGraph).length} items`);
|
|
321
|
+
return routerGraph;
|
|
322
|
+
};
|
|
323
|
+
if (typeof addEventListener === 'undefined') {
|
|
324
|
+
return createRouteGraph; // for nodejs
|
|
325
|
+
}
|
|
326
|
+
addEventListener('message', (e) => {
|
|
327
|
+
const { type } = e.data;
|
|
328
|
+
if (type === 'createRouteGraph') {
|
|
329
|
+
postMessage({ type, result: createRouteGraph(e.data) });
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
// this is a workaround to avoid importing web-worker in the main bundle (nextjs will try to inject invalid hot-reloading code)
|
|
334
|
+
export const routeGraphWorkerCode = `${routeGraphWorker.toString()}; ${routeGraphWorker.name}();`;
|