Skip to content

Commit

Permalink
Optimize absTick calculation in TickMath.getSqrtPriceAtTick (#663)
Browse files Browse the repository at this point in the history
* Optimize `absTick` calculation in `TickMath.getSqrtPriceAtTick`

The getSqrtPriceAtTick function in the TickMath library has been refactored with a more efficient assembly implementation. This optimization significantly reduces the gas usage by using bitwise operations for computing absolute value of a tick.

* Add test case for `getSqrtPriceAtTick` with `type(int24).min`

The new test case asserts that the function `getSqrtPriceAtTick` throws an error when called with the minimum valid input. This ensures that the function behaves as expected for all possible input values, enhancing the overall test coverage.

* Add comments about rounding in `getSqrtPriceAtTick`
  • Loading branch information
shuhuiluo authored May 21, 2024
1 parent 2b87b1e commit fa5164a
Show file tree
Hide file tree
Showing 33 changed files with 47 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .forge-snapshots/TickMathGetSqrtPriceAtTick.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
80082
76732
2 changes: 1 addition & 1 deletion .forge-snapshots/TickMathGetTickAtSqrtPrice.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
227576
224621
Original file line number Diff line number Diff line change
@@ -1 +1 @@
153494
153427
2 changes: 1 addition & 1 deletion .forge-snapshots/addLiquidity CA fee.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
331160
331093
2 changes: 1 addition & 1 deletion .forge-snapshots/addLiquidity with empty hook.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
286153
286086
2 changes: 1 addition & 1 deletion .forge-snapshots/addLiquidity with native token.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
143704
143637
Original file line number Diff line number Diff line change
@@ -1 +1 @@
301672
301605
2 changes: 1 addition & 1 deletion .forge-snapshots/initialize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
61811
61775
2 changes: 1 addition & 1 deletion .forge-snapshots/poolManager bytecode size.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
21667
21647
2 changes: 1 addition & 1 deletion .forge-snapshots/removeLiquidity CA fee.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
186626
186559
2 changes: 1 addition & 1 deletion .forge-snapshots/removeLiquidity with empty hook.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
122994
122927
2 changes: 1 addition & 1 deletion .forge-snapshots/removeLiquidity with native token.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
119781
119714
Original file line number Diff line number Diff line change
@@ -1 +1 @@
104808
104746
2 changes: 1 addition & 1 deletion .forge-snapshots/simple addLiquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
167300
167238
Original file line number Diff line number Diff line change
@@ -1 +1 @@
98405
98343
2 changes: 1 addition & 1 deletion .forge-snapshots/simple removeLiquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
90445
90383
2 changes: 1 addition & 1 deletion .forge-snapshots/simple swap with native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
116663
116560
2 changes: 1 addition & 1 deletion .forge-snapshots/simple swap.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
131824
131721
2 changes: 1 addition & 1 deletion .forge-snapshots/swap CA fee on unspecified.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
182962
182859
Original file line number Diff line number Diff line change
@@ -1 +1 @@
112435
112368
2 changes: 1 addition & 1 deletion .forge-snapshots/swap against liquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
123778
123711
2 changes: 1 addition & 1 deletion .forge-snapshots/swap burn 6909 for input.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135785
135713
2 changes: 1 addition & 1 deletion .forge-snapshots/swap burn native 6909 for input.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
125038
124966
2 changes: 1 addition & 1 deletion .forge-snapshots/swap mint native output as 6909.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
147042
146970
2 changes: 1 addition & 1 deletion .forge-snapshots/swap mint output as 6909.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
163678
163575
Original file line number Diff line number Diff line change
@@ -1 +1 @@
221922
221752
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with dynamic fee.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
147879
147776
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with hooks.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
123790
123723
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with lp fee and protocol fee.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
180059
179956
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with return dynamic fee.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
155738
155635
2 changes: 1 addition & 1 deletion .forge-snapshots/update dynamic fee in before swap.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
158341
158238
12 changes: 11 additions & 1 deletion src/libraries/TickMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,15 @@ library TickMath {
/// at the given tick
function getSqrtPriceAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
unchecked {
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
uint256 absTick;
assembly {
// mask = 0 if tick >= 0 else -1
let mask := sar(255, tick)
// If tick >= 0, |tick| = tick = 0 ^ tick
// If tick < 0, |tick| = ~~|tick| = ~(-|tick| - 1) = ~(tick - 1) = (-1) ^ (tick - 1)
// Either case, |tick| = mask ^ (tick + mask)
absTick := xor(mask, add(mask, tick))
}
if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();

uint256 price =
Expand Down Expand Up @@ -78,6 +86,8 @@ library TickMath {
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtPrice of the output price is always consistent
// `sub(shl(32, 1), 1)` is `type(uint32).max`
// `price + type(uint32).max` will not overflow because `price` fits in 192 bits
sqrtPriceX96 := shr(32, add(price, sub(shl(32, 1), 1)))
}
}
Expand Down
5 changes: 5 additions & 0 deletions test/libraries/TickMath.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ contract TickMathTestTest is Test, JavascriptFfi, GasSnapshot {
assertEq(maxTick, MAX_TICK);
}

function test_getSqrtPriceAtTick_throwsForInt24Min() public {
vm.expectRevert(TickMath.InvalidTick.selector);
tickMath.getSqrtPriceAtTick(type(int24).min);
}

function test_getSqrtPriceAtTick_throwsForTooLow() public {
vm.expectRevert(TickMath.InvalidTick.selector);
tickMath.getSqrtPriceAtTick(MIN_TICK - 1);
Expand Down

0 comments on commit fa5164a

Please sign in to comment.