@marko00/routing-finder-mare 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/copilot.data.migration.agent.xml +6 -0
- package/.idea/copilot.data.migration.ask.xml +6 -0
- package/.idea/copilot.data.migration.ask2agent.xml +6 -0
- package/.idea/copilot.data.migration.edit.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/php.xml +19 -0
- package/.idea/ratex-sdk.iml +8 -0
- package/.idea/vcs.xml +6 -0
- package/LICENSE-MIT +21 -0
- package/README.md +209 -0
- package/contracts/abi/BalancerHelperAbi.ts +1 -0
- package/contracts/abi/CamelotHelperAbi.ts +1 -0
- package/contracts/abi/RateXAbi.ts +482 -0
- package/contracts/abi/SushiSwapHelperAbi.ts +1 -0
- package/contracts/abi/UniswapHelperAbi.ts +1 -0
- package/contracts/abi/UniswapV2HelperAbi.ts +1 -0
- package/contracts/addresses-arbitrum.ts +8 -0
- package/contracts/addresses-mainnet.ts +7 -0
- package/contracts/addresses-polkadot.ts +9 -0
- package/contracts/addresses-sei.ts +9 -0
- package/contracts/rateX/BalancerHelper.ts +13 -0
- package/contracts/rateX/CamelotHelper.ts +13 -0
- package/contracts/rateX/SushiSwapHelper.ts +13 -0
- package/contracts/rateX/UniswapHelper.ts +19 -0
- package/contracts/rateX/UniswapV2Helper.ts +19 -0
- package/dexes/dexIdsList.ts +9 -0
- package/dexes/graph_queries/BalancerV2.ts +150 -0
- package/dexes/graph_queries/CamelotV2.ts +202 -0
- package/dexes/graph_queries/SushiSwapV2.ts +283 -0
- package/dexes/graph_queries/UniswapV2.ts +252 -0
- package/dexes/graph_queries/UniswapV3.ts +229 -0
- package/dexes/graph_queries/graphQueryFilters.ts +41 -0
- package/dexes/graph_queries/x_template.ts +67 -0
- package/dexes/pools/Balancer/BalancerState.ts +34 -0
- package/dexes/pools/Balancer/BalancerWeightedPool.ts +96 -0
- package/dexes/pools/Camelot.ts +164 -0
- package/dexes/pools/SushiSwapV2.ts +35 -0
- package/dexes/pools/UniswapV2.ts +36 -0
- package/dexes/pools/uniswap/UniswapV3.ts +40 -0
- package/dexes/pools/uniswap/testUniswapOffchainQuoter.ts +169 -0
- package/dexes/pools/uniswap/types.ts +174 -0
- package/dexes/pools/uniswap/uniswapOffchainQuoter.ts +173 -0
- package/dexes/pools/uniswap/uniswapState.ts +56 -0
- package/dexes/pools/uniswap/utils.ts +71 -0
- package/dist/contracts/abi/BalancerHelperAbi.d.ts +25 -0
- package/dist/contracts/abi/BalancerHelperAbi.js +4 -0
- package/dist/contracts/abi/CamelotHelperAbi.d.ts +45 -0
- package/dist/contracts/abi/CamelotHelperAbi.js +4 -0
- package/dist/contracts/abi/RateXAbi.d.ts +71 -0
- package/dist/contracts/abi/RateXAbi.js +485 -0
- package/dist/contracts/abi/SushiSwapHelperAbi.d.ts +45 -0
- package/dist/contracts/abi/SushiSwapHelperAbi.js +4 -0
- package/dist/contracts/abi/UniswapHelperAbi.d.ts +39 -0
- package/dist/contracts/abi/UniswapHelperAbi.js +4 -0
- package/dist/contracts/abi/UniswapV2HelperAbi.d.ts +45 -0
- package/dist/contracts/abi/UniswapV2HelperAbi.js +4 -0
- package/dist/contracts/addresses-arbitrum.d.ts +6 -0
- package/dist/contracts/addresses-arbitrum.js +10 -0
- package/dist/contracts/addresses-mainnet.d.ts +6 -0
- package/dist/contracts/addresses-mainnet.js +10 -0
- package/dist/contracts/addresses-polkadot.d.ts +6 -0
- package/dist/contracts/addresses-polkadot.js +10 -0
- package/dist/contracts/addresses-sei.d.ts +6 -0
- package/dist/contracts/addresses-sei.js +10 -0
- package/dist/contracts/rateX/BalancerHelper.d.ts +26 -0
- package/dist/contracts/rateX/BalancerHelper.js +14 -0
- package/dist/contracts/rateX/CamelotHelper.d.ts +46 -0
- package/dist/contracts/rateX/CamelotHelper.js +14 -0
- package/dist/contracts/rateX/SushiSwapHelper.d.ts +46 -0
- package/dist/contracts/rateX/SushiSwapHelper.js +14 -0
- package/dist/contracts/rateX/UniswapHelper.d.ts +40 -0
- package/dist/contracts/rateX/UniswapHelper.js +22 -0
- package/dist/contracts/rateX/UniswapV2Helper.d.ts +46 -0
- package/dist/contracts/rateX/UniswapV2Helper.js +22 -0
- package/dist/dexes/dexIdsList.d.ts +9 -0
- package/dist/dexes/dexIdsList.js +12 -0
- package/dist/dexes/graph_queries/BalancerV2.d.ts +14 -0
- package/dist/dexes/graph_queries/BalancerV2.js +141 -0
- package/dist/dexes/graph_queries/CamelotV2.d.ts +14 -0
- package/dist/dexes/graph_queries/CamelotV2.js +183 -0
- package/dist/dexes/graph_queries/SushiSwapV2.d.ts +14 -0
- package/dist/dexes/graph_queries/SushiSwapV2.js +263 -0
- package/dist/dexes/graph_queries/UniswapV2.d.ts +14 -0
- package/dist/dexes/graph_queries/UniswapV2.js +217 -0
- package/dist/dexes/graph_queries/UniswapV3.d.ts +14 -0
- package/dist/dexes/graph_queries/UniswapV3.js +198 -0
- package/dist/dexes/graph_queries/graphQueryFilters.d.ts +19 -0
- package/dist/dexes/graph_queries/graphQueryFilters.js +40 -0
- package/dist/dexes/graph_queries/x_template.d.ts +12 -0
- package/dist/dexes/graph_queries/x_template.js +57 -0
- package/dist/dexes/pools/Balancer/BalancerState.d.ts +6 -0
- package/dist/dexes/pools/Balancer/BalancerState.js +32 -0
- package/dist/dexes/pools/Balancer/BalancerWeightedPool.d.ts +12 -0
- package/dist/dexes/pools/Balancer/BalancerWeightedPool.js +109 -0
- package/dist/dexes/pools/Camelot.d.ts +12 -0
- package/dist/dexes/pools/Camelot.js +135 -0
- package/dist/dexes/pools/SushiSwapV2.d.ts +9 -0
- package/dist/dexes/pools/SushiSwapV2.js +34 -0
- package/dist/dexes/pools/UniswapV2.d.ts +9 -0
- package/dist/dexes/pools/UniswapV2.js +34 -0
- package/dist/dexes/pools/uniswap/UniswapV3.d.ts +7 -0
- package/dist/dexes/pools/uniswap/UniswapV3.js +36 -0
- package/dist/dexes/pools/uniswap/types.d.ts +76 -0
- package/dist/dexes/pools/uniswap/types.js +111 -0
- package/dist/dexes/pools/uniswap/uniswapOffchainQuoter.d.ts +13 -0
- package/dist/dexes/pools/uniswap/uniswapOffchainQuoter.js +121 -0
- package/dist/dexes/pools/uniswap/uniswapState.d.ts +14 -0
- package/dist/dexes/pools/uniswap/uniswapState.js +51 -0
- package/dist/dexes/pools/uniswap/utils.d.ts +3 -0
- package/dist/dexes/pools/uniswap/utils.js +41 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +41 -0
- package/dist/routes.d.ts +1 -0
- package/dist/routes.js +20 -0
- package/dist/routing/iterative_spliting/main.d.ts +3 -0
- package/dist/routing/iterative_spliting/main.js +104 -0
- package/dist/routing/iterative_spliting/multiHopSwap.d.ts +4 -0
- package/dist/routing/iterative_spliting/multiHopSwap.js +83 -0
- package/dist/routing/main.d.ts +2 -0
- package/dist/routing/main.js +22 -0
- package/dist/routing/uni_like_algo/algo_config.d.ts +2 -0
- package/dist/routing/uni_like_algo/algo_config.js +8 -0
- package/dist/routing/uni_like_algo/amount_distribution.d.ts +2 -0
- package/dist/routing/uni_like_algo/amount_distribution.js +17 -0
- package/dist/routing/uni_like_algo/compute_routes_backtrack.d.ts +3 -0
- package/dist/routing/uni_like_algo/compute_routes_backtrack.js +44 -0
- package/dist/routing/uni_like_algo/main.d.ts +2 -0
- package/dist/routing/uni_like_algo/main.js +49 -0
- package/dist/routing/uni_like_algo/routes_quoter.d.ts +21 -0
- package/dist/routing/uni_like_algo/routes_quoter.js +53 -0
- package/dist/routing/uni_like_algo/swap_finder.d.ts +25 -0
- package/dist/routing/uni_like_algo/swap_finder.js +154 -0
- package/dist/routing/uni_like_algo/types.d.ts +40 -0
- package/dist/routing/uni_like_algo/types.js +12 -0
- package/dist/swap/graph_communication.d.ts +5 -0
- package/dist/swap/graph_communication.js +187 -0
- package/dist/swap/my_local_storage.d.ts +8 -0
- package/dist/swap/my_local_storage.js +16 -0
- package/dist/utils/addresses.d.ts +24 -0
- package/dist/utils/addresses.js +60 -0
- package/dist/utils/math/fixed-points.d.ts +14 -0
- package/dist/utils/math/fixed-points.js +123 -0
- package/dist/utils/math/log-exp.d.ts +5 -0
- package/dist/utils/math/log-exp.js +385 -0
- package/dist/utils/math/math.d.ts +12 -0
- package/dist/utils/math/math.js +50 -0
- package/dist/utils/types/types.d.ts +51 -0
- package/dist/utils/types/types.js +25 -0
- package/dist/utils/utils.d.ts +20 -0
- package/dist/utils/utils.js +72 -0
- package/images/decenter_logo.png +0 -0
- package/index.ts +50 -0
- package/package.json +39 -0
- package/routes.ts +27 -0
- package/routing/iterative_spliting/main.ts +131 -0
- package/routing/iterative_spliting/multiHopSwap.ts +98 -0
- package/routing/main.ts +22 -0
- package/routing/uni_like_algo/algo_config.ts +7 -0
- package/routing/uni_like_algo/amount_distribution.ts +16 -0
- package/routing/uni_like_algo/compute_routes_backtrack.ts +81 -0
- package/routing/uni_like_algo/main.ts +65 -0
- package/routing/uni_like_algo/routes_quoter.ts +63 -0
- package/routing/uni_like_algo/swap_finder.ts +185 -0
- package/routing/uni_like_algo/types.ts +54 -0
- package/swap/graph_communication.ts +212 -0
- package/swap/my_local_storage.ts +27 -0
- package/tsconfig.json +26 -0
- package/utils/addresses.ts +64 -0
- package/utils/math/fixed-points.ts +88 -0
- package/utils/math/log-exp.ts +469 -0
- package/utils/math/math.ts +46 -0
- package/utils/types/types.ts +100 -0
- package/utils/utils.ts +125 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {AlgoParams, QueueItem, TQuoteUniLike, TRouteWithQuote} from "./types";
|
|
2
|
+
import Queue from "mnemonist/queue";
|
|
3
|
+
|
|
4
|
+
export class SwapFinder {
|
|
5
|
+
|
|
6
|
+
private algoParams: AlgoParams;
|
|
7
|
+
private percentagesToSortedQuotes: Map<number, TRouteWithQuote[]>;
|
|
8
|
+
private percentages: number[];
|
|
9
|
+
private amountIn: bigint;
|
|
10
|
+
private bestQuote: bigint;
|
|
11
|
+
private bestSwap: TRouteWithQuote[];
|
|
12
|
+
private queue: Queue<QueueItem>;
|
|
13
|
+
private numOfSplits: number;
|
|
14
|
+
|
|
15
|
+
public constructor(algoParams: AlgoParams, routesWithQuotes: TRouteWithQuote[], percentages: number[], amountIn: bigint) {
|
|
16
|
+
this.algoParams = algoParams;
|
|
17
|
+
this.percentages = percentages;
|
|
18
|
+
this.amountIn = amountIn;
|
|
19
|
+
this.percentagesToSortedQuotes = this.getSortedQuotes(routesWithQuotes);
|
|
20
|
+
|
|
21
|
+
this.bestQuote = BigInt(0);
|
|
22
|
+
this.bestSwap = [];
|
|
23
|
+
this.queue = new Queue<QueueItem>();
|
|
24
|
+
this.numOfSplits = 1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private readyToFinishSplitting() {
|
|
28
|
+
const maxSplitsReached: boolean = this.numOfSplits > this.algoParams.maxSplit;
|
|
29
|
+
const bestSwapNotImprovedWithNewSplit: boolean =
|
|
30
|
+
this.numOfSplits >= 3 && (this.bestSwap.length < this.numOfSplits - 1);
|
|
31
|
+
|
|
32
|
+
return maxSplitsReached || bestSwapNotImprovedWithNewSplit;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public findBestRoute(): TQuoteUniLike {
|
|
36
|
+
this.initBestQuoteAndSwapForFullAmount();
|
|
37
|
+
this.initQueueWithHighestQuotes();
|
|
38
|
+
|
|
39
|
+
while (this.queue.size > 0) {
|
|
40
|
+
let layer = this.queue.size;
|
|
41
|
+
this.numOfSplits++;
|
|
42
|
+
if (this.readyToFinishSplitting()) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
this.processLayer(layer);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this.addMissingAmountIn();
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
quote: this.bestQuote,
|
|
52
|
+
routes: this.bestSwap
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private addMissingAmountIn() {
|
|
57
|
+
const totalAmountIn = this.bestSwap.reduce((acc, route) => acc + route.amount.amountIn, BigInt(0));
|
|
58
|
+
const diff = this.amountIn - totalAmountIn;
|
|
59
|
+
if (diff > BigInt(0)) {
|
|
60
|
+
this.bestSwap[this.bestSwap.length - 1].amount.amountIn += diff;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private processLayer(layer: number) {
|
|
65
|
+
while (layer > 0) {
|
|
66
|
+
layer--;
|
|
67
|
+
const q = this.queue.dequeue()!;
|
|
68
|
+
this.processPairedItemsInLayer(q);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private processPairedItemsInLayer(q: QueueItem) {
|
|
73
|
+
for (let i = q.percentageIndex; i >= 0; --i) {
|
|
74
|
+
const percentage = this.percentages[i];
|
|
75
|
+
if (percentage > q.ramainingPercentage || !this.percentagesToSortedQuotes.has(percentage)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
this.processPairedItem(q, percentage, i);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private processPairedItem(q: QueueItem, percentage: number, index: number) {
|
|
83
|
+
const candidateRoutes = this.percentagesToSortedQuotes.get(percentage)!;
|
|
84
|
+
const routeWithQuote = this.findFirstRouteNotUsingUsedPools(q.currentRoutes, candidateRoutes);
|
|
85
|
+
if (!routeWithQuote) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const newRemainingPercentage = q.ramainingPercentage - percentage;
|
|
90
|
+
const newCurrentRoutes = [...q.currentRoutes, routeWithQuote];
|
|
91
|
+
|
|
92
|
+
if (newRemainingPercentage === 0) {
|
|
93
|
+
this.updateBestQuoteAndSwapIfBetter(newCurrentRoutes);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this.queue.enqueue({
|
|
97
|
+
percentageIndex: index,
|
|
98
|
+
currentRoutes: newCurrentRoutes,
|
|
99
|
+
ramainingPercentage: newRemainingPercentage
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private updateBestQuoteAndSwapIfBetter(currentRoutes: TRouteWithQuote[]) {
|
|
105
|
+
const quote = currentRoutes.reduce((acc, route) => acc + route.quote, BigInt(0));
|
|
106
|
+
if (quote > this.bestQuote) {
|
|
107
|
+
this.bestQuote = quote;
|
|
108
|
+
this.bestSwap = currentRoutes;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private initBestQuoteAndSwapForFullAmount() {
|
|
113
|
+
if (this.percentagesToSortedQuotes.has(100)) {
|
|
114
|
+
this.bestQuote = this.percentagesToSortedQuotes.get(100)![0].quote;
|
|
115
|
+
this.bestSwap = [this.percentagesToSortedQuotes.get(100)![0]];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private initQueueWithHighestQuotes() {
|
|
120
|
+
for (let i = this.percentages.length - 1; i >= 0; --i) {
|
|
121
|
+
this.insertHigestQuoteForPercentageIfExist(i);
|
|
122
|
+
this.insertSecondHigestQuoteForPercentageIfExist(i);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private insertHigestQuoteForPercentageIfExist(percentageIndex: number) {
|
|
127
|
+
const percentage = this.percentages[percentageIndex];
|
|
128
|
+
if (this.percentagesToSortedQuotes.has(percentage)) {
|
|
129
|
+
this.queue.enqueue({
|
|
130
|
+
percentageIndex: percentageIndex,
|
|
131
|
+
currentRoutes: [this.percentagesToSortedQuotes.get(percentage)![0]],
|
|
132
|
+
ramainingPercentage: 100 - percentage
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private insertSecondHigestQuoteForPercentageIfExist(percentageIndex: number) {
|
|
138
|
+
const percentage = this.percentages[percentageIndex];
|
|
139
|
+
if (this.percentagesToSortedQuotes.get(percentage)![1]) {
|
|
140
|
+
this.queue.enqueue({
|
|
141
|
+
percentageIndex: percentageIndex,
|
|
142
|
+
currentRoutes: [this.percentagesToSortedQuotes.get(percentage)![1]],
|
|
143
|
+
ramainingPercentage: 100 - percentage
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private getSortedQuotes(routeWithQuotes: TRouteWithQuote[]) {
|
|
149
|
+
const map = new Map<number, TRouteWithQuote[]>();
|
|
150
|
+
routeWithQuotes.forEach(routeWithQuote => {
|
|
151
|
+
const percentage = routeWithQuote.amount.percentage;
|
|
152
|
+
if (!map.has(percentage)) {
|
|
153
|
+
map.set(percentage, []);
|
|
154
|
+
}
|
|
155
|
+
map.get(percentage)?.push(routeWithQuote);
|
|
156
|
+
});
|
|
157
|
+
map.forEach((value, key) => {
|
|
158
|
+
value.sort((a, b) => {
|
|
159
|
+
return Number(b.quote - a.quote);
|
|
160
|
+
})
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return map;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private findFirstRouteNotUsingUsedPools(
|
|
167
|
+
usedRoutes: TRouteWithQuote[],
|
|
168
|
+
candidateRoutes: TRouteWithQuote[]
|
|
169
|
+
) {
|
|
170
|
+
const usedPoolsSet = new Set<string>();
|
|
171
|
+
usedRoutes.forEach(route => {
|
|
172
|
+
route.route.steps.forEach(step => usedPoolsSet.add(step.pool.poolId));
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
for (const candidateRoute of candidateRoutes) {
|
|
176
|
+
const candidatePools = candidateRoute.route.steps.map(step => step.pool.poolId);
|
|
177
|
+
if (candidatePools.some(pool => usedPoolsSet.has(pool))) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
return candidateRoute;
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {Pool} from "../../utils/types/types";
|
|
2
|
+
|
|
3
|
+
export interface TRouteStep {
|
|
4
|
+
pool: Pool,
|
|
5
|
+
tokenOut: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface TRoute {
|
|
9
|
+
steps: TRouteStep[],
|
|
10
|
+
tokenIn: string,
|
|
11
|
+
tokenOut: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface TRouteWithQuote {
|
|
15
|
+
route: TRoute,
|
|
16
|
+
quote: bigint,
|
|
17
|
+
amount: AmountPercentage
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AmountPercentage {
|
|
21
|
+
amountIn: bigint,
|
|
22
|
+
percentage: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class ComputeRoutesParams {
|
|
26
|
+
tokenIn: string;
|
|
27
|
+
tokenOut: string;
|
|
28
|
+
pools: Pool[];
|
|
29
|
+
maxHops: number;
|
|
30
|
+
|
|
31
|
+
constructor(tokenIn: string, tokenOut: string, pools: Pool[], maxHops: number) {
|
|
32
|
+
this.tokenIn = tokenIn;
|
|
33
|
+
this.tokenOut = tokenOut;
|
|
34
|
+
this.pools = pools;
|
|
35
|
+
this.maxHops = maxHops;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface QueueItem {
|
|
40
|
+
percentageIndex: number,
|
|
41
|
+
currentRoutes: TRouteWithQuote[],
|
|
42
|
+
ramainingPercentage: number
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface TQuoteUniLike {
|
|
46
|
+
routes: TRouteWithQuote[],
|
|
47
|
+
quote: bigint
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type AlgoParams = {
|
|
51
|
+
maxHops: number,
|
|
52
|
+
distributionPercentage: number,
|
|
53
|
+
maxSplit: number
|
|
54
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import Web3 from 'web3';
|
|
2
|
+
import { Pool, PoolInfo, DEXGraphFunctionality } from '../utils/types/types'
|
|
3
|
+
import { Dexes } from '../index';
|
|
4
|
+
import { myLocalStorage } from './my_local_storage';
|
|
5
|
+
import UniswapV2 from '../dexes/graph_queries/UniswapV2';
|
|
6
|
+
import SushiSwapV2 from '../dexes/graph_queries/SushiSwapV2';
|
|
7
|
+
import UniswapV3 from '../dexes/graph_queries/UniswapV3';
|
|
8
|
+
import BalancerV2 from '../dexes/graph_queries/BalancerV2';
|
|
9
|
+
import CamelotV2 from '../dexes/graph_queries/CamelotV2';
|
|
10
|
+
|
|
11
|
+
let initializedMainnet = false
|
|
12
|
+
let initializedArbitrum = false
|
|
13
|
+
let initializedSei = false;
|
|
14
|
+
let initializedPas = false;
|
|
15
|
+
|
|
16
|
+
let initializedDexes: DEXGraphFunctionality[] = []
|
|
17
|
+
let dexesPools: Map<DEXGraphFunctionality, PoolInfo[]> = new Map<DEXGraphFunctionality, PoolInfo[]>()
|
|
18
|
+
|
|
19
|
+
async function initializeDexes(chainId: number, graphApiKey: string, dexes: Array<Dexes>): Promise<void> {
|
|
20
|
+
try {
|
|
21
|
+
// Clear Previous Dex Graph Mappings and Initialized DEX array
|
|
22
|
+
dexesPools.clear()
|
|
23
|
+
initializedDexes = []
|
|
24
|
+
|
|
25
|
+
for (const dex of dexes) {
|
|
26
|
+
let Dex;
|
|
27
|
+
switch (dex) {
|
|
28
|
+
case Dexes.BALANCER:
|
|
29
|
+
Dex = BalancerV2;
|
|
30
|
+
break;
|
|
31
|
+
case Dexes.CAMELOT:
|
|
32
|
+
if (chainId === 1)
|
|
33
|
+
continue;
|
|
34
|
+
Dex = CamelotV2;
|
|
35
|
+
break;
|
|
36
|
+
case Dexes.SUSHISWAP_V2:
|
|
37
|
+
Dex = SushiSwapV2;
|
|
38
|
+
break;
|
|
39
|
+
case Dexes.UNISWAP_V2:
|
|
40
|
+
if (chainId === 42161)
|
|
41
|
+
continue;
|
|
42
|
+
Dex = UniswapV2;
|
|
43
|
+
break;
|
|
44
|
+
case Dexes.UNISWAP_V3:
|
|
45
|
+
Dex = UniswapV3;
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
throw Error("Invalid Dex value")
|
|
49
|
+
}
|
|
50
|
+
const dexInstance: DEXGraphFunctionality = Dex.initialize(myLocalStorage)
|
|
51
|
+
dexInstance.setEndpoint(chainId, graphApiKey)
|
|
52
|
+
initializedDexes.push(dexInstance)
|
|
53
|
+
dexesPools.set(dexInstance, [])
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error('Error reading directory dexes_graph:', err)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function checkInitializedDexes(chainId: number, graphApiKey: string, dexes: Array<Dexes>) {
|
|
61
|
+
if (chainId === 1 && !initializedMainnet) {
|
|
62
|
+
await initializeDexes(chainId, graphApiKey, dexes)
|
|
63
|
+
initializedArbitrum = false
|
|
64
|
+
initializedSei = false
|
|
65
|
+
initializedPas = false
|
|
66
|
+
initializedMainnet = true
|
|
67
|
+
}
|
|
68
|
+
if (chainId === 42161 && !initializedArbitrum) {
|
|
69
|
+
await initializeDexes(chainId, graphApiKey, dexes)
|
|
70
|
+
initializedMainnet = false
|
|
71
|
+
initializedSei = false
|
|
72
|
+
initializedPas = false
|
|
73
|
+
initializedArbitrum = true
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (chainId === 1329 && !initializedSei)
|
|
77
|
+
{
|
|
78
|
+
await initializeDexes(chainId, graphApiKey, dexes)
|
|
79
|
+
initializedMainnet = false
|
|
80
|
+
initializedArbitrum = false
|
|
81
|
+
initializedPas = false
|
|
82
|
+
initializedSei = true
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (chainId === 420420417 && !initializedPas)
|
|
86
|
+
{
|
|
87
|
+
await initializeDexes(chainId, graphApiKey, dexes)
|
|
88
|
+
initializedMainnet = false
|
|
89
|
+
initializedArbitrum = false
|
|
90
|
+
initializedSei = false
|
|
91
|
+
initializedPas = true
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Returns dictionary of dexes and their poolIds for token1 and token2:
|
|
97
|
+
* UniswapV3: [poolId1, poolId2, ...],
|
|
98
|
+
* SushiSwapV2: [poolId1, poolId2, ...]
|
|
99
|
+
*/
|
|
100
|
+
async function getPoolIdsForTokenPairs(tokenA: string, tokenB: string, numPools: number = 3, chainId: number, graphApiKey: string, dexes: Array<Dexes>): Promise<void> {
|
|
101
|
+
await checkInitializedDexes(chainId, graphApiKey, dexes)
|
|
102
|
+
|
|
103
|
+
const allPoolsPromises = initializedDexes.map((dex) => dex.getPoolsWithTokenPair(tokenA, tokenB, numPools))
|
|
104
|
+
const allPoolsResults = await Promise.all(allPoolsPromises)
|
|
105
|
+
|
|
106
|
+
initializedDexes.forEach((dex, index) => {
|
|
107
|
+
const pools = allPoolsResults[index]
|
|
108
|
+
if (dexesPools.has(dex)) {
|
|
109
|
+
dexesPools.get(dex)?.push(...pools)
|
|
110
|
+
} else {
|
|
111
|
+
dexesPools.set(dex, pools)
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Get pools from each dex in initializedDexes list that have token as one of the tokens in the pool
|
|
117
|
+
* @param token: token address to match (for now the chain is Arbitrum -> param for the future)
|
|
118
|
+
* @param numPools: number of pools to return from each dex
|
|
119
|
+
* @param amountIn: amount of token1 to swap (in wei) - currently unused
|
|
120
|
+
* @returns: list of poolIds
|
|
121
|
+
*/
|
|
122
|
+
async function getPoolIdsForToken(token: string, numPools: number = 5, chainId: number, graphApiKey: string, dexes: Array<Dexes>): Promise<void> {
|
|
123
|
+
await checkInitializedDexes(chainId, graphApiKey, dexes)
|
|
124
|
+
|
|
125
|
+
const allPoolsPromises = initializedDexes.map((dex) => dex.getPoolsWithToken(token, numPools))
|
|
126
|
+
const allPoolsResults = await Promise.all(allPoolsPromises)
|
|
127
|
+
|
|
128
|
+
initializedDexes.forEach((dex, index) => {
|
|
129
|
+
const pools = allPoolsResults[index]
|
|
130
|
+
if (dexesPools.has(dex)) {
|
|
131
|
+
dexesPools.get(dex)?.push(...pools)
|
|
132
|
+
} else {
|
|
133
|
+
dexesPools.set(dex, pools)
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Get top pools from each dex in initializedDexes list - returns a list of poolIds
|
|
139
|
+
* @param numPools: number of pools to return from each dex
|
|
140
|
+
* @param amountIn: amount of token1 to swap (in wei) - currently unused
|
|
141
|
+
* @returns: list of poolIds
|
|
142
|
+
*/
|
|
143
|
+
async function getTopPools(numPools: number = 5, chainId: number, graphApiKey: string, dexes: Array<Dexes>): Promise<void> {
|
|
144
|
+
await checkInitializedDexes(chainId, graphApiKey, dexes)
|
|
145
|
+
|
|
146
|
+
const allPoolsPromises = initializedDexes.map((dex) => dex.getTopPools(numPools))
|
|
147
|
+
const allPoolsResults = await Promise.all(allPoolsPromises)
|
|
148
|
+
|
|
149
|
+
initializedDexes.forEach((dex, index) => {
|
|
150
|
+
const pools = allPoolsResults[index]
|
|
151
|
+
if (dexesPools.has(dex)) {
|
|
152
|
+
dexesPools.get(dex)?.push(...pools)
|
|
153
|
+
} else {
|
|
154
|
+
dexesPools.set(dex, pools)
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* We are fetching pools from multiple dexes, so we might get duplicate pools
|
|
160
|
+
* top numTopPools pools for tokenFrom and tokenTo are fetched from each DEX
|
|
161
|
+
* top numTopPools by TVL from each DEX
|
|
162
|
+
* top numTopPools that contain tokenFrom and tokenTo from each DEX (possible direct swap)
|
|
163
|
+
*/
|
|
164
|
+
async function fetchPoolsData(
|
|
165
|
+
tokenFrom: string,
|
|
166
|
+
tokenTo: string,
|
|
167
|
+
numFromToPools: number = 5,
|
|
168
|
+
numTopPools: number = 5,
|
|
169
|
+
chainId: number,
|
|
170
|
+
rpcProvider: Web3,
|
|
171
|
+
graphApiKey: string,
|
|
172
|
+
dexes: Array<Dexes>
|
|
173
|
+
): Promise<Pool[]> {
|
|
174
|
+
let pools: Pool[] = []
|
|
175
|
+
dexesPools.forEach((poolInfos: PoolInfo[], dex: DEXGraphFunctionality) => {
|
|
176
|
+
dexesPools.set(dex, [])
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
await checkInitializedDexes(chainId, graphApiKey, dexes)
|
|
180
|
+
|
|
181
|
+
// call Graph API
|
|
182
|
+
const promises: Promise<void>[] = []
|
|
183
|
+
promises.push(getPoolIdsForToken(tokenFrom, numFromToPools, chainId, graphApiKey, dexes))
|
|
184
|
+
promises.push(getPoolIdsForToken(tokenTo, numFromToPools, chainId, graphApiKey, dexes))
|
|
185
|
+
promises.push(getTopPools(numTopPools, chainId, graphApiKey, dexes))
|
|
186
|
+
promises.push(getPoolIdsForTokenPairs(tokenFrom, tokenTo, numFromToPools, chainId, graphApiKey, dexes))
|
|
187
|
+
await Promise.all(promises)
|
|
188
|
+
filterDuplicatePools()
|
|
189
|
+
|
|
190
|
+
// call Solidity for additional pool data
|
|
191
|
+
const dexPoolsPromises: Promise<Pool[]>[] = []
|
|
192
|
+
for (let [dex, poolInfos] of dexesPools.entries()) {
|
|
193
|
+
dexPoolsPromises.push(dex.getAdditionalPoolDataFromSolidity(poolInfos, rpcProvider))
|
|
194
|
+
}
|
|
195
|
+
const allPoolsData = await Promise.all(dexPoolsPromises)
|
|
196
|
+
allPoolsData.forEach((poolsData: Pool[]) => {
|
|
197
|
+
pools.push(...poolsData)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
return pools
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function filterDuplicatePools(): void {
|
|
204
|
+
dexesPools.forEach((poolInfos: PoolInfo[], dex: DEXGraphFunctionality, self) => {
|
|
205
|
+
const filteredPoolInfos = poolInfos.filter((poolInfo: PoolInfo, index: number, allPoolInfos: PoolInfo[]) => {
|
|
206
|
+
return allPoolInfos.findIndex((pool2) => pool2.poolId === poolInfo.poolId) === index
|
|
207
|
+
})
|
|
208
|
+
self.set(dex, filteredPoolInfos)
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export { fetchPoolsData }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Pool } from "../utils/types/types";
|
|
2
|
+
|
|
3
|
+
interface ILocalStorage {
|
|
4
|
+
setItem(key: string, value: Pool): void;
|
|
5
|
+
getItem(key: string): Pool | null;
|
|
6
|
+
removeItem(key: string): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const values: { [key: string]: Pool } = {};
|
|
10
|
+
|
|
11
|
+
class MockLocalStorage implements ILocalStorage {
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
setItem(key: string, value: Pool): void {
|
|
15
|
+
values[key] = value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getItem(key: string): Pool | null {
|
|
19
|
+
return values[key] || null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
removeItem(key: string): void {
|
|
23
|
+
delete values[key];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const myLocalStorage: ILocalStorage = new MockLocalStorage();
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2019",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"outDir": "./dist",
|
|
13
|
+
"rootDir": ".",
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": false,
|
|
16
|
+
"noEmitOnError": true
|
|
17
|
+
},
|
|
18
|
+
"include": [
|
|
19
|
+
"."
|
|
20
|
+
],
|
|
21
|
+
"exclude": [
|
|
22
|
+
"node_modules",
|
|
23
|
+
"dist",
|
|
24
|
+
"./dexes/pools/uniswap/testUniswapOffchainQuoter.ts"
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// hardcode it like this for now
|
|
2
|
+
export const addresses = {
|
|
3
|
+
|
|
4
|
+
// Acutally used.
|
|
5
|
+
name: "sei",
|
|
6
|
+
uniQuoterV2: "0x38F759cf0Af1D0dcAEd723a3967A3B658738eDe9",
|
|
7
|
+
|
|
8
|
+
wethToken: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
9
|
+
daiToken: "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1",
|
|
10
|
+
usdtToken: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
|
|
11
|
+
wbtcToken: "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f",
|
|
12
|
+
usdcToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
13
|
+
uniToken: "0xFa7F8980b0f1E64A2062791cc3b0871572f1F7f0",
|
|
14
|
+
linkToken: "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4",
|
|
15
|
+
usdceToken: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8",
|
|
16
|
+
gmxToken: "0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a",
|
|
17
|
+
|
|
18
|
+
sushiRouter: "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506",
|
|
19
|
+
sushiFactory: "0xc35DADB65012eC5796536bD9864eD8773aBc74C4",
|
|
20
|
+
|
|
21
|
+
// uniQuoter: "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
|
|
22
|
+
// uniQuoterV2: "0x61fFE014bA17989E743c5F6cB21bF9697530B21e",
|
|
23
|
+
// uniRouter: "0xE592427A0AEce92De3Edee1F18E0157C05861564",
|
|
24
|
+
|
|
25
|
+
univ3_wbtc_eth_pool_0_05: "0x2f5e87C9312fa29aed5c179E456625D79015299c", // 0.05 fee
|
|
26
|
+
univ3_wbtc_eth_pool_0_3: "0x149e36E72726e0BceA5c59d40df2c43F60f5A22D", // 0.3 fee
|
|
27
|
+
sushi_wbtc_eth_pool: "0x515e252b2b5c22b4b2b6Df66c2eBeeA871AA4d69", // 0.3 fee always
|
|
28
|
+
gmx_usdc_pool_0_1: "0x0A36952Fb8C8dc6daeFB2fADb07C5212f560880e",
|
|
29
|
+
uni_weth_pool: "0xC24f7d8E51A64dc1238880BD00bb961D54cbeb29",
|
|
30
|
+
weth_link_pool: "0x468b88941e7Cc0B88c1869d68ab6b570bCEF62Ff",
|
|
31
|
+
dai_usdce_pool_0_0_1: "0xF0428617433652c9dc6D1093A42AdFbF30D29f74",
|
|
32
|
+
|
|
33
|
+
impersonate_weth: "0x0df5dfd95966753f01cb80e76dc20ea958238c46",
|
|
34
|
+
impersonate_dai: "0xd85e038593d7a098614721eae955ec2022b9b91b"
|
|
35
|
+
|
|
36
|
+
// name: "arbitrum",
|
|
37
|
+
//
|
|
38
|
+
// wethToken: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
39
|
+
// daiToken: "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1",
|
|
40
|
+
// usdtToken: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
|
|
41
|
+
// wbtcToken: "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f",
|
|
42
|
+
// usdcToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
43
|
+
// uniToken: "0xFa7F8980b0f1E64A2062791cc3b0871572f1F7f0",
|
|
44
|
+
// linkToken: "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4",
|
|
45
|
+
// usdceToken: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8",
|
|
46
|
+
// gmxToken: "0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a",
|
|
47
|
+
//
|
|
48
|
+
// sushiRouter: "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506",
|
|
49
|
+
// sushiFactory: "0xc35DADB65012eC5796536bD9864eD8773aBc74C4",
|
|
50
|
+
//
|
|
51
|
+
// uniQuoter: "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
|
|
52
|
+
// uniQuoterV2: "0x61fFE014bA17989E743c5F6cB21bF9697530B21e",
|
|
53
|
+
// uniRouter: "0xE592427A0AEce92De3Edee1F18E0157C05861564",
|
|
54
|
+
// univ3_wbtc_eth_pool_0_05: "0x2f5e87C9312fa29aed5c179E456625D79015299c", // 0.05 fee
|
|
55
|
+
// univ3_wbtc_eth_pool_0_3: "0x149e36E72726e0BceA5c59d40df2c43F60f5A22D", // 0.3 fee
|
|
56
|
+
// sushi_wbtc_eth_pool: "0x515e252b2b5c22b4b2b6Df66c2eBeeA871AA4d69", // 0.3 fee always
|
|
57
|
+
// gmx_usdc_pool_0_1: "0x0A36952Fb8C8dc6daeFB2fADb07C5212f560880e",
|
|
58
|
+
// uni_weth_pool: "0xC24f7d8E51A64dc1238880BD00bb961D54cbeb29",
|
|
59
|
+
// weth_link_pool: "0x468b88941e7Cc0B88c1869d68ab6b570bCEF62Ff",
|
|
60
|
+
// dai_usdce_pool_0_0_1: "0xF0428617433652c9dc6D1093A42AdFbF30D29f74",
|
|
61
|
+
//
|
|
62
|
+
// impersonate_weth: "0x0df5dfd95966753f01cb80e76dc20ea958238c46",
|
|
63
|
+
// impersonate_dai: "0xd85e038593d7a098614721eae955ec2022b9b91b"
|
|
64
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Ported from Solidity:
|
|
2
|
+
// https://github.com/balancer-labs/balancer-core-v2/blob/70843e6a61ad11208c1cfabf5cfe15be216ca8d3/pkg/solidity-utils/contracts/math/FixedPoint.sol
|
|
3
|
+
|
|
4
|
+
import BigNumber from "bignumber.js"
|
|
5
|
+
import * as logExp from "./log-exp"
|
|
6
|
+
|
|
7
|
+
export const ZERO = new BigNumber(0)
|
|
8
|
+
export const ONE = new BigNumber("1000000000000000000") // 10^18
|
|
9
|
+
|
|
10
|
+
export const MAX_POW_RELATIVE_ERROR = new BigNumber(10000) // 10^(-14)
|
|
11
|
+
|
|
12
|
+
// Minimum base for the power function when the exponent is 'free' (larger than ONE)
|
|
13
|
+
export const MIN_POW_BASE_FREE_EXPONENT = new BigNumber("700000000000000000") // 0.7e18
|
|
14
|
+
|
|
15
|
+
export const add = (a: BigNumber, b: BigNumber): BigNumber => {
|
|
16
|
+
// Fixed Point addition is the same as regular checked addition
|
|
17
|
+
return a.plus(b)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const sub = (a: BigNumber, b: BigNumber): BigNumber => {
|
|
21
|
+
// Fixed Point subtraction is the same as regular checked subtraction
|
|
22
|
+
if (b.gt(a))
|
|
23
|
+
throw new Error("SUB_OVERFLOW")
|
|
24
|
+
return a.minus(b)
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const mulDown = (a: BigNumber, b: BigNumber): BigNumber => {
|
|
28
|
+
return a.times(b).idiv(ONE)
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const mulUp = (a: BigNumber, b: BigNumber): BigNumber => {
|
|
32
|
+
const product = a.times(b)
|
|
33
|
+
if (product.isZero()) {
|
|
34
|
+
return product
|
|
35
|
+
} else {
|
|
36
|
+
// The traditional divUp formula is:
|
|
37
|
+
// divUp(x, y) := (x + y - 1) / y
|
|
38
|
+
// To avoid intermediate overflow in the addition, we distribute the division and get:
|
|
39
|
+
// divUp(x, y) := (x - 1) / y + 1
|
|
40
|
+
// Note that this requires x != 0, which we already tested for
|
|
41
|
+
return product.minus(new BigNumber(1)).idiv(ONE).plus(new BigNumber(1))
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const divDown = (a: BigNumber, b: BigNumber): BigNumber => {
|
|
46
|
+
if (b.isZero())
|
|
47
|
+
throw new Error("ZERO_DIVISION");
|
|
48
|
+
if (a.isZero())
|
|
49
|
+
return a
|
|
50
|
+
else
|
|
51
|
+
return a.times(ONE).idiv(b);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const divUp = (a: BigNumber, b: BigNumber): BigNumber => {
|
|
55
|
+
if (b.isZero())
|
|
56
|
+
throw new Error("ZERO_DIVISION");
|
|
57
|
+
if (a.isZero())
|
|
58
|
+
return a;
|
|
59
|
+
else {
|
|
60
|
+
// The traditional divUp formula is:
|
|
61
|
+
// divUp(x, y) := (x + y - 1) / y
|
|
62
|
+
// To avoid intermediate overflow in the addition, we distribute the division and get:
|
|
63
|
+
// divUp(x, y) := (x - 1) / y + 1
|
|
64
|
+
// Note that this requires x != 0, which we already tested for.
|
|
65
|
+
return a.times(ONE).minus(new BigNumber(1)).idiv(b).plus(new BigNumber(1));
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const powDown = (x: BigNumber, y: BigNumber): BigNumber => {
|
|
70
|
+
|
|
71
|
+
const raw = logExp.pow(x, y);
|
|
72
|
+
const maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), new BigNumber(1));
|
|
73
|
+
if (raw.lt(maxError))
|
|
74
|
+
return new BigNumber(0)
|
|
75
|
+
else {
|
|
76
|
+
return sub(raw, maxError)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const powUp = (x: BigNumber, y: BigNumber): BigNumber => {
|
|
81
|
+
const raw = logExp.pow(x, y)
|
|
82
|
+
const maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), new BigNumber(1))
|
|
83
|
+
return add(raw, maxError)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const complement = (x: BigNumber): BigNumber => {
|
|
87
|
+
return x.lt(ONE) ? ONE.minus(x) : new BigNumber(0)
|
|
88
|
+
}
|