@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,399 @@
|
|
|
1
|
+
import { CurrencyAmount, Price } from "./fractions";
|
|
2
|
+
import { Token } from "./token";
|
|
3
|
+
import { BigintIsh, FeeAmount, TICK_SPACINGS } from "../internalConstants";
|
|
4
|
+
import JSBI from "jsbi";
|
|
5
|
+
import invariant from "tiny-invariant";
|
|
6
|
+
import { NEGATIVE_ONE, ONE, Q128, ZERO } from "../internalConstants";
|
|
7
|
+
import { LiquidityMath } from "../utils/liquidityMath";
|
|
8
|
+
import { SwapMath } from "../utils/swapMath";
|
|
9
|
+
import { TickMath } from "../utils/tickMath";
|
|
10
|
+
import { Tick, TickConstructorArgs } from "./tick";
|
|
11
|
+
import { NoTickDataProvider, TickDataProvider } from "./tickDataProvider";
|
|
12
|
+
import { TickListDataProvider } from "./tickListDataProvider";
|
|
13
|
+
|
|
14
|
+
export interface PoolConstructorArgs {
|
|
15
|
+
id: number,
|
|
16
|
+
tokenA: Token,
|
|
17
|
+
tokenB: Token,
|
|
18
|
+
fee: FeeAmount,
|
|
19
|
+
sqrtPriceX64: BigintIsh,
|
|
20
|
+
liquidity: BigintIsh,
|
|
21
|
+
tickCurrent: number,
|
|
22
|
+
feeGrowthGlobalAX64: BigintIsh,
|
|
23
|
+
feeGrowthGlobalBX64: BigintIsh,
|
|
24
|
+
ticks:
|
|
25
|
+
| TickDataProvider
|
|
26
|
+
| (Tick | TickConstructorArgs)[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface StepComputations {
|
|
30
|
+
sqrtPriceStartX64: JSBI;
|
|
31
|
+
tickNext: number;
|
|
32
|
+
initialized: boolean;
|
|
33
|
+
sqrtPriceNextX64: JSBI;
|
|
34
|
+
amountIn: JSBI;
|
|
35
|
+
amountOut: JSBI;
|
|
36
|
+
feeAmount: JSBI;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* By default, pools will not allow operations that require ticks.
|
|
41
|
+
*/
|
|
42
|
+
const NO_TICK_DATA_PROVIDER_DEFAULT = new NoTickDataProvider();
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Represents a V3 pool
|
|
46
|
+
*/
|
|
47
|
+
export class Pool {
|
|
48
|
+
// public readonly id: number;
|
|
49
|
+
public readonly id: number;
|
|
50
|
+
public readonly tokenA: Token;
|
|
51
|
+
public readonly tokenB: Token;
|
|
52
|
+
public readonly fee: FeeAmount;
|
|
53
|
+
public readonly sqrtPriceX64: JSBI;
|
|
54
|
+
public readonly liquidity: JSBI;
|
|
55
|
+
public readonly tickCurrent: number;
|
|
56
|
+
public readonly feeGrowthGlobalAX64: JSBI;
|
|
57
|
+
public readonly feeGrowthGlobalBX64: JSBI;
|
|
58
|
+
public readonly tickDataProvider: TickDataProvider;
|
|
59
|
+
|
|
60
|
+
private _tokenAPrice?: Price<Token, Token>;
|
|
61
|
+
private _tokenBPrice?: Price<Token, Token>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Construct a pool
|
|
65
|
+
* @param tokenA One of the tokens in the pool
|
|
66
|
+
* @param tokenB The other token in the pool
|
|
67
|
+
* @param fee The fee in hundredths of a bips of the input amount of every swap that is collected by the pool
|
|
68
|
+
* @param sqrtPriceX64 The sqrt of the current ratio of amounts of tokenB to tokenA
|
|
69
|
+
* @param liquidity The current value of in range liquidity
|
|
70
|
+
* @param tickCurrent The current tick of the pool
|
|
71
|
+
* @param ticks The current state of the pool ticks or a data provider that can return tick data
|
|
72
|
+
*/
|
|
73
|
+
public constructor({
|
|
74
|
+
id,
|
|
75
|
+
tokenA,
|
|
76
|
+
tokenB,
|
|
77
|
+
fee,
|
|
78
|
+
sqrtPriceX64,
|
|
79
|
+
liquidity,
|
|
80
|
+
tickCurrent,
|
|
81
|
+
ticks = NO_TICK_DATA_PROVIDER_DEFAULT,
|
|
82
|
+
feeGrowthGlobalAX64 = 0,
|
|
83
|
+
feeGrowthGlobalBX64 = 0,
|
|
84
|
+
}: PoolConstructorArgs) {
|
|
85
|
+
invariant(Number.isInteger(fee) && fee < 1_000_000, "FEE");
|
|
86
|
+
|
|
87
|
+
const tickCurrentSqrtRatioX64 = TickMath.getSqrtRatioAtTick(tickCurrent);
|
|
88
|
+
const nextTickSqrtRatioX64 = TickMath.getSqrtRatioAtTick(tickCurrent + 1);
|
|
89
|
+
invariant(
|
|
90
|
+
JSBI.greaterThanOrEqual(
|
|
91
|
+
JSBI.BigInt(sqrtPriceX64),
|
|
92
|
+
tickCurrentSqrtRatioX64
|
|
93
|
+
) &&
|
|
94
|
+
JSBI.lessThanOrEqual(JSBI.BigInt(sqrtPriceX64), nextTickSqrtRatioX64),
|
|
95
|
+
"PRICE_BOUNDS"
|
|
96
|
+
);
|
|
97
|
+
// always create a copy of the list since we want the pool's tick list to be immutable
|
|
98
|
+
this.id = id;
|
|
99
|
+
this.fee = fee;
|
|
100
|
+
this.sqrtPriceX64 = JSBI.BigInt(sqrtPriceX64);
|
|
101
|
+
this.liquidity = JSBI.BigInt(liquidity);
|
|
102
|
+
this.tickCurrent = tickCurrent;
|
|
103
|
+
this.feeGrowthGlobalAX64 = JSBI.BigInt(feeGrowthGlobalAX64);
|
|
104
|
+
this.feeGrowthGlobalBX64 = JSBI.BigInt(feeGrowthGlobalBX64);
|
|
105
|
+
|
|
106
|
+
this.tickDataProvider = Array.isArray(ticks)
|
|
107
|
+
? new TickListDataProvider(ticks, TICK_SPACINGS[fee])
|
|
108
|
+
: ticks;
|
|
109
|
+
|
|
110
|
+
[this.tokenA, this.tokenB] = tokenA.sortsBefore(tokenB)
|
|
111
|
+
? [tokenA, tokenB]
|
|
112
|
+
: [tokenB, tokenA];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Returns true if the token is either tokenA or tokenB
|
|
117
|
+
* @param token The token to check
|
|
118
|
+
* @returns True if token is either tokenA or token
|
|
119
|
+
*/
|
|
120
|
+
public involvesToken(token: Token): boolean {
|
|
121
|
+
return token.equals(this.tokenA) || token.equals(this.tokenB);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Returns the current mid price of the pool in terms of tokenA, i.e. the ratio of tokenB over tokenA
|
|
126
|
+
*/
|
|
127
|
+
public get tokenAPrice(): Price<Token, Token> {
|
|
128
|
+
return (
|
|
129
|
+
this._tokenAPrice ??
|
|
130
|
+
(this._tokenAPrice = new Price(
|
|
131
|
+
this.tokenA,
|
|
132
|
+
this.tokenB,
|
|
133
|
+
Q128,
|
|
134
|
+
JSBI.multiply(this.sqrtPriceX64, this.sqrtPriceX64)
|
|
135
|
+
))
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns the current mid price of the pool in terms of tokenB, i.e. the ratio of tokenA over tokenB
|
|
141
|
+
*/
|
|
142
|
+
public get tokenBPrice(): Price<Token, Token> {
|
|
143
|
+
return (
|
|
144
|
+
this._tokenBPrice ??
|
|
145
|
+
(this._tokenBPrice = new Price(
|
|
146
|
+
this.tokenB,
|
|
147
|
+
this.tokenA,
|
|
148
|
+
JSBI.multiply(this.sqrtPriceX64, this.sqrtPriceX64),
|
|
149
|
+
Q128
|
|
150
|
+
))
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Return the price of the given token in terms of the other token in the pool.
|
|
156
|
+
* @param token The token to return price of
|
|
157
|
+
* @returns The price of the given token, in terms of the other.
|
|
158
|
+
*/
|
|
159
|
+
public priceOf(token: Token): Price<Token, Token> {
|
|
160
|
+
invariant(this.involvesToken(token), "TOKEN");
|
|
161
|
+
return token.equals(this.tokenA) ? this.tokenAPrice : this.tokenBPrice;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Given an input amount of a token, return the computed output amount, and a pool with state updated after the trade
|
|
166
|
+
* @param inputAmount The input amount for which to quote the output amount
|
|
167
|
+
* @param sqrtPriceLimitX64 The Q64.96 sqrt price limit
|
|
168
|
+
* @returns The output amount and the pool with updated state
|
|
169
|
+
*/
|
|
170
|
+
public async getOutputAmount(
|
|
171
|
+
inputAmount: CurrencyAmount<Token>,
|
|
172
|
+
sqrtPriceLimitX64?: JSBI
|
|
173
|
+
): Promise<[CurrencyAmount<Token>, Pool]> {
|
|
174
|
+
invariant(this.involvesToken(inputAmount.currency), "TOKEN");
|
|
175
|
+
|
|
176
|
+
const zeroForOne = inputAmount.currency.equals(this.tokenA);
|
|
177
|
+
|
|
178
|
+
const {
|
|
179
|
+
amountCalculated: outputAmount,
|
|
180
|
+
sqrtPriceX64,
|
|
181
|
+
liquidity,
|
|
182
|
+
tickCurrent,
|
|
183
|
+
} = await this.swap(zeroForOne, inputAmount.quotient, sqrtPriceLimitX64);
|
|
184
|
+
const outputToken = zeroForOne ? this.tokenB : this.tokenA;
|
|
185
|
+
return [
|
|
186
|
+
CurrencyAmount.fromRawAmount(
|
|
187
|
+
outputToken,
|
|
188
|
+
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
|
+
];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Given a desired output amount of a token, return the computed input amount and a pool with state updated after the trade
|
|
207
|
+
* @param outputAmount the output amount for which to quote the input amount
|
|
208
|
+
* @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
|
|
209
|
+
* @returns The input amount and the pool with updated state
|
|
210
|
+
*/
|
|
211
|
+
public async getInputAmount(
|
|
212
|
+
outputAmount: CurrencyAmount<Token>,
|
|
213
|
+
sqrtPriceLimitX64?: JSBI
|
|
214
|
+
): Promise<[CurrencyAmount<Token>, Pool]> {
|
|
215
|
+
const zeroForOne = outputAmount.currency.equals(this.tokenB);
|
|
216
|
+
|
|
217
|
+
const {
|
|
218
|
+
amountCalculated: inputAmount,
|
|
219
|
+
sqrtPriceX64,
|
|
220
|
+
liquidity,
|
|
221
|
+
tickCurrent,
|
|
222
|
+
} = await this.swap(
|
|
223
|
+
zeroForOne,
|
|
224
|
+
JSBI.multiply(outputAmount.quotient, NEGATIVE_ONE),
|
|
225
|
+
sqrtPriceLimitX64
|
|
226
|
+
);
|
|
227
|
+
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
|
+
];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Executes a swap
|
|
247
|
+
* @param zeroForOne Whether the amount in is tokenA or tokenB
|
|
248
|
+
* @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
|
|
249
|
+
* @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
|
|
250
|
+
* @returns amountCalculated
|
|
251
|
+
* @returns sqrtPriceX64
|
|
252
|
+
* @returns liquidity
|
|
253
|
+
* @returns tickCurrent
|
|
254
|
+
*/
|
|
255
|
+
private async swap(
|
|
256
|
+
zeroForOne: boolean,
|
|
257
|
+
amountSpecified: JSBI,
|
|
258
|
+
sqrtPriceLimitX64?: JSBI
|
|
259
|
+
): Promise<{
|
|
260
|
+
amountCalculated: JSBI;
|
|
261
|
+
sqrtPriceX64: JSBI;
|
|
262
|
+
liquidity: JSBI;
|
|
263
|
+
tickCurrent: number;
|
|
264
|
+
}> {
|
|
265
|
+
if (!sqrtPriceLimitX64)
|
|
266
|
+
sqrtPriceLimitX64 = zeroForOne
|
|
267
|
+
? JSBI.add(TickMath.MIN_SQRT_RATIO, ONE)
|
|
268
|
+
: JSBI.subtract(TickMath.MAX_SQRT_RATIO, ONE);
|
|
269
|
+
|
|
270
|
+
if (zeroForOne) {
|
|
271
|
+
invariant(
|
|
272
|
+
JSBI.greaterThan(sqrtPriceLimitX64, TickMath.MIN_SQRT_RATIO),
|
|
273
|
+
"RATIO_MIN"
|
|
274
|
+
);
|
|
275
|
+
invariant(
|
|
276
|
+
JSBI.lessThan(sqrtPriceLimitX64, this.sqrtPriceX64),
|
|
277
|
+
"RATIO_CURRENT"
|
|
278
|
+
);
|
|
279
|
+
} else {
|
|
280
|
+
invariant(
|
|
281
|
+
JSBI.lessThan(sqrtPriceLimitX64, TickMath.MAX_SQRT_RATIO),
|
|
282
|
+
"RATIO_MAX"
|
|
283
|
+
);
|
|
284
|
+
invariant(
|
|
285
|
+
JSBI.greaterThan(sqrtPriceLimitX64, this.sqrtPriceX64),
|
|
286
|
+
"RATIO_CURRENT"
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const exactInput = JSBI.greaterThanOrEqual(amountSpecified, ZERO);
|
|
291
|
+
|
|
292
|
+
// keep track of swap state
|
|
293
|
+
|
|
294
|
+
const state = {
|
|
295
|
+
amountSpecifiedRemaining: amountSpecified,
|
|
296
|
+
amountCalculated: ZERO,
|
|
297
|
+
sqrtPriceX64: this.sqrtPriceX64,
|
|
298
|
+
tick: this.tickCurrent,
|
|
299
|
+
liquidity: this.liquidity,
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// start swap while loop
|
|
303
|
+
while (
|
|
304
|
+
JSBI.notEqual(state.amountSpecifiedRemaining, ZERO) &&
|
|
305
|
+
state.sqrtPriceX64 != sqrtPriceLimitX64
|
|
306
|
+
) {
|
|
307
|
+
const step: Partial<StepComputations> = {};
|
|
308
|
+
step.sqrtPriceStartX64 = state.sqrtPriceX64;
|
|
309
|
+
|
|
310
|
+
// because each iteration of the while loop rounds, we can't optimize this code (relative to the smart contract)
|
|
311
|
+
// by simply traversing to the next available tick, we instead need to exactly replicate
|
|
312
|
+
// tickBitmap.nextInitializedTickWithinOneWord
|
|
313
|
+
[step.tickNext, step.initialized] =
|
|
314
|
+
await this.tickDataProvider.nextInitializedTickWithinOneWord(
|
|
315
|
+
state.tick,
|
|
316
|
+
zeroForOne,
|
|
317
|
+
this.tickSpacing
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
if (step.tickNext < TickMath.MIN_TICK) {
|
|
321
|
+
step.tickNext = TickMath.MIN_TICK;
|
|
322
|
+
} else if (step.tickNext > TickMath.MAX_TICK) {
|
|
323
|
+
step.tickNext = TickMath.MAX_TICK;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
step.sqrtPriceNextX64 = TickMath.getSqrtRatioAtTick(step.tickNext);
|
|
327
|
+
[state.sqrtPriceX64, step.amountIn, step.amountOut, step.feeAmount] =
|
|
328
|
+
SwapMath.computeSwapStep(
|
|
329
|
+
state.sqrtPriceX64,
|
|
330
|
+
(
|
|
331
|
+
zeroForOne
|
|
332
|
+
? JSBI.lessThan(step.sqrtPriceNextX64, sqrtPriceLimitX64)
|
|
333
|
+
: JSBI.greaterThan(step.sqrtPriceNextX64, sqrtPriceLimitX64)
|
|
334
|
+
)
|
|
335
|
+
? sqrtPriceLimitX64
|
|
336
|
+
: step.sqrtPriceNextX64,
|
|
337
|
+
state.liquidity,
|
|
338
|
+
state.amountSpecifiedRemaining,
|
|
339
|
+
this.fee
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
if (exactInput) {
|
|
343
|
+
state.amountSpecifiedRemaining = JSBI.subtract(
|
|
344
|
+
state.amountSpecifiedRemaining,
|
|
345
|
+
JSBI.add(step.amountIn, step.feeAmount)
|
|
346
|
+
);
|
|
347
|
+
state.amountCalculated = JSBI.subtract(
|
|
348
|
+
state.amountCalculated,
|
|
349
|
+
step.amountOut
|
|
350
|
+
);
|
|
351
|
+
} else {
|
|
352
|
+
state.amountSpecifiedRemaining = JSBI.add(
|
|
353
|
+
state.amountSpecifiedRemaining,
|
|
354
|
+
step.amountOut
|
|
355
|
+
);
|
|
356
|
+
state.amountCalculated = JSBI.add(
|
|
357
|
+
state.amountCalculated,
|
|
358
|
+
JSBI.add(step.amountIn, step.feeAmount)
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// TODO
|
|
363
|
+
if (JSBI.equal(state.sqrtPriceX64, step.sqrtPriceNextX64)) {
|
|
364
|
+
// if the tick is initialized, run the tick transition
|
|
365
|
+
if (step.initialized) {
|
|
366
|
+
let liquidityNet = JSBI.BigInt(
|
|
367
|
+
(await this.tickDataProvider.getTick(step.tickNext)).liquidityNet
|
|
368
|
+
);
|
|
369
|
+
// if we're moving leftward, we interpret liquidityNet as the opposite sign
|
|
370
|
+
// safe because liquidityNet cannot be type(int128).min
|
|
371
|
+
if (zeroForOne)
|
|
372
|
+
liquidityNet = JSBI.multiply(liquidityNet, NEGATIVE_ONE);
|
|
373
|
+
|
|
374
|
+
state.liquidity = LiquidityMath.addDelta(
|
|
375
|
+
state.liquidity,
|
|
376
|
+
liquidityNet
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext;
|
|
381
|
+
} else if (JSBI.notEqual(state.sqrtPriceX64, step.sqrtPriceStartX64)) {
|
|
382
|
+
// updated comparison function
|
|
383
|
+
// recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved
|
|
384
|
+
state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX64);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
amountCalculated: state.amountCalculated,
|
|
390
|
+
sqrtPriceX64: state.sqrtPriceX64,
|
|
391
|
+
liquidity: state.liquidity,
|
|
392
|
+
tickCurrent: state.tick,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
public get tickSpacing(): number {
|
|
397
|
+
return TICK_SPACINGS[this.fee];
|
|
398
|
+
}
|
|
399
|
+
}
|