Skip to content

Commit

Permalink
Refactor and optimize Pool.swap (#603)
Browse files Browse the repository at this point in the history
* Optimize tick transition in `Pool.swap`

Pool.sol has been updated with a block of assembly code for the assignment of `state.tick`. This is equivalent but slightly more efficient version of the previous code. Additionally, the snapshot values have been adjusted as a consequence of this change.

* Move `exactInput` and `step` declaration

* Update `while` condition in `Pool.swap`

The `while` condition within the `swap` function of the `Pool` contract has been changed for clarity and ease of understanding. The condition now explicitly checks for equality compared to the previous implementation. All corresponding snapshot files have been updated to reflect this change.

* Update tick boundaries conditions in `Pool.swap`

* Switch if-else branches in `Pool.swap`

This commit swaps the conditional branches in the `Pool.swap` function in `Pool.sol`. The switch leads to changes in calculated snapshots, indicating reduced gas.

* Refactor variable assignment in `Pool`

The refactoring of variable assignment in `Pool.sol` aims to increase code readability and maintainability. The change includes replacing separate lines of variable assignments with destructuring assignment, where multiple variables are assigned values in a single statement, making the code more concise and efficient.

* Refactor fee growth assignment in `Pool.swap`

This update simplifies the fee growth assignments in the `swap` method of the `Pool.sol` file. Previously, the fee growth assignments were performed inside a verbose conditional statement. The refactoring condenses this into a single line of code using a ternary operator, improving the code readability and maintainability.

* Optimize Pool.sol for reduced bytecode size

This commit includes an optimization in the Pool.sol code where a conditional statement was modified to reduce bytecode size. The snapshot of the bytecode size shows a slight decrease due to these changes, thus ensuring a more efficient contract deployment.
  • Loading branch information
shuhuiluo authored May 14, 2024
1 parent 5bcb2e6 commit 568f7c4
Show file tree
Hide file tree
Showing 17 changed files with 48 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .forge-snapshots/poolManager bytecode size.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
23858
23817
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 @@
117512
117381
2 changes: 1 addition & 1 deletion .forge-snapshots/simple swap.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
132751
132620
2 changes: 1 addition & 1 deletion .forge-snapshots/swap CA custom curve + swap noop.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135903
135892
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 @@
185018
184887
Original file line number Diff line number Diff line change
@@ -1 +1 @@
113919
113834
2 changes: 1 addition & 1 deletion .forge-snapshots/swap against liquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
125340
125255
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 @@
137302
137257
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 @@
126402
126357
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 @@
148480
148435
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 @@
165375
165244
Original file line number Diff line number Diff line change
@@ -1 +1 @@
224993
224777
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 @@
149642
149511
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with hooks.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
125352
125267
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 @@
181904
181833
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 @@
160195
160064
63 changes: 32 additions & 31 deletions src/libraries/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,7 @@ library Pool {
}

if (liquidityDelta != 0) {
int24 tick = self.slot0.tick;
uint160 sqrtPriceX96 = self.slot0.sqrtPriceX96;
(int24 tick, uint160 sqrtPriceX96) = (self.slot0.tick, self.slot0.sqrtPriceX96);
if (tick < tickLower) {
// current tick is below the passed range; liquidity can only become in range by crossing from left to
// right, when we'll need _more_ currency0 (it's becoming more valuable) so user must provide it
Expand Down Expand Up @@ -305,7 +304,6 @@ library Pool {
{
Slot0 memory slot0Start = self.slot0;
bool zeroForOne = params.zeroForOne;
bool exactInput = params.amountSpecified < 0;

SwapCache memory cache = SwapCache({
liquidityStart: self.liquidity,
Expand All @@ -322,6 +320,8 @@ library Pool {
swapFee =
cache.protocolFee == 0 ? slot0Start.lpFee : uint24(cache.protocolFee).calculateSwapFee(slot0Start.lpFee);

bool exactInput = params.amountSpecified < 0;

if (!exactInput && (swapFee == LPFeeLibrary.MAX_LP_FEE)) {
revert InvalidFeeForExactOut();
}
Expand All @@ -347,16 +347,17 @@ library Pool {
StepComputations memory step;

// continue swapping as long as we haven't used the entire input/output and haven't reached the price limit
while (state.amountSpecifiedRemaining != 0 && state.sqrtPriceX96 != params.sqrtPriceLimitX96) {
while (!(state.amountSpecifiedRemaining == 0 || state.sqrtPriceX96 == params.sqrtPriceLimitX96)) {
step.sqrtPriceStartX96 = state.sqrtPriceX96;

(step.tickNext, step.initialized) =
self.tickBitmap.nextInitializedTickWithinOneWord(state.tick, params.tickSpacing, zeroForOne);

// ensure that we do not overshoot the min/max tick, as the tick bitmap is not aware of these bounds
if (step.tickNext < TickMath.MIN_TICK) {
if (step.tickNext <= TickMath.MIN_TICK) {
step.tickNext = TickMath.MIN_TICK;
} else if (step.tickNext > TickMath.MAX_TICK) {
}
if (step.tickNext >= TickMath.MAX_TICK) {
step.tickNext = TickMath.MAX_TICK;
}

Expand All @@ -376,17 +377,17 @@ library Pool {
swapFee
);

if (exactInput) {
// safe because we test that amountSpecified > amountIn + feeAmount in SwapMath
if (!exactInput) {
unchecked {
state.amountSpecifiedRemaining += (step.amountIn + step.feeAmount).toInt256();
state.amountSpecifiedRemaining -= step.amountOut.toInt256();
}
state.amountCalculated = state.amountCalculated + step.amountOut.toInt256();
state.amountCalculated = state.amountCalculated - (step.amountIn + step.feeAmount).toInt256();
} else {
// safe because we test that amountSpecified > amountIn + feeAmount in SwapMath
unchecked {
state.amountSpecifiedRemaining -= step.amountOut.toInt256();
state.amountSpecifiedRemaining += (step.amountIn + step.feeAmount).toInt256();
}
state.amountCalculated = state.amountCalculated - (step.amountIn + step.feeAmount).toInt256();
state.amountCalculated = state.amountCalculated + step.amountOut.toInt256();
}

// if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee
Expand All @@ -413,15 +414,9 @@ library Pool {
if (state.sqrtPriceX96 == step.sqrtPriceNextX96) {
// if the tick is initialized, run the tick transition
if (step.initialized) {
uint256 feeGrowthGlobal0X128;
uint256 feeGrowthGlobal1X128;
if (!zeroForOne) {
feeGrowthGlobal0X128 = self.feeGrowthGlobal0X128;
feeGrowthGlobal1X128 = state.feeGrowthGlobalX128;
} else {
feeGrowthGlobal0X128 = state.feeGrowthGlobalX128;
feeGrowthGlobal1X128 = self.feeGrowthGlobal1X128;
}
(uint256 feeGrowthGlobal0X128, uint256 feeGrowthGlobal1X128) = zeroForOne
? (state.feeGrowthGlobalX128, self.feeGrowthGlobal1X128)
: (self.feeGrowthGlobal0X128, state.feeGrowthGlobalX128);
int128 liquidityNet =
Pool.crossTick(self, step.tickNext, feeGrowthGlobal0X128, feeGrowthGlobal1X128);
// if we're moving leftward, we interpret liquidityNet as the opposite sign
Expand All @@ -433,37 +428,43 @@ library Pool {
state.liquidity = LiquidityMath.addDelta(state.liquidity, liquidityNet);
}

// Equivalent to `state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext;`
unchecked {
state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext;
// cannot cast a bool to an int24 in Solidity
int24 _zeroForOne;
assembly {
_zeroForOne := zeroForOne
}
state.tick = step.tickNext - _zeroForOne;
}
} else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) {
// recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved
state.tick = TickMath.getTickAtSqrtPrice(state.sqrtPriceX96);
}
}

(self.slot0.sqrtPriceX96, self.slot0.tick) = (state.sqrtPriceX96, state.tick);
(self.slot0.tick, self.slot0.sqrtPriceX96) = (state.tick, state.sqrtPriceX96);

// update liquidity if it changed
if (cache.liquidityStart != state.liquidity) self.liquidity = state.liquidity;

// update fee growth global
if (zeroForOne) {
self.feeGrowthGlobal0X128 = state.feeGrowthGlobalX128;
} else {
if (!zeroForOne) {
self.feeGrowthGlobal1X128 = state.feeGrowthGlobalX128;
} else {
self.feeGrowthGlobal0X128 = state.feeGrowthGlobalX128;
}

unchecked {
if (zeroForOne == exactInput) {
if (zeroForOne != exactInput) {
result = toBalanceDelta(
(params.amountSpecified - state.amountSpecifiedRemaining).toInt128(),
state.amountCalculated.toInt128()
state.amountCalculated.toInt128(),
(params.amountSpecified - state.amountSpecifiedRemaining).toInt128()
);
} else {
result = toBalanceDelta(
state.amountCalculated.toInt128(),
(params.amountSpecified - state.amountSpecifiedRemaining).toInt128()
(params.amountSpecified - state.amountSpecifiedRemaining).toInt128(),
state.amountCalculated.toInt128()
);
}
}
Expand Down

0 comments on commit 568f7c4

Please sign in to comment.