Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Part 2] Feat/zellic gas optimization #184

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
184774
184048
2 changes: 1 addition & 1 deletion .forge-snapshots/BinHookTest#testMintSucceedsWithHook.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
311467
311216
2 changes: 1 addition & 1 deletion .forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
189692
189420
2 changes: 1 addition & 1 deletion .forge-snapshots/BinPoolManagerBytecodeSize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
24176
23911
Original file line number Diff line number Diff line change
@@ -1 +1 @@
32518
32521
Original file line number Diff line number Diff line change
@@ -1 +1 @@
970470
968494
Original file line number Diff line number Diff line change
@@ -1 +1 @@
329782
327806
Original file line number Diff line number Diff line change
@@ -1 +1 @@
337781
337530
Original file line number Diff line number Diff line change
@@ -1 +1 @@
140332
140081
Original file line number Diff line number Diff line change
@@ -1 +1 @@
173317
173046
Original file line number Diff line number Diff line change
@@ -1 +1 @@
179345
179074
Original file line number Diff line number Diff line change
@@ -1 +1 @@
133348
133077
Original file line number Diff line number Diff line change
@@ -1 +1 @@
163446
162720
Original file line number Diff line number Diff line change
@@ -1 +1 @@
304739
304488
2 changes: 1 addition & 1 deletion .forge-snapshots/CLPoolManagerBytecodeSize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
21216
20856
Original file line number Diff line number Diff line change
@@ -1 +1 @@
150173
149202
Original file line number Diff line number Diff line change
@@ -1 +1 @@
131090
130815
Original file line number Diff line number Diff line change
@@ -1 +1 @@
163667
163156
Original file line number Diff line number Diff line change
@@ -1 +1 @@
149106
148595
2 changes: 1 addition & 1 deletion .forge-snapshots/CLPoolManagerTest#swap_simple.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
71701
71190
Original file line number Diff line number Diff line change
@@ -1 +1 @@
143343
143062
2 changes: 1 addition & 1 deletion .forge-snapshots/CLPoolManagerTest#swap_withHooks.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
87879
87368
2 changes: 1 addition & 1 deletion .forge-snapshots/CLPoolManagerTest#swap_withNative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
71704
71193
Original file line number Diff line number Diff line change
@@ -1 +1 @@
31971
31953
7 changes: 4 additions & 3 deletions src/pool-bin/BinPoolManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {BinHooks} from "./libraries/BinHooks.sol";
import {PriceHelper} from "./libraries/PriceHelper.sol";
import {BeforeSwapDelta} from "../types/BeforeSwapDelta.sol";
import "./interfaces/IBinHooks.sol";
import {BinSlot0} from "./types/BinSlot0.sol";

