@alcorexchange/alcor-swap-sdk 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.
Files changed (110) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +12 -0
  3. package/LICENSE +21 -0
  4. package/build/entities/baseCurrency.js +27 -0
  5. package/build/entities/currency.js +2 -0
  6. package/build/entities/fractions/currencyAmount.js +80 -0
  7. package/build/entities/fractions/fraction.js +117 -0
  8. package/build/entities/fractions/index.js +11 -0
  9. package/build/entities/fractions/percent.js +46 -0
  10. package/build/entities/fractions/price.js +73 -0
  11. package/build/entities/index.js +26 -0
  12. package/build/entities/pool.js +248 -0
  13. package/build/entities/position.js +364 -0
  14. package/build/entities/route.js +70 -0
  15. package/build/entities/tick.js +23 -0
  16. package/build/entities/tickDataProvider.js +30 -0
  17. package/build/entities/tickListDataProvider.js +35 -0
  18. package/build/entities/token.js +53 -0
  19. package/build/entities/trade.js +464 -0
  20. package/build/index.js +19 -0
  21. package/build/internalConstants.js +54 -0
  22. package/build/utils/computeAllRoutes.js +39 -0
  23. package/build/utils/encodeSqrtRatioX64.js +21 -0
  24. package/build/utils/fullMath.js +22 -0
  25. package/build/utils/index.js +30 -0
  26. package/build/utils/isSorted.js +18 -0
  27. package/build/utils/liquidityMath.js +23 -0
  28. package/build/utils/maxLiquidityForAmounts.js +86 -0
  29. package/build/utils/mostSignificantBit.js +27 -0
  30. package/build/utils/nearestUsableTick.js +26 -0
  31. package/build/utils/positionLibrary.js +22 -0
  32. package/build/utils/priceTickConversions.js +51 -0
  33. package/build/utils/sortedInsert.js +39 -0
  34. package/build/utils/sqrt.js +33 -0
  35. package/build/utils/sqrtPriceMath.js +92 -0
  36. package/build/utils/swapMath.js +86 -0
  37. package/build/utils/tickLibrary.js +61 -0
  38. package/build/utils/tickList.js +110 -0
  39. package/build/utils/tickMath.js +122 -0
  40. package/jest.config.js +40 -0
  41. package/nodemon.json +6 -0
  42. package/package.json +51 -0
  43. package/src/entities/baseCurrency.ts +53 -0
  44. package/src/entities/currency.ts +3 -0
  45. package/src/entities/fractions/currencyAmount.ts +129 -0
  46. package/src/entities/fractions/fraction.ts +190 -0
  47. package/src/entities/fractions/index.ts +4 -0
  48. package/src/entities/fractions/percent.ts +54 -0
  49. package/src/entities/fractions/price.ts +127 -0
  50. package/src/entities/index.ts +11 -0
  51. package/src/entities/pool.ts +399 -0
  52. package/src/entities/position.ts +591 -0
  53. package/src/entities/route.ts +84 -0
  54. package/src/entities/tick.ts +48 -0
  55. package/src/entities/tickDataProvider.ts +43 -0
  56. package/src/entities/tickListDataProvider.ts +37 -0
  57. package/src/entities/token.ts +56 -0
  58. package/src/entities/trade.ts +650 -0
  59. package/src/index.ts +3 -0
  60. package/src/internalConstants.ts +58 -0
  61. package/src/utils/computeAllRoutes.ts +64 -0
  62. package/src/utils/encodeSqrtRatioX64.ts +20 -0
  63. package/src/utils/fullMath.ts +17 -0
  64. package/src/utils/index.ts +14 -0
  65. package/src/utils/isSorted.ts +17 -0
  66. package/src/utils/liquidityMath.ts +17 -0
  67. package/src/utils/maxLiquidityForAmounts.ts +127 -0
  68. package/src/utils/mostSignificantBit.ts +25 -0
  69. package/src/utils/nearestUsableTick.ts +23 -0
  70. package/src/utils/positionLibrary.ts +37 -0
  71. package/src/utils/priceTickConversions.ts +57 -0
  72. package/src/utils/sortedInsert.ts +35 -0
  73. package/src/utils/sqrt.ts +31 -0
  74. package/src/utils/sqrtPriceMath.ts +169 -0
  75. package/src/utils/swapMath.ts +175 -0
  76. package/src/utils/tickLibrary.ts +88 -0
  77. package/src/utils/tickList.ts +147 -0
  78. package/src/utils/tickMath.ts +166 -0
  79. package/test/bestTradeExactOut.test.ts +266 -0
  80. package/test/currencyAmount.test.js +92 -0
  81. package/test/currencyAmount.test.ts +114 -0
  82. package/test/encodeSqrtRatioX64.test.ts +33 -0
  83. package/test/fixtures/pools.json +276 -0
  84. package/test/fixtures/ticks.json +608 -0
  85. package/test/fraction.test.js +87 -0
  86. package/test/fraction.test.ts +176 -0
  87. package/test/isSorted.test.ts +52 -0
  88. package/test/maxLiquidityForAmounts.test copy.ts +256 -0
  89. package/test/mostSignificantBit.test.ts +32 -0
  90. package/test/nearestUsableTick.test.ts +54 -0
  91. package/test/percent.test.js +52 -0
  92. package/test/percent.test.ts +68 -0
  93. package/test/pool.test.ts +377 -0
  94. package/test/position.test.ts +579 -0
  95. package/test/positionLibrary.test.ts +31 -0
  96. package/test/price.test.js +57 -0
  97. package/test/price.test.ts +62 -0
  98. package/test/priceTickConversions.test.ts +137 -0
  99. package/test/sqrtPriceMath.test.ts +113 -0
  100. package/test/tick.test.js +22 -0
  101. package/test/tick.test.ts +28 -0
  102. package/test/tickDataProvider.test.ts +17 -0
  103. package/test/tickLibrary.test.ts +111 -0
  104. package/test/tickList.test.ts +215 -0
  105. package/test/tickListDataProvider.test.ts +64 -0
  106. package/test/tickMath.test.ts +66 -0
  107. package/test/token.test.ts +58 -0
  108. package/test/trade.test.ts +210 -0
  109. package/test2.ts +73 -0
  110. package/tsconfig.json +24 -0
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.Pool = void 0;
16
+ const fractions_1 = require("./fractions");
17
+ const internalConstants_1 = require("../internalConstants");
18
+ const jsbi_1 = __importDefault(require("jsbi"));
19
+ const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
20
+ const internalConstants_2 = require("../internalConstants");
21
+ const liquidityMath_1 = require("../utils/liquidityMath");
22
+ const swapMath_1 = require("../utils/swapMath");
23
+ const tickMath_1 = require("../utils/tickMath");
24
+ const tickDataProvider_1 = require("./tickDataProvider");
25
+ const tickListDataProvider_1 = require("./tickListDataProvider");
26
+ /**
27
+ * By default, pools will not allow operations that require ticks.
28
+ */
29
+ const NO_TICK_DATA_PROVIDER_DEFAULT = new tickDataProvider_1.NoTickDataProvider();
30
+ /**
31
+ * Represents a V3 pool
32
+ */
33
+ class Pool {
34
+ /**
35
+ * Construct a pool
36
+ * @param tokenA One of the tokens in the pool
37
+ * @param tokenB The other token in the pool
38
+ * @param fee The fee in hundredths of a bips of the input amount of every swap that is collected by the pool
39
+ * @param sqrtPriceX64 The sqrt of the current ratio of amounts of tokenB to tokenA
40
+ * @param liquidity The current value of in range liquidity
41
+ * @param tickCurrent The current tick of the pool
42
+ * @param ticks The current state of the pool ticks or a data provider that can return tick data
43
+ */
44
+ constructor({ id, tokenA, tokenB, fee, sqrtPriceX64, liquidity, tickCurrent, ticks = NO_TICK_DATA_PROVIDER_DEFAULT, feeGrowthGlobalAX64 = 0, feeGrowthGlobalBX64 = 0, }) {
45
+ (0, tiny_invariant_1.default)(Number.isInteger(fee) && fee < 1000000, "FEE");
46
+ const tickCurrentSqrtRatioX64 = tickMath_1.TickMath.getSqrtRatioAtTick(tickCurrent);
47
+ const nextTickSqrtRatioX64 = tickMath_1.TickMath.getSqrtRatioAtTick(tickCurrent + 1);
48
+ (0, tiny_invariant_1.default)(jsbi_1.default.greaterThanOrEqual(jsbi_1.default.BigInt(sqrtPriceX64), tickCurrentSqrtRatioX64) &&
49
+ jsbi_1.default.lessThanOrEqual(jsbi_1.default.BigInt(sqrtPriceX64), nextTickSqrtRatioX64), "PRICE_BOUNDS");
50
+ // always create a copy of the list since we want the pool's tick list to be immutable
51
+ this.id = id;
52
+ this.fee = fee;
53
+ this.sqrtPriceX64 = jsbi_1.default.BigInt(sqrtPriceX64);
54
+ this.liquidity = jsbi_1.default.BigInt(liquidity);
55
+ this.tickCurrent = tickCurrent;
56
+ this.feeGrowthGlobalAX64 = jsbi_1.default.BigInt(feeGrowthGlobalAX64);
57
+ this.feeGrowthGlobalBX64 = jsbi_1.default.BigInt(feeGrowthGlobalBX64);
58
+ this.tickDataProvider = Array.isArray(ticks)
59
+ ? new tickListDataProvider_1.TickListDataProvider(ticks, internalConstants_1.TICK_SPACINGS[fee])
60
+ : ticks;
61
+ [this.tokenA, this.tokenB] = tokenA.sortsBefore(tokenB)
62
+ ? [tokenA, tokenB]
63
+ : [tokenB, tokenA];
64
+ }
65
+ /**
66
+ * Returns true if the token is either tokenA or tokenB
67
+ * @param token The token to check
68
+ * @returns True if token is either tokenA or token
69
+ */
70
+ involvesToken(token) {
71
+ return token.equals(this.tokenA) || token.equals(this.tokenB);
72
+ }
73
+ /**
74
+ * Returns the current mid price of the pool in terms of tokenA, i.e. the ratio of tokenB over tokenA
75
+ */
76
+ get tokenAPrice() {
77
+ var _a;
78
+ return ((_a = this._tokenAPrice) !== null && _a !== void 0 ? _a : (this._tokenAPrice = new fractions_1.Price(this.tokenA, this.tokenB, internalConstants_2.Q128, jsbi_1.default.multiply(this.sqrtPriceX64, this.sqrtPriceX64))));
79
+ }
80
+ /**
81
+ * Returns the current mid price of the pool in terms of tokenB, i.e. the ratio of tokenA over tokenB
82
+ */
83
+ get tokenBPrice() {
84
+ var _a;
85
+ return ((_a = this._tokenBPrice) !== null && _a !== void 0 ? _a : (this._tokenBPrice = new fractions_1.Price(this.tokenB, this.tokenA, jsbi_1.default.multiply(this.sqrtPriceX64, this.sqrtPriceX64), internalConstants_2.Q128)));
86
+ }
87
+ /**
88
+ * Return the price of the given token in terms of the other token in the pool.
89
+ * @param token The token to return price of
90
+ * @returns The price of the given token, in terms of the other.
91
+ */
92
+ priceOf(token) {
93
+ (0, tiny_invariant_1.default)(this.involvesToken(token), "TOKEN");
94
+ return token.equals(this.tokenA) ? this.tokenAPrice : this.tokenBPrice;
95
+ }
96
+ /**
97
+ * Given an input amount of a token, return the computed output amount, and a pool with state updated after the trade
98
+ * @param inputAmount The input amount for which to quote the output amount
99
+ * @param sqrtPriceLimitX64 The Q64.96 sqrt price limit
100
+ * @returns The output amount and the pool with updated state
101
+ */
102
+ getOutputAmount(inputAmount, sqrtPriceLimitX64) {
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ (0, tiny_invariant_1.default)(this.involvesToken(inputAmount.currency), "TOKEN");
105
+ const zeroForOne = inputAmount.currency.equals(this.tokenA);
106
+ const { amountCalculated: outputAmount, sqrtPriceX64, liquidity, tickCurrent, } = yield this.swap(zeroForOne, inputAmount.quotient, sqrtPriceLimitX64);
107
+ const outputToken = zeroForOne ? this.tokenB : this.tokenA;
108
+ return [
109
+ fractions_1.CurrencyAmount.fromRawAmount(outputToken, jsbi_1.default.multiply(outputAmount, internalConstants_2.NEGATIVE_ONE)),
110
+ new Pool({
111
+ id: this.id,
112
+ tokenA: this.tokenA,
113
+ tokenB: this.tokenB,
114
+ fee: this.fee,
115
+ sqrtPriceX64,
116
+ liquidity,
117
+ tickCurrent,
118
+ ticks: this.tickDataProvider,
119
+ feeGrowthGlobalAX64: this.feeGrowthGlobalAX64,
120
+ feeGrowthGlobalBX64: this.feeGrowthGlobalBX64,
121
+ })
122
+ ];
123
+ });
124
+ }
125
+ /**
126
+ * Given a desired output amount of a token, return the computed input amount and a pool with state updated after the trade
127
+ * @param outputAmount the output amount for which to quote the input amount
128
+ * @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
129
+ * @returns The input amount and the pool with updated state
130
+ */
131
+ getInputAmount(outputAmount, sqrtPriceLimitX64) {
132
+ return __awaiter(this, void 0, void 0, function* () {
133
+ const zeroForOne = outputAmount.currency.equals(this.tokenB);
134
+ const { amountCalculated: inputAmount, sqrtPriceX64, liquidity, tickCurrent, } = yield this.swap(zeroForOne, jsbi_1.default.multiply(outputAmount.quotient, internalConstants_2.NEGATIVE_ONE), sqrtPriceLimitX64);
135
+ const inputToken = zeroForOne ? this.tokenA : this.tokenB;
136
+ return [
137
+ fractions_1.CurrencyAmount.fromRawAmount(inputToken, inputAmount),
138
+ new Pool({
139
+ id: this.id,
140
+ tokenA: this.tokenA,
141
+ tokenB: this.tokenB,
142
+ fee: this.fee,
143
+ sqrtPriceX64,
144
+ liquidity,
145
+ tickCurrent,
146
+ ticks: this.tickDataProvider,
147
+ feeGrowthGlobalAX64: this.feeGrowthGlobalAX64,
148
+ feeGrowthGlobalBX64: this.feeGrowthGlobalBX64,
149
+ }),
150
+ ];
151
+ });
152
+ }
153
+ /**
154
+ * Executes a swap
155
+ * @param zeroForOne Whether the amount in is tokenA or tokenB
156
+ * @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
157
+ * @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
158
+ * @returns amountCalculated
159
+ * @returns sqrtPriceX64
160
+ * @returns liquidity
161
+ * @returns tickCurrent
162
+ */
163
+ swap(zeroForOne, amountSpecified, sqrtPriceLimitX64) {
164
+ return __awaiter(this, void 0, void 0, function* () {
165
+ if (!sqrtPriceLimitX64)
166
+ sqrtPriceLimitX64 = zeroForOne
167
+ ? jsbi_1.default.add(tickMath_1.TickMath.MIN_SQRT_RATIO, internalConstants_2.ONE)
168
+ : jsbi_1.default.subtract(tickMath_1.TickMath.MAX_SQRT_RATIO, internalConstants_2.ONE);
169
+ if (zeroForOne) {
170
+ (0, tiny_invariant_1.default)(jsbi_1.default.greaterThan(sqrtPriceLimitX64, tickMath_1.TickMath.MIN_SQRT_RATIO), "RATIO_MIN");
171
+ (0, tiny_invariant_1.default)(jsbi_1.default.lessThan(sqrtPriceLimitX64, this.sqrtPriceX64), "RATIO_CURRENT");
172
+ }
173
+ else {
174
+ (0, tiny_invariant_1.default)(jsbi_1.default.lessThan(sqrtPriceLimitX64, tickMath_1.TickMath.MAX_SQRT_RATIO), "RATIO_MAX");
175
+ (0, tiny_invariant_1.default)(jsbi_1.default.greaterThan(sqrtPriceLimitX64, this.sqrtPriceX64), "RATIO_CURRENT");
176
+ }
177
+ const exactInput = jsbi_1.default.greaterThanOrEqual(amountSpecified, internalConstants_2.ZERO);
178
+ // keep track of swap state
179
+ const state = {
180
+ amountSpecifiedRemaining: amountSpecified,
181
+ amountCalculated: internalConstants_2.ZERO,
182
+ sqrtPriceX64: this.sqrtPriceX64,
183
+ tick: this.tickCurrent,
184
+ liquidity: this.liquidity,
185
+ };
186
+ // start swap while loop
187
+ while (jsbi_1.default.notEqual(state.amountSpecifiedRemaining, internalConstants_2.ZERO) &&
188
+ state.sqrtPriceX64 != sqrtPriceLimitX64) {
189
+ const step = {};
190
+ step.sqrtPriceStartX64 = state.sqrtPriceX64;
191
+ // because each iteration of the while loop rounds, we can't optimize this code (relative to the smart contract)
192
+ // by simply traversing to the next available tick, we instead need to exactly replicate
193
+ // tickBitmap.nextInitializedTickWithinOneWord
194
+ [step.tickNext, step.initialized] =
195
+ yield this.tickDataProvider.nextInitializedTickWithinOneWord(state.tick, zeroForOne, this.tickSpacing);
196
+ if (step.tickNext < tickMath_1.TickMath.MIN_TICK) {
197
+ step.tickNext = tickMath_1.TickMath.MIN_TICK;
198
+ }
199
+ else if (step.tickNext > tickMath_1.TickMath.MAX_TICK) {
200
+ step.tickNext = tickMath_1.TickMath.MAX_TICK;
201
+ }
202
+ step.sqrtPriceNextX64 = tickMath_1.TickMath.getSqrtRatioAtTick(step.tickNext);
203
+ [state.sqrtPriceX64, step.amountIn, step.amountOut, step.feeAmount] =
204
+ swapMath_1.SwapMath.computeSwapStep(state.sqrtPriceX64, (zeroForOne
205
+ ? jsbi_1.default.lessThan(step.sqrtPriceNextX64, sqrtPriceLimitX64)
206
+ : jsbi_1.default.greaterThan(step.sqrtPriceNextX64, sqrtPriceLimitX64))
207
+ ? sqrtPriceLimitX64
208
+ : step.sqrtPriceNextX64, state.liquidity, state.amountSpecifiedRemaining, this.fee);
209
+ if (exactInput) {
210
+ state.amountSpecifiedRemaining = jsbi_1.default.subtract(state.amountSpecifiedRemaining, jsbi_1.default.add(step.amountIn, step.feeAmount));
211
+ state.amountCalculated = jsbi_1.default.subtract(state.amountCalculated, step.amountOut);
212
+ }
213
+ else {
214
+ state.amountSpecifiedRemaining = jsbi_1.default.add(state.amountSpecifiedRemaining, step.amountOut);
215
+ state.amountCalculated = jsbi_1.default.add(state.amountCalculated, jsbi_1.default.add(step.amountIn, step.feeAmount));
216
+ }
217
+ // TODO
218
+ if (jsbi_1.default.equal(state.sqrtPriceX64, step.sqrtPriceNextX64)) {
219
+ // if the tick is initialized, run the tick transition
220
+ if (step.initialized) {
221
+ let liquidityNet = jsbi_1.default.BigInt((yield this.tickDataProvider.getTick(step.tickNext)).liquidityNet);
222
+ // if we're moving leftward, we interpret liquidityNet as the opposite sign
223
+ // safe because liquidityNet cannot be type(int128).min
224
+ if (zeroForOne)
225
+ liquidityNet = jsbi_1.default.multiply(liquidityNet, internalConstants_2.NEGATIVE_ONE);
226
+ state.liquidity = liquidityMath_1.LiquidityMath.addDelta(state.liquidity, liquidityNet);
227
+ }
228
+ state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext;
229
+ }
230
+ else if (jsbi_1.default.notEqual(state.sqrtPriceX64, step.sqrtPriceStartX64)) {
231
+ // updated comparison function
232
+ // recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved
233
+ state.tick = tickMath_1.TickMath.getTickAtSqrtRatio(state.sqrtPriceX64);
234
+ }
235
+ }
236
+ return {
237
+ amountCalculated: state.amountCalculated,
238
+ sqrtPriceX64: state.sqrtPriceX64,
239
+ liquidity: state.liquidity,
240
+ tickCurrent: state.tick,
241
+ };
242
+ });
243
+ }
244
+ get tickSpacing() {
245
+ return internalConstants_1.TICK_SPACINGS[this.fee];
246
+ }
247
+ }
248
+ exports.Pool = Pool;
@@ -0,0 +1,364 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.Position = void 0;
16
+ const fractions_1 = require("./fractions");
17
+ const internalConstants_1 = require("../internalConstants");
18
+ const jsbi_1 = __importDefault(require("jsbi"));
19
+ const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
20
+ const internalConstants_2 = require("../internalConstants");
21
+ const maxLiquidityForAmounts_1 = require("../utils/maxLiquidityForAmounts");
22
+ const priceTickConversions_1 = require("../utils/priceTickConversions");
23
+ const sqrtPriceMath_1 = require("../utils/sqrtPriceMath");
24
+ const tickMath_1 = require("../utils/tickMath");
25
+ const encodeSqrtRatioX64_1 = require("../utils/encodeSqrtRatioX64");
26
+ const pool_1 = require("./pool");
27
+ const utils_1 = require("../utils");
28
+ class Position {
29
+ /**
30
+ * Constructs a position for a given pool with the given liquidity
31
+ * @param pool For which pool the liquidity is assigned
32
+ * @param liquidity The amount of liquidity that is in the position
33
+ * @param lower The lower tick of the position
34
+ * @param upper The upper tick of the position
35
+ */
36
+ constructor({ id, owner, pool, liquidity, tickLower, tickUpper, feeGrowthInsideALastX64 = 0, feeGrowthInsideBLastX64 = 0, }) {
37
+ // cached resuts for the getters
38
+ this._tokenAAmount = null;
39
+ this._tokenBAmount = null;
40
+ this._mintAmounts = null;
41
+ (0, tiny_invariant_1.default)(tickLower < tickUpper, "TICK_ORDER");
42
+ (0, tiny_invariant_1.default)(tickLower >= tickMath_1.TickMath.MIN_TICK && tickLower % pool.tickSpacing === 0, "TICK_LOWER");
43
+ (0, tiny_invariant_1.default)(tickUpper <= tickMath_1.TickMath.MAX_TICK && tickUpper % pool.tickSpacing === 0, "TICK_UPPER");
44
+ this.id = id;
45
+ this.owner = owner;
46
+ this.pool = pool;
47
+ this.tickLower = tickLower;
48
+ this.tickUpper = tickUpper;
49
+ this.liquidity = jsbi_1.default.BigInt(liquidity);
50
+ this.feeGrowthInsideALastX64 = jsbi_1.default.BigInt(feeGrowthInsideALastX64);
51
+ this.feeGrowthInsideBLastX64 = jsbi_1.default.BigInt(feeGrowthInsideBLastX64);
52
+ }
53
+ get inRange() {
54
+ return (this.tickLower < this.pool.tickCurrent &&
55
+ this.pool.tickCurrent < this.tickUpper);
56
+ }
57
+ /**
58
+ * Returns the price of tokenA at the lower tick
59
+ */
60
+ get tokenAPriceLower() {
61
+ return (0, priceTickConversions_1.tickToPrice)(this.pool.tokenA, this.pool.tokenB, this.tickLower);
62
+ }
63
+ /**
64
+ * Returns the price of tokenA at the upper tick
65
+ */
66
+ get tokenAPriceUpper() {
67
+ return (0, priceTickConversions_1.tickToPrice)(this.pool.tokenA, this.pool.tokenB, this.tickUpper);
68
+ }
69
+ /**
70
+ * Returns the amount of tokenA that this position's liquidity could be burned for at the current pool price
71
+ */
72
+ get amountA() {
73
+ if (this._tokenAAmount === null) {
74
+ if (this.pool.tickCurrent < this.tickLower) {
75
+ this._tokenAAmount = fractions_1.CurrencyAmount.fromRawAmount(this.pool.tokenA, sqrtPriceMath_1.SqrtPriceMath.getAmountADelta(tickMath_1.TickMath.getSqrtRatioAtTick(this.tickLower), tickMath_1.TickMath.getSqrtRatioAtTick(this.tickUpper), this.liquidity, false));
76
+ }
77
+ else if (this.pool.tickCurrent < this.tickUpper) {
78
+ this._tokenAAmount = fractions_1.CurrencyAmount.fromRawAmount(this.pool.tokenA, sqrtPriceMath_1.SqrtPriceMath.getAmountADelta(this.pool.sqrtPriceX64, tickMath_1.TickMath.getSqrtRatioAtTick(this.tickUpper), this.liquidity, false));
79
+ }
80
+ else {
81
+ this._tokenAAmount = fractions_1.CurrencyAmount.fromRawAmount(this.pool.tokenA, internalConstants_2.ZERO);
82
+ }
83
+ }
84
+ return this._tokenAAmount;
85
+ }
86
+ /**
87
+ * Returns the amount of tokenB that this position's liquidity could be burned for at the current pool price
88
+ */
89
+ get amountB() {
90
+ if (this._tokenBAmount === null) {
91
+ if (this.pool.tickCurrent < this.tickLower) {
92
+ this._tokenBAmount = fractions_1.CurrencyAmount.fromRawAmount(this.pool.tokenB, internalConstants_2.ZERO);
93
+ }
94
+ else if (this.pool.tickCurrent < this.tickUpper) {
95
+ this._tokenBAmount = fractions_1.CurrencyAmount.fromRawAmount(this.pool.tokenB, sqrtPriceMath_1.SqrtPriceMath.getAmountBDelta(tickMath_1.TickMath.getSqrtRatioAtTick(this.tickLower), this.pool.sqrtPriceX64, this.liquidity, false));
96
+ }
97
+ else {
98
+ this._tokenBAmount = fractions_1.CurrencyAmount.fromRawAmount(this.pool.tokenB, sqrtPriceMath_1.SqrtPriceMath.getAmountBDelta(tickMath_1.TickMath.getSqrtRatioAtTick(this.tickLower), tickMath_1.TickMath.getSqrtRatioAtTick(this.tickUpper), this.liquidity, false));
99
+ }
100
+ }
101
+ return this._tokenBAmount;
102
+ }
103
+ /**
104
+ * Returns the lower and upper sqrt ratios if the price 'slips' up to slippage tolerance percentage
105
+ * @param slippageTolerance The amount by which the price can 'slip' before the transaction will revert
106
+ * @returns The sqrt ratios after slippage
107
+ */
108
+ ratiosAfterSlippage(slippageTolerance) {
109
+ const priceLower = this.pool.tokenAPrice.asFraction.multiply(new fractions_1.Percent(1).subtract(slippageTolerance));
110
+ const priceUpper = this.pool.tokenAPrice.asFraction.multiply(slippageTolerance.add(1));
111
+ let sqrtPriceX64Lower = (0, encodeSqrtRatioX64_1.encodeSqrtRatioX64)(priceLower.numerator, priceLower.denominator);
112
+ if (jsbi_1.default.lessThanOrEqual(sqrtPriceX64Lower, tickMath_1.TickMath.MIN_SQRT_RATIO)) {
113
+ sqrtPriceX64Lower = jsbi_1.default.add(tickMath_1.TickMath.MIN_SQRT_RATIO, jsbi_1.default.BigInt(1));
114
+ }
115
+ let sqrtPriceX64Upper = (0, encodeSqrtRatioX64_1.encodeSqrtRatioX64)(priceUpper.numerator, priceUpper.denominator);
116
+ if (jsbi_1.default.greaterThanOrEqual(sqrtPriceX64Upper, tickMath_1.TickMath.MAX_SQRT_RATIO)) {
117
+ sqrtPriceX64Upper = jsbi_1.default.subtract(tickMath_1.TickMath.MAX_SQRT_RATIO, jsbi_1.default.BigInt(1));
118
+ }
119
+ return {
120
+ sqrtPriceX64Lower,
121
+ sqrtPriceX64Upper,
122
+ };
123
+ }
124
+ /**
125
+ * Returns the minimum amounts that must be sent in order to safely mint the amount of liquidity held by the position
126
+ * with the given slippage tolerance
127
+ * @param slippageTolerance Tolerance of unfavorable slippage from the current price
128
+ * @returns The amounts, with slippage
129
+ */
130
+ mintAmountsWithSlippage(slippageTolerance) {
131
+ // get lower/upper prices
132
+ const { sqrtPriceX64Upper, sqrtPriceX64Lower } = this.ratiosAfterSlippage(slippageTolerance);
133
+ // construct counterfactual pools
134
+ const poolLower = new pool_1.Pool({
135
+ id: this.pool.id,
136
+ tokenA: this.pool.tokenA,
137
+ tokenB: this.pool.tokenB,
138
+ fee: this.pool.fee,
139
+ sqrtPriceX64: sqrtPriceX64Lower,
140
+ liquidity: 0 /* liquidity doesn't matter */,
141
+ tickCurrent: tickMath_1.TickMath.getTickAtSqrtRatio(sqrtPriceX64Lower),
142
+ feeGrowthGlobalAX64: this.feeGrowthInsideALastX64,
143
+ feeGrowthGlobalBX64: this.feeGrowthInsideBLastX64,
144
+ ticks: this.pool.tickDataProvider
145
+ });
146
+ const poolUpper = new pool_1.Pool({
147
+ id: this.pool.id,
148
+ tokenA: this.pool.tokenA,
149
+ tokenB: this.pool.tokenB,
150
+ fee: this.pool.fee,
151
+ sqrtPriceX64: sqrtPriceX64Upper,
152
+ liquidity: 0 /* liquidity doesn't matter */,
153
+ tickCurrent: tickMath_1.TickMath.getTickAtSqrtRatio(sqrtPriceX64Upper),
154
+ feeGrowthGlobalAX64: this.feeGrowthInsideALastX64,
155
+ feeGrowthGlobalBX64: this.feeGrowthInsideBLastX64,
156
+ ticks: this.pool.tickDataProvider
157
+ });
158
+ // because the router is imprecise, we need to calculate the position that will be created (assuming no slippage)
159
+ const positionThatWillBeCreated = Position.fromAmounts(Object.assign(Object.assign({ id: this.id, owner: this.owner, pool: this.pool, tickLower: this.tickLower, tickUpper: this.tickUpper }, this.mintAmounts), { useFullPrecision: false, feeGrowthInsideALastX64: this.feeGrowthInsideALastX64, feeGrowthInsideBLastX64: this.feeGrowthInsideBLastX64 }));
160
+ // we want the smaller amounts...
161
+ // ...which occurs at the upper price for amountA...
162
+ const { amountA } = new Position({
163
+ id: this.id,
164
+ owner: this.owner,
165
+ pool: poolUpper,
166
+ liquidity: positionThatWillBeCreated.liquidity,
167
+ tickLower: this.tickLower,
168
+ tickUpper: this.tickUpper,
169
+ feeGrowthInsideALastX64: this.feeGrowthInsideALastX64,
170
+ feeGrowthInsideBLastX64: this.feeGrowthInsideBLastX64,
171
+ }).mintAmounts;
172
+ // ...and the lower for amountB
173
+ const { amountB } = new Position({
174
+ id: this.id,
175
+ owner: this.owner,
176
+ pool: poolLower,
177
+ liquidity: positionThatWillBeCreated.liquidity,
178
+ tickLower: this.tickLower,
179
+ tickUpper: this.tickUpper,
180
+ feeGrowthInsideALastX64: this.feeGrowthInsideALastX64,
181
+ feeGrowthInsideBLastX64: this.feeGrowthInsideBLastX64,
182
+ }).mintAmounts;
183
+ return { amountA, amountB };
184
+ }
185
+ /**
186
+ * Returns the minimum amounts that should be requested in order to safely burn the amount of liquidity held by the
187
+ * position with the given slippage tolerance
188
+ * @param slippageTolerance tolerance of unfavorable slippage from the current price
189
+ * @returns The amounts, with slippage
190
+ */
191
+ burnAmountsWithSlippage(slippageTolerance) {
192
+ // get lower/upper prices
193
+ const { sqrtPriceX64Upper, sqrtPriceX64Lower } = this.ratiosAfterSlippage(slippageTolerance);
194
+ // construct counterfactual pools
195
+ const poolLower = new pool_1.Pool({
196
+ id: this.pool.id,
197
+ tokenA: this.pool.tokenA,
198
+ tokenB: this.pool.tokenB,
199
+ fee: this.pool.fee,
200
+ sqrtPriceX64: sqrtPriceX64Lower,
201
+ liquidity: 0 /* liquidity doesn't matter */,
202
+ tickCurrent: tickMath_1.TickMath.getTickAtSqrtRatio(sqrtPriceX64Lower),
203
+ feeGrowthGlobalAX64: this.feeGrowthInsideALastX64,
204
+ feeGrowthGlobalBX64: this.feeGrowthInsideBLastX64,
205
+ ticks: this.pool.tickDataProvider
206
+ });
207
+ const poolUpper = new pool_1.Pool({
208
+ id: this.pool.id,
209
+ tokenA: this.pool.tokenA,
210
+ tokenB: this.pool.tokenB,
211
+ fee: this.pool.fee,
212
+ sqrtPriceX64: sqrtPriceX64Upper,
213
+ liquidity: 0 /* liquidity doesn't matter */,
214
+ tickCurrent: tickMath_1.TickMath.getTickAtSqrtRatio(sqrtPriceX64Upper),
215
+ feeGrowthGlobalAX64: this.feeGrowthInsideALastX64,
216
+ feeGrowthGlobalBX64: this.feeGrowthInsideBLastX64,
217
+ ticks: this.pool.tickDataProvider
218
+ });
219
+ // we want the smaller amounts...
220
+ // ...which occurs at the upper price for amountA...
221
+ const amountA = new Position({
222
+ id: this.id,
223
+ owner: this.owner,
224
+ pool: poolUpper,
225
+ liquidity: this.liquidity,
226
+ tickLower: this.tickLower,
227
+ tickUpper: this.tickUpper,
228
+ feeGrowthInsideALastX64: this.feeGrowthInsideALastX64,
229
+ feeGrowthInsideBLastX64: this.feeGrowthInsideBLastX64,
230
+ }).amountA;
231
+ // ...and the lower for amountB
232
+ const amountB = new Position({
233
+ id: this.id,
234
+ owner: this.owner,
235
+ pool: poolLower,
236
+ liquidity: this.liquidity,
237
+ tickLower: this.tickLower,
238
+ tickUpper: this.tickUpper,
239
+ feeGrowthInsideALastX64: this.feeGrowthInsideALastX64,
240
+ feeGrowthInsideBLastX64: this.feeGrowthInsideBLastX64,
241
+ }).amountB;
242
+ return { amountA: amountA, amountB: amountB };
243
+ }
244
+ /**
245
+ * Returns the minimum amounts that must be sent in order to mint the amount of liquidity held by the position at
246
+ * the current price for the pool
247
+ */
248
+ get mintAmounts() {
249
+ if (this._mintAmounts === null) {
250
+ if (this.pool.tickCurrent < this.tickLower) {
251
+ return {
252
+ amountA: sqrtPriceMath_1.SqrtPriceMath.getAmountADelta(tickMath_1.TickMath.getSqrtRatioAtTick(this.tickLower), tickMath_1.TickMath.getSqrtRatioAtTick(this.tickUpper), this.liquidity, true),
253
+ amountB: internalConstants_2.ZERO,
254
+ };
255
+ }
256
+ else if (this.pool.tickCurrent < this.tickUpper) {
257
+ return {
258
+ amountA: sqrtPriceMath_1.SqrtPriceMath.getAmountADelta(this.pool.sqrtPriceX64, tickMath_1.TickMath.getSqrtRatioAtTick(this.tickUpper), this.liquidity, true),
259
+ amountB: sqrtPriceMath_1.SqrtPriceMath.getAmountBDelta(tickMath_1.TickMath.getSqrtRatioAtTick(this.tickLower), this.pool.sqrtPriceX64, this.liquidity, true),
260
+ };
261
+ }
262
+ else {
263
+ return {
264
+ amountA: internalConstants_2.ZERO,
265
+ amountB: sqrtPriceMath_1.SqrtPriceMath.getAmountBDelta(tickMath_1.TickMath.getSqrtRatioAtTick(this.tickLower), tickMath_1.TickMath.getSqrtRatioAtTick(this.tickUpper), this.liquidity, true),
266
+ };
267
+ }
268
+ }
269
+ return this._mintAmounts;
270
+ }
271
+ /**
272
+ * Computes the maximum amount of liquidity received for a given amount of tokenA, tokenB,
273
+ * and the prices at the tick boundaries.
274
+ * @param pool The pool for which the position should be created
275
+ * @param lower The lower tick of the position
276
+ * @param upper The upper tick of the position
277
+ * @param amountA tokenA amount
278
+ * @param amountB tokenB amount
279
+ * @param useFullPrecision If false, liquidity will be maximized according to what the router can calculate,
280
+ * not what core can theoretically support
281
+ * @returns The amount of liquidity for the position
282
+ */
283
+ static fromAmounts({ id, owner, pool, tickLower, tickUpper, amountA, amountB, useFullPrecision, feeGrowthInsideALastX64, feeGrowthInsideBLastX64, }) {
284
+ const sqrtRatioLX64 = tickMath_1.TickMath.getSqrtRatioAtTick(tickLower);
285
+ const sqrtRatioUX64 = tickMath_1.TickMath.getSqrtRatioAtTick(tickUpper);
286
+ return new Position({
287
+ id,
288
+ owner,
289
+ pool,
290
+ tickLower,
291
+ tickUpper,
292
+ liquidity: (0, maxLiquidityForAmounts_1.maxLiquidityForAmounts)(pool.sqrtPriceX64, sqrtRatioLX64, sqrtRatioUX64, amountA, amountB, useFullPrecision),
293
+ feeGrowthInsideALastX64,
294
+ feeGrowthInsideBLastX64
295
+ });
296
+ }
297
+ /**
298
+ * Computes a position with the maximum amount of liquidity received for a given amount of tokenA, assuming an unlimited amount of tokenB
299
+ * @param pool The pool for which the position is created
300
+ * @param lower The lower tick
301
+ * @param upper The upper tick
302
+ * @param amountA The desired amount of tokenA
303
+ * @param useFullPrecision If true, liquidity will be maximized according to what the router can calculate,
304
+ * not what core can theoretically support
305
+ * @returns The position
306
+ */
307
+ static fromAmountA({ id, owner, pool, tickLower, tickUpper, amountA, useFullPrecision, feeGrowthInsideALastX64, feeGrowthInsideBLastX64 }) {
308
+ return Position.fromAmounts({
309
+ id,
310
+ owner,
311
+ pool,
312
+ tickLower,
313
+ tickUpper,
314
+ amountA,
315
+ amountB: internalConstants_1.MaxUint64,
316
+ useFullPrecision,
317
+ feeGrowthInsideALastX64,
318
+ feeGrowthInsideBLastX64
319
+ });
320
+ }
321
+ /**
322
+ * Computes a position with the maximum amount of liquidity received for a given amount of tokenB, assuming an unlimited amount of tokenA
323
+ * @param pool The pool for which the position is created
324
+ * @param lower The lower tick
325
+ * @param upper The upper tick
326
+ * @param amountB The desired amount of tokenB
327
+ * @returns The position
328
+ */
329
+ static fromAmountB({ id, owner, pool, tickLower, tickUpper, amountB, feeGrowthInsideALastX64, feeGrowthInsideBLastX64, }) {
330
+ // this function always uses full precision,
331
+ return Position.fromAmounts({
332
+ id,
333
+ owner,
334
+ pool,
335
+ tickLower,
336
+ tickUpper,
337
+ amountA: internalConstants_1.MaxUint64,
338
+ amountB,
339
+ useFullPrecision: true,
340
+ feeGrowthInsideALastX64,
341
+ feeGrowthInsideBLastX64,
342
+ });
343
+ }
344
+ /**
345
+ * Computes a position fees
346
+ * @returns The position
347
+ */
348
+ getFees() {
349
+ return __awaiter(this, void 0, void 0, function* () {
350
+ const { liquidity, tickLower, tickUpper, feeGrowthInsideALastX64, feeGrowthInsideBLastX64, pool } = this;
351
+ const lower = yield this.pool.tickDataProvider.getTick(tickLower);
352
+ const upper = yield this.pool.tickDataProvider.getTick(tickUpper);
353
+ const { feeGrowthGlobalAX64, feeGrowthGlobalBX64 } = pool;
354
+ const [feeGrowthInsideAX64, feeGrowthInsideBX64] = utils_1.TickLibrary.getFeeGrowthInside(lower, upper, tickLower, tickUpper, pool.tickCurrent, feeGrowthGlobalAX64, feeGrowthGlobalBX64);
355
+ const tokensOwedA = jsbi_1.default.divide(jsbi_1.default.multiply((0, utils_1.subIn128)(feeGrowthInsideAX64, feeGrowthInsideALastX64), liquidity), internalConstants_1.Q64);
356
+ const tokensOwedB = jsbi_1.default.divide(jsbi_1.default.multiply((0, utils_1.subIn128)(feeGrowthInsideBX64, feeGrowthInsideBLastX64), liquidity), internalConstants_1.Q64);
357
+ return {
358
+ feesA: fractions_1.CurrencyAmount.fromRawAmount(this.pool.tokenA, tokensOwedA),
359
+ feesB: fractions_1.CurrencyAmount.fromRawAmount(this.pool.tokenB, tokensOwedB),
360
+ };
361
+ });
362
+ }
363
+ }
364
+ exports.Position = Position;