@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,169 @@
1
+ import JSBI from "jsbi";
2
+ import invariant from "tiny-invariant";
3
+ import { ONE, ZERO, Q64, MaxUint128 } from "../internalConstants";
4
+ import { FullMath } from "./fullMath";
5
+
6
+ function multiplyIn128(x: JSBI, y: JSBI): JSBI {
7
+ const product = JSBI.multiply(x, y);
8
+ return JSBI.bitwiseAnd(product, MaxUint128);
9
+ }
10
+
11
+ function addIn128(x: JSBI, y: JSBI): JSBI {
12
+ const sum = JSBI.add(x, y);
13
+ return JSBI.bitwiseAnd(sum, MaxUint128);
14
+ }
15
+
16
+ export abstract class SqrtPriceMath {
17
+ /**
18
+ * Cannot be constructed.
19
+ */
20
+ private constructor() {}
21
+
22
+ public static getAmountADelta(
23
+ sqrtRatioLX64: JSBI,
24
+ sqrtRatioUX64: JSBI,
25
+ liquidity: JSBI,
26
+ roundUp: boolean
27
+ ): JSBI {
28
+ if (JSBI.greaterThan(sqrtRatioLX64, sqrtRatioUX64)) {
29
+ [sqrtRatioLX64, sqrtRatioUX64] = [sqrtRatioUX64, sqrtRatioLX64];
30
+ }
31
+
32
+ const numerator1 = JSBI.leftShift(liquidity, JSBI.BigInt(64));
33
+ const numerator2 = JSBI.subtract(sqrtRatioUX64, sqrtRatioLX64);
34
+
35
+ return roundUp
36
+ ? FullMath.mulDivRoundingUp(
37
+ FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioUX64),
38
+ ONE,
39
+ sqrtRatioLX64
40
+ )
41
+ : JSBI.divide(
42
+ JSBI.divide(JSBI.multiply(numerator1, numerator2), sqrtRatioUX64),
43
+ sqrtRatioLX64
44
+ );
45
+ }
46
+
47
+ public static getAmountBDelta(
48
+ sqrtRatioLX64: JSBI,
49
+ sqrtRatioUX64: JSBI,
50
+ liquidity: JSBI,
51
+ roundUp: boolean
52
+ ): JSBI {
53
+ if (JSBI.greaterThan(sqrtRatioLX64, sqrtRatioUX64)) {
54
+ [sqrtRatioLX64, sqrtRatioUX64] = [sqrtRatioUX64, sqrtRatioLX64];
55
+ }
56
+
57
+ return roundUp
58
+ ? FullMath.mulDivRoundingUp(
59
+ liquidity,
60
+ JSBI.subtract(sqrtRatioUX64, sqrtRatioLX64),
61
+ Q64
62
+ )
63
+ : JSBI.divide(
64
+ JSBI.multiply(liquidity, JSBI.subtract(sqrtRatioUX64, sqrtRatioLX64)),
65
+ Q64
66
+ );
67
+ }
68
+
69
+ public static getNextSqrtPriceFromInput(
70
+ sqrtPX64: JSBI,
71
+ liquidity: JSBI,
72
+ amountIn: JSBI,
73
+ zeroForOne: boolean
74
+ ): JSBI {
75
+ invariant(JSBI.greaterThan(sqrtPX64, ZERO));
76
+ invariant(JSBI.greaterThan(liquidity, ZERO));
77
+
78
+ return zeroForOne
79
+ ? this.getNextSqrtPriceFromAmountARoundingUp(
80
+ sqrtPX64,
81
+ liquidity,
82
+ amountIn,
83
+ true
84
+ )
85
+ : this.getNextSqrtPriceFromAmountBRoundingDown(
86
+ sqrtPX64,
87
+ liquidity,
88
+ amountIn,
89
+ true
90
+ );
91
+ }
92
+
93
+ public static getNextSqrtPriceFromOutput(
94
+ sqrtPX64: JSBI,
95
+ liquidity: JSBI,
96
+ amountOut: JSBI,
97
+ zeroForOne: boolean
98
+ ): JSBI {
99
+ invariant(JSBI.greaterThan(sqrtPX64, ZERO));
100
+ invariant(JSBI.greaterThan(liquidity, ZERO));
101
+
102
+ return zeroForOne
103
+ ? this.getNextSqrtPriceFromAmountBRoundingDown(
104
+ sqrtPX64,
105
+ liquidity,
106
+ amountOut,
107
+ false
108
+ )
109
+ : this.getNextSqrtPriceFromAmountARoundingUp(
110
+ sqrtPX64,
111
+ liquidity,
112
+ amountOut,
113
+ false
114
+ );
115
+ }
116
+
117
+ private static getNextSqrtPriceFromAmountARoundingUp(
118
+ sqrtPX64: JSBI,
119
+ liquidity: JSBI,
120
+ amount: JSBI,
121
+ add: boolean
122
+ ): JSBI {
123
+ if (JSBI.equal(amount, ZERO)) return sqrtPX64;
124
+ const numerator1 = JSBI.leftShift(liquidity, JSBI.BigInt(64));
125
+
126
+ if (add) {
127
+ let product = multiplyIn128(amount, sqrtPX64);
128
+ if (JSBI.equal(JSBI.divide(product, amount), sqrtPX64)) {
129
+ const denominator = addIn128(numerator1, product);
130
+ if (JSBI.greaterThanOrEqual(denominator, numerator1)) {
131
+ return FullMath.mulDivRoundingUp(numerator1, sqrtPX64, denominator);
132
+ }
133
+ }
134
+
135
+ return FullMath.mulDivRoundingUp(
136
+ numerator1,
137
+ ONE,
138
+ JSBI.add(JSBI.divide(numerator1, sqrtPX64), amount)
139
+ );
140
+ } else {
141
+ let product = multiplyIn128(amount, sqrtPX64);
142
+
143
+ invariant(JSBI.equal(JSBI.divide(product, amount), sqrtPX64));
144
+ invariant(JSBI.greaterThan(numerator1, product));
145
+ const denominator = JSBI.subtract(numerator1, product);
146
+ return FullMath.mulDivRoundingUp(numerator1, sqrtPX64, denominator);
147
+ }
148
+ }
149
+
150
+ private static getNextSqrtPriceFromAmountBRoundingDown(
151
+ sqrtPX64: JSBI,
152
+ liquidity: JSBI,
153
+ amount: JSBI,
154
+ add: boolean
155
+ ): JSBI {
156
+ if (add) {
157
+ const quotient = JSBI.lessThanOrEqual(amount, MaxUint128)
158
+ ? JSBI.divide(JSBI.leftShift(amount, JSBI.BigInt(64)), liquidity)
159
+ : JSBI.divide(JSBI.multiply(amount, Q64), liquidity);
160
+
161
+ return JSBI.add(sqrtPX64, quotient);
162
+ } else {
163
+ const quotient = FullMath.mulDivRoundingUp(amount, Q64, liquidity);
164
+
165
+ invariant(JSBI.greaterThan(sqrtPX64, quotient));
166
+ return JSBI.subtract(sqrtPX64, quotient);
167
+ }
168
+ }
169
+ }
@@ -0,0 +1,175 @@
1
+ import JSBI from "jsbi";
2
+ import { NEGATIVE_ONE, ZERO, FeeAmount } from "../internalConstants";
3
+ import { FullMath } from "./fullMath";
4
+ import { SqrtPriceMath } from "./sqrtPriceMath";
5
+
6
+ const MAX_FEE = JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(6));
7
+
8
+ export abstract class SwapMath {
9
+ /**
10
+ * Cannot be constructed.
11
+ */
12
+ private constructor() {}
13
+
14
+ public static computeSwapStep(
15
+ sqrtRatioCurrentX64: JSBI,
16
+ sqrtRatioTargetX64: JSBI,
17
+ liquidity: JSBI,
18
+ amountRemaining: JSBI,
19
+ feePips: FeeAmount
20
+ ): [JSBI, JSBI, JSBI, JSBI] {
21
+ const returnValues: Partial<{
22
+ sqrtRatioNextX64: JSBI;
23
+ amountIn: JSBI;
24
+ amountOut: JSBI;
25
+ feeAmount: JSBI;
26
+ }> = {};
27
+
28
+ const zeroForOne = JSBI.greaterThanOrEqual(
29
+ sqrtRatioCurrentX64,
30
+ sqrtRatioTargetX64
31
+ );
32
+ const exactIn = JSBI.greaterThanOrEqual(amountRemaining, ZERO);
33
+
34
+ if (exactIn) {
35
+ const amountRemainingLessFee = JSBI.divide(
36
+ JSBI.multiply(
37
+ amountRemaining,
38
+ JSBI.subtract(MAX_FEE, JSBI.BigInt(feePips))
39
+ ),
40
+ MAX_FEE
41
+ );
42
+ returnValues.amountIn = zeroForOne
43
+ ? SqrtPriceMath.getAmountADelta(
44
+ sqrtRatioTargetX64,
45
+ sqrtRatioCurrentX64,
46
+ liquidity,
47
+ true
48
+ )
49
+ : SqrtPriceMath.getAmountBDelta(
50
+ sqrtRatioCurrentX64,
51
+ sqrtRatioTargetX64,
52
+ liquidity,
53
+ true
54
+ );
55
+ if (
56
+ JSBI.greaterThanOrEqual(amountRemainingLessFee, returnValues.amountIn!)
57
+ ) {
58
+ returnValues.sqrtRatioNextX64 = sqrtRatioTargetX64;
59
+ } else {
60
+ returnValues.sqrtRatioNextX64 = SqrtPriceMath.getNextSqrtPriceFromInput(
61
+ sqrtRatioCurrentX64,
62
+ liquidity,
63
+ amountRemainingLessFee,
64
+ zeroForOne
65
+ );
66
+ }
67
+ } else {
68
+ returnValues.amountOut = zeroForOne
69
+ ? SqrtPriceMath.getAmountBDelta(
70
+ sqrtRatioTargetX64,
71
+ sqrtRatioCurrentX64,
72
+ liquidity,
73
+ false
74
+ )
75
+ : SqrtPriceMath.getAmountADelta(
76
+ sqrtRatioCurrentX64,
77
+ sqrtRatioTargetX64,
78
+ liquidity,
79
+ false
80
+ );
81
+ if (
82
+ JSBI.greaterThanOrEqual(
83
+ JSBI.multiply(amountRemaining, NEGATIVE_ONE),
84
+ returnValues.amountOut
85
+ )
86
+ ) {
87
+ returnValues.sqrtRatioNextX64 = sqrtRatioTargetX64;
88
+ } else {
89
+ returnValues.sqrtRatioNextX64 =
90
+ SqrtPriceMath.getNextSqrtPriceFromOutput(
91
+ sqrtRatioCurrentX64,
92
+ liquidity,
93
+ JSBI.multiply(amountRemaining, NEGATIVE_ONE),
94
+ zeroForOne
95
+ );
96
+ }
97
+ }
98
+
99
+ const max = JSBI.equal(sqrtRatioTargetX64, returnValues.sqrtRatioNextX64);
100
+
101
+ if (zeroForOne) {
102
+ returnValues.amountIn =
103
+ max && exactIn
104
+ ? returnValues.amountIn
105
+ : SqrtPriceMath.getAmountADelta(
106
+ returnValues.sqrtRatioNextX64,
107
+ sqrtRatioCurrentX64,
108
+ liquidity,
109
+ true
110
+ );
111
+ returnValues.amountOut =
112
+ max && !exactIn
113
+ ? returnValues.amountOut
114
+ : SqrtPriceMath.getAmountBDelta(
115
+ returnValues.sqrtRatioNextX64,
116
+ sqrtRatioCurrentX64,
117
+ liquidity,
118
+ false
119
+ );
120
+ } else {
121
+ returnValues.amountIn =
122
+ max && exactIn
123
+ ? returnValues.amountIn
124
+ : SqrtPriceMath.getAmountBDelta(
125
+ sqrtRatioCurrentX64,
126
+ returnValues.sqrtRatioNextX64,
127
+ liquidity,
128
+ true
129
+ );
130
+ returnValues.amountOut =
131
+ max && !exactIn
132
+ ? returnValues.amountOut
133
+ : SqrtPriceMath.getAmountADelta(
134
+ sqrtRatioCurrentX64,
135
+ returnValues.sqrtRatioNextX64,
136
+ liquidity,
137
+ false
138
+ );
139
+ }
140
+
141
+ if (
142
+ !exactIn &&
143
+ JSBI.greaterThan(
144
+ returnValues.amountOut!,
145
+ JSBI.multiply(amountRemaining, NEGATIVE_ONE)
146
+ )
147
+ ) {
148
+ returnValues.amountOut = JSBI.multiply(amountRemaining, NEGATIVE_ONE);
149
+ }
150
+
151
+ if (
152
+ exactIn &&
153
+ JSBI.notEqual(returnValues.sqrtRatioNextX64, sqrtRatioTargetX64)
154
+ ) {
155
+ // we didn't reach the target, so take the remainder of the maximum input as fee
156
+ returnValues.feeAmount = JSBI.subtract(
157
+ amountRemaining,
158
+ returnValues.amountIn!
159
+ );
160
+ } else {
161
+ returnValues.feeAmount = FullMath.mulDivRoundingUp(
162
+ returnValues.amountIn!,
163
+ JSBI.BigInt(feePips),
164
+ JSBI.subtract(MAX_FEE, JSBI.BigInt(feePips))
165
+ );
166
+ }
167
+
168
+ return [
169
+ returnValues.sqrtRatioNextX64!,
170
+ returnValues.amountIn!,
171
+ returnValues.amountOut!,
172
+ returnValues.feeAmount!,
173
+ ];
174
+ }
175
+ }
@@ -0,0 +1,88 @@
1
+ import JSBI from "jsbi";
2
+ import { BigintIsh, ZERO, Q256, Q128 } from "../internalConstants";
3
+
4
+ interface FeeGrowthOutside {
5
+ feeGrowthOutsideAX64: JSBI;
6
+ feeGrowthOutsideBX64: JSBI;
7
+ }
8
+
9
+ export function subIn256(x: JSBI, y: JSBI): JSBI {
10
+ const difference = JSBI.subtract(x, y);
11
+
12
+ if (JSBI.lessThan(difference, ZERO)) {
13
+ return JSBI.add(Q256, difference);
14
+ } else {
15
+ return difference;
16
+ }
17
+ }
18
+
19
+ export function subIn128(x: JSBI, y: JSBI): JSBI {
20
+ const difference = JSBI.subtract(x, y);
21
+
22
+ if (JSBI.lessThan(difference, ZERO)) {
23
+ return JSBI.add(Q128, difference);
24
+ } else {
25
+ return difference;
26
+ }
27
+ }
28
+
29
+ export abstract class TickLibrary {
30
+ /**
31
+ * Cannot be constructed.
32
+ */
33
+ private constructor() {}
34
+
35
+ public static getFeeGrowthInside(
36
+ feeGrowthOutsideLower: FeeGrowthOutside,
37
+ feeGrowthOutsideUpper: FeeGrowthOutside,
38
+ tickLower: number,
39
+ tickUpper: number,
40
+ tickCurrent: number,
41
+ feeGrowthGlobalAX64: JSBI,
42
+ feeGrowthGlobalBX64: JSBI
43
+ ) {
44
+ let feeGrowthBelowAX64: JSBI;
45
+ let feeGrowthBelowBX64: JSBI;
46
+ if (tickCurrent >= tickLower) {
47
+ feeGrowthBelowAX64 = feeGrowthOutsideLower.feeGrowthOutsideAX64;
48
+ feeGrowthBelowBX64 = feeGrowthOutsideLower.feeGrowthOutsideBX64;
49
+ } else {
50
+ feeGrowthBelowAX64 = subIn128(
51
+ feeGrowthGlobalAX64,
52
+ feeGrowthOutsideLower.feeGrowthOutsideAX64
53
+ );
54
+
55
+ feeGrowthBelowBX64 = subIn128(
56
+ feeGrowthGlobalBX64,
57
+ feeGrowthOutsideLower.feeGrowthOutsideBX64
58
+ );
59
+ }
60
+
61
+ let feeGrowthAboveAX64: JSBI;
62
+ let feeGrowthAboveBX64: JSBI;
63
+ if (tickCurrent < tickUpper) {
64
+ feeGrowthAboveAX64 = feeGrowthOutsideUpper.feeGrowthOutsideAX64;
65
+ feeGrowthAboveBX64 = feeGrowthOutsideUpper.feeGrowthOutsideBX64;
66
+ } else {
67
+ feeGrowthAboveAX64 = subIn128(
68
+ feeGrowthGlobalAX64,
69
+ feeGrowthOutsideUpper.feeGrowthOutsideAX64
70
+ );
71
+ feeGrowthAboveBX64 = subIn128(
72
+ feeGrowthGlobalBX64,
73
+ feeGrowthOutsideUpper.feeGrowthOutsideBX64
74
+ );
75
+ }
76
+
77
+ return [
78
+ subIn128(
79
+ subIn128(feeGrowthGlobalAX64, feeGrowthBelowAX64),
80
+ feeGrowthAboveAX64
81
+ ),
82
+ subIn128(
83
+ subIn128(feeGrowthGlobalBX64, feeGrowthBelowBX64),
84
+ feeGrowthAboveBX64
85
+ ),
86
+ ];
87
+ }
88
+ }
@@ -0,0 +1,147 @@
1
+ import JSBI from "jsbi";
2
+ import invariant from "tiny-invariant";
3
+ import { Tick } from "../entities/tick";
4
+ import { ZERO } from "../internalConstants";
5
+ import { isSorted } from "./isSorted";
6
+
7
+ function tickComparator(a: Tick, b: Tick) {
8
+ return a.id - b.id;
9
+ }
10
+
11
+ /**x
12
+ * Utility methods for interacting with sorted lists of ticks
13
+ */
14
+ export abstract class TickList {
15
+ /**
16
+ * Cannot be constructed
17
+ */
18
+ private constructor() {}
19
+
20
+ public static validateList(ticks: Tick[], tickSpacing: number) {
21
+ invariant(tickSpacing > 0, "TICK_SPACING_NONZERO");
22
+ // ensure ticks are spaced appropriately
23
+ invariant(
24
+ ticks.every(({ id }) => id % tickSpacing === 0),
25
+ "TICK_SPACING"
26
+ );
27
+
28
+ // ensure tick liquidity deltas sum to 0
29
+ invariant(
30
+ JSBI.equal(
31
+ ticks.reduce(
32
+ (accumulator, { liquidityNet }) =>
33
+ JSBI.add(accumulator, liquidityNet),
34
+ ZERO
35
+ ),
36
+ ZERO
37
+ ),
38
+ "ZERO_NET"
39
+ );
40
+
41
+ invariant(isSorted(ticks, tickComparator), "SORTED");
42
+ }
43
+
44
+ public static isBelowSmallest(ticks: readonly Tick[], tick: number): boolean {
45
+ invariant(ticks.length > 0, "LENGTH");
46
+ return tick < ticks[0].id;
47
+ }
48
+
49
+ public static isAtOrAboveLargest(
50
+ ticks: readonly Tick[],
51
+ tick: number
52
+ ): boolean {
53
+ invariant(ticks.length > 0, "LENGTH");
54
+ return tick >= ticks[ticks.length - 1].id;
55
+ }
56
+
57
+ public static getTick(ticks: readonly Tick[], id: number): Tick {
58
+ const tick = ticks[this.binarySearch(ticks, id)];
59
+ invariant(tick.id === id, "NOT_CONTAINED");
60
+ return tick;
61
+ }
62
+
63
+ /**
64
+ * Finds the largest tick in the list of ticks that is less than or equal to tick
65
+ * @param ticks list of ticks
66
+ * @param tick tick to find the largest tick that is less than or equal to tick
67
+ * @private
68
+ */
69
+ private static binarySearch(ticks: readonly Tick[], tick: number): number {
70
+ invariant(!this.isBelowSmallest(ticks, tick), "BELOW_SMALLEST");
71
+
72
+ let l = 0;
73
+ let r = ticks.length - 1;
74
+ let i;
75
+ while (true) {
76
+ i = Math.floor((l + r) / 2);
77
+
78
+ if (
79
+ ticks[i].id <= tick &&
80
+ (i === ticks.length - 1 || ticks[i + 1].id > tick)
81
+ ) {
82
+ return i;
83
+ }
84
+
85
+ if (ticks[i].id < tick) {
86
+ l = i + 1;
87
+ } else {
88
+ r = i - 1;
89
+ }
90
+ }
91
+ }
92
+
93
+ public static nextInitializedTick(
94
+ ticks: readonly Tick[],
95
+ tick: number,
96
+ lte: boolean
97
+ ): Tick {
98
+ if (lte) {
99
+ invariant(!TickList.isBelowSmallest(ticks, tick), "BELOW_SMALLEST");
100
+ if (TickList.isAtOrAboveLargest(ticks, tick)) {
101
+ return ticks[ticks.length - 1];
102
+ }
103
+ const id = this.binarySearch(ticks, tick);
104
+ return ticks[id];
105
+ } else {
106
+ invariant(!this.isAtOrAboveLargest(ticks, tick), "AT_OR_ABOVE_LARGEST");
107
+ if (this.isBelowSmallest(ticks, tick)) {
108
+ return ticks[0];
109
+ }
110
+ const id = this.binarySearch(ticks, tick);
111
+ return ticks[id + 1];
112
+ }
113
+ }
114
+
115
+ public static nextInitializedTickWithinOneWord(
116
+ ticks: readonly Tick[],
117
+ tick: number,
118
+ lte: boolean,
119
+ tickSpacing: number
120
+ ): [number, boolean] {
121
+ const compressed = Math.floor(tick / tickSpacing); // matches rounding in the code
122
+
123
+ if (lte) {
124
+ const wordPos = compressed >> 7;
125
+ const minimum = (wordPos << 7) * tickSpacing;
126
+
127
+ if (TickList.isBelowSmallest(ticks, tick)) {
128
+ return [minimum, false];
129
+ }
130
+
131
+ const id = TickList.nextInitializedTick(ticks, tick, lte).id;
132
+ const nextInitializedTick = Math.max(minimum, id);
133
+ return [nextInitializedTick, nextInitializedTick === id];
134
+ } else {
135
+ const wordPos = (compressed + 1) >> 7;
136
+ const maximum = (((wordPos + 1) << 7) - 1) * tickSpacing;
137
+
138
+ if (this.isAtOrAboveLargest(ticks, tick)) {
139
+ return [maximum, false];
140
+ }
141
+
142
+ const id = this.nextInitializedTick(ticks, tick, lte).id;
143
+ const nextInitializedTick = Math.min(maximum, id);
144
+ return [nextInitializedTick, nextInitializedTick === id];
145
+ }
146
+ }
147
+ }