@alcorexchange/alcor-swap-sdk 1.0.26 → 1.0.28
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/build/entities/fractions/currencyAmount.d.ts +6 -0
- package/build/entities/fractions/currencyAmount.js +27 -0
- package/build/entities/pool.d.ts +26 -2
- package/build/entities/pool.js +113 -32
- package/build/entities/route.d.ts +20 -0
- package/build/entities/route.js +73 -6
- package/build/entities/tick.d.ts +2 -0
- package/build/entities/tick.js +24 -0
- package/build/entities/tickListDataProvider.d.ts +3 -1
- package/build/entities/tickListDataProvider.js +6 -0
- package/build/entities/token.d.ts +6 -0
- package/build/entities/token.js +10 -0
- package/build/entities/trade.js +4 -4
- package/build/utils/computeAllRoutes.d.ts +3 -0
- package/build/utils/computeAllRoutes.js +32 -1
- package/package.json +2 -1
- package/src/entities/fractions/currencyAmount.ts +32 -0
- package/src/entities/pool.ts +130 -39
- package/src/entities/route.ts +104 -26
- package/src/entities/tick.ts +26 -0
- package/src/entities/tickListDataProvider.ts +9 -1
- package/src/entities/token.ts +12 -0
- package/src/entities/trade.ts +4 -4
- package/src/utils/computeAllRoutes.ts +60 -0
- package/test/pool.test.ts +5 -5
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import JSBI from "jsbi";
|
|
2
3
|
import { Currency } from "../currency";
|
|
4
|
+
import { Token } from "../token";
|
|
3
5
|
import { Fraction } from "./fraction";
|
|
4
6
|
import { BigintIsh, Rounding } from "../../internalConstants";
|
|
5
7
|
export declare class CurrencyAmount<T extends Currency> extends Fraction {
|
|
@@ -29,4 +31,8 @@ export declare class CurrencyAmount<T extends Currency> extends Fraction {
|
|
|
29
31
|
toAsset(...args: any[]): string;
|
|
30
32
|
toExtendedAsset(...args: any[]): string;
|
|
31
33
|
toExtendedAssetObject(...args: any[]): object;
|
|
34
|
+
static toJSON<T extends Currency>(amount: CurrencyAmount<T>): object;
|
|
35
|
+
static fromJSON(json: any): CurrencyAmount<Token>;
|
|
36
|
+
static toBuffer<T extends Currency>(amount: CurrencyAmount<T>): object;
|
|
37
|
+
static fromBuffer(buffer: Buffer): CurrencyAmount<Token>;
|
|
32
38
|
}
|
|
@@ -4,8 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.CurrencyAmount = void 0;
|
|
7
|
+
const msgpack_lite_1 = __importDefault(require("msgpack-lite"));
|
|
7
8
|
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
|
|
8
9
|
const jsbi_1 = __importDefault(require("jsbi"));
|
|
10
|
+
const token_1 = require("../token");
|
|
9
11
|
const fraction_1 = require("./fraction");
|
|
10
12
|
const big_js_1 = __importDefault(require("big.js"));
|
|
11
13
|
const toformat_1 = __importDefault(require("toformat"));
|
|
@@ -79,5 +81,30 @@ class CurrencyAmount extends fraction_1.Fraction {
|
|
|
79
81
|
toExtendedAssetObject(...args) {
|
|
80
82
|
return { quantity: `${this.toFixed(...args)} ${this.currency.symbol}`, contract: this.currency.contract };
|
|
81
83
|
}
|
|
84
|
+
static toJSON(amount) {
|
|
85
|
+
return {
|
|
86
|
+
currency: token_1.Token.toJSON(amount.currency),
|
|
87
|
+
numerator: amount.numerator.toString(),
|
|
88
|
+
denominator: amount.denominator.toString(),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
static fromJSON(json) {
|
|
92
|
+
const currency = token_1.Token.fromJSON(json.currency);
|
|
93
|
+
const numerator = jsbi_1.default.BigInt(json.numerator);
|
|
94
|
+
const denominator = jsbi_1.default.BigInt(json.denominator);
|
|
95
|
+
return new CurrencyAmount(currency, numerator, denominator);
|
|
96
|
+
}
|
|
97
|
+
static toBuffer(amount) {
|
|
98
|
+
const json = {
|
|
99
|
+
currency: token_1.Token.toJSON(amount.currency),
|
|
100
|
+
numerator: amount.numerator.toString(),
|
|
101
|
+
denominator: amount.denominator.toString(),
|
|
102
|
+
};
|
|
103
|
+
return msgpack_lite_1.default.encode(json);
|
|
104
|
+
}
|
|
105
|
+
static fromBuffer(buffer) {
|
|
106
|
+
const json = msgpack_lite_1.default.decode(buffer);
|
|
107
|
+
return this.fromJSON(json);
|
|
108
|
+
}
|
|
82
109
|
}
|
|
83
110
|
exports.CurrencyAmount = CurrencyAmount;
|
package/build/entities/pool.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { CurrencyAmount, Price } from "./fractions";
|
|
2
3
|
import { Token } from "./token";
|
|
3
4
|
import { BigintIsh, FeeAmount } from "../internalConstants";
|
|
@@ -30,6 +31,11 @@ export declare class Pool {
|
|
|
30
31
|
readonly feeGrowthGlobalAX64: JSBI;
|
|
31
32
|
readonly feeGrowthGlobalBX64: JSBI;
|
|
32
33
|
readonly tickDataProvider: TickDataProvider;
|
|
34
|
+
json?: any;
|
|
35
|
+
buffer?: Buffer;
|
|
36
|
+
bufferHash?: string;
|
|
37
|
+
static hashToPoolMap: Map<string, Pool>;
|
|
38
|
+
static idToPoolMap: Map<number, Pool>;
|
|
33
39
|
private _tokenAPrice?;
|
|
34
40
|
private _tokenBPrice?;
|
|
35
41
|
/**
|
|
@@ -69,14 +75,14 @@ export declare class Pool {
|
|
|
69
75
|
* @param sqrtPriceLimitX64 The Q64.96 sqrt price limit
|
|
70
76
|
* @returns The output amount and the pool with updated state
|
|
71
77
|
*/
|
|
72
|
-
getOutputAmount(inputAmount: CurrencyAmount<Token>, sqrtPriceLimitX64?: JSBI):
|
|
78
|
+
getOutputAmount(inputAmount: CurrencyAmount<Token>, sqrtPriceLimitX64?: JSBI): CurrencyAmount<Token>;
|
|
73
79
|
/**
|
|
74
80
|
* Given a desired output amount of a token, return the computed input amount and a pool with state updated after the trade
|
|
75
81
|
* @param outputAmount the output amount for which to quote the input amount
|
|
76
82
|
* @param sqrtPriceLimitX64 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this value after the swap. If one for zero, the price cannot be greater than this value after the swap
|
|
77
83
|
* @returns The input amount and the pool with updated state
|
|
78
84
|
*/
|
|
79
|
-
getInputAmount(outputAmount: CurrencyAmount<Token>, sqrtPriceLimitX64?: JSBI):
|
|
85
|
+
getInputAmount(outputAmount: CurrencyAmount<Token>, sqrtPriceLimitX64?: JSBI): CurrencyAmount<Token>;
|
|
80
86
|
/**
|
|
81
87
|
* Executes a swap
|
|
82
88
|
* @param zeroForOne Whether the amount in is tokenA or tokenB
|
|
@@ -89,4 +95,22 @@ export declare class Pool {
|
|
|
89
95
|
*/
|
|
90
96
|
private swap;
|
|
91
97
|
get tickSpacing(): number;
|
|
98
|
+
static toJSON(pool: Pool): object;
|
|
99
|
+
static fromJSON(json: any): Pool;
|
|
100
|
+
/**
|
|
101
|
+
* Converts the pool to a Buffer using msgpack encoding.
|
|
102
|
+
* @param {Pool} pool - The pool instance to convert.
|
|
103
|
+
* @returns {Buffer} The encoded buffer.
|
|
104
|
+
*/
|
|
105
|
+
static toBuffer(pool: Pool): Buffer;
|
|
106
|
+
/**
|
|
107
|
+
* Creates a Pool instance from a Buffer or serialized data.
|
|
108
|
+
* @param {Buffer | any} data - The buffer or serialized data.
|
|
109
|
+
* @returns {Pool} The pool instance.
|
|
110
|
+
*/
|
|
111
|
+
static fromBuffer(data: Buffer | any): Pool;
|
|
112
|
+
static fromId(id: number): Pool;
|
|
113
|
+
static createHash(buffer: Buffer, pool?: Pool): string;
|
|
114
|
+
static hashEquals(pool: Pool, hash: string): boolean;
|
|
115
|
+
equals(other: Pool): boolean;
|
|
92
116
|
}
|
package/build/entities/pool.js
CHANGED
|
@@ -4,7 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Pool = void 0;
|
|
7
|
+
const msgpack_lite_1 = __importDefault(require("msgpack-lite"));
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
7
9
|
const fractions_1 = require("./fractions");
|
|
10
|
+
const token_1 = require("./token");
|
|
8
11
|
const internalConstants_1 = require("../internalConstants");
|
|
9
12
|
const jsbi_1 = __importDefault(require("jsbi"));
|
|
10
13
|
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
|
|
@@ -93,23 +96,9 @@ class Pool {
|
|
|
93
96
|
getOutputAmount(inputAmount, sqrtPriceLimitX64) {
|
|
94
97
|
(0, tiny_invariant_1.default)(this.involvesToken(inputAmount.currency), "TOKEN");
|
|
95
98
|
const zeroForOne = inputAmount.currency.equals(this.tokenA);
|
|
96
|
-
const { amountCalculated: outputAmount,
|
|
99
|
+
const { amountCalculated: outputAmount, } = this.swap(zeroForOne, inputAmount.quotient, sqrtPriceLimitX64);
|
|
97
100
|
const outputToken = zeroForOne ? this.tokenB : this.tokenA;
|
|
98
|
-
return
|
|
99
|
-
fractions_1.CurrencyAmount.fromRawAmount(outputToken, jsbi_1.default.multiply(outputAmount, internalConstants_2.NEGATIVE_ONE)),
|
|
100
|
-
new Pool({
|
|
101
|
-
id: this.id,
|
|
102
|
-
tokenA: this.tokenA,
|
|
103
|
-
tokenB: this.tokenB,
|
|
104
|
-
fee: this.fee,
|
|
105
|
-
sqrtPriceX64,
|
|
106
|
-
liquidity,
|
|
107
|
-
tickCurrent,
|
|
108
|
-
ticks: this.tickDataProvider,
|
|
109
|
-
feeGrowthGlobalAX64: this.feeGrowthGlobalAX64,
|
|
110
|
-
feeGrowthGlobalBX64: this.feeGrowthGlobalBX64,
|
|
111
|
-
})
|
|
112
|
-
];
|
|
101
|
+
return fractions_1.CurrencyAmount.fromRawAmount(outputToken, jsbi_1.default.multiply(outputAmount, internalConstants_2.NEGATIVE_ONE));
|
|
113
102
|
}
|
|
114
103
|
/**
|
|
115
104
|
* Given a desired output amount of a token, return the computed input amount and a pool with state updated after the trade
|
|
@@ -119,23 +108,9 @@ class Pool {
|
|
|
119
108
|
*/
|
|
120
109
|
getInputAmount(outputAmount, sqrtPriceLimitX64) {
|
|
121
110
|
const zeroForOne = outputAmount.currency.equals(this.tokenB);
|
|
122
|
-
const { amountCalculated: inputAmount,
|
|
111
|
+
const { amountCalculated: inputAmount, } = this.swap(zeroForOne, jsbi_1.default.multiply(outputAmount.quotient, internalConstants_2.NEGATIVE_ONE), sqrtPriceLimitX64);
|
|
123
112
|
const inputToken = zeroForOne ? this.tokenA : this.tokenB;
|
|
124
|
-
return
|
|
125
|
-
fractions_1.CurrencyAmount.fromRawAmount(inputToken, inputAmount),
|
|
126
|
-
new Pool({
|
|
127
|
-
id: this.id,
|
|
128
|
-
tokenA: this.tokenA,
|
|
129
|
-
tokenB: this.tokenB,
|
|
130
|
-
fee: this.fee,
|
|
131
|
-
sqrtPriceX64,
|
|
132
|
-
liquidity,
|
|
133
|
-
tickCurrent,
|
|
134
|
-
ticks: this.tickDataProvider,
|
|
135
|
-
feeGrowthGlobalAX64: this.feeGrowthGlobalAX64,
|
|
136
|
-
feeGrowthGlobalBX64: this.feeGrowthGlobalBX64,
|
|
137
|
-
}),
|
|
138
|
-
];
|
|
113
|
+
return fractions_1.CurrencyAmount.fromRawAmount(inputToken, inputAmount);
|
|
139
114
|
}
|
|
140
115
|
/**
|
|
141
116
|
* Executes a swap
|
|
@@ -229,5 +204,111 @@ class Pool {
|
|
|
229
204
|
get tickSpacing() {
|
|
230
205
|
return internalConstants_1.TICK_SPACINGS[this.fee];
|
|
231
206
|
}
|
|
207
|
+
static toJSON(pool) {
|
|
208
|
+
if (pool.json)
|
|
209
|
+
return pool.json;
|
|
210
|
+
pool.json = {
|
|
211
|
+
id: pool.id,
|
|
212
|
+
tokenA: token_1.Token.toJSON(pool.tokenA),
|
|
213
|
+
tokenB: token_1.Token.toJSON(pool.tokenB),
|
|
214
|
+
fee: pool.fee,
|
|
215
|
+
sqrtPriceX64: pool.sqrtPriceX64.toString(),
|
|
216
|
+
liquidity: pool.liquidity.toString(),
|
|
217
|
+
tickCurrent: pool.tickCurrent,
|
|
218
|
+
feeGrowthGlobalAX64: pool.feeGrowthGlobalAX64.toString(),
|
|
219
|
+
feeGrowthGlobalBX64: pool.feeGrowthGlobalBX64.toString(),
|
|
220
|
+
tickDataProvider: tickListDataProvider_1.TickListDataProvider.toJSON(pool.tickDataProvider.ticks)
|
|
221
|
+
};
|
|
222
|
+
return pool.json;
|
|
223
|
+
}
|
|
224
|
+
static fromJSON(json) {
|
|
225
|
+
return new Pool({
|
|
226
|
+
id: json.id,
|
|
227
|
+
tokenA: token_1.Token.fromJSON(json.tokenA),
|
|
228
|
+
tokenB: token_1.Token.fromJSON(json.tokenB),
|
|
229
|
+
fee: json.fee,
|
|
230
|
+
sqrtPriceX64: jsbi_1.default.BigInt(json.sqrtPriceX64),
|
|
231
|
+
liquidity: jsbi_1.default.BigInt(json.liquidity),
|
|
232
|
+
tickCurrent: json.tickCurrent,
|
|
233
|
+
feeGrowthGlobalAX64: jsbi_1.default.BigInt(json.feeGrowthGlobalAX64),
|
|
234
|
+
feeGrowthGlobalBX64: jsbi_1.default.BigInt(json.feeGrowthGlobalBX64),
|
|
235
|
+
ticks: tickListDataProvider_1.TickListDataProvider.fromJSON(json.tickDataProvider)
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Converts the pool to a Buffer using msgpack encoding.
|
|
240
|
+
* @param {Pool} pool - The pool instance to convert.
|
|
241
|
+
* @returns {Buffer} The encoded buffer.
|
|
242
|
+
*/
|
|
243
|
+
static toBuffer(pool) {
|
|
244
|
+
if (pool.buffer)
|
|
245
|
+
return pool.buffer;
|
|
246
|
+
const json = Pool.toJSON(pool);
|
|
247
|
+
pool.buffer = msgpack_lite_1.default.encode(json);
|
|
248
|
+
pool.bufferHash = Pool.createHash(pool.buffer);
|
|
249
|
+
return pool.buffer;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Creates a Pool instance from a Buffer or serialized data.
|
|
253
|
+
* @param {Buffer | any} data - The buffer or serialized data.
|
|
254
|
+
* @returns {Pool} The pool instance.
|
|
255
|
+
*/
|
|
256
|
+
static fromBuffer(data) {
|
|
257
|
+
const bufferHash = Pool.createHash(data instanceof Buffer ? data : data.buffer);
|
|
258
|
+
if (this.hashToPoolMap.has(bufferHash)) {
|
|
259
|
+
return this.hashToPoolMap.get(bufferHash);
|
|
260
|
+
}
|
|
261
|
+
const json = msgpack_lite_1.default.decode(data instanceof Buffer ? data : data.buffer);
|
|
262
|
+
const pool = Pool.fromJSON(json);
|
|
263
|
+
this.hashToPoolMap.set(bufferHash, pool);
|
|
264
|
+
this.idToPoolMap.set(pool.id, pool);
|
|
265
|
+
return pool;
|
|
266
|
+
}
|
|
267
|
+
static fromId(id) {
|
|
268
|
+
//console.log('fromId', id)
|
|
269
|
+
const pool = Pool.idToPoolMap.get(id);
|
|
270
|
+
if (!pool)
|
|
271
|
+
throw new Error('pool does not exist in idToPoolMap');
|
|
272
|
+
return pool;
|
|
273
|
+
}
|
|
274
|
+
static createHash(buffer, pool) {
|
|
275
|
+
if (pool && pool.bufferHash) {
|
|
276
|
+
return pool.bufferHash;
|
|
277
|
+
}
|
|
278
|
+
const hash = crypto_1.default.createHash('sha256');
|
|
279
|
+
hash.update(buffer);
|
|
280
|
+
const hexHash = hash.digest('hex');
|
|
281
|
+
if (pool) {
|
|
282
|
+
pool.bufferHash = hexHash;
|
|
283
|
+
}
|
|
284
|
+
return hexHash;
|
|
285
|
+
}
|
|
286
|
+
static hashEquals(pool, hash) {
|
|
287
|
+
return pool.bufferHash === hash;
|
|
288
|
+
}
|
|
289
|
+
equals(other) {
|
|
290
|
+
// Сравниваем id пулов
|
|
291
|
+
if (this.id !== other.id)
|
|
292
|
+
return false;
|
|
293
|
+
// Сравниваем fee
|
|
294
|
+
if (this.fee !== other.fee)
|
|
295
|
+
return false;
|
|
296
|
+
// Сравниваем sqrtPriceX64
|
|
297
|
+
if (!jsbi_1.default.equal(this.sqrtPriceX64, other.sqrtPriceX64))
|
|
298
|
+
return false;
|
|
299
|
+
// Сравниваем liquidity
|
|
300
|
+
if (!jsbi_1.default.equal(this.liquidity, other.liquidity))
|
|
301
|
+
return false;
|
|
302
|
+
// Сравниваем tickCurrent
|
|
303
|
+
if (this.tickCurrent !== other.tickCurrent)
|
|
304
|
+
return false;
|
|
305
|
+
// Сравниваем токены (предполагается, что у Token есть метод equals)
|
|
306
|
+
if (!this.tokenA.equals(other.tokenA) || !this.tokenB.equals(other.tokenB))
|
|
307
|
+
return false;
|
|
308
|
+
// Если все проверки прошли, объекты считаются равными
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
232
311
|
}
|
|
233
312
|
exports.Pool = Pool;
|
|
313
|
+
Pool.hashToPoolMap = new Map();
|
|
314
|
+
Pool.idToPoolMap = new Map();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { Currency } from './currency';
|
|
2
3
|
import { Price } from './fractions';
|
|
3
4
|
import { Token } from './token';
|
|
@@ -24,4 +25,23 @@ export declare class Route<TInput extends Currency, TOutput extends Currency> {
|
|
|
24
25
|
* Returns the mid price of the route
|
|
25
26
|
*/
|
|
26
27
|
get midPrice(): Price<TInput, TOutput>;
|
|
28
|
+
static toJSON(route: Route<Currency, Currency>, lightWeightVersion?: boolean): {
|
|
29
|
+
pools: (number | Buffer)[];
|
|
30
|
+
input: {
|
|
31
|
+
contract: string;
|
|
32
|
+
decimals: number;
|
|
33
|
+
symbol: string;
|
|
34
|
+
};
|
|
35
|
+
output: {
|
|
36
|
+
contract: string;
|
|
37
|
+
decimals: number;
|
|
38
|
+
symbol: string;
|
|
39
|
+
};
|
|
40
|
+
_midPrice: Price<Token, Token> | null;
|
|
41
|
+
};
|
|
42
|
+
static fromJSON(json: any): Route<Token, Token>;
|
|
43
|
+
static toBuffer(route: Route<Currency, Currency>, lightWeightVersion?: boolean): any;
|
|
44
|
+
static fromBuffer(buffer: Buffer): Route<Token, Token>;
|
|
45
|
+
static toBufferAdvanced(route: Route<Currency, Currency>, pools: any[]): any;
|
|
46
|
+
equals(other: Route<Currency, Currency>): boolean;
|
|
27
47
|
}
|
package/build/entities/route.js
CHANGED
|
@@ -4,8 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Route = void 0;
|
|
7
|
+
const msgpack_lite_1 = __importDefault(require("msgpack-lite"));
|
|
7
8
|
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
|
|
8
9
|
const fractions_1 = require("./fractions");
|
|
10
|
+
const token_1 = require("./token");
|
|
11
|
+
const pool_1 = require("./pool");
|
|
9
12
|
/**
|
|
10
13
|
* Represents a list of pools through which a swap can occur
|
|
11
14
|
* @template TInput The input token
|
|
@@ -30,8 +33,11 @@ class Route {
|
|
|
30
33
|
const tokenPath = [wrappedInput];
|
|
31
34
|
for (const [i, pool] of pools.entries()) {
|
|
32
35
|
const currentInputToken = tokenPath[i];
|
|
33
|
-
(0, tiny_invariant_1.default)(currentInputToken.equals(pool.tokenA) ||
|
|
34
|
-
|
|
36
|
+
(0, tiny_invariant_1.default)(currentInputToken.equals(pool.tokenA) ||
|
|
37
|
+
currentInputToken.equals(pool.tokenB), 'PATH');
|
|
38
|
+
const nextToken = currentInputToken.equals(pool.tokenA)
|
|
39
|
+
? pool.tokenB
|
|
40
|
+
: pool.tokenA;
|
|
35
41
|
tokenPath.push(nextToken);
|
|
36
42
|
}
|
|
37
43
|
this.pools = pools;
|
|
@@ -49,22 +55,83 @@ class Route {
|
|
|
49
55
|
return nextInput.equals(pool.tokenA)
|
|
50
56
|
? {
|
|
51
57
|
nextInput: pool.tokenB,
|
|
52
|
-
price: price.multiply(pool.tokenAPrice)
|
|
58
|
+
price: price.multiply(pool.tokenAPrice),
|
|
53
59
|
}
|
|
54
60
|
: {
|
|
55
61
|
nextInput: pool.tokenA,
|
|
56
|
-
price: price.multiply(pool.tokenBPrice)
|
|
62
|
+
price: price.multiply(pool.tokenBPrice),
|
|
57
63
|
};
|
|
58
64
|
}, this.pools[0].tokenA.equals(this.input)
|
|
59
65
|
? {
|
|
60
66
|
nextInput: this.pools[0].tokenB,
|
|
61
|
-
price: this.pools[0].tokenAPrice
|
|
67
|
+
price: this.pools[0].tokenAPrice,
|
|
62
68
|
}
|
|
63
69
|
: {
|
|
64
70
|
nextInput: this.pools[0].tokenA,
|
|
65
|
-
price: this.pools[0].tokenBPrice
|
|
71
|
+
price: this.pools[0].tokenBPrice,
|
|
66
72
|
}).price;
|
|
67
73
|
return (this._midPrice = new fractions_1.Price(this.input, this.output, price.denominator, price.numerator));
|
|
68
74
|
}
|
|
75
|
+
static toJSON(route, lightWeightVersion = false) {
|
|
76
|
+
return {
|
|
77
|
+
pools: route.pools.map((pool) => {
|
|
78
|
+
if (lightWeightVersion) {
|
|
79
|
+
return pool.id;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
return pool_1.Pool.toBuffer(pool);
|
|
83
|
+
}
|
|
84
|
+
}),
|
|
85
|
+
input: token_1.Token.toJSON(route.input),
|
|
86
|
+
output: token_1.Token.toJSON(route.output),
|
|
87
|
+
_midPrice: route._midPrice,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
static fromJSON(json) {
|
|
91
|
+
const pools = json.pools.map((pool) => {
|
|
92
|
+
if (typeof pool === 'number') {
|
|
93
|
+
return pool_1.Pool.fromId(pool);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return pool_1.Pool.fromBuffer(Buffer.from(pool));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const input = token_1.Token.fromJSON(json.input);
|
|
100
|
+
const output = token_1.Token.fromJSON(json.output);
|
|
101
|
+
return new Route(pools, input, output);
|
|
102
|
+
}
|
|
103
|
+
static toBuffer(route, lightWeightVersion = false) {
|
|
104
|
+
const json = this.toJSON(route, lightWeightVersion);
|
|
105
|
+
return msgpack_lite_1.default.encode(json);
|
|
106
|
+
}
|
|
107
|
+
static fromBuffer(buffer) {
|
|
108
|
+
const json = msgpack_lite_1.default.decode(buffer);
|
|
109
|
+
return this.fromJSON(json);
|
|
110
|
+
}
|
|
111
|
+
static toBufferAdvanced(route, pools) {
|
|
112
|
+
const json = {
|
|
113
|
+
pools: pools.map((pool) => {
|
|
114
|
+
if (typeof pool === 'number' || Buffer.isBuffer(pool)) {
|
|
115
|
+
return pool;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
return pool_1.Pool.toBuffer(pool);
|
|
119
|
+
}
|
|
120
|
+
}),
|
|
121
|
+
input: token_1.Token.toJSON(route.input),
|
|
122
|
+
output: token_1.Token.toJSON(route.output),
|
|
123
|
+
_midPrice: route._midPrice,
|
|
124
|
+
};
|
|
125
|
+
return msgpack_lite_1.default.encode(json);
|
|
126
|
+
}
|
|
127
|
+
equals(other) {
|
|
128
|
+
if (this.pools.length !== other.pools.length)
|
|
129
|
+
return false;
|
|
130
|
+
for (let i = 0; i < this.pools.length; i++) {
|
|
131
|
+
if (!this.pools[i].equals(other.pools[i]))
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
return this.input.equals(other.input) && this.output.equals(other.output);
|
|
135
|
+
}
|
|
69
136
|
}
|
|
70
137
|
exports.Route = Route;
|
package/build/entities/tick.d.ts
CHANGED
|
@@ -20,4 +20,6 @@ export declare class Tick {
|
|
|
20
20
|
readonly secondsOutside: JSBI;
|
|
21
21
|
readonly secondsPerLiquidityOutsideX64: JSBI;
|
|
22
22
|
constructor({ id, liquidityGross, liquidityNet, feeGrowthOutsideAX64, feeGrowthOutsideBX64, tickCumulativeOutside, secondsOutside, secondsPerLiquidityOutsideX64, }: TickConstructorArgs);
|
|
23
|
+
static toJSON(tick: Tick): object;
|
|
24
|
+
static fromJSON(json: any): Tick;
|
|
23
25
|
}
|
package/build/entities/tick.js
CHANGED
|
@@ -19,5 +19,29 @@ class Tick {
|
|
|
19
19
|
this.secondsOutside = jsbi_1.default.BigInt(secondsOutside);
|
|
20
20
|
this.secondsPerLiquidityOutsideX64 = jsbi_1.default.BigInt(secondsPerLiquidityOutsideX64);
|
|
21
21
|
}
|
|
22
|
+
static toJSON(tick) {
|
|
23
|
+
return {
|
|
24
|
+
id: tick.id,
|
|
25
|
+
liquidityGross: tick.liquidityGross.toString(),
|
|
26
|
+
liquidityNet: tick.liquidityNet.toString(),
|
|
27
|
+
feeGrowthOutsideAX64: tick.feeGrowthOutsideAX64.toString(),
|
|
28
|
+
feeGrowthOutsideBX64: tick.feeGrowthOutsideBX64.toString(),
|
|
29
|
+
tickCumulativeOutside: tick.tickCumulativeOutside.toString(),
|
|
30
|
+
secondsOutside: tick.secondsOutside.toString(),
|
|
31
|
+
secondsPerLiquidityOutsideX64: tick.secondsPerLiquidityOutsideX64.toString(),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
static fromJSON(json) {
|
|
35
|
+
return new Tick({
|
|
36
|
+
id: json.id,
|
|
37
|
+
liquidityGross: jsbi_1.default.BigInt(json.liquidityGross),
|
|
38
|
+
liquidityNet: jsbi_1.default.BigInt(json.liquidityNet),
|
|
39
|
+
feeGrowthOutsideAX64: jsbi_1.default.BigInt(json.feeGrowthOutsideAX64),
|
|
40
|
+
feeGrowthOutsideBX64: jsbi_1.default.BigInt(json.feeGrowthOutsideBX64),
|
|
41
|
+
tickCumulativeOutside: jsbi_1.default.BigInt(json.tickCumulativeOutside),
|
|
42
|
+
secondsOutside: jsbi_1.default.BigInt(json.secondsOutside),
|
|
43
|
+
secondsPerLiquidityOutsideX64: jsbi_1.default.BigInt(json.secondsPerLiquidityOutsideX64),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
22
46
|
}
|
|
23
47
|
exports.Tick = Tick;
|
|
@@ -4,8 +4,10 @@ import { TickDataProvider } from "./tickDataProvider";
|
|
|
4
4
|
* A data provider for ticks that is backed by an in-memory array of ticks.
|
|
5
5
|
*/
|
|
6
6
|
export declare class TickListDataProvider implements TickDataProvider {
|
|
7
|
-
|
|
7
|
+
ticks: readonly Tick[];
|
|
8
8
|
constructor(ticks: (Tick | TickConstructorArgs)[], tickSpacing: number);
|
|
9
9
|
getTick(tick: number): Tick;
|
|
10
10
|
nextInitializedTickWithinOneWord(tick: number, lte: boolean, tickSpacing: number): [number, boolean];
|
|
11
|
+
static toJSON(ticks: Tick[]): object;
|
|
12
|
+
static fromJSON(ticksArray: any): TickListDataProvider;
|
|
11
13
|
}
|
|
@@ -18,5 +18,11 @@ class TickListDataProvider {
|
|
|
18
18
|
nextInitializedTickWithinOneWord(tick, lte, tickSpacing) {
|
|
19
19
|
return tickList_1.TickList.nextInitializedTickWithinOneWord(this.ticks, tick, lte, tickSpacing);
|
|
20
20
|
}
|
|
21
|
+
static toJSON(ticks) {
|
|
22
|
+
return ticks.map((tick) => tick_1.Tick.toJSON(tick));
|
|
23
|
+
}
|
|
24
|
+
static fromJSON(ticksArray) {
|
|
25
|
+
return ticksArray.map(tick_1.Tick.fromJSON);
|
|
26
|
+
}
|
|
21
27
|
}
|
|
22
28
|
exports.TickListDataProvider = TickListDataProvider;
|
|
@@ -21,4 +21,10 @@ export declare class Token extends BaseCurrency {
|
|
|
21
21
|
* @throws if the tokens have the same contract and symbol
|
|
22
22
|
*/
|
|
23
23
|
sortsBefore(other: Token): boolean;
|
|
24
|
+
static toJSON(token: Token): {
|
|
25
|
+
contract: string;
|
|
26
|
+
decimals: number;
|
|
27
|
+
symbol: string;
|
|
28
|
+
};
|
|
29
|
+
static fromJSON(json: any): Token;
|
|
24
30
|
}
|
package/build/entities/token.js
CHANGED
|
@@ -48,5 +48,15 @@ class Token extends baseCurrency_1.BaseCurrency {
|
|
|
48
48
|
return (0, eos_common_1.name)(this.contract).raw().lt((0, eos_common_1.name)(other.contract).raw());
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
static toJSON(token) {
|
|
52
|
+
return {
|
|
53
|
+
contract: token.contract,
|
|
54
|
+
decimals: token.decimals,
|
|
55
|
+
symbol: token.symbol,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
static fromJSON(json) {
|
|
59
|
+
return new Token(json.contract, json.decimals, json.symbol);
|
|
60
|
+
}
|
|
51
61
|
}
|
|
52
62
|
exports.Token = Token;
|
package/build/entities/trade.js
CHANGED
|
@@ -164,7 +164,7 @@ class Trade {
|
|
|
164
164
|
amounts[0] = amount;
|
|
165
165
|
for (let i = 0; i < route.tokenPath.length - 1; i++) {
|
|
166
166
|
const pool = route.pools[i];
|
|
167
|
-
const
|
|
167
|
+
const outputAmount = pool.getOutputAmount(amounts[i]);
|
|
168
168
|
amounts[i + 1] = outputAmount;
|
|
169
169
|
}
|
|
170
170
|
inputAmount = fractions_1.CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator);
|
|
@@ -175,7 +175,7 @@ class Trade {
|
|
|
175
175
|
amounts[amounts.length - 1] = amount;
|
|
176
176
|
for (let i = route.tokenPath.length - 1; i > 0; i--) {
|
|
177
177
|
const pool = route.pools[i - 1];
|
|
178
|
-
const
|
|
178
|
+
const inputAmount = pool.getInputAmount(amounts[i]);
|
|
179
179
|
amounts[i - 1] = inputAmount;
|
|
180
180
|
}
|
|
181
181
|
inputAmount = fractions_1.CurrencyAmount.fromFractionalAmount(route.input, amounts[0].numerator, amounts[0].denominator);
|
|
@@ -208,7 +208,7 @@ class Trade {
|
|
|
208
208
|
amounts[0] = fractions_1.CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator);
|
|
209
209
|
for (let i = 0; i < route.tokenPath.length - 1; i++) {
|
|
210
210
|
const pool = route.pools[i];
|
|
211
|
-
const
|
|
211
|
+
const outputAmount = pool.getOutputAmount(amounts[i]);
|
|
212
212
|
amounts[i + 1] = outputAmount;
|
|
213
213
|
}
|
|
214
214
|
outputAmount = fractions_1.CurrencyAmount.fromFractionalAmount(route.output, amounts[amounts.length - 1].numerator, amounts[amounts.length - 1].denominator);
|
|
@@ -219,7 +219,7 @@ class Trade {
|
|
|
219
219
|
amounts[amounts.length - 1] = fractions_1.CurrencyAmount.fromFractionalAmount(route.output, amount.numerator, amount.denominator);
|
|
220
220
|
for (let i = route.tokenPath.length - 1; i > 0; i--) {
|
|
221
221
|
const pool = route.pools[i - 1];
|
|
222
|
-
const
|
|
222
|
+
const inputAmount = pool.getInputAmount(amounts[i]);
|
|
223
223
|
amounts[i - 1] = inputAmount;
|
|
224
224
|
}
|
|
225
225
|
inputAmount = fractions_1.CurrencyAmount.fromFractionalAmount(route.input, amounts[0].numerator, amounts[0].denominator);
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import { Token, Pool, Route } from '../entities';
|
|
2
2
|
export declare function computeAllRoutes(tokenIn: Token, tokenOut: Token, pools: Pool[], maxHops: number): Route<Token, Token>[];
|
|
3
|
+
export declare function computeAllRoutesFromMap(tokenIn: Token, tokenOut: Token, poolMap: {
|
|
4
|
+
[tokenId: string]: Pool[];
|
|
5
|
+
}, maxHops: number): Route<Token, Token>[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.computeAllRoutes = void 0;
|
|
3
|
+
exports.computeAllRoutesFromMap = exports.computeAllRoutes = void 0;
|
|
4
4
|
const entities_1 = require("../entities");
|
|
5
5
|
function computeAllRoutes(tokenIn, tokenOut, pools, maxHops) {
|
|
6
6
|
const poolsUsed = Array(pools.length).fill(false);
|
|
@@ -37,3 +37,34 @@ function computeAllRoutes(tokenIn, tokenOut, pools, maxHops) {
|
|
|
37
37
|
return routes;
|
|
38
38
|
}
|
|
39
39
|
exports.computeAllRoutes = computeAllRoutes;
|
|
40
|
+
function computeAllRoutesFromMap(tokenIn, tokenOut, poolMap, maxHops) {
|
|
41
|
+
const routes = [];
|
|
42
|
+
const computeRoutes = (tokenIn, tokenOut, currentRoute, visitedPools, _previousTokenOut) => {
|
|
43
|
+
if (currentRoute.length > maxHops) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (currentRoute.length > 0 &&
|
|
47
|
+
currentRoute[currentRoute.length - 1].involvesToken(tokenOut)) {
|
|
48
|
+
routes.push(new entities_1.Route([...currentRoute], tokenIn, tokenOut));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const previousTokenOut = _previousTokenOut ? _previousTokenOut : tokenIn;
|
|
52
|
+
const relevantPools = poolMap[previousTokenOut.id] || [];
|
|
53
|
+
for (const curPool of relevantPools) {
|
|
54
|
+
if (visitedPools.has(curPool)) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const currentTokenOut = curPool.tokenA.equals(previousTokenOut)
|
|
58
|
+
? curPool.tokenB
|
|
59
|
+
: curPool.tokenA;
|
|
60
|
+
currentRoute.push(curPool);
|
|
61
|
+
visitedPools.add(curPool);
|
|
62
|
+
computeRoutes(tokenIn, tokenOut, currentRoute, visitedPools, currentTokenOut);
|
|
63
|
+
visitedPools.delete(curPool);
|
|
64
|
+
currentRoute.pop();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
computeRoutes(tokenIn, tokenOut, [], new Set());
|
|
68
|
+
return routes;
|
|
69
|
+
}
|
|
70
|
+
exports.computeAllRoutesFromMap = computeAllRoutesFromMap;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alcorexchange/alcor-swap-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.28",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"eosjs": "^22.1.0",
|
|
56
56
|
"eosjs-account-name": "2.3.0",
|
|
57
57
|
"jsbi": "^4.3.0",
|
|
58
|
+
"msgpack-lite": "^0.1.26",
|
|
58
59
|
"node-fetch": "2",
|
|
59
60
|
"tiny-invariant": "^1.1.0",
|
|
60
61
|
"tiny-warning": "^1.0.3",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import msgpack from "msgpack-lite"
|
|
2
|
+
|
|
1
3
|
import invariant from "tiny-invariant";
|
|
2
4
|
import JSBI from "jsbi";
|
|
3
5
|
import { Currency } from "../currency";
|
|
@@ -130,4 +132,34 @@ export class CurrencyAmount<T extends Currency> extends Fraction {
|
|
|
130
132
|
public toExtendedAssetObject(...args): object {
|
|
131
133
|
return { quantity: `${this.toFixed(...args)} ${this.currency.symbol}`, contract: this.currency.contract }
|
|
132
134
|
}
|
|
135
|
+
|
|
136
|
+
static toJSON<T extends Currency>(amount: CurrencyAmount<T>): object {
|
|
137
|
+
return {
|
|
138
|
+
currency: Token.toJSON(amount.currency),
|
|
139
|
+
numerator: amount.numerator.toString(),
|
|
140
|
+
denominator: amount.denominator.toString(),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static fromJSON(json: any) {
|
|
145
|
+
const currency = Token.fromJSON(json.currency);
|
|
146
|
+
const numerator = JSBI.BigInt(json.numerator);
|
|
147
|
+
const denominator = JSBI.BigInt(json.denominator);
|
|
148
|
+
return new CurrencyAmount(currency, numerator, denominator);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static toBuffer<T extends Currency>(amount: CurrencyAmount<T>): object {
|
|
152
|
+
const json = {
|
|
153
|
+
currency: Token.toJSON(amount.currency),
|
|
154
|
+
numerator: amount.numerator.toString(),
|
|
155
|
+
denominator: amount.denominator.toString(),
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return msgpack.encode(json);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static fromBuffer(buffer: Buffer) {
|
|
162
|
+
const json = msgpack.decode(buffer)
|
|
163
|
+
return this.fromJSON(json)
|
|
164
|
+
}
|
|
133
165
|
}
|
package/src/entities/pool.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import msgpack from "msgpack-lite";
|
|
2
|
+
import crypto, {createHash} from 'crypto';
|
|
3
|
+
|
|
1
4
|
import { CurrencyAmount, Price } from "./fractions";
|
|
2
5
|
import { Token } from "./token";
|
|
3
6
|
import { BigintIsh, FeeAmount, TICK_SPACINGS } from "../internalConstants";
|
|
@@ -57,6 +60,14 @@ export class Pool {
|
|
|
57
60
|
public readonly feeGrowthGlobalBX64: JSBI;
|
|
58
61
|
public readonly tickDataProvider: TickDataProvider;
|
|
59
62
|
|
|
63
|
+
public json?: any
|
|
64
|
+
public buffer?: Buffer
|
|
65
|
+
public bufferHash?: string
|
|
66
|
+
|
|
67
|
+
static hashToPoolMap: Map<string, Pool> = new Map()
|
|
68
|
+
public static idToPoolMap: Map<number, Pool> = new Map()
|
|
69
|
+
|
|
70
|
+
|
|
60
71
|
private _tokenAPrice?: Price<Token, Token>;
|
|
61
72
|
private _tokenBPrice?: Price<Token, Token>;
|
|
62
73
|
|
|
@@ -170,36 +181,19 @@ export class Pool {
|
|
|
170
181
|
public getOutputAmount(
|
|
171
182
|
inputAmount: CurrencyAmount<Token>,
|
|
172
183
|
sqrtPriceLimitX64?: JSBI
|
|
173
|
-
):
|
|
184
|
+
): CurrencyAmount<Token> {
|
|
174
185
|
invariant(this.involvesToken(inputAmount.currency), "TOKEN");
|
|
175
186
|
|
|
176
187
|
const zeroForOne = inputAmount.currency.equals(this.tokenA);
|
|
177
188
|
|
|
178
189
|
const {
|
|
179
190
|
amountCalculated: outputAmount,
|
|
180
|
-
sqrtPriceX64,
|
|
181
|
-
liquidity,
|
|
182
|
-
tickCurrent,
|
|
183
191
|
} = this.swap(zeroForOne, inputAmount.quotient, sqrtPriceLimitX64);
|
|
184
192
|
const outputToken = zeroForOne ? this.tokenB : this.tokenA;
|
|
185
|
-
return
|
|
186
|
-
CurrencyAmount.fromRawAmount(
|
|
193
|
+
return CurrencyAmount.fromRawAmount(
|
|
187
194
|
outputToken,
|
|
188
195
|
JSBI.multiply(outputAmount, NEGATIVE_ONE)
|
|
189
|
-
)
|
|
190
|
-
new Pool({
|
|
191
|
-
id: this.id,
|
|
192
|
-
tokenA: this.tokenA,
|
|
193
|
-
tokenB: this.tokenB,
|
|
194
|
-
fee: this.fee,
|
|
195
|
-
sqrtPriceX64,
|
|
196
|
-
liquidity,
|
|
197
|
-
tickCurrent,
|
|
198
|
-
ticks: this.tickDataProvider,
|
|
199
|
-
feeGrowthGlobalAX64: this.feeGrowthGlobalAX64,
|
|
200
|
-
feeGrowthGlobalBX64: this.feeGrowthGlobalBX64,
|
|
201
|
-
})
|
|
202
|
-
];
|
|
196
|
+
)
|
|
203
197
|
}
|
|
204
198
|
|
|
205
199
|
/**
|
|
@@ -211,35 +205,18 @@ export class Pool {
|
|
|
211
205
|
public getInputAmount(
|
|
212
206
|
outputAmount: CurrencyAmount<Token>,
|
|
213
207
|
sqrtPriceLimitX64?: JSBI
|
|
214
|
-
):
|
|
208
|
+
): CurrencyAmount<Token> {
|
|
215
209
|
const zeroForOne = outputAmount.currency.equals(this.tokenB);
|
|
216
210
|
|
|
217
211
|
const {
|
|
218
212
|
amountCalculated: inputAmount,
|
|
219
|
-
sqrtPriceX64,
|
|
220
|
-
liquidity,
|
|
221
|
-
tickCurrent,
|
|
222
213
|
} = this.swap(
|
|
223
214
|
zeroForOne,
|
|
224
215
|
JSBI.multiply(outputAmount.quotient, NEGATIVE_ONE),
|
|
225
216
|
sqrtPriceLimitX64
|
|
226
217
|
);
|
|
227
218
|
const inputToken = zeroForOne ? this.tokenA : this.tokenB;
|
|
228
|
-
return
|
|
229
|
-
CurrencyAmount.fromRawAmount(inputToken, inputAmount),
|
|
230
|
-
new Pool({
|
|
231
|
-
id: this.id,
|
|
232
|
-
tokenA: this.tokenA,
|
|
233
|
-
tokenB: this.tokenB,
|
|
234
|
-
fee: this.fee,
|
|
235
|
-
sqrtPriceX64,
|
|
236
|
-
liquidity,
|
|
237
|
-
tickCurrent,
|
|
238
|
-
ticks: this.tickDataProvider,
|
|
239
|
-
feeGrowthGlobalAX64: this.feeGrowthGlobalAX64,
|
|
240
|
-
feeGrowthGlobalBX64: this.feeGrowthGlobalBX64,
|
|
241
|
-
}),
|
|
242
|
-
];
|
|
219
|
+
return CurrencyAmount.fromRawAmount(inputToken, inputAmount)
|
|
243
220
|
}
|
|
244
221
|
|
|
245
222
|
/**
|
|
@@ -396,4 +373,118 @@ export class Pool {
|
|
|
396
373
|
public get tickSpacing(): number {
|
|
397
374
|
return TICK_SPACINGS[this.fee];
|
|
398
375
|
}
|
|
376
|
+
|
|
377
|
+
static toJSON(pool: Pool): object {
|
|
378
|
+
if (pool.json) return pool.json
|
|
379
|
+
pool.json = {
|
|
380
|
+
id: pool.id,
|
|
381
|
+
tokenA: Token.toJSON(pool.tokenA),
|
|
382
|
+
tokenB: Token.toJSON(pool.tokenB),
|
|
383
|
+
fee: pool.fee,
|
|
384
|
+
sqrtPriceX64: pool.sqrtPriceX64.toString(),
|
|
385
|
+
liquidity: pool.liquidity.toString(),
|
|
386
|
+
tickCurrent: pool.tickCurrent,
|
|
387
|
+
feeGrowthGlobalAX64: pool.feeGrowthGlobalAX64.toString(),
|
|
388
|
+
feeGrowthGlobalBX64: pool.feeGrowthGlobalBX64.toString(),
|
|
389
|
+
tickDataProvider: TickListDataProvider.toJSON((pool.tickDataProvider as TickListDataProvider).ticks as Tick[])
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return pool.json
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
static fromJSON(json: any): Pool {
|
|
396
|
+
return new Pool({
|
|
397
|
+
id: json.id,
|
|
398
|
+
tokenA: Token.fromJSON(json.tokenA),
|
|
399
|
+
tokenB: Token.fromJSON(json.tokenB),
|
|
400
|
+
fee: json.fee,
|
|
401
|
+
sqrtPriceX64: JSBI.BigInt(json.sqrtPriceX64),
|
|
402
|
+
liquidity: JSBI.BigInt(json.liquidity),
|
|
403
|
+
tickCurrent: json.tickCurrent,
|
|
404
|
+
feeGrowthGlobalAX64: JSBI.BigInt(json.feeGrowthGlobalAX64),
|
|
405
|
+
feeGrowthGlobalBX64: JSBI.BigInt(json.feeGrowthGlobalBX64),
|
|
406
|
+
ticks: TickListDataProvider.fromJSON(json.tickDataProvider)
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Converts the pool to a Buffer using msgpack encoding.
|
|
411
|
+
* @param {Pool} pool - The pool instance to convert.
|
|
412
|
+
* @returns {Buffer} The encoded buffer.
|
|
413
|
+
*/
|
|
414
|
+
static toBuffer(pool: Pool): Buffer {
|
|
415
|
+
if (pool.buffer) return pool.buffer;
|
|
416
|
+
|
|
417
|
+
const json = Pool.toJSON(pool);
|
|
418
|
+
pool.buffer = msgpack.encode(json);
|
|
419
|
+
pool.bufferHash = Pool.createHash(pool.buffer as Buffer);
|
|
420
|
+
|
|
421
|
+
return pool.buffer as Buffer;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Creates a Pool instance from a Buffer or serialized data.
|
|
426
|
+
* @param {Buffer | any} data - The buffer or serialized data.
|
|
427
|
+
* @returns {Pool} The pool instance.
|
|
428
|
+
*/
|
|
429
|
+
static fromBuffer(data: Buffer | any): Pool {
|
|
430
|
+
const bufferHash = Pool.createHash(data instanceof Buffer ? data : data.buffer);
|
|
431
|
+
|
|
432
|
+
if (this.hashToPoolMap.has(bufferHash)) {
|
|
433
|
+
return <Pool>this.hashToPoolMap.get(bufferHash);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const json = msgpack.decode(data instanceof Buffer ? data : data.buffer);
|
|
437
|
+
const pool = Pool.fromJSON(json);
|
|
438
|
+
|
|
439
|
+
this.hashToPoolMap.set(bufferHash, pool);
|
|
440
|
+
this.idToPoolMap.set(pool.id, pool);
|
|
441
|
+
|
|
442
|
+
return pool;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
static fromId(id: number): Pool {
|
|
446
|
+
//console.log('fromId', id)
|
|
447
|
+
const pool = Pool.idToPoolMap.get(id)
|
|
448
|
+
if (!pool) throw new Error('pool does not exist in idToPoolMap')
|
|
449
|
+
return pool;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
static createHash(buffer: Buffer, pool?: Pool) {
|
|
453
|
+
if (pool && pool.bufferHash) {
|
|
454
|
+
return pool.bufferHash
|
|
455
|
+
}
|
|
456
|
+
const hash = crypto.createHash('sha256');
|
|
457
|
+
hash.update(buffer);
|
|
458
|
+
const hexHash = hash.digest('hex');
|
|
459
|
+
|
|
460
|
+
if (pool) {
|
|
461
|
+
pool.bufferHash = hexHash
|
|
462
|
+
}
|
|
463
|
+
return hexHash
|
|
464
|
+
}
|
|
465
|
+
static hashEquals(pool: Pool, hash: string) {
|
|
466
|
+
return pool.bufferHash === hash
|
|
467
|
+
}
|
|
468
|
+
public equals(other: Pool): boolean {
|
|
469
|
+
// Сравниваем id пулов
|
|
470
|
+
if (this.id !== other.id) return false;
|
|
471
|
+
|
|
472
|
+
// Сравниваем fee
|
|
473
|
+
if (this.fee !== other.fee) return false;
|
|
474
|
+
|
|
475
|
+
// Сравниваем sqrtPriceX64
|
|
476
|
+
if (!JSBI.equal(this.sqrtPriceX64, other.sqrtPriceX64)) return false;
|
|
477
|
+
|
|
478
|
+
// Сравниваем liquidity
|
|
479
|
+
if (!JSBI.equal(this.liquidity, other.liquidity)) return false;
|
|
480
|
+
|
|
481
|
+
// Сравниваем tickCurrent
|
|
482
|
+
if (this.tickCurrent !== other.tickCurrent) return false;
|
|
483
|
+
|
|
484
|
+
// Сравниваем токены (предполагается, что у Token есть метод equals)
|
|
485
|
+
if (!this.tokenA.equals(other.tokenA) || !this.tokenB.equals(other.tokenB)) return false;
|
|
486
|
+
|
|
487
|
+
// Если все проверки прошли, объекты считаются равными
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
399
490
|
}
|
package/src/entities/route.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import msgpack from "msgpack-lite"
|
|
1
2
|
import invariant from 'tiny-invariant'
|
|
2
3
|
|
|
3
4
|
import { Currency } from './currency'
|
|
@@ -12,12 +13,12 @@ import { Pool } from './pool'
|
|
|
12
13
|
* @template TOutput The output token
|
|
13
14
|
*/
|
|
14
15
|
export class Route<TInput extends Currency, TOutput extends Currency> {
|
|
15
|
-
public readonly pools: Pool[]
|
|
16
|
-
public readonly tokenPath: Token[]
|
|
17
|
-
public readonly input: TInput
|
|
18
|
-
public readonly output: TOutput
|
|
16
|
+
public readonly pools: Pool[];
|
|
17
|
+
public readonly tokenPath: Token[];
|
|
18
|
+
public readonly input: TInput;
|
|
19
|
+
public readonly output: TOutput;
|
|
19
20
|
|
|
20
|
-
private _midPrice: Price<TInput, TOutput> | null = null
|
|
21
|
+
private _midPrice: Price<TInput, TOutput> | null = null;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Creates an instance of route.
|
|
@@ -26,59 +27,136 @@ export class Route<TInput extends Currency, TOutput extends Currency> {
|
|
|
26
27
|
* @param output The output token
|
|
27
28
|
*/
|
|
28
29
|
public constructor(pools: Pool[], input: TInput, output: TOutput) {
|
|
29
|
-
invariant(pools.length > 0, 'POOLS')
|
|
30
|
+
invariant(pools.length > 0, 'POOLS');
|
|
30
31
|
|
|
31
|
-
const wrappedInput = input
|
|
32
|
-
invariant(pools[0].involvesToken(wrappedInput), 'INPUT')
|
|
32
|
+
const wrappedInput = input;
|
|
33
|
+
invariant(pools[0].involvesToken(wrappedInput), 'INPUT');
|
|
33
34
|
|
|
34
|
-
invariant(pools[pools.length - 1].involvesToken(output), 'OUTPUT')
|
|
35
|
+
invariant(pools[pools.length - 1].involvesToken(output), 'OUTPUT');
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* Normalizes tokenA-tokenB order and selects the next token/fee step to add to the path
|
|
38
39
|
* */
|
|
39
|
-
const tokenPath: Token[] = [wrappedInput]
|
|
40
|
+
const tokenPath: Token[] = [wrappedInput];
|
|
40
41
|
for (const [i, pool] of pools.entries()) {
|
|
41
|
-
const currentInputToken = tokenPath[i]
|
|
42
|
-
invariant(
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const currentInputToken = tokenPath[i];
|
|
43
|
+
invariant(
|
|
44
|
+
currentInputToken.equals(pool.tokenA) ||
|
|
45
|
+
currentInputToken.equals(pool.tokenB),
|
|
46
|
+
'PATH'
|
|
47
|
+
);
|
|
48
|
+
const nextToken = currentInputToken.equals(pool.tokenA)
|
|
49
|
+
? pool.tokenB
|
|
50
|
+
: pool.tokenA;
|
|
51
|
+
tokenPath.push(nextToken);
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
this.pools = pools
|
|
48
|
-
this.tokenPath = tokenPath
|
|
49
|
-
this.input = input
|
|
50
|
-
this.output = output ?? tokenPath[tokenPath.length - 1]
|
|
54
|
+
this.pools = pools;
|
|
55
|
+
this.tokenPath = tokenPath;
|
|
56
|
+
this.input = input;
|
|
57
|
+
this.output = output ?? tokenPath[tokenPath.length - 1];
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
/**
|
|
54
61
|
* Returns the mid price of the route
|
|
55
62
|
*/
|
|
56
63
|
public get midPrice(): Price<TInput, TOutput> {
|
|
57
|
-
if (this._midPrice !== null) return this._midPrice
|
|
64
|
+
if (this._midPrice !== null) return this._midPrice;
|
|
58
65
|
|
|
59
66
|
const price = this.pools.slice(1).reduce(
|
|
60
67
|
({ nextInput, price }, pool) => {
|
|
61
68
|
return nextInput.equals(pool.tokenA)
|
|
62
69
|
? {
|
|
63
70
|
nextInput: pool.tokenB,
|
|
64
|
-
price: price.multiply(pool.tokenAPrice)
|
|
71
|
+
price: price.multiply(pool.tokenAPrice),
|
|
65
72
|
}
|
|
66
73
|
: {
|
|
67
74
|
nextInput: pool.tokenA,
|
|
68
|
-
price: price.multiply(pool.tokenBPrice)
|
|
69
|
-
}
|
|
75
|
+
price: price.multiply(pool.tokenBPrice),
|
|
76
|
+
};
|
|
70
77
|
},
|
|
71
78
|
this.pools[0].tokenA.equals(this.input)
|
|
72
79
|
? {
|
|
73
80
|
nextInput: this.pools[0].tokenB,
|
|
74
|
-
price: this.pools[0].tokenAPrice
|
|
81
|
+
price: this.pools[0].tokenAPrice,
|
|
75
82
|
}
|
|
76
83
|
: {
|
|
77
84
|
nextInput: this.pools[0].tokenA,
|
|
78
|
-
price: this.pools[0].tokenBPrice
|
|
85
|
+
price: this.pools[0].tokenBPrice,
|
|
79
86
|
}
|
|
80
|
-
).price
|
|
87
|
+
).price;
|
|
88
|
+
|
|
89
|
+
return (this._midPrice = new Price(
|
|
90
|
+
this.input,
|
|
91
|
+
this.output,
|
|
92
|
+
price.denominator,
|
|
93
|
+
price.numerator
|
|
94
|
+
));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static toJSON(route: Route<Currency, Currency>, lightWeightVersion = false) {
|
|
98
|
+
return {
|
|
99
|
+
pools: route.pools.map((pool) => {
|
|
100
|
+
if (lightWeightVersion) {
|
|
101
|
+
return pool.id;
|
|
102
|
+
} else {
|
|
103
|
+
return Pool.toBuffer(pool);
|
|
104
|
+
}
|
|
105
|
+
}),
|
|
106
|
+
input: Token.toJSON(route.input),
|
|
107
|
+
output: Token.toJSON(route.output),
|
|
108
|
+
_midPrice: route._midPrice,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static fromJSON(json: any) {
|
|
113
|
+
const pools = json.pools.map((pool) => {
|
|
114
|
+
if (typeof pool === 'number') {
|
|
115
|
+
return Pool.fromId(pool);
|
|
116
|
+
} else {
|
|
117
|
+
return Pool.fromBuffer(Buffer.from(pool));
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
const input = Token.fromJSON(json.input);
|
|
121
|
+
const output = Token.fromJSON(json.output);
|
|
122
|
+
return new Route(pools, input, output);
|
|
123
|
+
}
|
|
81
124
|
|
|
82
|
-
|
|
125
|
+
static toBuffer(
|
|
126
|
+
route: Route<Currency, Currency>,
|
|
127
|
+
lightWeightVersion = false
|
|
128
|
+
) {
|
|
129
|
+
const json = this.toJSON(route, lightWeightVersion);
|
|
130
|
+
return msgpack.encode(json);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static fromBuffer(buffer: Buffer) {
|
|
134
|
+
const json = msgpack.decode(buffer);
|
|
135
|
+
return this.fromJSON(json);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static toBufferAdvanced(route: Route<Currency, Currency>, pools: any[]) {
|
|
139
|
+
const json = {
|
|
140
|
+
pools: pools.map((pool) => {
|
|
141
|
+
if (typeof pool === 'number' || Buffer.isBuffer(pool)) {
|
|
142
|
+
return pool;
|
|
143
|
+
} else {
|
|
144
|
+
return Pool.toBuffer(pool);
|
|
145
|
+
}
|
|
146
|
+
}),
|
|
147
|
+
input: Token.toJSON(route.input),
|
|
148
|
+
output: Token.toJSON(route.output),
|
|
149
|
+
_midPrice: route._midPrice,
|
|
150
|
+
};
|
|
151
|
+
return msgpack.encode(json);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public equals(other: Route<Currency, Currency>): boolean {
|
|
155
|
+
if (this.pools.length !== other.pools.length) return false;
|
|
156
|
+
|
|
157
|
+
for (let i = 0; i < this.pools.length; i++) {
|
|
158
|
+
if (!this.pools[i].equals(other.pools[i])) return false;
|
|
159
|
+
}
|
|
160
|
+
return this.input.equals(other.input) && this.output.equals(other.output);
|
|
83
161
|
}
|
|
84
162
|
}
|
package/src/entities/tick.ts
CHANGED
|
@@ -45,4 +45,30 @@ export class Tick {
|
|
|
45
45
|
this.secondsOutside = JSBI.BigInt(secondsOutside);
|
|
46
46
|
this.secondsPerLiquidityOutsideX64 = JSBI.BigInt(secondsPerLiquidityOutsideX64);
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
static toJSON(tick: Tick): object {
|
|
50
|
+
return {
|
|
51
|
+
id: tick.id,
|
|
52
|
+
liquidityGross: tick.liquidityGross.toString(),
|
|
53
|
+
liquidityNet: tick.liquidityNet.toString(),
|
|
54
|
+
feeGrowthOutsideAX64: tick.feeGrowthOutsideAX64.toString(),
|
|
55
|
+
feeGrowthOutsideBX64: tick.feeGrowthOutsideBX64.toString(),
|
|
56
|
+
tickCumulativeOutside: tick.tickCumulativeOutside.toString(),
|
|
57
|
+
secondsOutside: tick.secondsOutside.toString(),
|
|
58
|
+
secondsPerLiquidityOutsideX64: tick.secondsPerLiquidityOutsideX64.toString(),
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static fromJSON(json: any): Tick {
|
|
63
|
+
return new Tick({
|
|
64
|
+
id: json.id,
|
|
65
|
+
liquidityGross: JSBI.BigInt(json.liquidityGross),
|
|
66
|
+
liquidityNet: JSBI.BigInt(json.liquidityNet),
|
|
67
|
+
feeGrowthOutsideAX64: JSBI.BigInt(json.feeGrowthOutsideAX64),
|
|
68
|
+
feeGrowthOutsideBX64: JSBI.BigInt(json.feeGrowthOutsideBX64),
|
|
69
|
+
tickCumulativeOutside: JSBI.BigInt(json.tickCumulativeOutside),
|
|
70
|
+
secondsOutside: JSBI.BigInt(json.secondsOutside),
|
|
71
|
+
secondsPerLiquidityOutsideX64: JSBI.BigInt(json.secondsPerLiquidityOutsideX64),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
48
74
|
}
|
|
@@ -6,7 +6,7 @@ import { TickDataProvider } from "./tickDataProvider";
|
|
|
6
6
|
* A data provider for ticks that is backed by an in-memory array of ticks.
|
|
7
7
|
*/
|
|
8
8
|
export class TickListDataProvider implements TickDataProvider {
|
|
9
|
-
|
|
9
|
+
public ticks: readonly Tick[];
|
|
10
10
|
|
|
11
11
|
constructor(ticks: (Tick | TickConstructorArgs)[], tickSpacing: number) {
|
|
12
12
|
const ticksMapped: Tick[] = ticks.map((t) =>
|
|
@@ -34,4 +34,12 @@ export class TickListDataProvider implements TickDataProvider {
|
|
|
34
34
|
tickSpacing
|
|
35
35
|
);
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
static toJSON(ticks: Tick[]): object {
|
|
39
|
+
return ticks.map((tick) => Tick.toJSON(tick));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static fromJSON(ticksArray: any): TickListDataProvider {
|
|
43
|
+
return ticksArray.map(Tick.fromJSON);
|
|
44
|
+
}
|
|
37
45
|
}
|
package/src/entities/token.ts
CHANGED
|
@@ -51,4 +51,16 @@ export class Token extends BaseCurrency {
|
|
|
51
51
|
return name(this.contract).raw().lt(name(other.contract).raw());
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
static toJSON(token: Token) {
|
|
56
|
+
return {
|
|
57
|
+
contract: token.contract,
|
|
58
|
+
decimals: token.decimals,
|
|
59
|
+
symbol: token.symbol,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static fromJSON(json: any) {
|
|
64
|
+
return new Token(json.contract, json.decimals, json.symbol);
|
|
65
|
+
}
|
|
54
66
|
}
|
package/src/entities/trade.ts
CHANGED
|
@@ -240,7 +240,7 @@ export class Trade<TInput extends Currency, TOutput extends Currency, TTradeType
|
|
|
240
240
|
amounts[0] = amount
|
|
241
241
|
for (let i = 0; i < route.tokenPath.length - 1; i++) {
|
|
242
242
|
const pool = route.pools[i]
|
|
243
|
-
const
|
|
243
|
+
const outputAmount = pool.getOutputAmount(amounts[i])
|
|
244
244
|
amounts[i + 1] = outputAmount
|
|
245
245
|
}
|
|
246
246
|
inputAmount = CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator)
|
|
@@ -254,7 +254,7 @@ export class Trade<TInput extends Currency, TOutput extends Currency, TTradeType
|
|
|
254
254
|
amounts[amounts.length - 1] = amount
|
|
255
255
|
for (let i = route.tokenPath.length - 1; i > 0; i--) {
|
|
256
256
|
const pool = route.pools[i - 1]
|
|
257
|
-
const
|
|
257
|
+
const inputAmount = pool.getInputAmount(amounts[i])
|
|
258
258
|
amounts[i - 1] = inputAmount
|
|
259
259
|
}
|
|
260
260
|
inputAmount = CurrencyAmount.fromFractionalAmount(route.input, amounts[0].numerator, amounts[0].denominator)
|
|
@@ -302,7 +302,7 @@ export class Trade<TInput extends Currency, TOutput extends Currency, TTradeType
|
|
|
302
302
|
|
|
303
303
|
for (let i = 0; i < route.tokenPath.length - 1; i++) {
|
|
304
304
|
const pool = route.pools[i]
|
|
305
|
-
const
|
|
305
|
+
const outputAmount = pool.getOutputAmount(amounts[i])
|
|
306
306
|
amounts[i + 1] = outputAmount
|
|
307
307
|
}
|
|
308
308
|
|
|
@@ -322,7 +322,7 @@ export class Trade<TInput extends Currency, TOutput extends Currency, TTradeType
|
|
|
322
322
|
|
|
323
323
|
for (let i = route.tokenPath.length - 1; i > 0; i--) {
|
|
324
324
|
const pool = route.pools[i - 1]
|
|
325
|
-
const
|
|
325
|
+
const inputAmount = pool.getInputAmount(amounts[i])
|
|
326
326
|
amounts[i - 1] = inputAmount
|
|
327
327
|
}
|
|
328
328
|
|
|
@@ -62,3 +62,63 @@ export function computeAllRoutes(
|
|
|
62
62
|
|
|
63
63
|
return routes;
|
|
64
64
|
}
|
|
65
|
+
|
|
66
|
+
export function computeAllRoutesFromMap(
|
|
67
|
+
tokenIn: Token,
|
|
68
|
+
tokenOut: Token,
|
|
69
|
+
poolMap: { [tokenId: string]: Pool[] },
|
|
70
|
+
maxHops: number
|
|
71
|
+
): Route<Token , Token>[] {
|
|
72
|
+
const routes: Route<Token, Token>[] = [];
|
|
73
|
+
|
|
74
|
+
const computeRoutes = (
|
|
75
|
+
tokenIn: Token,
|
|
76
|
+
tokenOut: Token,
|
|
77
|
+
currentRoute: Pool[],
|
|
78
|
+
visitedPools: Set<Pool>,
|
|
79
|
+
_previousTokenOut?: Token
|
|
80
|
+
) => {
|
|
81
|
+
if (currentRoute.length > maxHops) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (
|
|
86
|
+
currentRoute.length > 0 &&
|
|
87
|
+
currentRoute[currentRoute.length - 1]!.involvesToken(tokenOut)
|
|
88
|
+
) {
|
|
89
|
+
routes.push(new Route([...currentRoute], tokenIn, tokenOut));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const previousTokenOut = _previousTokenOut ? _previousTokenOut : tokenIn;
|
|
94
|
+
const relevantPools = poolMap[previousTokenOut.id] || [];
|
|
95
|
+
|
|
96
|
+
for (const curPool of relevantPools) {
|
|
97
|
+
if (visitedPools.has(curPool)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const currentTokenOut = curPool.tokenA.equals(previousTokenOut)
|
|
102
|
+
? curPool.tokenB
|
|
103
|
+
: curPool.tokenA;
|
|
104
|
+
|
|
105
|
+
currentRoute.push(curPool);
|
|
106
|
+
visitedPools.add(curPool);
|
|
107
|
+
|
|
108
|
+
computeRoutes(
|
|
109
|
+
tokenIn,
|
|
110
|
+
tokenOut,
|
|
111
|
+
currentRoute,
|
|
112
|
+
visitedPools,
|
|
113
|
+
currentTokenOut
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
visitedPools.delete(curPool);
|
|
117
|
+
currentRoute.pop();
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
computeRoutes(tokenIn, tokenOut, [], new Set());
|
|
122
|
+
|
|
123
|
+
return routes;
|
|
124
|
+
}
|
package/test/pool.test.ts
CHANGED
|
@@ -292,14 +292,14 @@ describe("Pool", () => {
|
|
|
292
292
|
describe("#getOutputAmount", () => {
|
|
293
293
|
it("USDC -> DAI", async () => {
|
|
294
294
|
const inputAmount = CurrencyAmount.fromRawAmount(USDC, 100);
|
|
295
|
-
const
|
|
295
|
+
const outputAmount = await pool.getOutputAmount(inputAmount);
|
|
296
296
|
expect(outputAmount.currency.equals(DAI)).toBe(true);
|
|
297
297
|
expect(outputAmount.quotient).toEqual(JSBI.BigInt(98));
|
|
298
298
|
});
|
|
299
299
|
|
|
300
300
|
it("DAI -> USDC", async () => {
|
|
301
301
|
const inputAmount = CurrencyAmount.fromRawAmount(DAI, 100);
|
|
302
|
-
const
|
|
302
|
+
const outputAmount = await pool.getOutputAmount(inputAmount);
|
|
303
303
|
expect(outputAmount.currency.equals(USDC)).toBe(true);
|
|
304
304
|
expect(outputAmount.quotient).toEqual(JSBI.BigInt(98));
|
|
305
305
|
});
|
|
@@ -308,14 +308,14 @@ describe("Pool", () => {
|
|
|
308
308
|
describe("#getInputAmount", () => {
|
|
309
309
|
it("USDC -> DAI", async () => {
|
|
310
310
|
const outputAmount = CurrencyAmount.fromRawAmount(DAI, 98);
|
|
311
|
-
const
|
|
311
|
+
const inputAmount = await pool.getInputAmount(outputAmount);
|
|
312
312
|
expect(inputAmount.currency.equals(USDC)).toBe(true);
|
|
313
313
|
expect(inputAmount.quotient).toEqual(JSBI.BigInt(100));
|
|
314
314
|
});
|
|
315
315
|
|
|
316
316
|
it("DAI -> USDC", async () => {
|
|
317
317
|
const outputAmount = CurrencyAmount.fromRawAmount(USDC, 98);
|
|
318
|
-
const
|
|
318
|
+
const inputAmount = await pool.getInputAmount(outputAmount);
|
|
319
319
|
expect(inputAmount.currency.equals(DAI)).toBe(true);
|
|
320
320
|
expect(inputAmount.quotient).toEqual(JSBI.BigInt(100));
|
|
321
321
|
});
|
|
@@ -367,7 +367,7 @@ describe("Pool", () => {
|
|
|
367
367
|
});
|
|
368
368
|
it("correctly handles two BigIntegers", async () => {
|
|
369
369
|
const inputAmount = CurrencyAmount.fromRawAmount(USDC, 100);
|
|
370
|
-
const
|
|
370
|
+
const outputAmount = await pool.getOutputAmount(inputAmount);
|
|
371
371
|
pool.getInputAmount(outputAmount);
|
|
372
372
|
expect(outputAmount.currency.equals(DAI)).toBe(true);
|
|
373
373
|
// if output is correct, function has succeeded
|