@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.
- package/.eslintignore +2 -0
- package/.eslintrc +12 -0
- package/LICENSE +21 -0
- package/build/entities/baseCurrency.js +27 -0
- package/build/entities/currency.js +2 -0
- package/build/entities/fractions/currencyAmount.js +80 -0
- package/build/entities/fractions/fraction.js +117 -0
- package/build/entities/fractions/index.js +11 -0
- package/build/entities/fractions/percent.js +46 -0
- package/build/entities/fractions/price.js +73 -0
- package/build/entities/index.js +26 -0
- package/build/entities/pool.js +248 -0
- package/build/entities/position.js +364 -0
- package/build/entities/route.js +70 -0
- package/build/entities/tick.js +23 -0
- package/build/entities/tickDataProvider.js +30 -0
- package/build/entities/tickListDataProvider.js +35 -0
- package/build/entities/token.js +53 -0
- package/build/entities/trade.js +464 -0
- package/build/index.js +19 -0
- package/build/internalConstants.js +54 -0
- package/build/utils/computeAllRoutes.js +39 -0
- package/build/utils/encodeSqrtRatioX64.js +21 -0
- package/build/utils/fullMath.js +22 -0
- package/build/utils/index.js +30 -0
- package/build/utils/isSorted.js +18 -0
- package/build/utils/liquidityMath.js +23 -0
- package/build/utils/maxLiquidityForAmounts.js +86 -0
- package/build/utils/mostSignificantBit.js +27 -0
- package/build/utils/nearestUsableTick.js +26 -0
- package/build/utils/positionLibrary.js +22 -0
- package/build/utils/priceTickConversions.js +51 -0
- package/build/utils/sortedInsert.js +39 -0
- package/build/utils/sqrt.js +33 -0
- package/build/utils/sqrtPriceMath.js +92 -0
- package/build/utils/swapMath.js +86 -0
- package/build/utils/tickLibrary.js +61 -0
- package/build/utils/tickList.js +110 -0
- package/build/utils/tickMath.js +122 -0
- package/jest.config.js +40 -0
- package/nodemon.json +6 -0
- package/package.json +51 -0
- package/src/entities/baseCurrency.ts +53 -0
- package/src/entities/currency.ts +3 -0
- package/src/entities/fractions/currencyAmount.ts +129 -0
- package/src/entities/fractions/fraction.ts +190 -0
- package/src/entities/fractions/index.ts +4 -0
- package/src/entities/fractions/percent.ts +54 -0
- package/src/entities/fractions/price.ts +127 -0
- package/src/entities/index.ts +11 -0
- package/src/entities/pool.ts +399 -0
- package/src/entities/position.ts +591 -0
- package/src/entities/route.ts +84 -0
- package/src/entities/tick.ts +48 -0
- package/src/entities/tickDataProvider.ts +43 -0
- package/src/entities/tickListDataProvider.ts +37 -0
- package/src/entities/token.ts +56 -0
- package/src/entities/trade.ts +650 -0
- package/src/index.ts +3 -0
- package/src/internalConstants.ts +58 -0
- package/src/utils/computeAllRoutes.ts +64 -0
- package/src/utils/encodeSqrtRatioX64.ts +20 -0
- package/src/utils/fullMath.ts +17 -0
- package/src/utils/index.ts +14 -0
- package/src/utils/isSorted.ts +17 -0
- package/src/utils/liquidityMath.ts +17 -0
- package/src/utils/maxLiquidityForAmounts.ts +127 -0
- package/src/utils/mostSignificantBit.ts +25 -0
- package/src/utils/nearestUsableTick.ts +23 -0
- package/src/utils/positionLibrary.ts +37 -0
- package/src/utils/priceTickConversions.ts +57 -0
- package/src/utils/sortedInsert.ts +35 -0
- package/src/utils/sqrt.ts +31 -0
- package/src/utils/sqrtPriceMath.ts +169 -0
- package/src/utils/swapMath.ts +175 -0
- package/src/utils/tickLibrary.ts +88 -0
- package/src/utils/tickList.ts +147 -0
- package/src/utils/tickMath.ts +166 -0
- package/test/bestTradeExactOut.test.ts +266 -0
- package/test/currencyAmount.test.js +92 -0
- package/test/currencyAmount.test.ts +114 -0
- package/test/encodeSqrtRatioX64.test.ts +33 -0
- package/test/fixtures/pools.json +276 -0
- package/test/fixtures/ticks.json +608 -0
- package/test/fraction.test.js +87 -0
- package/test/fraction.test.ts +176 -0
- package/test/isSorted.test.ts +52 -0
- package/test/maxLiquidityForAmounts.test copy.ts +256 -0
- package/test/mostSignificantBit.test.ts +32 -0
- package/test/nearestUsableTick.test.ts +54 -0
- package/test/percent.test.js +52 -0
- package/test/percent.test.ts +68 -0
- package/test/pool.test.ts +377 -0
- package/test/position.test.ts +579 -0
- package/test/positionLibrary.test.ts +31 -0
- package/test/price.test.js +57 -0
- package/test/price.test.ts +62 -0
- package/test/priceTickConversions.test.ts +137 -0
- package/test/sqrtPriceMath.test.ts +113 -0
- package/test/tick.test.js +22 -0
- package/test/tick.test.ts +28 -0
- package/test/tickDataProvider.test.ts +17 -0
- package/test/tickLibrary.test.ts +111 -0
- package/test/tickList.test.ts +215 -0
- package/test/tickListDataProvider.test.ts +64 -0
- package/test/tickMath.test.ts +66 -0
- package/test/token.test.ts +58 -0
- package/test/trade.test.ts +210 -0
- package/test2.ts +73 -0
- 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
|
+
}
|