/// @notice Holds the state for all bin pools
contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload {
Expand Down Expand Up @@ -59,9 +60,9 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload {

/// @inheritdoc IBinPoolManager
function getSlot0(PoolId id) external view override returns (uint24 activeId, uint24 protocolFee, uint24 lpFee) {
BinPool.Slot0 memory slot0 = pools[id].slot0;
BinSlot0 slot0 = pools[id].slot0;

return (slot0.activeId, slot0.protocolFee, slot0.lpFee);
return (slot0.activeId(), slot0.protocolFee(), slot0.lpFee());
}

/// @inheritdoc IBinPoolManager
Expand Down Expand Up @@ -282,7 +283,7 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload {
BinHooks.beforeDonate(key, amount0, amount1, hookData);

/// @dev Share is 1:1 liquidity when liquidity is first added to bin
uint256 currentBinShare = pool.shareOfBin[pool.slot0.activeId];
uint256 currentBinShare = pool.shareOfBin[pool.slot0.activeId()];
if (currentBinShare <= MIN_BIN_SHARE_FOR_DONATE) {
revert InsufficientBinShareForDonate(currentBinShare);
}
Expand Down
47 changes: 18 additions & 29 deletions src/pool-bin/libraries/BinPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity ^0.8.0;

import {BalanceDelta, toBalanceDelta} from "../../types/BalanceDelta.sol";
import {BinSlot0} from "../types/BinSlot0.sol";
import {LiquidityConfigurations} from "./math/LiquidityConfigurations.sol";
import {PackedUint128Math} from "./math/PackedUint128Math.sol";
import {Uint256x256Math} from "./math/Uint256x256Math.sol";
Expand Down Expand Up @@ -48,21 +49,9 @@ library BinPool {
/// @dev if swap exactIn, x for y, unspecifiedToken = token y. if swap x for exact out y, unspecified token is x
error BinPool__InsufficientAmountUnSpecified();

struct Slot0 {
// the current activeId
uint24 activeId;
// protocol fee, expressed in hundredths of a bip
// upper 12 bits are for 1->0, and the lower 12 are for 0->1
// the maximum is 1000 - meaning the maximum protocol fee is 0.1%
// the protocolFee is taken from the input first, then the lpFee is taken from the remaining input
uint24 protocolFee;
// lp fee, either static at initialize or dynamic via hook
uint24 lpFee;
}

/// @dev The state of a pool
struct State {
Slot0 slot0;
BinSlot0 slot0;
/// @notice binId ==> (reserve of token x and y in the bin)
mapping(uint256 binId => bytes32 reserve) reserveOfBin;
/// @notice binId ==> (total share minted)
Expand All @@ -79,21 +68,21 @@ library BinPool {

function initialize(State storage self, uint24 activeId, uint24 protocolFee, uint24 lpFee) internal {
/// An initialized pool will not have activeId: 0
if (self.slot0.activeId != 0) revert PoolAlreadyInitialized();
if (self.slot0.activeId() != 0) revert PoolAlreadyInitialized();

self.slot0 = Slot0({activeId: activeId, protocolFee: protocolFee, lpFee: lpFee});
self.slot0 = BinSlot0.wrap(bytes32(0)).setActiveId(activeId).setProtocolFee(protocolFee).setLpFee(lpFee);
}

function setProtocolFee(State storage self, uint24 protocolFee) internal {
self.checkPoolInitialized();
self.slot0.protocolFee = protocolFee;
self.slot0 = self.slot0.setProtocolFee(protocolFee);
}

/// @notice Only dynamic fee pools may update the swap fee.
function setLPFee(State storage self, uint24 lpFee) internal {
self.checkPoolInitialized();

self.slot0.lpFee = lpFee;
self.slot0 = self.slot0.setLpFee(lpFee);
}

struct SwapParams {
Expand All @@ -118,17 +107,17 @@ library BinPool {
internal
returns (BalanceDelta result, SwapState memory swapState)
{
Slot0 memory slot0Cache = self.slot0;
swapState.activeId = slot0Cache.activeId;
BinSlot0 slot0Cache = self.slot0;
swapState.activeId = slot0Cache.activeId();
bool swapForY = params.swapForY;
swapState.protocolFee =
swapForY ? slot0Cache.protocolFee.getZeroForOneFee() : slot0Cache.protocolFee.getOneForZeroFee();
swapForY ? slot0Cache.protocolFee().getZeroForOneFee() : slot0Cache.protocolFee().getOneForZeroFee();
bool exactInput = params.amountSpecified < 0;

{
uint24 lpFee = params.lpFeeOverride.isOverride()
? params.lpFeeOverride.removeOverrideAndValidate(LPFeeLibrary.TEN_PERCENT_FEE)
: slot0Cache.lpFee;
: slot0Cache.lpFee();

/// @dev swap fee includes protocolFee (charged first) and lpFee
swapState.swapFee = swapState.protocolFee == 0 ? lpFee : swapState.protocolFee.calculateSwapFee(lpFee);
Expand Down Expand Up @@ -173,7 +162,7 @@ library BinPool {

if (amountsInWithFees > 0) {
/// @dev calc protocol fee for current bin, totalFee * protocolFee / (protocolFee + lpFee)
bytes32 pFee = totalFee.getProtocolFeeAmt(slot0Cache.protocolFee, swapState.swapFee);
bytes32 pFee = totalFee.getProtocolFeeAmt(slot0Cache.protocolFee(), swapState.swapFee);
if (pFee != 0) {
swapState.feeAmountToProtocol = swapState.feeAmountToProtocol.add(pFee);
amountsInWithFees = amountsInWithFees.sub(pFee);
Expand All @@ -200,7 +189,7 @@ library BinPool {

if (amountsUnspecified == 0) revert BinPool__InsufficientAmountUnSpecified();

self.slot0.activeId = swapState.activeId;
self.slot0 = self.slot0.setActiveId(swapState.activeId);
unchecked {
// uncheckeck as negating positive int128 is safe
if (exactInput) {
Expand Down Expand Up @@ -350,7 +339,7 @@ library BinPool {
internal
returns (BalanceDelta result, uint24 activeId)
{
activeId = self.slot0.activeId;
activeId = self.slot0.activeId();
bytes32 amountIn = amount0.encode(amount1);

bytes32 binReserves = self.reserveOfBin[activeId];
Expand Down Expand Up @@ -428,8 +417,8 @@ library BinPool {
bytes32 compositionFeeAmount
)
{
Slot0 memory slot0Cache = self.slot0;
uint24 activeId = slot0Cache.activeId;
BinSlot0 slot0Cache = self.slot0;
uint24 activeId = slot0Cache.activeId();
bytes32 binReserves = self.reserveOfBin[id];

uint256 price = id.getPriceFromId(params.binStep);
Expand All @@ -443,11 +432,11 @@ library BinPool {
/// eg. current bin is 40/60 (a,b) but user tries to add liquidity with 50/50 ratio
uint24 lpFee = params.lpFeeOverride.isOverride()
? params.lpFeeOverride.removeOverrideAndValidate(LPFeeLibrary.TEN_PERCENT_FEE)
: slot0Cache.lpFee;
: slot0Cache.lpFee();

bytes32 feesAmount;
(feesAmount, feeAmountToProtocol) =
binReserves.getCompositionFeesAmount(slot0Cache.protocolFee, lpFee, amountsIn, supply, shares);
binReserves.getCompositionFeesAmount(slot0Cache.protocolFee(), lpFee, amountsIn, supply, shares);
compositionFeeAmount = feesAmount;
if (feesAmount != 0) {
{
Expand Down Expand Up @@ -494,7 +483,7 @@ library BinPool {
}

function checkPoolInitialized(State storage self) internal view {
if (self.slot0.activeId == 0) {
if (self.slot0.activeId() == 0) {
// revert PoolNotInitialized();
assembly ("memory-safe") {
mstore(0x00, 0x486aa307)
Expand Down
81 changes: 81 additions & 0 deletions src/pool-bin/types/BinSlot0.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
* @dev BinSlot0 is a packed version of solidity structure.
* Using the packaged version saves gas by not storing the structure fields in memory slots.
*
* Layout:
* 184 bits empty | 24 bits lpFee | 12 bits protocolFee 1->0 | 12 bits protocolFee 0->1 | 24 bits activeId
*
* Fields in the direction from the least significant bit:
*
* The current activeId
* uint24 activeId;
*
* Protocol fee, expressed in hundredths of a bip, upper 12 bits are for 1->0, and the lower 12 are for 0->1
* the maximum is 1000 - meaning the maximum protocol fee is 0.1%
* the protocolFee is taken from the input first, then the lpFee is taken from the remaining input
* uint24 protocolFee;
*
* The current LP fee of the pool. If the pool is dynamic, this does not include the dynamic fee flag.
* uint24 lpFee;
*/
type BinSlot0 is bytes32;

using BinSlot0Library for BinSlot0 global;

/// @notice Library for getting and setting values in the Slot0 type
library BinSlot0Library {
uint24 internal constant MASK_24_BITS = 0xFFFFFF;

uint8 internal constant PROTOCOL_FEE_OFFSET = 24;
uint8 internal constant LP_FEE_OFFSET = 48;

////////////////////////////////////////////////////////////////////////////////////////
// #### GETTERS ####
////////////////////////////////////////////////////////////////////////////////////////
function activeId(BinSlot0 _packed) internal pure returns (uint24 _activeId) {
assembly ("memory-safe") {
_activeId := and(MASK_24_BITS, _packed)
}
}

function protocolFee(BinSlot0 _packed) internal pure returns (uint24 _protocolFee) {
assembly ("memory-safe") {
_protocolFee := and(MASK_24_BITS, shr(PROTOCOL_FEE_OFFSET, _packed))
}
}

function lpFee(BinSlot0 _packed) internal pure returns (uint24 _lpFee) {
assembly ("memory-safe") {
_lpFee := and(MASK_24_BITS, shr(LP_FEE_OFFSET, _packed))
}
}

////////////////////////////////////////////////////////////////////////////////////////
// #### SETTERS ####
////////////////////////////////////////////////////////////////////////////////////////
function setActiveId(BinSlot0 _packed, uint24 _activeId) internal pure returns (BinSlot0 _result) {
assembly ("memory-safe") {
_result := or(and(not(MASK_24_BITS), _packed), and(MASK_24_BITS, _activeId))
}
}

function setProtocolFee(BinSlot0 _packed, uint24 _protocolFee) internal pure returns (BinSlot0 _result) {
assembly ("memory-safe") {
_result :=
or(
and(not(shl(PROTOCOL_FEE_OFFSET, MASK_24_BITS)), _packed),
shl(PROTOCOL_FEE_OFFSET, and(MASK_24_BITS, _protocolFee))
)
}
}

function setLpFee(BinSlot0 _packed, uint24 _lpFee) internal pure returns (BinSlot0 _result) {
assembly ("memory-safe") {
_result :=
or(and(not(shl(LP_FEE_OFFSET, MASK_24_BITS)), _packed), shl(LP_FEE_OFFSET, and(MASK_24_BITS, _lpFee)))
}
}
}
5 changes: 3 additions & 2 deletions src/pool-cl/CLPoolManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {CLHooks} from "./libraries/CLHooks.sol";
import {BeforeSwapDelta} from "../types/BeforeSwapDelta.sol";
import {Currency} from "../types/Currency.sol";
import {TickMath} from "./libraries/TickMath.sol";
import {CLSlot0} from "./types/CLSlot0.sol";

contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload {
using SafeCast for int256;
Expand Down Expand Up @@ -53,8 +54,8 @@ contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload {
override
returns (uint160 sqrtPriceX96, int24 tick, uint24 protocolFee, uint24 lpFee)
{
CLPool.Slot0 memory slot0 = pools[id].slot0;
return (slot0.sqrtPriceX96, slot0.tick, slot0.protocolFee, slot0.lpFee);
CLSlot0 slot0 = pools[id].slot0;
return (slot0.sqrtPriceX96(), slot0.tick(), slot0.protocolFee(), slot0.lpFee());
}

/// @inheritdoc ICLPoolManager
Expand Down
Loading
Loading