From 64cffed4f1f1254d31224f1c5c74f2a1337f98c2 Mon Sep 17 00:00:00 2001 From: gnarlycow Date: Sun, 21 Jul 2024 17:35:16 -0700 Subject: [PATCH 01/13] Add support for Velodrome/Aerodrome SlipStream. --- foundry.toml | 1 + src/NPMCaller.sol | 83 ++++++++- ... => ICommonNonfungiblePositionManager.sol} | 73 +------- .../IPCSV3NonfungiblePositionManager.sol | 12 ++ .../ISlipStreamNonfungiblePositionManager.sol | 94 ++++++++++ .../IUniswapV3NonfungiblePositionManager.sol | 72 ++++++++ test/Base.t.sol | 62 +++++-- test/NPMCaller.t.sol | 166 ++++++++++++++++-- 8 files changed, 460 insertions(+), 103 deletions(-) rename src/interfaces/{INonfungiblePositionManager.sol => ICommonNonfungiblePositionManager.sol} (64%) create mode 100644 src/interfaces/IPCSV3NonfungiblePositionManager.sol create mode 100644 src/interfaces/ISlipStreamNonfungiblePositionManager.sol create mode 100644 src/interfaces/IUniswapV3NonfungiblePositionManager.sol diff --git a/foundry.toml b/foundry.toml index 1cd1dd1..5021a7b 100644 --- a/foundry.toml +++ b/foundry.toml @@ -22,5 +22,6 @@ via_ir = false [rpc_endpoints] mainnet = "${MAINNET_RPC_URL}" +base = "${BASE_RPC_URL}" # See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/src/NPMCaller.sol b/src/NPMCaller.sol index 14581bf..5cd5d0c 100644 --- a/src/NPMCaller.sol +++ b/src/NPMCaller.sol @@ -2,7 +2,8 @@ pragma solidity >=0.8.0; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; -import {INonfungiblePositionManager as INPM, IERC721Permit, IPeripheryImmutableState} from "./interfaces/INonfungiblePositionManager.sol"; +import {IUniswapV3NonfungiblePositionManager as IUniV3NPM, ICommonNonfungiblePositionManager as INPM, IERC721Permit, IPeripheryImmutableState} from "./interfaces/IUniswapV3NonfungiblePositionManager.sol"; +import {ISlipStreamNonfungiblePositionManager as ISlipStreamNPM} from "./interfaces/ISlipStreamNonfungiblePositionManager.sol"; // details about the uniswap position struct PositionFull { @@ -39,6 +40,15 @@ struct Position { uint128 liquidity; } +struct SlipStreamPosition { + address token0; + address token1; + int24 tickSpacing; + int24 tickLower; + int24 tickUpper; + uint128 liquidity; +} + /// @title Uniswap v3 Nonfungible Position Manager Caller /// @author Aperture Finance /// @notice Gas efficient library to call `INonfungiblePositionManager` assuming it exists. @@ -241,7 +251,7 @@ library NPMCaller { /// @param npm Uniswap v3 Nonfungible Position Manager /// @param tokenId The ID of the token that represents the position function positionsFull(INPM npm, uint256 tokenId) internal view returns (PositionFull memory pos) { - bytes4 selector = INPM.positions.selector; + bytes4 selector = IUniV3NPM.positions.selector; assembly ("memory-safe") { // Write the abi-encoded calldata into memory. mstore(0, selector) @@ -255,11 +265,33 @@ library NPMCaller { } } - /// @dev Equivalent to `INonfungiblePositionManager.positions(tokenId)` + /// @dev Equivalent to `IUniswapV3NonfungiblePositionManager.positions(tokenId)` /// @param npm Uniswap v3 Nonfungible Position Manager /// @param tokenId The ID of the token that represents the position function positions(INPM npm, uint256 tokenId) internal view returns (Position memory pos) { - bytes4 selector = INPM.positions.selector; + bytes4 selector = IUniV3NPM.positions.selector; + assembly ("memory-safe") { + // Write the abi-encoded calldata into memory. + mstore(0, selector) + mstore(4, tokenId) + // We use 36 because of the length of our calldata. + // We copy up to 256 bytes of return data at `pos` which is the free memory pointer. + if iszero(staticcall(gas(), npm, 0, 0x24, pos, 0x100)) { + // Bubble up the revert reason. + revert(pos, returndatasize()) + } + // Move the free memory pointer to the end of the struct. + mstore(0x40, add(pos, 0x100)) + // Skip the first two struct members. + pos := add(pos, 0x40) + } + } + + /// @dev Equivalent to `ISlipStreamNonfungiblePositionManager.positions(tokenId)` + /// @param npm SlipStream Nonfungible Position Manager + /// @param tokenId The ID of the token that represents the position + function positionsSlipStream(INPM npm, uint256 tokenId) internal view returns (SlipStreamPosition memory pos) { + bytes4 selector = ISlipStreamNPM.positions.selector; assembly ("memory-safe") { // Write the abi-encoded calldata into memory. mstore(0, selector) @@ -277,14 +309,14 @@ library NPMCaller { } } - /// @dev Equivalent to `INonfungiblePositionManager.mint` + /// @dev Equivalent to `IUniswapV3NonfungiblePositionManager.mint` /// @param npm Uniswap v3 Nonfungible Position Manager /// @param params The parameters for minting a position function mint( INPM npm, - INPM.MintParams memory params + IUniV3NPM.MintParams memory params ) internal returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) { - uint32 selector = uint32(INPM.mint.selector); + uint32 selector = uint32(IUniV3NPM.mint.selector); assembly ("memory-safe") { // Cache the free memory pointer. let fmp := mload(0x40) @@ -293,7 +325,7 @@ library NPMCaller { let wordBeforeParams := mload(memBeforeParams) // Write the function selector 4 bytes before `params`. mstore(memBeforeParams, selector) - // We use 356 because of the length of our calldata. + // We use 356 (0x164) because of the length of our calldata. // We copy up to 128 bytes of return data at the free memory pointer. if iszero(call(gas(), npm, 0, sub(params, 4), 0x164, 0, 0x80)) { // Bubble up the revert reason. @@ -312,6 +344,41 @@ library NPMCaller { } } + /// @dev Equivalent to `ISlipStreamUniswapV3NonfungiblePositionManager.mint` + /// @param npm SlipStream Nonfungible Position Manager + /// @param params The parameters for minting a position + function mint( + INPM npm, + ISlipStreamNPM.MintParams memory params + ) internal returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) { + uint32 selector = uint32(ISlipStreamNPM.mint.selector); + assembly ("memory-safe") { + // Cache the free memory pointer. + let fmp := mload(0x40) + // Cache the memory word before `params`. + let memBeforeParams := sub(params, 0x20) + let wordBeforeParams := mload(memBeforeParams) + // Write the function selector 4 bytes before `params`. + mstore(memBeforeParams, selector) + // We use 388 (0x184) because of the length of our calldata. + // We copy up to 128 bytes of return data at the free memory pointer. + if iszero(call(gas(), npm, 0, sub(params, 4), 0x184, 0, 0x80)) { + // Bubble up the revert reason. + revert(0, returndatasize()) + } + // Read the return data. + tokenId := mload(0) + liquidity := mload(0x20) + amount0 := mload(0x40) + amount1 := mload(0x60) + // Restore the free memory pointer, zero pointer and memory word before `params`. + // `memBeforeParams` >= 0x60 so restore it after `mload`. + mstore(memBeforeParams, wordBeforeParams) + mstore(0x40, fmp) + mstore(0x60, 0) + } + } + /// @dev Equivalent to `INonfungiblePositionManager.increaseLiquidity` /// @param npm Uniswap v3 Nonfungible Position Manager /// @param params The parameters for increasing liquidity in a position diff --git a/src/interfaces/INonfungiblePositionManager.sol b/src/interfaces/ICommonNonfungiblePositionManager.sol similarity index 64% rename from src/interfaces/INonfungiblePositionManager.sol rename to src/interfaces/ICommonNonfungiblePositionManager.sol index 544ff14..c850f6a 100644 --- a/src/interfaces/INonfungiblePositionManager.sol +++ b/src/interfaces/ICommonNonfungiblePositionManager.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.0; import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {IERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; -import {IPoolInitializer} from "@uniswap/v3-periphery/contracts/interfaces/IPoolInitializer.sol"; import {IERC721Permit} from "@uniswap/v3-periphery/contracts/interfaces/IERC721Permit.sol"; import {IPeripheryPayments} from "@uniswap/v3-periphery/contracts/interfaces/IPeripheryPayments.sol"; import {IPeripheryImmutableState} from "@uniswap/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol"; @@ -12,8 +11,7 @@ import {IPeripheryImmutableState} from "@uniswap/v3-periphery/contracts/interfac /// @title Non-fungible token for positions /// @notice Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred /// and authorized. -interface INonfungiblePositionManager is - IPoolInitializer, +interface ICommonNonfungiblePositionManager is IPeripheryPayments, IPeripheryImmutableState, IERC721Metadata, @@ -41,67 +39,6 @@ interface INonfungiblePositionManager is /// @param amount1 The amount of token1 owed to the position that was collected event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1); - /// @notice Returns the position information associated with a given token ID. - /// @dev Throws if the token ID is not valid. - /// @param tokenId The ID of the token that represents the position - /// @return nonce The nonce for permits - /// @return operator The address that is approved for spending - /// @return token0 The address of the token0 for a specific pool - /// @return token1 The address of the token1 for a specific pool - /// @return fee The fee associated with the pool - /// @return tickLower The lower end of the tick range for the position - /// @return tickUpper The higher end of the tick range for the position - /// @return liquidity The liquidity of the position - /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position - /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position - /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation - /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation - function positions( - uint256 tokenId - ) - external - view - returns ( - uint96 nonce, - address operator, - address token0, - address token1, - uint24 fee, - int24 tickLower, - int24 tickUpper, - uint128 liquidity, - uint256 feeGrowthInside0LastX128, - uint256 feeGrowthInside1LastX128, - uint128 tokensOwed0, - uint128 tokensOwed1 - ); - - struct MintParams { - address token0; - address token1; - uint24 fee; - int24 tickLower; - int24 tickUpper; - uint256 amount0Desired; - uint256 amount1Desired; - uint256 amount0Min; - uint256 amount1Min; - address recipient; - uint256 deadline; - } - - /// @notice Creates a new position wrapped in a NFT - /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized - /// a method does not exist, i.e. the pool is assumed to be initialized. - /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata - /// @return tokenId The ID of the token that represents the minted position - /// @return liquidity The amount of liquidity for this position - /// @return amount0 The amount of token0 - /// @return amount1 The amount of token1 - function mint( - MintParams calldata params - ) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); - struct IncreaseLiquidityParams { uint256 tokenId; uint256 amount0Desired; @@ -166,11 +103,3 @@ interface INonfungiblePositionManager is /// @param tokenId The ID of the token that is being burned function burn(uint256 tokenId) external payable; } - -/// @title Non-fungible token for PancakeSwap V3 positions -/// @notice Wraps PCSV3 positions in a non-fungible token interface which allows for them to be transferred -/// and authorized. -interface IPCSV3NonfungiblePositionManager is INonfungiblePositionManager { - /// @return Returns the address of the PancakeSwap V3 deployer - function deployer() external view returns (address); -} diff --git a/src/interfaces/IPCSV3NonfungiblePositionManager.sol b/src/interfaces/IPCSV3NonfungiblePositionManager.sol new file mode 100644 index 0000000..5fca1f9 --- /dev/null +++ b/src/interfaces/IPCSV3NonfungiblePositionManager.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.8.0; + +import "./IUniswapV3NonfungiblePositionManager.sol"; + +/// @title Non-fungible token for PancakeSwap V3 positions +/// @notice Wraps PCSV3 positions in a non-fungible token interface which allows for them to be transferred +/// and authorized. +interface IPCSV3NonfungiblePositionManager is IUniswapV3NonfungiblePositionManager { + /// @return Returns the address of the PancakeSwap V3 deployer + function deployer() external view returns (address); +} diff --git a/src/interfaces/ISlipStreamNonfungiblePositionManager.sol b/src/interfaces/ISlipStreamNonfungiblePositionManager.sol new file mode 100644 index 0000000..a3d2c73 --- /dev/null +++ b/src/interfaces/ISlipStreamNonfungiblePositionManager.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +import "./ICommonNonfungiblePositionManager.sol"; + +// Adapted from https://github.com/velodrome-finance/slipstream/blob/main/contracts/periphery/interfaces/INonfungiblePositionManager.sol. +/// @title Non-fungible token for positions in SlipStream +/// @notice Wraps CL positions in a non-fungible token interface which allows for them to be transferred +/// and authorized. +interface ISlipStreamNonfungiblePositionManager is ICommonNonfungiblePositionManager { + /// @notice Emitted when a new Token Descriptor is set + /// @param tokenDescriptor Address of the new Token Descriptor + event TokenDescriptorChanged(address indexed tokenDescriptor); + /// @notice Emitted when a new Owner is set + /// @param owner Address of the new Owner + event TransferOwnership(address indexed owner); + + /// @notice Returns the position information associated with a given token ID. + /// @dev Throws if the token ID is not valid. + /// @param tokenId The ID of the token that represents the position + /// @return nonce The nonce for permits + /// @return operator The address that is approved for spending + /// @return token0 The address of the token0 for a specific pool + /// @return token1 The address of the token1 for a specific pool + /// @return tickSpacing The tick spacing associated with the pool + /// @return tickLower The lower end of the tick range for the position + /// @return tickUpper The higher end of the tick range for the position + /// @return liquidity The liquidity of the position + /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position + /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position + /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation + /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation + function positions( + uint256 tokenId + ) + external + view + returns ( + uint96 nonce, + address operator, + address token0, + address token1, + int24 tickSpacing, + int24 tickLower, + int24 tickUpper, + uint128 liquidity, + uint256 feeGrowthInside0LastX128, + uint256 feeGrowthInside1LastX128, + uint128 tokensOwed0, + uint128 tokensOwed1 + ); + + /// @notice Returns the address of the Token Descriptor, that handles generating token URIs for Positions + function tokenDescriptor() external view returns (address); + + /// @notice Returns the address of the Owner, that is allowed to set a new TokenDescriptor + function owner() external view returns (address); + + struct MintParams { + address token0; + address token1; + int24 tickSpacing; + int24 tickLower; + int24 tickUpper; + uint256 amount0Desired; + uint256 amount1Desired; + uint256 amount0Min; + uint256 amount1Min; + address recipient; + uint256 deadline; + uint160 sqrtPriceX96; + } + + /// @notice Creates a new position wrapped in a NFT + /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized + /// a method does not exist, i.e. the pool is assumed to be initialized. + /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata + /// @return tokenId The ID of the token that represents the minted position + /// @return liquidity The amount of liquidity for this position + /// @return amount0 The amount of token0 + /// @return amount1 The amount of token1 + function mint( + MintParams calldata params + ) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); + + /// @notice Sets a new Token Descriptor + /// @param _tokenDescriptor Address of the new Token Descriptor to be chosen + function setTokenDescriptor(address _tokenDescriptor) external; + + /// @notice Sets a new Owner address + /// @param _owner Address of the new Owner to be chosen + function setOwner(address _owner) external; +} diff --git a/src/interfaces/IUniswapV3NonfungiblePositionManager.sol b/src/interfaces/IUniswapV3NonfungiblePositionManager.sol new file mode 100644 index 0000000..268a047 --- /dev/null +++ b/src/interfaces/IUniswapV3NonfungiblePositionManager.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.8.0; + +import "./ICommonNonfungiblePositionManager.sol"; + +import {IPoolInitializer} from "@uniswap/v3-periphery/contracts/interfaces/IPoolInitializer.sol"; + +/// @title Non-fungible token for positions in Uniswap V3 +/// @notice Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred +/// and authorized. +interface IUniswapV3NonfungiblePositionManager is ICommonNonfungiblePositionManager, IPoolInitializer { + /// @notice Returns the position information associated with a given token ID. + /// @dev Throws if the token ID is not valid. + /// @param tokenId The ID of the token that represents the position + /// @return nonce The nonce for permits + /// @return operator The address that is approved for spending + /// @return token0 The address of the token0 for a specific pool + /// @return token1 The address of the token1 for a specific pool + /// @return fee The fee associated with the pool + /// @return tickLower The lower end of the tick range for the position + /// @return tickUpper The higher end of the tick range for the position + /// @return liquidity The liquidity of the position + /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position + /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position + /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation + /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation + function positions( + uint256 tokenId + ) + external + view + returns ( + uint96 nonce, + address operator, + address token0, + address token1, + uint24 fee, + int24 tickLower, + int24 tickUpper, + uint128 liquidity, + uint256 feeGrowthInside0LastX128, + uint256 feeGrowthInside1LastX128, + uint128 tokensOwed0, + uint128 tokensOwed1 + ); + + struct MintParams { + address token0; + address token1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint256 amount0Desired; + uint256 amount1Desired; + uint256 amount0Min; + uint256 amount1Min; + address recipient; + uint256 deadline; + } + + /// @notice Creates a new position wrapped in a NFT + /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized + /// a method does not exist, i.e. the pool is assumed to be initialized. + /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata + /// @return tokenId The ID of the token that represents the minted position + /// @return liquidity The amount of liquidity for this position + /// @return amount0 The amount of token0 + /// @return amount1 The amount of token1 + function mint( + MintParams calldata params + ) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); +} diff --git a/test/Base.t.sol b/test/Base.t.sol index 5e0127f..7da72a9 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -8,19 +8,45 @@ import {IPancakeV3Factory} from "@pancakeswap/v3-core/contracts/interfaces/IPanc import {IPancakeV3Pool} from "@pancakeswap/v3-core/contracts/interfaces/IPancakeV3Pool.sol"; import {IUniswapV3Factory} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol"; import {IUniswapV3Pool} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; -import {INonfungiblePositionManager} from "src/interfaces/INonfungiblePositionManager.sol"; import {TickBitmap} from "src/TickBitmap.sol"; import {TickMath} from "src/TickMath.sol"; +import {ICommonNonfungiblePositionManager} from "src/interfaces/ICommonNonfungiblePositionManager.sol"; + +// Partial interface for the SlipStream factory. +interface ISlipStreamCLFactory { + /// @notice Returns the pool address for a given pair of tokens and a tick spacing, or address 0 if it does not exist + /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order + /// @param tokenA The contract address of either token0 or token1 + /// @param tokenB The contract address of the other token + /// @param tickSpacing The tick spacing of the pool + /// @return pool The pool address + function getPool(address tokenA, address tokenB, int24 tickSpacing) external view returns (address pool); +} + +interface ISlipStreamCLPool { + function slot0() + external + view + returns ( + uint160 sqrtPriceX96, + int24 tick, + uint16 observationIndex, + uint16 observationCardinality, + uint16 observationCardinalityNext, + bool unlocked + ); +} /// @dev Base test class for all tests. abstract contract BaseTest is Test { address internal factory; - INonfungiblePositionManager internal npm; - address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; - address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + ICommonNonfungiblePositionManager internal npm; + address internal WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + address internal USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address internal token0; address internal token1; uint24 internal fee; + int24 internal tickSpacingSlipStream; address internal pool; int24 internal tickSpacing; // `dex` is used to determine which DEX to use for the test. @@ -29,23 +55,37 @@ abstract contract BaseTest is Test { enum DEX { UniswapV3, - PancakeSwapV3 + PancakeSwapV3, + SlipStream } function setUp() public virtual {} function createFork() internal { - vm.createSelectFork("mainnet", 17000000); if (dex == DEX.UniswapV3) { + vm.createSelectFork("mainnet", 17000000); + WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; factory = 0x1F98431c8aD98523631AE4a59f267346ea31F984; - npm = INonfungiblePositionManager(0xC36442b4a4522E871399CD717aBDD847Ab11FE88); + npm = ICommonNonfungiblePositionManager(0xC36442b4a4522E871399CD717aBDD847Ab11FE88); fee = 3000; pool = IUniswapV3Factory(factory).getPool(WETH, USDC, fee); - } else { + } else if (dex == DEX.PancakeSwapV3) { + vm.createSelectFork("mainnet", 17000000); factory = 0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865; - npm = INonfungiblePositionManager(0x46A15B0b27311cedF172AB29E4f4766fbE7F4364); + WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + npm = ICommonNonfungiblePositionManager(0x46A15B0b27311cedF172AB29E4f4766fbE7F4364); fee = 500; pool = IPancakeV3Factory(factory).getPool(WETH, USDC, fee); + } else { + vm.createSelectFork("base", 17406959); + factory = 0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A; + npm = ICommonNonfungiblePositionManager(0x827922686190790b37229fd06084350E74485b72); + WETH = 0x4200000000000000000000000000000000000006; + USDC = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; + tickSpacingSlipStream = 100; + pool = ISlipStreamCLFactory(factory).getPool(WETH, USDC, tickSpacingSlipStream); } tickSpacing = IUniswapV3Pool(pool).tickSpacing(); token0 = IUniswapV3Pool(pool).token0(); @@ -85,8 +125,10 @@ abstract contract BaseTest is Test { function currentTick() internal view returns (int24 tick) { if (dex == DEX.UniswapV3) { (, tick, , , , , ) = IUniswapV3Pool(pool).slot0(); - } else { + } else if (dex == DEX.PancakeSwapV3) { (, tick, , , , , ) = IPancakeV3Pool(pool).slot0(); + } else { + (, tick, , , , ) = ISlipStreamCLPool(pool).slot0(); } } } diff --git a/test/NPMCaller.t.sol b/test/NPMCaller.t.sol index 67fdb85..ea565d8 100644 --- a/test/NPMCaller.t.sol +++ b/test/NPMCaller.t.sol @@ -10,9 +10,9 @@ import "./Base.t.sol"; contract NPMCallerWrapper { using SafeTransferLib for address; - INonfungiblePositionManager internal immutable npm; + INPM internal immutable npm; - constructor(INonfungiblePositionManager _npm) { + constructor(INPM _npm) { npm = _npm; } @@ -60,7 +60,27 @@ contract NPMCallerWrapper { return NPMCaller.positions(npm, tokenId); } - function mint(INPM.MintParams memory params) external returns (uint256, uint128, uint256, uint256) { + function positionsSlipStream(uint256 tokenId) external view returns (SlipStreamPosition memory) { + return NPMCaller.positionsSlipStream(npm, tokenId); + } + + function mint(IUniV3NPM.MintParams memory params) external returns (uint256, uint128, uint256, uint256) { + uint256 amount0Desired = params.amount0Desired; + uint256 amount1Desired = params.amount1Desired; + if (amount0Desired != 0) { + address token0 = params.token0; + token0.safeTransferFrom(msg.sender, address(this), amount0Desired); + token0.safeApprove(address(npm), amount0Desired); + } + if (amount1Desired != 0) { + address token1 = params.token1; + token1.safeTransferFrom(msg.sender, address(this), amount1Desired); + token1.safeApprove(address(npm), amount1Desired); + } + return NPMCaller.mint(npm, params); + } + + function mint(ISlipStreamNPM.MintParams memory params) external returns (uint256, uint128, uint256, uint256) { uint256 amount0Desired = params.amount0Desired; uint256 amount1Desired = params.amount1Desired; if (amount0Desired != 0) { @@ -133,7 +153,7 @@ contract NPMCallerTest is BaseTest { /// @dev Returns the digest used in the permit signature verification function permitDigest(address spender, uint256 tokenId, uint256 deadline) internal view returns (bytes32) { - (uint96 nonce, , , , , , , , , , , ) = npm.positions(tokenId); + (uint96 nonce, , , , , , , , , , , ) = IUniV3NPM(address(npm)).positions(tokenId); return MessageHashUtils.toTypedDataHash( DOMAIN_SEPARATOR, @@ -204,14 +224,14 @@ contract NPMCallerTest is BaseTest { } } - function testRevert_GetApproved() public { + function testRevert_GetApproved() public virtual { vm.expectRevert("ERC721: approved query for nonexistent token"); npmCaller.getApproved(0); } function test_Approve() public { NPMCallerWrapper _npmCaller = npmCaller; - uint256 tokenId = npm.totalSupply(); + uint256 tokenId = npm.tokenByIndex(0); vm.prank(npm.ownerOf(tokenId)); npm.setApprovalForAll(address(_npmCaller), true); _npmCaller.approve(address(this), tokenId); @@ -219,7 +239,7 @@ contract NPMCallerTest is BaseTest { } function test_IsApprovedForAll() public view { - address owner = npm.ownerOf(npm.totalSupply()); + address owner = npm.ownerOf(npm.tokenByIndex(0)); assertEq( npmCaller.isApprovedForAll(owner, address(this)), npm.isApprovedForAll(owner, address(this)), @@ -256,8 +276,20 @@ contract NPMCallerTest is BaseTest { function testFuzz_PositionsFull(uint256 tokenId) public view virtual { tokenId = bound(tokenId, 1, 10000); try npmCaller.positionsFull(tokenId) returns (PositionFull memory pos) { - (uint96 nonce, , address token0, , , int24 tickLower, , uint128 liquidity, , , , uint128 tokensOwed1) = npm - .positions(tokenId); + ( + uint96 nonce, + , + address token0, + , + , + int24 tickLower, + , + uint128 liquidity, + , + , + , + uint128 tokensOwed1 + ) = IUniV3NPM(address(npm)).positions(tokenId); assertEq(nonce, pos.nonce, "nonce"); assertEq(token0, pos.token0, "token0"); assertEq(tickLower, pos.tickLower, "tickLower"); @@ -286,7 +318,7 @@ contract NPMCallerTest is BaseTest { , , - ) = npm.positions(tokenId); + ) = IUniV3NPM(address(npm)).positions(tokenId); assertEq(token0, pos.token0, "token0"); assertEq(token1, pos.token1, "token1"); assertEq(fee, pos.fee, "fee"); @@ -298,12 +330,12 @@ contract NPMCallerTest is BaseTest { } } - function testRevert_Positions() public { + function testRevert_Positions() public virtual { vm.expectRevert("Invalid token ID"); npmCaller.positions(0); } - function test_Mint() public returns (uint256 tokenId) { + function test_Mint() public virtual returns (uint256 tokenId) { int24 tick = matchSpacing(currentTick()); uint256 amount1Desired = 1e18; address _token1 = token1; @@ -311,7 +343,7 @@ contract NPMCallerTest is BaseTest { NPMCallerWrapper _npmCaller = npmCaller; _token1.safeApprove(address(_npmCaller), amount1Desired); (tokenId, , , ) = _npmCaller.mint( - INPM.MintParams({ + IUniV3NPM.MintParams({ token0: token0, token1: _token1, fee: fee, @@ -438,3 +470,111 @@ contract NPMCallerPCSTest is NPMCallerTest { super.testFuzz_TokenOfOwnerByIndex(tokenId); } } + +contract NPMCallerSlipStreamTest is NPMCallerTest { + function setUp() public override { + dex = DEX.SlipStream; + super.setUp(); + } + + function test_Mint() public override returns (uint256 tokenId) { + int24 tick = matchSpacing(currentTick()); + uint256 amount1Desired = 1e18; + address _token1 = token1; + deal(_token1, address(this), amount1Desired); + NPMCallerWrapper _npmCaller = npmCaller; + SafeTransferLib.safeApprove(_token1, address(_npmCaller), amount1Desired); + (tokenId, , , ) = _npmCaller.mint( + ISlipStreamNPM.MintParams({ + token0: token0, + token1: _token1, + tickSpacing: tickSpacingSlipStream, + tickLower: tick - tickSpacing, + tickUpper: tick, + amount0Desired: 0, + amount1Desired: amount1Desired, + amount0Min: 0, + amount1Min: 0, + recipient: user, + deadline: block.timestamp, + sqrtPriceX96: 0 + }) + ); + } + + // Skipping testFuzz_PositionsFull as PositionsFull is not yet implemented for SlipStream. + function testFuzz_PositionsFull(uint256 tokenId) public view override {} + + /// forge-config: default.fuzz.runs = 16 + /// forge-config: ci.fuzz.runs = 16 + function testFuzz_Positions(uint256 tokenIndex) public view override { + tokenIndex = bound(tokenIndex, 1, 10000); + uint256 tokenId = npm.tokenByIndex(tokenIndex); + SlipStreamPosition memory pos = npmCaller.positionsSlipStream(tokenId); + ( + , + , + address token0, + address token1, + int24 tickSpacing, + int24 tickLower, + int24 tickUpper, + uint128 liquidity, + , + , + , + + ) = ISlipStreamNPM(address(npm)).positions(tokenId); + assertEq(token0, pos.token0, "token0"); + assertEq(token1, pos.token1, "token1"); + assertEq(tickSpacing, pos.tickSpacing, "tickSpacing"); + assertEq(tickLower, pos.tickLower, "tickLower"); + assertEq(tickUpper, pos.tickUpper, "tickUpper"); + assertEq(liquidity, pos.liquidity, "liquidity"); + } + + function testRevert_Positions() public override { + vm.expectRevert(bytes("ID")); + npmCaller.positions(0); + } + + /// forge-config: default.fuzz.runs = 16 + /// forge-config: ci.fuzz.runs = 16 + function testFuzz_GetApproved(uint256 tokenIndex) public view override { + tokenIndex = bound(tokenIndex, 1, 10000); + uint256 tokenId = npm.tokenByIndex(tokenIndex); + address operator = npm.getApproved(tokenId); + assertEq(operator, npmCaller.getApproved(tokenId), "getApproved"); + } + + function testRevert_GetApproved() public override { + vm.expectRevert(bytes("NE")); + npmCaller.getApproved(0); + } + + // The following functions are overridden trivially so the in-line fuzz configuration is applied. + + /// forge-config: default.fuzz.runs = 16 + /// forge-config: ci.fuzz.runs = 16 + function testFuzz_BalanceOf(address owner) public view override { + super.testFuzz_BalanceOf(owner); + } + + /// forge-config: default.fuzz.runs = 16 + /// forge-config: ci.fuzz.runs = 16 + function testFuzz_IsApprovedForAll(uint256 tokenId) public override { + super.testFuzz_IsApprovedForAll(tokenId); + } + + /// forge-config: default.fuzz.runs = 16 + /// forge-config: ci.fuzz.runs = 16 + function testFuzz_OwnerOf(uint256 tokenId) public override { + super.testFuzz_OwnerOf(tokenId); + } + + /// forge-config: default.fuzz.runs = 16 + /// forge-config: ci.fuzz.runs = 16 + function testFuzz_TokenOfOwnerByIndex(uint256 tokenId) public view override { + super.testFuzz_TokenOfOwnerByIndex(tokenId); + } +} From 0052822ca699488b4d644fb6a1781437a264041c Mon Sep 17 00:00:00 2001 From: gnarlycow Date: Sun, 21 Jul 2024 19:18:50 -0700 Subject: [PATCH 02/13] Update GH workflow config and package version. --- .github/workflows/test.yml | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 03a12a6..338e78d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,6 +9,7 @@ on: env: FOUNDRY_PROFILE: ci MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} + BASE_RPC_URL: ${{ secrets.BASE_RPC_URL }} jobs: check: diff --git a/package.json b/package.json index 38b6f8a..c775382 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@aperture_finance/uni-v3-lib", "description": "A suite of Solidity libraries that have been imported and rewritten from Uniswap's v3-core and v3-periphery", - "version": "2.1.0", + "version": "3.0.0", "author": "Aperture Finance", "homepage": "https://aperture.finance/", "license": "GPL-2.0-or-later", From d000e72ba30ad939d019b44e21d93a1950a90520 Mon Sep 17 00:00:00 2001 From: gnarlycow Date: Sat, 27 Jul 2024 15:17:26 -0700 Subject: [PATCH 03/13] Resolve comments. --- README.md | 8 ++++++++ package.json | 4 ++-- test/Base.t.sol | 3 ++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 67f7f66..10aed63 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,14 @@ To run the tests: forge test ``` +## Inline Assembly + +The libraries in this repository make use of [in-line assembly](https://docs.soliditylang.org/en/latest/assembly.html) for fine-grained control and optimizations. Knowledge of ABI encoding is required to understand how to calculate calldata length and parameter offsets. Helpful links: + +- [ABI Specification](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding) +- [HashEx Online ABI Encoder Tool](https://abi.hashex.org) +- [Solidity Memory Layout](https://docs.soliditylang.org/en/latest/internals/layout_in_memory.html) + ## Contributions Contributions are welcome. Please ensure that any modifications pass all tests before submitting a pull request. diff --git a/package.json b/package.json index c775382..91e9b0f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@aperture_finance/uni-v3-lib", "description": "A suite of Solidity libraries that have been imported and rewritten from Uniswap's v3-core and v3-periphery", - "version": "3.0.0", + "version": "3.0.1", "author": "Aperture Finance", "homepage": "https://aperture.finance/", "license": "GPL-2.0-or-later", @@ -51,4 +51,4 @@ "endOfLine": "lf", "printWidth": 120 } -} +} \ No newline at end of file diff --git a/test/Base.t.sol b/test/Base.t.sol index 7da72a9..9c55021 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -12,7 +12,8 @@ import {TickBitmap} from "src/TickBitmap.sol"; import {TickMath} from "src/TickMath.sol"; import {ICommonNonfungiblePositionManager} from "src/interfaces/ICommonNonfungiblePositionManager.sol"; -// Partial interface for the SlipStream factory. +// Partial interface for the SlipStream factory. SlipStream factory is named "CLFactory" and "CL" presumably stands for concentrated liquidity. +// https://github.com/velodrome-finance/slipstream/blob/main/contracts/core/interfaces/ICLFactory.sol interface ISlipStreamCLFactory { /// @notice Returns the pool address for a given pair of tokens and a tick spacing, or address 0 if it does not exist /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order From 4135e00613871e0f0fa0c848f808113ae4d7857a Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Fri, 17 May 2024 00:17:33 -0400 Subject: [PATCH 04/13] Rename, optimize and test `getSqrtPriceTarget` --- .gas-snapshot | 163 ++++++++++++++++++++++---------------------- src/SwapMath.sol | 22 +++--- test/SwapMath.t.sol | 13 ++++ 3 files changed, 106 insertions(+), 92 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 052cb05..56bc558 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,38 +1,38 @@ -BitMathTest:testFuzz_LSB(uint256) (runs: 65545, μ: 17627, ~: 17625) -BitMathTest:testFuzz_MSB(uint256) (runs: 65545, μ: 17649, ~: 17643) +BitMathTest:testFuzz_LSB(uint256) (runs: 65537, μ: 17627, ~: 17625) +BitMathTest:testFuzz_MSB(uint256) (runs: 65537, μ: 17649, ~: 17643) BitMathTest:testGas_LSB() (gas: 239714) BitMathTest:testGas_LSB_Og() (gas: 305805) BitMathTest:testGas_MSB() (gas: 255269) BitMathTest:testGas_MSB_Og() (gas: 288889) -FullMathTest:testFuzz_MulDivQ128(uint256,uint256) (runs: 65543, μ: 4047, ~: 3965) -FullMathTest:testFuzz_MulDivQ96(uint256,uint256) (runs: 65543, μ: 4022, ~: 3950) -FullMathTest:testFuzz_MulDivUp_OZ(uint256,uint256,uint256) (runs: 65545, μ: 4943, ~: 4743) -FullMathTest:testFuzz_MulDivUp_Og(uint256,uint256,uint256) (runs: 65545, μ: 10030, ~: 9829) -FullMathTest:testFuzz_MulDiv_OZ(uint256,uint256,uint256) (runs: 65545, μ: 4208, ~: 4075) -FullMathTest:testFuzz_MulDiv_Og(uint256,uint256,uint256) (runs: 65545, μ: 9567, ~: 9435) -FullMathTest:testFuzz_Sqrt(uint256) (runs: 65545, μ: 4411, ~: 4411) -LiquidityAmountsTest:testFuzz_GetAmount0ForLiquidity(uint160,uint160,uint128) (runs: 65545, μ: 20520, ~: 20778) -LiquidityAmountsTest:testFuzz_GetAmount1ForLiquidity(uint160,uint160,uint128) (runs: 65545, μ: 20074, ~: 20016) -LiquidityAmountsTest:testFuzz_GetAmountsForLiquidity(uint160,uint160,uint160,uint128) (runs: 65545, μ: 23047, ~: 23154) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmount0(uint160,uint160,uint256) (runs: 65545, μ: 20592, ~: 20845) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmount1(uint160,uint160,uint256) (runs: 65545, μ: 20176, ~: 20159) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmounts(uint160,uint160,uint160,uint256,uint256) (runs: 65545, μ: 22569, ~: 22643) +FullMathTest:testFuzz_MulDivQ128(uint256,uint256) (runs: 65537, μ: 4047, ~: 3965) +FullMathTest:testFuzz_MulDivQ96(uint256,uint256) (runs: 65537, μ: 4022, ~: 3950) +FullMathTest:testFuzz_MulDivUp_OZ(uint256,uint256,uint256) (runs: 65537, μ: 4943, ~: 4743) +FullMathTest:testFuzz_MulDivUp_Og(uint256,uint256,uint256) (runs: 65537, μ: 10030, ~: 9829) +FullMathTest:testFuzz_MulDiv_OZ(uint256,uint256,uint256) (runs: 65537, μ: 4208, ~: 4075) +FullMathTest:testFuzz_MulDiv_Og(uint256,uint256,uint256) (runs: 65537, μ: 9567, ~: 9435) +FullMathTest:testFuzz_Sqrt(uint256) (runs: 65537, μ: 4411, ~: 4411) +LiquidityAmountsTest:testFuzz_GetAmount0ForLiquidity(uint160,uint160,uint128) (runs: 65537, μ: 20520, ~: 20778) +LiquidityAmountsTest:testFuzz_GetAmount1ForLiquidity(uint160,uint160,uint128) (runs: 65537, μ: 20074, ~: 20016) +LiquidityAmountsTest:testFuzz_GetAmountsForLiquidity(uint160,uint160,uint160,uint128) (runs: 65537, μ: 23047, ~: 23154) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmount0(uint160,uint160,uint256) (runs: 65537, μ: 20592, ~: 20845) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmount1(uint160,uint160,uint256) (runs: 65537, μ: 20176, ~: 20159) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmounts(uint160,uint160,uint160,uint256,uint256) (runs: 65537, μ: 22569, ~: 22643) LiquidityAmountsTest:testGas_GetAmountsForLiquidity() (gas: 261590) LiquidityAmountsTest:testGas_GetAmountsForLiquidity_Og() (gas: 243788) LiquidityAmountsTest:testGas_GetLiquidityForAmounts() (gas: 264457) LiquidityAmountsTest:testGas_GetLiquidityForAmounts_Og() (gas: 280733) -LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65545, μ: 11955, ~: 14772) +LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65537, μ: 11955, ~: 14772) LiquidityMathTest:testGas_AddDelta() (gas: 139593) LiquidityMathTest:testGas_AddDelta_Og() (gas: 137264) LiquidityMathTest:testRevert_LA() (gas: 8858) LiquidityMathTest:testRevert_LS() (gas: 8846) -NPMCallerPCSTest:testFuzz_BalanceOf(address) (runs: 25, μ: 17700, ~: 17700) -NPMCallerPCSTest:testFuzz_GetApproved(uint256) (runs: 25, μ: 23214, ~: 23225) -NPMCallerPCSTest:testFuzz_IsApprovedForAll(uint256) (runs: 25, μ: 31315, ~: 19570) -NPMCallerPCSTest:testFuzz_OwnerOf(uint256) (runs: 25, μ: 24228, ~: 23905) -NPMCallerPCSTest:testFuzz_Positions(uint256) (runs: 25, μ: 31050, ~: 28027) -NPMCallerPCSTest:testFuzz_PositionsFull(uint256) (runs: 25, μ: 31379, ~: 28338) -NPMCallerPCSTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 25, μ: 74269, ~: 16548) +NPMCallerPCSTest:testFuzz_BalanceOf(address) (runs: 17, μ: 17700, ~: 17700) +NPMCallerPCSTest:testFuzz_GetApproved(uint256) (runs: 17, μ: 23267, ~: 23225) +NPMCallerPCSTest:testFuzz_IsApprovedForAll(uint256) (runs: 17, μ: 36899, ~: 19570) +NPMCallerPCSTest:testFuzz_OwnerOf(uint256) (runs: 17, μ: 24437, ~: 23905) +NPMCallerPCSTest:testFuzz_Positions(uint256) (runs: 17, μ: 32530, ~: 28027) +NPMCallerPCSTest:testFuzz_PositionsFull(uint256) (runs: 17, μ: 32868, ~: 28338) +NPMCallerPCSTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 17, μ: 101861, ~: 16548) NPMCallerPCSTest:testRevert_GetApproved() (gas: 13940) NPMCallerPCSTest:testRevert_OwnerOf() (gas: 14230) NPMCallerPCSTest:testRevert_Positions() (gas: 24310) @@ -47,13 +47,13 @@ NPMCallerPCSTest:test_Mint() (gas: 731515) NPMCallerPCSTest:test_Permit() (gas: 820018) NPMCallerPCSTest:test_SetApprovalForAll() (gas: 61346) NPMCallerPCSTest:test_TotalSupply() (gas: 16574) -NPMCallerTest:testFuzz_BalanceOf(address) (runs: 25, μ: 17726, ~: 17726) -NPMCallerTest:testFuzz_GetApproved(uint256) (runs: 25, μ: 23999, ~: 24213) -NPMCallerTest:testFuzz_IsApprovedForAll(uint256) (runs: 25, μ: 79097, ~: 79311) -NPMCallerTest:testFuzz_OwnerOf(uint256) (runs: 25, μ: 26302, ~: 26516) -NPMCallerTest:testFuzz_Positions(uint256) (runs: 25, μ: 43970, ~: 44184) -NPMCallerTest:testFuzz_PositionsFull(uint256) (runs: 25, μ: 44372, ~: 44586) -NPMCallerTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 25, μ: 68660, ~: 45699) +NPMCallerTest:testFuzz_BalanceOf(address) (runs: 17, μ: 17726, ~: 17726) +NPMCallerTest:testFuzz_GetApproved(uint256) (runs: 17, μ: 23915, ~: 24089) +NPMCallerTest:testFuzz_IsApprovedForAll(uint256) (runs: 17, μ: 79013, ~: 79187) +NPMCallerTest:testFuzz_OwnerOf(uint256) (runs: 17, μ: 26218, ~: 26392) +NPMCallerTest:testFuzz_Positions(uint256) (runs: 17, μ: 43886, ~: 44060) +NPMCallerTest:testFuzz_PositionsFull(uint256) (runs: 17, μ: 44288, ~: 44462) +NPMCallerTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 17, μ: 43488, ~: 45699) NPMCallerTest:testRevert_GetApproved() (gas: 13940) NPMCallerTest:testRevert_OwnerOf() (gas: 14207) NPMCallerTest:testRevert_Positions() (gas: 24310) @@ -68,26 +68,26 @@ NPMCallerTest:test_Mint() (gas: 607783) NPMCallerTest:test_Permit() (gas: 696349) NPMCallerTest:test_SetApprovalForAll() (gas: 61346) NPMCallerTest:test_TotalSupply() (gas: 16585) -PoolAddressPCSTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65545, μ: 20454, ~: 20459) -PoolAddressPCSTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65545, μ: 15645, ~: 15650) -PoolAddressPCSTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65545, μ: 22208, ~: 22213) -PoolAddressPCSTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65545, μ: 17374, ~: 17379) -PoolAddressPCSTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65545, μ: 15993, ~: 15998) +PoolAddressPCSTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65537, μ: 20454, ~: 20459) +PoolAddressPCSTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65537, μ: 15645, ~: 15650) +PoolAddressPCSTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65537, μ: 22208, ~: 22213) +PoolAddressPCSTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65537, μ: 17374, ~: 17379) +PoolAddressPCSTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65537, μ: 15993, ~: 15998) PoolAddressPCSTest:testGas_ComputeAddress() (gas: 12229) PoolAddressPCSTest:testGas_ComputeAddress_Og() (gas: 12774) -PoolAddressTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65545, μ: 20454, ~: 20459) -PoolAddressTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65545, μ: 15645, ~: 15650) -PoolAddressTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65545, μ: 22208, ~: 22213) -PoolAddressTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65545, μ: 17374, ~: 17379) -PoolAddressTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65545, μ: 15993, ~: 15998) +PoolAddressTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65537, μ: 20454, ~: 20459) +PoolAddressTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65537, μ: 15645, ~: 15650) +PoolAddressTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65537, μ: 22208, ~: 22213) +PoolAddressTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65537, μ: 17374, ~: 17379) +PoolAddressTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65537, μ: 15993, ~: 15998) PoolAddressTest:testGas_ComputeAddress() (gas: 12229) PoolAddressTest:testGas_ComputeAddress_Og() (gas: 12774) -PoolCallerPCSTest:testFuzz_LiquidityNet(int24) (runs: 25, μ: 22049, ~: 22049) -PoolCallerPCSTest:testFuzz_Observations(uint256) (runs: 10, μ: 278, ~: 278) -PoolCallerPCSTest:testFuzz_Positions(bytes32) (runs: 25, μ: 24545, ~: 24545) -PoolCallerPCSTest:testFuzz_Swap(bool,uint256,bytes) (runs: 25, μ: 364659, ~: 362861) -PoolCallerPCSTest:testFuzz_TickBitmap(int16) (runs: 25, μ: 14017, ~: 14017) -PoolCallerPCSTest:testFuzz_Ticks(int24) (runs: 25, μ: 27808, ~: 27808) +PoolCallerPCSTest:testFuzz_LiquidityNet(int24) (runs: 17, μ: 22049, ~: 22049) +PoolCallerPCSTest:testFuzz_Observations(uint256) (runs: 2, μ: 278, ~: 278) +PoolCallerPCSTest:testFuzz_Positions(bytes32) (runs: 17, μ: 24545, ~: 24545) +PoolCallerPCSTest:testFuzz_Swap(bool,uint256,bytes) (runs: 17, μ: 353078, ~: 362861) +PoolCallerPCSTest:testFuzz_TickBitmap(int16) (runs: 17, μ: 14017, ~: 14017) +PoolCallerPCSTest:testFuzz_Ticks(int24) (runs: 17, μ: 27808, ~: 27808) PoolCallerPCSTest:testRevert_AS_Swap() (gas: 35364) PoolCallerPCSTest:testRevert_SPL_Swap() (gas: 40085) PoolCallerPCSTest:test_Fee() (gas: 11396) @@ -100,12 +100,12 @@ PoolCallerPCSTest:test_Slot0() (gas: 20497) PoolCallerPCSTest:test_SqrtPriceX96AndTick() (gas: 16086) PoolCallerPCSTest:test_Swap() (gas: 476655) PoolCallerPCSTest:test_TickSpacing() (gas: 11445) -PoolCallerTest:testFuzz_LiquidityNet(int24) (runs: 25, μ: 22023, ~: 22023) -PoolCallerTest:testFuzz_Observations(uint256) (runs: 25, μ: 24399, ~: 24514) -PoolCallerTest:testFuzz_Positions(bytes32) (runs: 25, μ: 24560, ~: 24560) -PoolCallerTest:testFuzz_Swap(bool,uint256,bytes) (runs: 25, μ: 310430, ~: 284899) -PoolCallerTest:testFuzz_TickBitmap(int16) (runs: 25, μ: 14032, ~: 14032) -PoolCallerTest:testFuzz_Ticks(int24) (runs: 25, μ: 27782, ~: 27782) +PoolCallerTest:testFuzz_LiquidityNet(int24) (runs: 17, μ: 22023, ~: 22023) +PoolCallerTest:testFuzz_Observations(uint256) (runs: 17, μ: 24345, ~: 24514) +PoolCallerTest:testFuzz_Positions(bytes32) (runs: 17, μ: 24560, ~: 24560) +PoolCallerTest:testFuzz_Swap(bool,uint256,bytes) (runs: 17, μ: 307955, ~: 284899) +PoolCallerTest:testFuzz_TickBitmap(int16) (runs: 17, μ: 14032, ~: 14032) +PoolCallerTest:testFuzz_Ticks(int24) (runs: 17, μ: 27782, ~: 27782) PoolCallerTest:testRevert_AS_Swap() (gas: 35416) PoolCallerTest:testRevert_SPL_Swap() (gas: 38054) PoolCallerTest:test_Fee() (gas: 11396) @@ -123,20 +123,20 @@ SafeCastTest:testRevert_ToInt256() (gas: 3101) SafeCastTest:testRevert_ToUint128() (gas: 3121) SafeCastTest:testRevert_ToUint160() (gas: 3077) SafeCastTest:testToInt128() (gas: 3166) -SafeCastTest:testToInt128(int256) (runs: 65545, μ: 3328, ~: 3360) -SafeCastTest:testToInt128(uint256) (runs: 65545, μ: 3231, ~: 3257) +SafeCastTest:testToInt128(int256) (runs: 65537, μ: 3328, ~: 3360) +SafeCastTest:testToInt128(uint256) (runs: 65537, μ: 3231, ~: 3257) SafeCastTest:testToInt256() (gas: 3160) -SafeCastTest:testToInt256(uint256) (runs: 65545, μ: 3266, ~: 3270) -SafeCastTest:testToUint128(uint256) (runs: 65545, μ: 3229, ~: 3255) -SafeCastTest:testToUint160(uint256) (runs: 65545, μ: 3258, ~: 3278) -SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65545, μ: 15642, ~: 15557) -SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,uint128,bool) (runs: 65545, μ: 15741, ~: 15660) -SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,int128) (runs: 65545, μ: 15239, ~: 15183) -SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,uint128,bool) (runs: 65545, μ: 15385, ~: 15432) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65545, μ: 19145, ~: 18742) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65545, μ: 21234, ~: 21304) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65545, μ: 15573, ~: 15506) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65545, μ: 15388, ~: 14913) +SafeCastTest:testToInt256(uint256) (runs: 65537, μ: 3266, ~: 3270) +SafeCastTest:testToUint128(uint256) (runs: 65537, μ: 3229, ~: 3255) +SafeCastTest:testToUint160(uint256) (runs: 65537, μ: 3258, ~: 3278) +SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65537, μ: 15642, ~: 15557) +SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,uint128,bool) (runs: 65537, μ: 15741, ~: 15660) +SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,int128) (runs: 65537, μ: 15239, ~: 15183) +SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,uint128,bool) (runs: 65537, μ: 15385, ~: 15432) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65537, μ: 19145, ~: 18742) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65537, μ: 21234, ~: 21304) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65537, μ: 15573, ~: 15506) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65537, μ: 15388, ~: 14913) SqrtPriceMathTest:testGas_GetAmount0Delta() (gas: 322902) SqrtPriceMathTest:testGas_GetAmount0Delta_Og() (gas: 318258) SqrtPriceMathTest:testGas_GetAmount1Delta() (gas: 281567) @@ -145,37 +145,38 @@ SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput() (gas: 303816) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput_Og() (gas: 285701) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput() (gas: 286028) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput_Og() (gas: 269021) -SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65545, μ: 27058, ~: 27142) -SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65545, μ: 29078, ~: 29027) -SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65545, μ: 28629, ~: 28529) +SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65537, μ: 27036, ~: 27120) +SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65537, μ: 29080, ~: 29027) +SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65537, μ: 28608, ~: 28507) +SwapMathTest:testFuzz_getSqrtPriceTarget(bool,uint160,uint160) (runs: 65537, μ: 3503, ~: 3503) SwapMathTest:testGas_ComputeSwapStep() (gas: 515479) -SwapMathTest:testGas_ComputeSwapStepExactIn() (gas: 534633) +SwapMathTest:testGas_ComputeSwapStepExactIn() (gas: 534678) SwapMathTest:testGas_ComputeSwapStepExactIn_Og() (gas: 563266) -SwapMathTest:testGas_ComputeSwapStepExactOut() (gas: 482455) -SwapMathTest:testGas_ComputeSwapStepExactOut_Og() (gas: 557534) +SwapMathTest:testGas_ComputeSwapStepExactOut() (gas: 482433) +SwapMathTest:testGas_ComputeSwapStepExactOut_Og() (gas: 557512) SwapMathTest:testGas_ComputeSwapStep_Og() (gas: 577793) -TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65545, μ: 9447, ~: 9545) -TickBitmapPCSTest:testFuzz_FlipTick(int24) (runs: 65545, μ: 111941, ~: 112231) -TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65545, μ: 112852, ~: 112809) -TickBitmapPCSTest:testFuzz_Position(int24) (runs: 65545, μ: 3856, ~: 3856) +TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65537, μ: 9447, ~: 9545) +TickBitmapPCSTest:testFuzz_FlipTick(int24) (runs: 65537, μ: 111941, ~: 112231) +TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65537, μ: 112852, ~: 112809) +TickBitmapPCSTest:testFuzz_Position(int24) (runs: 65537, μ: 3856, ~: 3856) TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord() (gas: 12546976) TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635559) TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_GT() (gas: 108376) TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 108883) TickBitmapPCSTest:test_NextInitializedTick_GT() (gas: 119576) TickBitmapPCSTest:test_NextInitializedTick_LTE() (gas: 124247) -TickBitmapTest:testFuzz_Compress(int24,int24) (runs: 65545, μ: 9447, ~: 9545) -TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65545, μ: 111942, ~: 112231) -TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65545, μ: 112853, ~: 112809) -TickBitmapTest:testFuzz_Position(int24) (runs: 65545, μ: 3856, ~: 3856) +TickBitmapTest:testFuzz_Compress(int24,int24) (runs: 65537, μ: 9447, ~: 9545) +TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65537, μ: 111942, ~: 112231) +TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65537, μ: 112853, ~: 112809) +TickBitmapTest:testFuzz_Position(int24) (runs: 65537, μ: 3856, ~: 3856) TickBitmapTest:testGas_NextInitializedTickWithinOneWord() (gas: 12546976) TickBitmapTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635559) TickBitmapTest:test_NextInitializedTickWithinOneWord_GT() (gas: 286334) TickBitmapTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 299879) TickBitmapTest:test_NextInitializedTick_GT() (gas: 491345) TickBitmapTest:test_NextInitializedTick_LTE() (gas: 610898) -TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65545, μ: 18073, ~: 17908) -TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65545, μ: 16602, ~: 16618) +TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65537, μ: 18073, ~: 17908) +TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65537, μ: 16602, ~: 16618) TickMathTest:testGas_GetSqrtRatioAtTick() (gas: 174214) TickMathTest:testGas_GetSqrtRatioAtTick_Og() (gas: 180351) TickMathTest:testGas_GetTickAtSqrtRatio() (gas: 284999) diff --git a/src/SwapMath.sol b/src/SwapMath.sol index 7d35454..2012843 100644 --- a/src/SwapMath.sol +++ b/src/SwapMath.sol @@ -13,23 +13,23 @@ library SwapMath { /// @notice Computes the sqrt price target for the next swap step /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0 /// @param sqrtPriceNextX96 The Q64.96 sqrt price for the next initialized tick - /// @param sqrtPriceLimitX96 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 - /// @return sqrtRatioTargetX96 The price target for the next swap step - function getSqrtRatioTarget( + /// @param sqrtPriceLimitX96 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 + /// @return sqrtPriceTargetX96 The price target for the next swap step + function getSqrtPriceTarget( bool zeroForOne, uint160 sqrtPriceNextX96, uint160 sqrtPriceLimitX96 - ) internal pure returns (uint160 sqrtRatioTargetX96) { + ) internal pure returns (uint160 sqrtPriceTargetX96) { assembly { // a flag to toggle between sqrtPriceNextX96 and sqrtPriceLimitX96 - // when zeroForOne == true, nextOrLimit reduces to sqrtPriceNextX96 > sqrtPriceLimitX96 - // sqrtRatioTargetX96 = max(sqrtPriceNextX96, sqrtPriceLimitX96) - // when zeroForOne == false, nextOrLimit reduces to sqrtPriceNextX96 <= sqrtPriceLimitX96 - // sqrtRatioTargetX96 = min(sqrtPriceNextX96, sqrtPriceLimitX96) - let nextOrLimit := xor(gt(sqrtPriceNextX96, sqrtPriceLimitX96), iszero(zeroForOne)) + // when zeroForOne == true, nextOrLimit reduces to sqrtPriceNextX96 >= sqrtPriceLimitX96 + // sqrtPriceTargetX96 = max(sqrtPriceNextX96, sqrtPriceLimitX96) + // when zeroForOne == false, nextOrLimit reduces to sqrtPriceNextX96 < sqrtPriceLimitX96 + // sqrtPriceTargetX96 = min(sqrtPriceNextX96, sqrtPriceLimitX96) + let nextOrLimit := xor(lt(sqrtPriceNextX96, sqrtPriceLimitX96), zeroForOne) let symDiff := xor(sqrtPriceNextX96, sqrtPriceLimitX96) - sqrtRatioTargetX96 := xor(sqrtPriceLimitX96, mul(symDiff, nextOrLimit)) + sqrtPriceTargetX96 := xor(sqrtPriceLimitX96, mul(symDiff, nextOrLimit)) } } diff --git a/test/SwapMath.t.sol b/test/SwapMath.t.sol index 10d9aaf..a76d4ff 100644 --- a/test/SwapMath.t.sol +++ b/test/SwapMath.t.sol @@ -62,6 +62,19 @@ contract SwapMathTest is BaseTest { wrapper = new SwapMathWrapper(); } + function testFuzz_getSqrtPriceTarget( + bool zeroForOne, + uint160 sqrtPriceNextX96, + uint160 sqrtPriceLimitX96 + ) external pure { + assertEq( + SwapMath.getSqrtPriceTarget(zeroForOne, sqrtPriceNextX96, sqrtPriceLimitX96), + (zeroForOne ? sqrtPriceNextX96 < sqrtPriceLimitX96 : sqrtPriceNextX96 > sqrtPriceLimitX96) + ? sqrtPriceLimitX96 + : sqrtPriceNextX96 + ); + } + function testFuzz_ComputeSwapStep( uint160 sqrtRatioCurrentX96, uint160 sqrtRatioTargetX96, From aac93b2d8963b8846d3b6500ce817f74edcc1847 Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Fri, 17 May 2024 01:03:46 -0400 Subject: [PATCH 05/13] Refactor calculation of 'ratio' in TickMath.sol The existing assembly code calculating the 'ratio' variable in TickMath.sol has been refactored for simplicity and efficiency. This result is achieved by removing an unnecessary mask operation and replacing it with a more straightforward expression that improves code readability and reduces complexity. --- .gas-snapshot | 10 +++++----- src/TickMath.sol | 14 ++++---------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 56bc558..410fdbb 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -21,7 +21,7 @@ LiquidityAmountsTest:testGas_GetAmountsForLiquidity() (gas: 261590) LiquidityAmountsTest:testGas_GetAmountsForLiquidity_Og() (gas: 243788) LiquidityAmountsTest:testGas_GetLiquidityForAmounts() (gas: 264457) LiquidityAmountsTest:testGas_GetLiquidityForAmounts_Og() (gas: 280733) -LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65537, μ: 11955, ~: 14772) +LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65537, μ: 11956, ~: 14772) LiquidityMathTest:testGas_AddDelta() (gas: 139593) LiquidityMathTest:testGas_AddDelta_Og() (gas: 137264) LiquidityMathTest:testRevert_LA() (gas: 8858) @@ -175,11 +175,11 @@ TickBitmapTest:test_NextInitializedTickWithinOneWord_GT() (gas: 286334) TickBitmapTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 299879) TickBitmapTest:test_NextInitializedTick_GT() (gas: 491345) TickBitmapTest:test_NextInitializedTick_LTE() (gas: 610898) -TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65537, μ: 18073, ~: 17908) -TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65537, μ: 16602, ~: 16618) -TickMathTest:testGas_GetSqrtRatioAtTick() (gas: 174214) +TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65537, μ: 18058, ~: 17894) +TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65537, μ: 16597, ~: 16611) +TickMathTest:testGas_GetSqrtRatioAtTick() (gas: 173514) TickMathTest:testGas_GetSqrtRatioAtTick_Og() (gas: 180351) -TickMathTest:testGas_GetTickAtSqrtRatio() (gas: 284999) +TickMathTest:testGas_GetTickAtSqrtRatio() (gas: 284369) TickMathTest:testGas_GetTickAtSqrtRatio_Og() (gas: 317582) TickMathTest:testRevert_GetSqrtRatioAtTick() (gas: 11527) TickMathTest:testRevert_GetTickAtSqrtRatio() (gas: 11267) \ No newline at end of file diff --git a/src/TickMath.sol b/src/TickMath.sol index ae4e152..e940412 100644 --- a/src/TickMath.sol +++ b/src/TickMath.sol @@ -49,18 +49,12 @@ library TickMath { } } - // Equivalent: ratio = 2**128 / sqrt(1.0001) if absTick & 0x1 else 1 << 128 + // Equivalent to: + // ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; + // or ratio = int(2**128 / sqrt(1.0001)) if (absTick & 0x1) else 1 << 128 uint256 ratio; assembly { - ratio := and( - shr( - // 128 if absTick & 0x1 else 0 - shl(7, and(absTick, 0x1)), - // upper 128 bits of 2**256 / sqrt(1.0001) where the 128th bit is 1 - 0xfffcb933bd6fad37aa2d162d1a59400100000000000000000000000000000000 - ), - 0x1ffffffffffffffffffffffffffffffff // mask lower 129 bits - ) + ratio := xor(shl(128, 1), mul(xor(shl(128, 1), 0xfffcb933bd6fad37aa2d162d1a594001), and(absTick, 0x1))) } // Iterate through 1th to 19th bit of absTick because MAX_TICK < 2**20 // Equivalent to: From bbf195480426a7f0cf996ad7d1f21ede5113220a Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Fri, 17 May 2024 16:22:40 -0400 Subject: [PATCH 06/13] Refactor arithmetic operations in `TickMath` --- .gas-snapshot | 6 +++--- src/TickMath.sol | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 410fdbb..5df9e19 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -175,11 +175,11 @@ TickBitmapTest:test_NextInitializedTickWithinOneWord_GT() (gas: 286334) TickBitmapTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 299879) TickBitmapTest:test_NextInitializedTick_GT() (gas: 491345) TickBitmapTest:test_NextInitializedTick_LTE() (gas: 610898) -TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65537, μ: 18058, ~: 17894) -TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65537, μ: 16597, ~: 16611) +TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65537, μ: 18040, ~: 17876) +TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65537, μ: 16578, ~: 16593) TickMathTest:testGas_GetSqrtRatioAtTick() (gas: 173514) TickMathTest:testGas_GetSqrtRatioAtTick_Og() (gas: 180351) -TickMathTest:testGas_GetTickAtSqrtRatio() (gas: 284369) +TickMathTest:testGas_GetTickAtSqrtRatio() (gas: 282569) TickMathTest:testGas_GetTickAtSqrtRatio_Og() (gas: 317582) TickMathTest:testRevert_GetSqrtRatioAtTick() (gas: 11527) TickMathTest:testRevert_GetTickAtSqrtRatio() (gas: 11267) \ No newline at end of file diff --git a/src/TickMath.sol b/src/TickMath.sol index e940412..c4d231f 100644 --- a/src/TickMath.sol +++ b/src/TickMath.sol @@ -92,7 +92,7 @@ library TickMath { // 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 getTickAtSqrtRatio of the output price is always consistent assembly { - sqrtPriceX96 := shr(32, add(ratio, 0xffffffff)) + sqrtPriceX96 := shr(32, add(ratio, sub(shl(32, 1), 1))) } } } @@ -169,67 +169,67 @@ library TickMath { // f = (r**2 >= 2**255) let f := slt(square, 0) // r = r**2 >> 128 if r**2 >= 2**255 else r**2 >> 127 - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(63, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(62, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(61, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(60, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(59, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(58, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(57, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(56, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(55, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(54, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(53, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(52, f), log_2X64) square := mul(r, r) f := slt(square, 0) - r := shr(add(127, f), square) + r := shr(127, shr(f, square)) log_2X64 := or(shl(51, f), log_2X64) log_2X64 := or(shl(50, slt(mul(r, r), 0)), log_2X64) From e1f779336388898cae465eb7004da70eb0177318 Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Wed, 22 May 2024 02:06:12 -0400 Subject: [PATCH 07/13] Refactor `computeSwapStep` to remove unnecessary variable The `amountRemainingAbs` variable in SwapMath.sol was removed to simplify code logic. The conversion to an unsigned integer is now performed directly where required, which eliminates the need for the intermediate variable. This change improves code readability and maintainability. --- .gas-snapshot | 160 +++++++++++++++++++++++------------------------ src/SwapMath.sol | 13 ++-- 2 files changed, 85 insertions(+), 88 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 5df9e19..fe48d7f 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,38 +1,38 @@ -BitMathTest:testFuzz_LSB(uint256) (runs: 65537, μ: 17627, ~: 17625) -BitMathTest:testFuzz_MSB(uint256) (runs: 65537, μ: 17649, ~: 17643) +BitMathTest:testFuzz_LSB(uint256) (runs: 65541, μ: 17626, ~: 17625) +BitMathTest:testFuzz_MSB(uint256) (runs: 65541, μ: 17649, ~: 17643) BitMathTest:testGas_LSB() (gas: 239714) BitMathTest:testGas_LSB_Og() (gas: 305805) BitMathTest:testGas_MSB() (gas: 255269) BitMathTest:testGas_MSB_Og() (gas: 288889) -FullMathTest:testFuzz_MulDivQ128(uint256,uint256) (runs: 65537, μ: 4047, ~: 3965) -FullMathTest:testFuzz_MulDivQ96(uint256,uint256) (runs: 65537, μ: 4022, ~: 3950) -FullMathTest:testFuzz_MulDivUp_OZ(uint256,uint256,uint256) (runs: 65537, μ: 4943, ~: 4743) -FullMathTest:testFuzz_MulDivUp_Og(uint256,uint256,uint256) (runs: 65537, μ: 10030, ~: 9829) -FullMathTest:testFuzz_MulDiv_OZ(uint256,uint256,uint256) (runs: 65537, μ: 4208, ~: 4075) -FullMathTest:testFuzz_MulDiv_Og(uint256,uint256,uint256) (runs: 65537, μ: 9567, ~: 9435) -FullMathTest:testFuzz_Sqrt(uint256) (runs: 65537, μ: 4411, ~: 4411) -LiquidityAmountsTest:testFuzz_GetAmount0ForLiquidity(uint160,uint160,uint128) (runs: 65537, μ: 20520, ~: 20778) -LiquidityAmountsTest:testFuzz_GetAmount1ForLiquidity(uint160,uint160,uint128) (runs: 65537, μ: 20074, ~: 20016) -LiquidityAmountsTest:testFuzz_GetAmountsForLiquidity(uint160,uint160,uint160,uint128) (runs: 65537, μ: 23047, ~: 23154) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmount0(uint160,uint160,uint256) (runs: 65537, μ: 20592, ~: 20845) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmount1(uint160,uint160,uint256) (runs: 65537, μ: 20176, ~: 20159) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmounts(uint160,uint160,uint160,uint256,uint256) (runs: 65537, μ: 22569, ~: 22643) +FullMathTest:testFuzz_MulDivQ128(uint256,uint256) (runs: 65539, μ: 4047, ~: 3965) +FullMathTest:testFuzz_MulDivQ96(uint256,uint256) (runs: 65539, μ: 4022, ~: 3950) +FullMathTest:testFuzz_MulDivUp_OZ(uint256,uint256,uint256) (runs: 65539, μ: 4945, ~: 4743) +FullMathTest:testFuzz_MulDivUp_Og(uint256,uint256,uint256) (runs: 65539, μ: 10032, ~: 9829) +FullMathTest:testFuzz_MulDiv_OZ(uint256,uint256,uint256) (runs: 65539, μ: 4209, ~: 4075) +FullMathTest:testFuzz_MulDiv_Og(uint256,uint256,uint256) (runs: 65539, μ: 9568, ~: 9435) +FullMathTest:testFuzz_Sqrt(uint256) (runs: 65541, μ: 4411, ~: 4411) +LiquidityAmountsTest:testFuzz_GetAmount0ForLiquidity(uint160,uint160,uint128) (runs: 65541, μ: 20520, ~: 20778) +LiquidityAmountsTest:testFuzz_GetAmount1ForLiquidity(uint160,uint160,uint128) (runs: 65541, μ: 20073, ~: 20016) +LiquidityAmountsTest:testFuzz_GetAmountsForLiquidity(uint160,uint160,uint160,uint128) (runs: 65541, μ: 23054, ~: 23154) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmount0(uint160,uint160,uint256) (runs: 65541, μ: 20592, ~: 20845) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmount1(uint160,uint160,uint256) (runs: 65541, μ: 20175, ~: 20159) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmounts(uint160,uint160,uint160,uint256,uint256) (runs: 65541, μ: 22572, ~: 22643) LiquidityAmountsTest:testGas_GetAmountsForLiquidity() (gas: 261590) LiquidityAmountsTest:testGas_GetAmountsForLiquidity_Og() (gas: 243788) LiquidityAmountsTest:testGas_GetLiquidityForAmounts() (gas: 264457) LiquidityAmountsTest:testGas_GetLiquidityForAmounts_Og() (gas: 280733) -LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65537, μ: 11956, ~: 14772) +LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65541, μ: 11968, ~: 14772) LiquidityMathTest:testGas_AddDelta() (gas: 139593) LiquidityMathTest:testGas_AddDelta_Og() (gas: 137264) LiquidityMathTest:testRevert_LA() (gas: 8858) LiquidityMathTest:testRevert_LS() (gas: 8846) -NPMCallerPCSTest:testFuzz_BalanceOf(address) (runs: 17, μ: 17700, ~: 17700) -NPMCallerPCSTest:testFuzz_GetApproved(uint256) (runs: 17, μ: 23267, ~: 23225) -NPMCallerPCSTest:testFuzz_IsApprovedForAll(uint256) (runs: 17, μ: 36899, ~: 19570) -NPMCallerPCSTest:testFuzz_OwnerOf(uint256) (runs: 17, μ: 24437, ~: 23905) -NPMCallerPCSTest:testFuzz_Positions(uint256) (runs: 17, μ: 32530, ~: 28027) -NPMCallerPCSTest:testFuzz_PositionsFull(uint256) (runs: 17, μ: 32868, ~: 28338) -NPMCallerPCSTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 17, μ: 101861, ~: 16548) +NPMCallerPCSTest:testFuzz_BalanceOf(address) (runs: 21, μ: 17700, ~: 17700) +NPMCallerPCSTest:testFuzz_GetApproved(uint256) (runs: 21, μ: 23183, ~: 23225) +NPMCallerPCSTest:testFuzz_IsApprovedForAll(uint256) (runs: 21, μ: 30724, ~: 19570) +NPMCallerPCSTest:testFuzz_OwnerOf(uint256) (runs: 21, μ: 24181, ~: 23905) +NPMCallerPCSTest:testFuzz_Positions(uint256) (runs: 21, μ: 30874, ~: 28027) +NPMCallerPCSTest:testFuzz_PositionsFull(uint256) (runs: 21, μ: 31203, ~: 28338) +NPMCallerPCSTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 21, μ: 21395, ~: 16548) NPMCallerPCSTest:testRevert_GetApproved() (gas: 13940) NPMCallerPCSTest:testRevert_OwnerOf() (gas: 14230) NPMCallerPCSTest:testRevert_Positions() (gas: 24310) @@ -47,13 +47,13 @@ NPMCallerPCSTest:test_Mint() (gas: 731515) NPMCallerPCSTest:test_Permit() (gas: 820018) NPMCallerPCSTest:test_SetApprovalForAll() (gas: 61346) NPMCallerPCSTest:test_TotalSupply() (gas: 16574) -NPMCallerTest:testFuzz_BalanceOf(address) (runs: 17, μ: 17726, ~: 17726) -NPMCallerTest:testFuzz_GetApproved(uint256) (runs: 17, μ: 23915, ~: 24089) -NPMCallerTest:testFuzz_IsApprovedForAll(uint256) (runs: 17, μ: 79013, ~: 79187) -NPMCallerTest:testFuzz_OwnerOf(uint256) (runs: 17, μ: 26218, ~: 26392) -NPMCallerTest:testFuzz_Positions(uint256) (runs: 17, μ: 43886, ~: 44060) -NPMCallerTest:testFuzz_PositionsFull(uint256) (runs: 17, μ: 44288, ~: 44462) -NPMCallerTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 17, μ: 43488, ~: 45699) +NPMCallerTest:testFuzz_BalanceOf(address) (runs: 21, μ: 17726, ~: 17726) +NPMCallerTest:testFuzz_GetApproved(uint256) (runs: 21, μ: 24010, ~: 24213) +NPMCallerTest:testFuzz_IsApprovedForAll(uint256) (runs: 21, μ: 79108, ~: 79311) +NPMCallerTest:testFuzz_OwnerOf(uint256) (runs: 21, μ: 26313, ~: 26516) +NPMCallerTest:testFuzz_Positions(uint256) (runs: 21, μ: 43981, ~: 44184) +NPMCallerTest:testFuzz_PositionsFull(uint256) (runs: 21, μ: 44383, ~: 44586) +NPMCallerTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 21, μ: 114170, ~: 40070) NPMCallerTest:testRevert_GetApproved() (gas: 13940) NPMCallerTest:testRevert_OwnerOf() (gas: 14207) NPMCallerTest:testRevert_Positions() (gas: 24310) @@ -68,26 +68,26 @@ NPMCallerTest:test_Mint() (gas: 607783) NPMCallerTest:test_Permit() (gas: 696349) NPMCallerTest:test_SetApprovalForAll() (gas: 61346) NPMCallerTest:test_TotalSupply() (gas: 16585) -PoolAddressPCSTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65537, μ: 20454, ~: 20459) -PoolAddressPCSTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65537, μ: 15645, ~: 15650) -PoolAddressPCSTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65537, μ: 22208, ~: 22213) -PoolAddressPCSTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65537, μ: 17374, ~: 17379) -PoolAddressPCSTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65537, μ: 15993, ~: 15998) +PoolAddressPCSTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65541, μ: 20454, ~: 20459) +PoolAddressPCSTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65541, μ: 15645, ~: 15650) +PoolAddressPCSTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65541, μ: 22208, ~: 22213) +PoolAddressPCSTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65541, μ: 17374, ~: 17379) +PoolAddressPCSTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65541, μ: 15993, ~: 15998) PoolAddressPCSTest:testGas_ComputeAddress() (gas: 12229) PoolAddressPCSTest:testGas_ComputeAddress_Og() (gas: 12774) -PoolAddressTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65537, μ: 20454, ~: 20459) -PoolAddressTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65537, μ: 15645, ~: 15650) -PoolAddressTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65537, μ: 22208, ~: 22213) -PoolAddressTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65537, μ: 17374, ~: 17379) -PoolAddressTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65537, μ: 15993, ~: 15998) +PoolAddressTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65541, μ: 20454, ~: 20459) +PoolAddressTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65541, μ: 15645, ~: 15650) +PoolAddressTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65541, μ: 22208, ~: 22213) +PoolAddressTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65541, μ: 17374, ~: 17379) +PoolAddressTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65541, μ: 15993, ~: 15998) PoolAddressTest:testGas_ComputeAddress() (gas: 12229) PoolAddressTest:testGas_ComputeAddress_Og() (gas: 12774) -PoolCallerPCSTest:testFuzz_LiquidityNet(int24) (runs: 17, μ: 22049, ~: 22049) -PoolCallerPCSTest:testFuzz_Observations(uint256) (runs: 2, μ: 278, ~: 278) -PoolCallerPCSTest:testFuzz_Positions(bytes32) (runs: 17, μ: 24545, ~: 24545) -PoolCallerPCSTest:testFuzz_Swap(bool,uint256,bytes) (runs: 17, μ: 353078, ~: 362861) -PoolCallerPCSTest:testFuzz_TickBitmap(int16) (runs: 17, μ: 14017, ~: 14017) -PoolCallerPCSTest:testFuzz_Ticks(int24) (runs: 17, μ: 27808, ~: 27808) +PoolCallerPCSTest:testFuzz_LiquidityNet(int24) (runs: 21, μ: 22049, ~: 22049) +PoolCallerPCSTest:testFuzz_Observations(uint256) (runs: 6, μ: 278, ~: 278) +PoolCallerPCSTest:testFuzz_Positions(bytes32) (runs: 21, μ: 24545, ~: 24545) +PoolCallerPCSTest:testFuzz_Swap(bool,uint256,bytes) (runs: 21, μ: 409893, ~: 383922) +PoolCallerPCSTest:testFuzz_TickBitmap(int16) (runs: 21, μ: 14017, ~: 14017) +PoolCallerPCSTest:testFuzz_Ticks(int24) (runs: 21, μ: 27808, ~: 27808) PoolCallerPCSTest:testRevert_AS_Swap() (gas: 35364) PoolCallerPCSTest:testRevert_SPL_Swap() (gas: 40085) PoolCallerPCSTest:test_Fee() (gas: 11396) @@ -100,12 +100,12 @@ PoolCallerPCSTest:test_Slot0() (gas: 20497) PoolCallerPCSTest:test_SqrtPriceX96AndTick() (gas: 16086) PoolCallerPCSTest:test_Swap() (gas: 476655) PoolCallerPCSTest:test_TickSpacing() (gas: 11445) -PoolCallerTest:testFuzz_LiquidityNet(int24) (runs: 17, μ: 22023, ~: 22023) -PoolCallerTest:testFuzz_Observations(uint256) (runs: 17, μ: 24345, ~: 24514) -PoolCallerTest:testFuzz_Positions(bytes32) (runs: 17, μ: 24560, ~: 24560) -PoolCallerTest:testFuzz_Swap(bool,uint256,bytes) (runs: 17, μ: 307955, ~: 284899) -PoolCallerTest:testFuzz_TickBitmap(int16) (runs: 17, μ: 14032, ~: 14032) -PoolCallerTest:testFuzz_Ticks(int24) (runs: 17, μ: 27782, ~: 27782) +PoolCallerTest:testFuzz_LiquidityNet(int24) (runs: 21, μ: 22023, ~: 22023) +PoolCallerTest:testFuzz_Observations(uint256) (runs: 21, μ: 24383, ~: 24514) +PoolCallerTest:testFuzz_Positions(bytes32) (runs: 21, μ: 24560, ~: 24560) +PoolCallerTest:testFuzz_Swap(bool,uint256,bytes) (runs: 21, μ: 352923, ~: 364543) +PoolCallerTest:testFuzz_TickBitmap(int16) (runs: 21, μ: 14032, ~: 14032) +PoolCallerTest:testFuzz_Ticks(int24) (runs: 21, μ: 27782, ~: 27782) PoolCallerTest:testRevert_AS_Swap() (gas: 35416) PoolCallerTest:testRevert_SPL_Swap() (gas: 38054) PoolCallerTest:test_Fee() (gas: 11396) @@ -123,20 +123,20 @@ SafeCastTest:testRevert_ToInt256() (gas: 3101) SafeCastTest:testRevert_ToUint128() (gas: 3121) SafeCastTest:testRevert_ToUint160() (gas: 3077) SafeCastTest:testToInt128() (gas: 3166) -SafeCastTest:testToInt128(int256) (runs: 65537, μ: 3328, ~: 3360) -SafeCastTest:testToInt128(uint256) (runs: 65537, μ: 3231, ~: 3257) +SafeCastTest:testToInt128(int256) (runs: 65541, μ: 3328, ~: 3360) +SafeCastTest:testToInt128(uint256) (runs: 65541, μ: 3231, ~: 3257) SafeCastTest:testToInt256() (gas: 3160) -SafeCastTest:testToInt256(uint256) (runs: 65537, μ: 3266, ~: 3270) -SafeCastTest:testToUint128(uint256) (runs: 65537, μ: 3229, ~: 3255) -SafeCastTest:testToUint160(uint256) (runs: 65537, μ: 3258, ~: 3278) -SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65537, μ: 15642, ~: 15557) -SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,uint128,bool) (runs: 65537, μ: 15741, ~: 15660) -SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,int128) (runs: 65537, μ: 15239, ~: 15183) -SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,uint128,bool) (runs: 65537, μ: 15385, ~: 15432) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65537, μ: 19145, ~: 18742) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65537, μ: 21234, ~: 21304) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65537, μ: 15573, ~: 15506) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65537, μ: 15388, ~: 14913) +SafeCastTest:testToInt256(uint256) (runs: 65541, μ: 3266, ~: 3270) +SafeCastTest:testToUint128(uint256) (runs: 65541, μ: 3229, ~: 3255) +SafeCastTest:testToUint160(uint256) (runs: 65541, μ: 3258, ~: 3278) +SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65541, μ: 15641, ~: 15557) +SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,uint128,bool) (runs: 65541, μ: 15744, ~: 15660) +SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,int128) (runs: 65541, μ: 15239, ~: 15183) +SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,uint128,bool) (runs: 65541, μ: 15386, ~: 15432) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65541, μ: 19141, ~: 18742) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65541, μ: 21231, ~: 21304) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65541, μ: 15572, ~: 15506) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65541, μ: 15383, ~: 14913) SqrtPriceMathTest:testGas_GetAmount0Delta() (gas: 322902) SqrtPriceMathTest:testGas_GetAmount0Delta_Og() (gas: 318258) SqrtPriceMathTest:testGas_GetAmount1Delta() (gas: 281567) @@ -145,38 +145,38 @@ SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput() (gas: 303816) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput_Og() (gas: 285701) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput() (gas: 286028) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput_Og() (gas: 269021) -SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65537, μ: 27036, ~: 27120) -SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65537, μ: 29080, ~: 29027) -SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65537, μ: 28608, ~: 28507) -SwapMathTest:testFuzz_getSqrtPriceTarget(bool,uint160,uint160) (runs: 65537, μ: 3503, ~: 3503) -SwapMathTest:testGas_ComputeSwapStep() (gas: 515479) +SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65541, μ: 27024, ~: 27110) +SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65541, μ: 29076, ~: 29027) +SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65541, μ: 28603, ~: 28507) +SwapMathTest:testFuzz_getSqrtPriceTarget(bool,uint160,uint160) (runs: 65541, μ: 3503, ~: 3503) +SwapMathTest:testGas_ComputeSwapStep() (gas: 514452) SwapMathTest:testGas_ComputeSwapStepExactIn() (gas: 534678) SwapMathTest:testGas_ComputeSwapStepExactIn_Og() (gas: 563266) SwapMathTest:testGas_ComputeSwapStepExactOut() (gas: 482433) SwapMathTest:testGas_ComputeSwapStepExactOut_Og() (gas: 557512) SwapMathTest:testGas_ComputeSwapStep_Og() (gas: 577793) -TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65537, μ: 9447, ~: 9545) -TickBitmapPCSTest:testFuzz_FlipTick(int24) (runs: 65537, μ: 111941, ~: 112231) -TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65537, μ: 112852, ~: 112809) -TickBitmapPCSTest:testFuzz_Position(int24) (runs: 65537, μ: 3856, ~: 3856) +TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65541, μ: 9445, ~: 9545) +TickBitmapPCSTest:testFuzz_FlipTick(int24) (runs: 65541, μ: 111941, ~: 112231) +TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65541, μ: 112848, ~: 112796) +TickBitmapPCSTest:testFuzz_Position(int24) (runs: 65541, μ: 3856, ~: 3856) TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord() (gas: 12546976) TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635559) TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_GT() (gas: 108376) TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 108883) TickBitmapPCSTest:test_NextInitializedTick_GT() (gas: 119576) TickBitmapPCSTest:test_NextInitializedTick_LTE() (gas: 124247) -TickBitmapTest:testFuzz_Compress(int24,int24) (runs: 65537, μ: 9447, ~: 9545) -TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65537, μ: 111942, ~: 112231) -TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65537, μ: 112853, ~: 112809) -TickBitmapTest:testFuzz_Position(int24) (runs: 65537, μ: 3856, ~: 3856) +TickBitmapTest:testFuzz_Compress(int24,int24) (runs: 65541, μ: 9445, ~: 9545) +TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65541, μ: 111943, ~: 112231) +TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65541, μ: 112846, ~: 112796) +TickBitmapTest:testFuzz_Position(int24) (runs: 65541, μ: 3856, ~: 3856) TickBitmapTest:testGas_NextInitializedTickWithinOneWord() (gas: 12546976) TickBitmapTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635559) TickBitmapTest:test_NextInitializedTickWithinOneWord_GT() (gas: 286334) TickBitmapTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 299879) TickBitmapTest:test_NextInitializedTick_GT() (gas: 491345) TickBitmapTest:test_NextInitializedTick_LTE() (gas: 610898) -TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65537, μ: 18040, ~: 17876) -TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65537, μ: 16578, ~: 16593) +TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65541, μ: 18039, ~: 17876) +TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65541, μ: 16579, ~: 16593) TickMathTest:testGas_GetSqrtRatioAtTick() (gas: 173514) TickMathTest:testGas_GetSqrtRatioAtTick_Og() (gas: 180351) TickMathTest:testGas_GetTickAtSqrtRatio() (gas: 282569) diff --git a/src/SwapMath.sol b/src/SwapMath.sol index 2012843..7c9e359 100644 --- a/src/SwapMath.sol +++ b/src/SwapMath.sol @@ -55,11 +55,9 @@ library SwapMath { bool zeroForOne = sqrtRatioCurrentX96 >= sqrtRatioTargetX96; uint256 feeComplement = MAX_FEE_PIPS - feePips; bool exactOut = amountRemaining < 0; - uint256 amountRemainingAbs; if (!exactOut) { - amountRemainingAbs = uint256(amountRemaining); - uint256 amountRemainingLessFee = FullMath.mulDiv(amountRemainingAbs, feeComplement, MAX_FEE_PIPS); + uint256 amountRemainingLessFee = FullMath.mulDiv(uint256(amountRemaining), feeComplement, MAX_FEE_PIPS); amountIn = zeroForOne ? SqrtPriceMath.getAmount0Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, true) : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, true); @@ -73,11 +71,11 @@ library SwapMath { sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromInput( sqrtRatioCurrentX96, liquidity, - amountIn, + amountRemainingLessFee, zeroForOne ); // we didn't reach the target, so take the remainder of the maximum input as fee - feeAmount = amountRemainingAbs - amountIn; + feeAmount = uint256(amountRemaining) - amountIn; } amountOut = zeroForOne ? SqrtPriceMath.getAmount1Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, false) @@ -86,13 +84,12 @@ library SwapMath { amountOut = zeroForOne ? SqrtPriceMath.getAmount1Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, false) : SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, false); - amountRemainingAbs = uint256(-amountRemaining); - if (amountRemainingAbs >= amountOut) { + if (uint256(-amountRemaining) >= amountOut) { // `amountOut` is capped by the target price sqrtRatioNextX96 = sqrtRatioTargetX96; } else { // cap the output amount to not exceed the remaining output amount - amountOut = amountRemainingAbs; + amountOut = uint256(-amountRemaining); sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromOutput( sqrtRatioCurrentX96, liquidity, From 3c393aee04cf7aa08b30ce8a98340a745ce1dbb6 Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Sun, 26 May 2024 03:48:30 -0400 Subject: [PATCH 08/13] Added new test cases and modified existing ones for TickMath and TickBitmap In this commit, new test cases are added for TickMath.t.sol to examine the 'Revert_GetSqrtRatioAtTick' and 'Revert_GetTickAtSqrtRatio' methods; and also added new functions to test bitmap manipulations in TickBitmap.t.sol such as 'flipTick' and 'isInitialized'. Additionally, existing test cases are modified to improve coverage and enhance test robustness. --- .gas-snapshot | 230 +++++++++++++++++++++--------------------- test/TickBitmap.t.sol | 66 +++++++++--- test/TickMath.t.sol | 20 ++++ 3 files changed, 189 insertions(+), 127 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index fe48d7f..08609f3 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,113 +1,113 @@ -BitMathTest:testFuzz_LSB(uint256) (runs: 65541, μ: 17626, ~: 17625) -BitMathTest:testFuzz_MSB(uint256) (runs: 65541, μ: 17649, ~: 17643) +BitMathTest:testFuzz_LSB(uint256) (runs: 65546, μ: 17626, ~: 17625) +BitMathTest:testFuzz_MSB(uint256) (runs: 65546, μ: 17649, ~: 17643) BitMathTest:testGas_LSB() (gas: 239714) BitMathTest:testGas_LSB_Og() (gas: 305805) BitMathTest:testGas_MSB() (gas: 255269) BitMathTest:testGas_MSB_Og() (gas: 288889) -FullMathTest:testFuzz_MulDivQ128(uint256,uint256) (runs: 65539, μ: 4047, ~: 3965) -FullMathTest:testFuzz_MulDivQ96(uint256,uint256) (runs: 65539, μ: 4022, ~: 3950) -FullMathTest:testFuzz_MulDivUp_OZ(uint256,uint256,uint256) (runs: 65539, μ: 4945, ~: 4743) -FullMathTest:testFuzz_MulDivUp_Og(uint256,uint256,uint256) (runs: 65539, μ: 10032, ~: 9829) -FullMathTest:testFuzz_MulDiv_OZ(uint256,uint256,uint256) (runs: 65539, μ: 4209, ~: 4075) -FullMathTest:testFuzz_MulDiv_Og(uint256,uint256,uint256) (runs: 65539, μ: 9568, ~: 9435) -FullMathTest:testFuzz_Sqrt(uint256) (runs: 65541, μ: 4411, ~: 4411) -LiquidityAmountsTest:testFuzz_GetAmount0ForLiquidity(uint160,uint160,uint128) (runs: 65541, μ: 20520, ~: 20778) -LiquidityAmountsTest:testFuzz_GetAmount1ForLiquidity(uint160,uint160,uint128) (runs: 65541, μ: 20073, ~: 20016) -LiquidityAmountsTest:testFuzz_GetAmountsForLiquidity(uint160,uint160,uint160,uint128) (runs: 65541, μ: 23054, ~: 23154) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmount0(uint160,uint160,uint256) (runs: 65541, μ: 20592, ~: 20845) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmount1(uint160,uint160,uint256) (runs: 65541, μ: 20175, ~: 20159) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmounts(uint160,uint160,uint160,uint256,uint256) (runs: 65541, μ: 22572, ~: 22643) +FullMathTest:testFuzz_MulDivQ128(uint256,uint256) (runs: 65544, μ: 4048, ~: 3965) +FullMathTest:testFuzz_MulDivQ96(uint256,uint256) (runs: 65544, μ: 4022, ~: 3950) +FullMathTest:testFuzz_MulDivUp_OZ(uint256,uint256,uint256) (runs: 65544, μ: 4944, ~: 4743) +FullMathTest:testFuzz_MulDivUp_Og(uint256,uint256,uint256) (runs: 65544, μ: 10031, ~: 9829) +FullMathTest:testFuzz_MulDiv_OZ(uint256,uint256,uint256) (runs: 65544, μ: 4209, ~: 4075) +FullMathTest:testFuzz_MulDiv_Og(uint256,uint256,uint256) (runs: 65544, μ: 9567, ~: 9435) +FullMathTest:testFuzz_Sqrt(uint256) (runs: 65546, μ: 4411, ~: 4411) +LiquidityAmountsTest:testFuzz_GetAmount0ForLiquidity(uint160,uint160,uint128) (runs: 65546, μ: 20519, ~: 20778) +LiquidityAmountsTest:testFuzz_GetAmount1ForLiquidity(uint160,uint160,uint128) (runs: 65546, μ: 20073, ~: 20016) +LiquidityAmountsTest:testFuzz_GetAmountsForLiquidity(uint160,uint160,uint160,uint128) (runs: 65546, μ: 23054, ~: 23154) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmount0(uint160,uint160,uint256) (runs: 65546, μ: 20601, ~: 20853) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmount1(uint160,uint160,uint256) (runs: 65546, μ: 20184, ~: 20167) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmounts(uint160,uint160,uint160,uint256,uint256) (runs: 65546, μ: 22571, ~: 22643) LiquidityAmountsTest:testGas_GetAmountsForLiquidity() (gas: 261590) LiquidityAmountsTest:testGas_GetAmountsForLiquidity_Og() (gas: 243788) LiquidityAmountsTest:testGas_GetLiquidityForAmounts() (gas: 264457) LiquidityAmountsTest:testGas_GetLiquidityForAmounts_Og() (gas: 280733) -LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65541, μ: 11968, ~: 14772) +LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65546, μ: 11954, ~: 14751) LiquidityMathTest:testGas_AddDelta() (gas: 139593) LiquidityMathTest:testGas_AddDelta_Og() (gas: 137264) LiquidityMathTest:testRevert_LA() (gas: 8858) LiquidityMathTest:testRevert_LS() (gas: 8846) -NPMCallerPCSTest:testFuzz_BalanceOf(address) (runs: 21, μ: 17700, ~: 17700) -NPMCallerPCSTest:testFuzz_GetApproved(uint256) (runs: 21, μ: 23183, ~: 23225) -NPMCallerPCSTest:testFuzz_IsApprovedForAll(uint256) (runs: 21, μ: 30724, ~: 19570) -NPMCallerPCSTest:testFuzz_OwnerOf(uint256) (runs: 21, μ: 24181, ~: 23905) -NPMCallerPCSTest:testFuzz_Positions(uint256) (runs: 21, μ: 30874, ~: 28027) -NPMCallerPCSTest:testFuzz_PositionsFull(uint256) (runs: 21, μ: 31203, ~: 28338) -NPMCallerPCSTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 21, μ: 21395, ~: 16548) +NPMCallerPCSTest:testFuzz_BalanceOf(address) (runs: 26, μ: 17700, ~: 17700) +NPMCallerPCSTest:testFuzz_GetApproved(uint256) (runs: 26, μ: 23203, ~: 23225) +NPMCallerPCSTest:testFuzz_IsApprovedForAll(uint256) (runs: 26, μ: 30835, ~: 19549) +NPMCallerPCSTest:testFuzz_OwnerOf(uint256) (runs: 26, μ: 24204, ~: 23905) +NPMCallerPCSTest:testFuzz_Positions(uint256) (runs: 26, μ: 30905, ~: 28006) +NPMCallerPCSTest:testFuzz_PositionsFull(uint256) (runs: 26, μ: 31245, ~: 28317) +NPMCallerPCSTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 26, μ: 21809, ~: 16527) NPMCallerPCSTest:testRevert_GetApproved() (gas: 13940) NPMCallerPCSTest:testRevert_OwnerOf() (gas: 14230) -NPMCallerPCSTest:testRevert_Positions() (gas: 24310) -NPMCallerPCSTest:test_Approve() (gas: 129477) -NPMCallerPCSTest:test_Burn() (gas: 1059108) -NPMCallerPCSTest:test_Collect() (gas: 1001971) -NPMCallerPCSTest:test_DecreaseLiquidity() (gas: 921869) -NPMCallerPCSTest:test_Factory() (gas: 14733) -NPMCallerPCSTest:test_IncreaseLiquidity() (gas: 1242174) +NPMCallerPCSTest:testRevert_Positions() (gas: 24315) +NPMCallerPCSTest:test_Approve() (gas: 129472) +NPMCallerPCSTest:test_Burn() (gas: 1059122) +NPMCallerPCSTest:test_Collect() (gas: 1001985) +NPMCallerPCSTest:test_DecreaseLiquidity() (gas: 921883) +NPMCallerPCSTest:test_Factory() (gas: 14728) +NPMCallerPCSTest:test_IncreaseLiquidity() (gas: 1242186) NPMCallerPCSTest:test_IsApprovedForAll() (gas: 26548) -NPMCallerPCSTest:test_Mint() (gas: 731515) -NPMCallerPCSTest:test_Permit() (gas: 820018) +NPMCallerPCSTest:test_Mint() (gas: 731510) +NPMCallerPCSTest:test_Permit() (gas: 820007) NPMCallerPCSTest:test_SetApprovalForAll() (gas: 61346) NPMCallerPCSTest:test_TotalSupply() (gas: 16574) -NPMCallerTest:testFuzz_BalanceOf(address) (runs: 21, μ: 17726, ~: 17726) -NPMCallerTest:testFuzz_GetApproved(uint256) (runs: 21, μ: 24010, ~: 24213) -NPMCallerTest:testFuzz_IsApprovedForAll(uint256) (runs: 21, μ: 79108, ~: 79311) -NPMCallerTest:testFuzz_OwnerOf(uint256) (runs: 21, μ: 26313, ~: 26516) -NPMCallerTest:testFuzz_Positions(uint256) (runs: 21, μ: 43981, ~: 44184) -NPMCallerTest:testFuzz_PositionsFull(uint256) (runs: 21, μ: 44383, ~: 44586) -NPMCallerTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 21, μ: 114170, ~: 40070) +NPMCallerTest:testFuzz_BalanceOf(address) (runs: 26, μ: 17726, ~: 17726) +NPMCallerTest:testFuzz_GetApproved(uint256) (runs: 26, μ: 24018, ~: 24208) +NPMCallerTest:testFuzz_IsApprovedForAll(uint256) (runs: 26, μ: 79121, ~: 79311) +NPMCallerTest:testFuzz_OwnerOf(uint256) (runs: 26, μ: 26321, ~: 26511) +NPMCallerTest:testFuzz_Positions(uint256) (runs: 26, μ: 43987, ~: 44177) +NPMCallerTest:testFuzz_PositionsFull(uint256) (runs: 26, μ: 44450, ~: 44640) +NPMCallerTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 26, μ: 94305, ~: 42884) NPMCallerTest:testRevert_GetApproved() (gas: 13940) NPMCallerTest:testRevert_OwnerOf() (gas: 14207) -NPMCallerTest:testRevert_Positions() (gas: 24310) -NPMCallerTest:test_Approve() (gas: 129466) -NPMCallerTest:test_Burn() (gas: 955410) -NPMCallerTest:test_Collect() (gas: 898267) -NPMCallerTest:test_DecreaseLiquidity() (gas: 818137) -NPMCallerTest:test_Factory() (gas: 14733) -NPMCallerTest:test_IncreaseLiquidity() (gas: 1116310) +NPMCallerTest:testRevert_Positions() (gas: 24315) +NPMCallerTest:test_Approve() (gas: 129461) +NPMCallerTest:test_Burn() (gas: 955424) +NPMCallerTest:test_Collect() (gas: 898281) +NPMCallerTest:test_DecreaseLiquidity() (gas: 818151) +NPMCallerTest:test_Factory() (gas: 14728) +NPMCallerTest:test_IncreaseLiquidity() (gas: 1116322) NPMCallerTest:test_IsApprovedForAll() (gas: 26525) -NPMCallerTest:test_Mint() (gas: 607783) -NPMCallerTest:test_Permit() (gas: 696349) +NPMCallerTest:test_Mint() (gas: 607778) +NPMCallerTest:test_Permit() (gas: 696338) NPMCallerTest:test_SetApprovalForAll() (gas: 61346) NPMCallerTest:test_TotalSupply() (gas: 16585) -PoolAddressPCSTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65541, μ: 20454, ~: 20459) -PoolAddressPCSTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65541, μ: 15645, ~: 15650) -PoolAddressPCSTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65541, μ: 22208, ~: 22213) -PoolAddressPCSTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65541, μ: 17374, ~: 17379) -PoolAddressPCSTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65541, μ: 15993, ~: 15998) +PoolAddressPCSTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65546, μ: 20454, ~: 20459) +PoolAddressPCSTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65546, μ: 15689, ~: 15694) +PoolAddressPCSTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65546, μ: 22208, ~: 22213) +PoolAddressPCSTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65546, μ: 17369, ~: 17374) +PoolAddressPCSTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65546, μ: 16038, ~: 16043) PoolAddressPCSTest:testGas_ComputeAddress() (gas: 12229) PoolAddressPCSTest:testGas_ComputeAddress_Og() (gas: 12774) -PoolAddressTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65541, μ: 20454, ~: 20459) -PoolAddressTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65541, μ: 15645, ~: 15650) -PoolAddressTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65541, μ: 22208, ~: 22213) -PoolAddressTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65541, μ: 17374, ~: 17379) -PoolAddressTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65541, μ: 15993, ~: 15998) +PoolAddressTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65546, μ: 20454, ~: 20459) +PoolAddressTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65546, μ: 15689, ~: 15694) +PoolAddressTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65546, μ: 22208, ~: 22213) +PoolAddressTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65546, μ: 17369, ~: 17374) +PoolAddressTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65546, μ: 16038, ~: 16043) PoolAddressTest:testGas_ComputeAddress() (gas: 12229) PoolAddressTest:testGas_ComputeAddress_Og() (gas: 12774) -PoolCallerPCSTest:testFuzz_LiquidityNet(int24) (runs: 21, μ: 22049, ~: 22049) -PoolCallerPCSTest:testFuzz_Observations(uint256) (runs: 6, μ: 278, ~: 278) -PoolCallerPCSTest:testFuzz_Positions(bytes32) (runs: 21, μ: 24545, ~: 24545) -PoolCallerPCSTest:testFuzz_Swap(bool,uint256,bytes) (runs: 21, μ: 409893, ~: 383922) -PoolCallerPCSTest:testFuzz_TickBitmap(int16) (runs: 21, μ: 14017, ~: 14017) -PoolCallerPCSTest:testFuzz_Ticks(int24) (runs: 21, μ: 27808, ~: 27808) -PoolCallerPCSTest:testRevert_AS_Swap() (gas: 35364) -PoolCallerPCSTest:testRevert_SPL_Swap() (gas: 40085) +PoolCallerPCSTest:testFuzz_LiquidityNet(int24) (runs: 26, μ: 22056, ~: 22056) +PoolCallerPCSTest:testFuzz_Observations(uint256) (runs: 11, μ: 278, ~: 278) +PoolCallerPCSTest:testFuzz_Positions(bytes32) (runs: 26, μ: 24548, ~: 24548) +PoolCallerPCSTest:testFuzz_Swap(bool,uint256,bytes) (runs: 26, μ: 419230, ~: 399315) +PoolCallerPCSTest:testFuzz_TickBitmap(int16) (runs: 26, μ: 14017, ~: 14017) +PoolCallerPCSTest:testFuzz_Ticks(int24) (runs: 26, μ: 27815, ~: 27815) +PoolCallerPCSTest:testRevert_AS_Swap() (gas: 35335) +PoolCallerPCSTest:testRevert_SPL_Swap() (gas: 40056) PoolCallerPCSTest:test_Fee() (gas: 11396) PoolCallerPCSTest:test_FeeGrowthGlobal0X128() (gas: 13539) PoolCallerPCSTest:test_FeeGrowthGlobal1X128() (gas: 13541) PoolCallerPCSTest:test_Liquidity() (gas: 13720) -PoolCallerPCSTest:test_LiquidityNet() (gas: 28041) +PoolCallerPCSTest:test_LiquidityNet() (gas: 28048) PoolCallerPCSTest:test_ProtocolFees() (gas: 14768) PoolCallerPCSTest:test_Slot0() (gas: 20497) PoolCallerPCSTest:test_SqrtPriceX96AndTick() (gas: 16086) -PoolCallerPCSTest:test_Swap() (gas: 476655) +PoolCallerPCSTest:test_Swap() (gas: 476634) PoolCallerPCSTest:test_TickSpacing() (gas: 11445) -PoolCallerTest:testFuzz_LiquidityNet(int24) (runs: 21, μ: 22023, ~: 22023) -PoolCallerTest:testFuzz_Observations(uint256) (runs: 21, μ: 24383, ~: 24514) -PoolCallerTest:testFuzz_Positions(bytes32) (runs: 21, μ: 24560, ~: 24560) -PoolCallerTest:testFuzz_Swap(bool,uint256,bytes) (runs: 21, μ: 352923, ~: 364543) -PoolCallerTest:testFuzz_TickBitmap(int16) (runs: 21, μ: 14032, ~: 14032) -PoolCallerTest:testFuzz_Ticks(int24) (runs: 21, μ: 27782, ~: 27782) -PoolCallerTest:testRevert_AS_Swap() (gas: 35416) -PoolCallerTest:testRevert_SPL_Swap() (gas: 38054) +PoolCallerTest:testFuzz_LiquidityNet(int24) (runs: 26, μ: 22023, ~: 22023) +PoolCallerTest:testFuzz_Observations(uint256) (runs: 26, μ: 24376, ~: 24509) +PoolCallerTest:testFuzz_Positions(bytes32) (runs: 26, μ: 24563, ~: 24563) +PoolCallerTest:testFuzz_Swap(bool,uint256,bytes) (runs: 26, μ: 351284, ~: 352732) +PoolCallerTest:testFuzz_TickBitmap(int16) (runs: 26, μ: 14032, ~: 14032) +PoolCallerTest:testFuzz_Ticks(int24) (runs: 26, μ: 27782, ~: 27782) +PoolCallerTest:testRevert_AS_Swap() (gas: 35387) +PoolCallerTest:testRevert_SPL_Swap() (gas: 38025) PoolCallerTest:test_Fee() (gas: 11396) PoolCallerTest:test_FeeGrowthGlobal0X128() (gas: 13539) PoolCallerTest:test_FeeGrowthGlobal1X128() (gas: 13585) @@ -116,27 +116,27 @@ PoolCallerTest:test_LiquidityNet() (gas: 25830) PoolCallerTest:test_ProtocolFees() (gas: 14768) PoolCallerTest:test_Slot0() (gas: 19717) PoolCallerTest:test_SqrtPriceX96AndTick() (gas: 13653) -PoolCallerTest:test_Swap() (gas: 425347) +PoolCallerTest:test_Swap() (gas: 425326) PoolCallerTest:test_TickSpacing() (gas: 11445) SafeCastTest:testRevert_ToInt128() (gas: 3099) SafeCastTest:testRevert_ToInt256() (gas: 3101) SafeCastTest:testRevert_ToUint128() (gas: 3121) SafeCastTest:testRevert_ToUint160() (gas: 3077) SafeCastTest:testToInt128() (gas: 3166) -SafeCastTest:testToInt128(int256) (runs: 65541, μ: 3328, ~: 3360) -SafeCastTest:testToInt128(uint256) (runs: 65541, μ: 3231, ~: 3257) +SafeCastTest:testToInt128(int256) (runs: 65546, μ: 3328, ~: 3360) +SafeCastTest:testToInt128(uint256) (runs: 65546, μ: 3231, ~: 3257) SafeCastTest:testToInt256() (gas: 3160) -SafeCastTest:testToInt256(uint256) (runs: 65541, μ: 3266, ~: 3270) -SafeCastTest:testToUint128(uint256) (runs: 65541, μ: 3229, ~: 3255) -SafeCastTest:testToUint160(uint256) (runs: 65541, μ: 3258, ~: 3278) -SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65541, μ: 15641, ~: 15557) -SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,uint128,bool) (runs: 65541, μ: 15744, ~: 15660) -SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,int128) (runs: 65541, μ: 15239, ~: 15183) -SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,uint128,bool) (runs: 65541, μ: 15386, ~: 15432) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65541, μ: 19141, ~: 18742) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65541, μ: 21231, ~: 21304) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65541, μ: 15572, ~: 15506) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65541, μ: 15383, ~: 14913) +SafeCastTest:testToInt256(uint256) (runs: 65546, μ: 3266, ~: 3270) +SafeCastTest:testToUint128(uint256) (runs: 65546, μ: 3229, ~: 3255) +SafeCastTest:testToUint160(uint256) (runs: 65546, μ: 3258, ~: 3278) +SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65546, μ: 15641, ~: 15557) +SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,uint128,bool) (runs: 65546, μ: 15743, ~: 15660) +SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,int128) (runs: 65546, μ: 15239, ~: 15183) +SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,uint128,bool) (runs: 65546, μ: 15386, ~: 15432) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65546, μ: 19140, ~: 18742) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65546, μ: 21230, ~: 21304) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65546, μ: 15572, ~: 15506) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65546, μ: 15385, ~: 14913) SqrtPriceMathTest:testGas_GetAmount0Delta() (gas: 322902) SqrtPriceMathTest:testGas_GetAmount0Delta_Og() (gas: 318258) SqrtPriceMathTest:testGas_GetAmount1Delta() (gas: 281567) @@ -145,41 +145,45 @@ SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput() (gas: 303816) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput_Og() (gas: 285701) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput() (gas: 286028) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput_Og() (gas: 269021) -SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65541, μ: 27024, ~: 27110) -SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65541, μ: 29076, ~: 29027) -SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65541, μ: 28603, ~: 28507) -SwapMathTest:testFuzz_getSqrtPriceTarget(bool,uint160,uint160) (runs: 65541, μ: 3503, ~: 3503) +SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65546, μ: 27026, ~: 27110) +SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 29080, ~: 29027) +SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 28605, ~: 28507) +SwapMathTest:testFuzz_getSqrtPriceTarget(bool,uint160,uint160) (runs: 65546, μ: 3503, ~: 3503) SwapMathTest:testGas_ComputeSwapStep() (gas: 514452) SwapMathTest:testGas_ComputeSwapStepExactIn() (gas: 534678) SwapMathTest:testGas_ComputeSwapStepExactIn_Og() (gas: 563266) SwapMathTest:testGas_ComputeSwapStepExactOut() (gas: 482433) SwapMathTest:testGas_ComputeSwapStepExactOut_Og() (gas: 557512) SwapMathTest:testGas_ComputeSwapStep_Og() (gas: 577793) -TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65541, μ: 9445, ~: 9545) -TickBitmapPCSTest:testFuzz_FlipTick(int24) (runs: 65541, μ: 111941, ~: 112231) -TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65541, μ: 112848, ~: 112796) -TickBitmapPCSTest:testFuzz_Position(int24) (runs: 65541, μ: 3856, ~: 3856) -TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord() (gas: 12546976) -TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635559) +TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65546, μ: 9279, ~: 9380) +TickBitmapPCSTest:testFuzz_FlipTick(int24) (runs: 65546, μ: 111721, ~: 112007) +TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65546, μ: 65305, ~: 65238) +TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65546, μ: 112965, ~: 112913) +TickBitmapPCSTest:testFuzz_Position(int24) (runs: 65546, μ: 3859, ~: 3859) +TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord() (gas: 12603786) +TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635537) TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_GT() (gas: 108376) TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 108883) -TickBitmapPCSTest:test_NextInitializedTick_GT() (gas: 119576) +TickBitmapPCSTest:test_NextInitializedTick_GT() (gas: 119621) TickBitmapPCSTest:test_NextInitializedTick_LTE() (gas: 124247) -TickBitmapTest:testFuzz_Compress(int24,int24) (runs: 65541, μ: 9445, ~: 9545) -TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65541, μ: 111943, ~: 112231) -TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65541, μ: 112846, ~: 112796) -TickBitmapTest:testFuzz_Position(int24) (runs: 65541, μ: 3856, ~: 3856) -TickBitmapTest:testGas_NextInitializedTickWithinOneWord() (gas: 12546976) -TickBitmapTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635559) +TickBitmapTest:testFuzz_Compress(int24,int24) (runs: 65546, μ: 9279, ~: 9380) +TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65546, μ: 111721, ~: 112007) +TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65546, μ: 65305, ~: 65238) +TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65546, μ: 112965, ~: 112913) +TickBitmapTest:testFuzz_Position(int24) (runs: 65546, μ: 3859, ~: 3859) +TickBitmapTest:testGas_NextInitializedTickWithinOneWord() (gas: 12603786) +TickBitmapTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635537) TickBitmapTest:test_NextInitializedTickWithinOneWord_GT() (gas: 286334) TickBitmapTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 299879) -TickBitmapTest:test_NextInitializedTick_GT() (gas: 491345) +TickBitmapTest:test_NextInitializedTick_GT() (gas: 491390) TickBitmapTest:test_NextInitializedTick_LTE() (gas: 610898) -TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65541, μ: 18039, ~: 17876) -TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65541, μ: 16579, ~: 16593) +TickMathTest:testFuzzRevert_GetSqrtRatioAtTick(int24) (runs: 65546, μ: 14697, ~: 14839) +TickMathTest:testFuzzRevert_GetTickAtSqrtRatio(uint160,bool) (runs: 65546, μ: 12915, ~: 13070) +TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65546, μ: 18006, ~: 17843) +TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65546, μ: 16576, ~: 16588) TickMathTest:testGas_GetSqrtRatioAtTick() (gas: 173514) -TickMathTest:testGas_GetSqrtRatioAtTick_Og() (gas: 180351) +TickMathTest:testGas_GetSqrtRatioAtTick_Og() (gas: 180373) TickMathTest:testGas_GetTickAtSqrtRatio() (gas: 282569) -TickMathTest:testGas_GetTickAtSqrtRatio_Og() (gas: 317582) +TickMathTest:testGas_GetTickAtSqrtRatio_Og() (gas: 317560) TickMathTest:testRevert_GetSqrtRatioAtTick() (gas: 11527) -TickMathTest:testRevert_GetTickAtSqrtRatio() (gas: 11267) \ No newline at end of file +TickMathTest:testRevert_GetTickAtSqrtRatio() (gas: 11262) \ No newline at end of file diff --git a/test/TickBitmap.t.sol b/test/TickBitmap.t.sol index 1cc7539..1e3a888 100644 --- a/test/TickBitmap.t.sol +++ b/test/TickBitmap.t.sol @@ -11,20 +11,39 @@ contract TickBitmapWrapper is ITickBitmap { mapping(int16 => uint256) public bitmap; function flipTick(int24 tick) external { - bitmap.flipTick(tick, 1); + flipTick(tick, 1); + } + + function flipTick(int24 tick, int24 tickSpacing) public { + bitmap.flipTick(tick, tickSpacing); } function nextInitializedTickWithinOneWord( int24 tick, bool lte ) external view returns (int24 next, bool initialized) { - return bitmap.nextInitializedTickWithinOneWord(tick, 1, lte); + return nextInitializedTickWithinOneWord(tick, 1, lte); + } + + function nextInitializedTickWithinOneWord( + int24 tick, + int24 tickSpacing, + bool lte + ) public view returns (int24 next, bool initialized) { + return bitmap.nextInitializedTickWithinOneWord(tick, tickSpacing, lte); + } + + function isInitialized(int24 tick, int24 tickSpacing) public view returns (bool) { + unchecked { + if (tick % tickSpacing != 0) return false; + (int16 wordPos, uint8 bitPos) = TickBitmap.position(tick / tickSpacing); + return bitmap[wordPos] & (1 << bitPos) != 0; + } } // returns whether the given tick is initialized - function isInitialized(int24 tick) external view returns (bool) { - (int24 next, bool initialized) = bitmap.nextInitializedTickWithinOneWord(tick, 1, true); - return next == tick ? initialized : false; + function isInitialized(int24 tick) public view returns (bool) { + return isInitialized(tick, 1); } } @@ -40,19 +59,13 @@ contract TickBitmapTest is BaseTest { } function testFuzz_Position(int24 tick) public pure { - int16 wordPos; - uint8 bitPos; - assembly { - // signed arithmetic shift right - wordPos := sar(8, tick) - bitPos := and(tick, 255) - } - assertEq(int256(wordPos), tick >> 8); + (int16 wordPos, uint8 bitPos) = TickBitmap.position(tick); + assertEq(wordPos, tick >> 8); assertEq(bitPos, uint8(int8(tick % 256))); } function testFuzz_Compress(int24 tick, int24 _tickSpacing) public pure { - _tickSpacing = int24(bound(_tickSpacing, 1, 200)); + _tickSpacing = int24(bound(_tickSpacing, 1, type(int24).max)); int24 compressed = tick / _tickSpacing; if (tick < 0 && tick % _tickSpacing != 0) compressed--; assertEq(TickBitmap.compress(tick, _tickSpacing), compressed); @@ -65,6 +78,31 @@ contract TickBitmapTest is BaseTest { assertEq(wrapper.isInitialized(tick), ogWrapper.isInitialized(tick)); } + function testFuzz_NextInitializedTickWithinOneWord( + int24 tick, + int24 tickSpacing, + uint8 nextBitPos, + bool lte + ) public { + tick = int24(bound(tick, TickMath.MIN_TICK, TickMath.MAX_TICK)); + tickSpacing = int24(bound(tickSpacing, 1, type(int16).max)); + int24 compressed = TickBitmap.compress(tick, tickSpacing); + if (!lte) ++compressed; + (int16 wordPos, uint8 bitPos) = TickBitmap.position(compressed); + + if (lte) { + nextBitPos = uint8(bound(nextBitPos, 0, bitPos)); + } else { + nextBitPos = uint8(bound(nextBitPos, bitPos, 255)); + } + // Choose the next initialized tick within one word at random and flip it. + int24 nextInitializedTick = ((int24(wordPos) << 8) + int24(uint24(nextBitPos))) * tickSpacing; + wrapper.flipTick(nextInitializedTick, tickSpacing); + (int24 next, bool initialized) = wrapper.nextInitializedTickWithinOneWord(tick, tickSpacing, lte); + assertEq(initialized, true); + assertEq(next, nextInitializedTick); + } + function testFuzz_NextInitializedTickWithinOneWord(int24 tick, uint8 nextBitPos, bool lte) public { tick = int24(bound(tick, TickMath.MIN_TICK, TickMath.MAX_TICK)); int24 compressed = lte ? tick : tick + 1; diff --git a/test/TickMath.t.sol b/test/TickMath.t.sol index 17e5320..798ce1c 100644 --- a/test/TickMath.t.sol +++ b/test/TickMath.t.sol @@ -48,6 +48,16 @@ contract TickMathTest is Test { wrapper.getSqrtRatioAtTick(TickMath.MAX_TICK + 1); } + function testFuzzRevert_GetSqrtRatioAtTick(int24 tick) public { + if (tick > 0) { + tick = int24(bound(tick, TickMath.MAX_TICK + 1, type(int24).max)); + } else { + tick = int24(bound(tick, type(int24).min, TickMath.MIN_TICK - 1)); + } + vm.expectRevert(bytes("T")); + wrapper.getSqrtRatioAtTick(tick); + } + /// @notice Test the equivalence of the original and new `getSqrtRatioAtTick` function testFuzz_GetSqrtRatioAtTick(int24 tick) public view { tick = int24(bound(tick, TickMath.MIN_TICK, TickMath.MAX_TICK)); @@ -81,6 +91,16 @@ contract TickMathTest is Test { wrapper.getTickAtSqrtRatio(TickMath.MAX_SQRT_RATIO); } + function testFuzzRevert_GetTickAtSqrtRatio(uint160 sqrtPriceX96, bool gte) public { + if (gte) { + sqrtPriceX96 = uint160(bound(sqrtPriceX96, TickMath.MAX_SQRT_RATIO, type(uint160).max)); + } else { + sqrtPriceX96 = uint160(bound(sqrtPriceX96, 0, TickMath.MIN_SQRT_RATIO - 1)); + } + vm.expectRevert(bytes("R")); + wrapper.getTickAtSqrtRatio(sqrtPriceX96); + } + /// @notice Test the equivalence of `getTickAtSqrtRatio` and the original library function testFuzz_GetTickAtSqrtRatio(uint160 sqrtPriceX96) public view { sqrtPriceX96 = uint160(bound(sqrtPriceX96, TickMath.MIN_SQRT_RATIO, TickMath.MAX_SQRT_RATIO - 1)); From e096d9943f163e39fdfd4dfb96c49ead9eb36dcd Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Sun, 26 May 2024 03:59:29 -0400 Subject: [PATCH 09/13] Update bit mask calculation in TickBitmap module The calculation method for the bit mask in the TickBitmap module has been changed. The new calculation approach "(2 << bitPos) - 1" replaces the previous "(1 << (bitPos + 1)) - 1" resulting in better efficiency and clarity. The changes are reflected throughout the TickBitmap module ensuring that all functions using this calculation are now updated. --- .gas-snapshot | 24 ++++++++++++------------ src/TickBitmap.sol | 18 +++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 08609f3..e5c03db 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -155,28 +155,28 @@ SwapMathTest:testGas_ComputeSwapStepExactIn_Og() (gas: 563266) SwapMathTest:testGas_ComputeSwapStepExactOut() (gas: 482433) SwapMathTest:testGas_ComputeSwapStepExactOut_Og() (gas: 557512) SwapMathTest:testGas_ComputeSwapStep_Og() (gas: 577793) -TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65546, μ: 9279, ~: 9380) +TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65546, μ: 9280, ~: 9380) TickBitmapPCSTest:testFuzz_FlipTick(int24) (runs: 65546, μ: 111721, ~: 112007) -TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65546, μ: 65305, ~: 65238) -TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65546, μ: 112965, ~: 112913) +TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65546, μ: 65299, ~: 65226) +TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65546, μ: 112957, ~: 112901) TickBitmapPCSTest:testFuzz_Position(int24) (runs: 65546, μ: 3859, ~: 3859) -TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord() (gas: 12603786) +TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord() (gas: 12597642) TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635537) TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_GT() (gas: 108376) -TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 108883) +TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 108823) TickBitmapPCSTest:test_NextInitializedTick_GT() (gas: 119621) -TickBitmapPCSTest:test_NextInitializedTick_LTE() (gas: 124247) +TickBitmapPCSTest:test_NextInitializedTick_LTE() (gas: 124127) TickBitmapTest:testFuzz_Compress(int24,int24) (runs: 65546, μ: 9279, ~: 9380) -TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65546, μ: 111721, ~: 112007) -TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65546, μ: 65305, ~: 65238) -TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65546, μ: 112965, ~: 112913) +TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65546, μ: 111722, ~: 112007) +TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65546, μ: 65299, ~: 65226) +TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65546, μ: 112959, ~: 112901) TickBitmapTest:testFuzz_Position(int24) (runs: 65546, μ: 3859, ~: 3859) -TickBitmapTest:testGas_NextInitializedTickWithinOneWord() (gas: 12603786) +TickBitmapTest:testGas_NextInitializedTickWithinOneWord() (gas: 12597642) TickBitmapTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635537) TickBitmapTest:test_NextInitializedTickWithinOneWord_GT() (gas: 286334) -TickBitmapTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 299879) +TickBitmapTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 298343) TickBitmapTest:test_NextInitializedTick_GT() (gas: 491390) -TickBitmapTest:test_NextInitializedTick_LTE() (gas: 610898) +TickBitmapTest:test_NextInitializedTick_LTE() (gas: 607826) TickMathTest:testFuzzRevert_GetSqrtRatioAtTick(int24) (runs: 65546, μ: 14697, ~: 14839) TickMathTest:testFuzzRevert_GetTickAtSqrtRatio(uint160,bool) (runs: 65546, μ: 12915, ~: 13070) TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65546, μ: 18006, ~: 17843) diff --git a/src/TickBitmap.sol b/src/TickBitmap.sol index cb34567..b56da0a 100644 --- a/src/TickBitmap.sol +++ b/src/TickBitmap.sol @@ -80,9 +80,9 @@ library TickBitmap { // all the 1s at or to the right of the current bitPos uint256 masked; assembly ("memory-safe") { - // mask = (1 << (bitPos + 1)) - 1 - // (bitPos + 1) may overflow but fine since 1 << 256 = 0 - let mask := sub(shl(add(bitPos, 1), 1), 1) + // mask = (1 << (bitPos + 1)) - 1 = (2 << bitPos) - 1 + // (2 << bitPos) may overflow but fine since 2 << 255 = 0 + let mask := sub(shl(bitPos, 2), 1) // masked = self[wordPos] & mask mstore(0, wordPos) mstore(0x20, self.slot) @@ -162,9 +162,9 @@ library TickBitmap { // Reuse the same word if the position doesn't change tickWord = wordPos == lastWordPos ? lastWord : pool.tickBitmap(wordPos); assembly { - // mask = (1 << (bitPos + 1)) - 1 - // (bitPos + 1) may overflow but fine since 1 << 256 = 0 - let mask := sub(shl(add(bitPos, 1), 1), 1) + // mask = (1 << (bitPos + 1)) - 1 = (2 << bitPos) - 1 + // (2 << bitPos) may overflow but fine since 2 << 255 = 0 + let mask := sub(shl(bitPos, 2), 1) // all the 1s at or to the right of the current bitPos masked := and(tickWord, mask) } @@ -242,9 +242,9 @@ library TickBitmap { // Reuse the same word if the position doesn't change tickWord = wordPos == lastWordPos ? lastWord : pool.tickBitmap(wordPos); assembly { - // mask = (1 << (bitPos + 1)) - 1 - // (bitPos + 1) may overflow but fine since 1 << 256 = 0 - let mask := sub(shl(add(bitPos, 1), 1), 1) + // mask = (1 << (bitPos + 1)) - 1 = (2 << bitPos) - 1 + // (2 << bitPos) may overflow but fine since 2 << 255 = 0 + let mask := sub(shl(bitPos, 2), 1) // all the 1s at or to the right of the current bitPos masked := and(tickWord, mask) } From 42595cb45d62da75caccace4948efddeb765678b Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Sun, 26 May 2024 04:43:22 -0400 Subject: [PATCH 10/13] Refactor SqrtPriceMath.sol to improve variable naming This commit improves readability with clearer variable naming and avoids implicit upcasting in SqrtPriceMath.sol. We have replaced certain variable names for better understanding of the operations being carried out. This includes replacing `liquidity256` with `_liquidity`, and `sign` with `roundUp`. The commit also replaces `amount >> 160 == 0` check for overflow with `amount <= type(uint160).max`. --- .gas-snapshot | 18 ++++++------ src/SqrtPriceMath.sol | 65 ++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index e5c03db..b235d4a 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -129,27 +129,27 @@ SafeCastTest:testToInt256() (gas: 3160) SafeCastTest:testToInt256(uint256) (runs: 65546, μ: 3266, ~: 3270) SafeCastTest:testToUint128(uint256) (runs: 65546, μ: 3229, ~: 3255) SafeCastTest:testToUint160(uint256) (runs: 65546, μ: 3258, ~: 3278) -SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65546, μ: 15641, ~: 15557) +SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65546, μ: 15642, ~: 15557) SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,uint128,bool) (runs: 65546, μ: 15743, ~: 15660) SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,int128) (runs: 65546, μ: 15239, ~: 15183) SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,uint128,bool) (runs: 65546, μ: 15386, ~: 15432) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65546, μ: 19140, ~: 18742) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65546, μ: 21230, ~: 21304) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65546, μ: 15572, ~: 15506) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65546, μ: 15385, ~: 14913) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65546, μ: 19138, ~: 18732) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65546, μ: 21234, ~: 21310) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65546, μ: 15568, ~: 15496) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65546, μ: 15384, ~: 14916) SqrtPriceMathTest:testGas_GetAmount0Delta() (gas: 322902) SqrtPriceMathTest:testGas_GetAmount0Delta_Og() (gas: 318258) SqrtPriceMathTest:testGas_GetAmount1Delta() (gas: 281567) SqrtPriceMathTest:testGas_GetAmount1Delta_Og() (gas: 306610) -SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput() (gas: 303816) +SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput() (gas: 303466) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput_Og() (gas: 285701) -SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput() (gas: 286028) +SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput() (gas: 286328) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput_Og() (gas: 269021) SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65546, μ: 27026, ~: 27110) -SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 29080, ~: 29027) +SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 29078, ~: 29027) SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 28605, ~: 28507) SwapMathTest:testFuzz_getSqrtPriceTarget(bool,uint160,uint160) (runs: 65546, μ: 3503, ~: 3503) -SwapMathTest:testGas_ComputeSwapStep() (gas: 514452) +SwapMathTest:testGas_ComputeSwapStep() (gas: 514575) SwapMathTest:testGas_ComputeSwapStepExactIn() (gas: 534678) SwapMathTest:testGas_ComputeSwapStepExactIn_Og() (gas: 563266) SwapMathTest:testGas_ComputeSwapStepExactOut() (gas: 482433) diff --git a/src/SqrtPriceMath.sol b/src/SqrtPriceMath.sol index c5cabad..7bbfb09 100644 --- a/src/SqrtPriceMath.sol +++ b/src/SqrtPriceMath.sol @@ -13,7 +13,6 @@ import "./UnsafeMath.sol"; /// @author Modified from Uniswap (https://github.com/uniswap/v3-core/blob/main/contracts/libraries/SqrtPriceMath.sol) /// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas library SqrtPriceMath { - using UnsafeMath for *; using SafeCast for uint256; /// @notice Gets the next sqrt price given a delta of token0 @@ -36,38 +35,39 @@ library SqrtPriceMath { // we short circuit amount == 0 because the result is otherwise not guaranteed to equal the input price if (amount == 0) return sqrtPX96; uint256 numerator1; + uint256 _sqrtPX96; assembly { numerator1 := shl(96, liquidity) + _sqrtPX96 := sqrtPX96 } if (add) { unchecked { - uint256 product = amount * sqrtPX96; + uint256 product = amount * _sqrtPX96; // checks for overflow - if (product.div(amount) == sqrtPX96) { - // denominator = liquidity + amount * sqrtPX96 + if (UnsafeMath.div(product, amount) == _sqrtPX96) { uint256 denominator = numerator1 + product; // checks for overflow - if (denominator >= numerator1) + if (denominator >= numerator1) { // always fits in 160 bits - return uint160(FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator)); + return uint160(FullMath.mulDivRoundingUp(numerator1, _sqrtPX96, denominator)); + } } } - - // liquidity / (liquidity / sqrtPX96 + amount) - return uint160(numerator1.divRoundingUp(numerator1.div(sqrtPX96) + amount)); + // denominator is checked for overflow + return uint160(UnsafeMath.divRoundingUp(numerator1, UnsafeMath.div(numerator1, _sqrtPX96) + amount)); } else { uint256 denominator; assembly ("memory-safe") { // if the product overflows, we know the denominator underflows // in addition, we must check that the denominator does not underflow - let product := mul(amount, sqrtPX96) - if iszero(and(eq(div(product, amount), sqrtPX96), gt(numerator1, product))) { + let product := mul(amount, _sqrtPX96) + if iszero(and(eq(div(product, amount), _sqrtPX96), gt(numerator1, product))) { revert(0, 0) } denominator := sub(numerator1, product) } - return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator).toUint160(); + return FullMath.mulDivRoundingUp(numerator1, _sqrtPX96, denominator).toUint160(); } } @@ -87,25 +87,25 @@ library SqrtPriceMath { uint256 amount, bool add ) internal pure returns (uint160 nextSqrtPrice) { - uint256 liquidity256; + uint256 _liquidity; assembly { - liquidity256 := liquidity + _liquidity := liquidity } // if we're adding (subtracting), rounding down requires rounding the quotient down (up) // in both cases, avoid a mulDiv for most inputs if (add) { uint256 quotient = ( - amount <= type(uint160).max - ? (amount << FixedPoint96.RESOLUTION).div(liquidity256) - : FullMath.mulDiv(amount, FixedPoint96.Q96, liquidity256) + amount >> 160 == 0 + ? UnsafeMath.div((amount << FixedPoint96.RESOLUTION), _liquidity) + : FullMath.mulDiv(amount, FixedPoint96.Q96, _liquidity) ); nextSqrtPrice = (uint256(sqrtPX96) + quotient).toUint160(); } else { uint256 quotient = ( - amount <= type(uint160).max - ? (amount << FixedPoint96.RESOLUTION).divRoundingUp(liquidity256) - : FullMath.mulDivRoundingUp(amount, FixedPoint96.Q96, liquidity256) + amount >> 160 == 0 + ? UnsafeMath.divRoundingUp(amount << FixedPoint96.RESOLUTION, _liquidity) + : FullMath.mulDivRoundingUp(amount, FixedPoint96.Q96, _liquidity) ); assembly ("memory-safe") { if iszero(gt(sqrtPX96, quotient)) { @@ -227,9 +227,10 @@ library SqrtPriceMath { ) internal pure returns (uint256 amount1) { uint256 numerator = TernaryLib.absDiffU160(sqrtRatioAX96, sqrtRatioBX96); uint256 denominator = FixedPoint96.Q96; - uint256 liquidity256; + uint256 _liquidity; assembly { - liquidity256 := liquidity + // avoid implicit upcasting + _liquidity := liquidity } /** * Equivalent to: @@ -238,9 +239,9 @@ library SqrtPriceMath { * : FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96); * Cannot overflow because `type(uint128).max * type(uint160).max >> 96 < (1 << 192)`. */ - amount1 = FullMath.mulDivQ96(liquidity256, numerator); + amount1 = FullMath.mulDivQ96(_liquidity, numerator); assembly { - amount1 := add(amount1, and(gt(mulmod(liquidity256, numerator, denominator), 0), roundUp)) + amount1 := add(amount1, and(gt(mulmod(_liquidity, numerator, denominator), 0), roundUp)) } } @@ -260,19 +261,19 @@ library SqrtPriceMath { * ? -getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256() * : getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256(); */ - bool sign; + bool roundUp; uint256 mask; uint128 liquidityAbs; assembly { // mask = 0 if liquidity >= 0 else -1 mask := sar(255, liquidity) - // sign = 1 if liquidity >= 0 else 0 - sign := iszero(mask) + // roundUp = 1 if liquidity >= 0 else 0 + roundUp := iszero(mask) liquidityAbs := xor(mask, add(mask, liquidity)) } // amount0Abs = liquidity / sqrt(lower) - liquidity / sqrt(upper) < type(uint224).max // always fits in 224 bits, no need for toInt256() - uint256 amount0Abs = getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, liquidityAbs, sign); + uint256 amount0Abs = getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, liquidityAbs, roundUp); assembly { // If liquidity >= 0, amount0 = |amount0| = 0 ^ |amount0| // If liquidity < 0, amount0 = -|amount0| = ~|amount0| + 1 = (-1) ^ |amount0| - (-1) @@ -296,19 +297,19 @@ library SqrtPriceMath { * ? -getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256() * : getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256(); */ - bool sign; + bool roundUp; uint256 mask; uint128 liquidityAbs; assembly { // mask = 0 if liquidity >= 0 else -1 mask := sar(255, liquidity) - // sign = 1 if liquidity >= 0 else 0 - sign := iszero(mask) + // roundUp = 1 if liquidity >= 0 else 0 + roundUp := iszero(mask) liquidityAbs := xor(mask, add(mask, liquidity)) } // amount1Abs = liquidity * (sqrt(upper) - sqrt(lower)) < type(uint192).max // always fits in 192 bits, no need for toInt256() - uint256 amount1Abs = getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, liquidityAbs, sign); + uint256 amount1Abs = getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, liquidityAbs, roundUp); assembly { // If liquidity >= 0, amount1 = |amount1| = 0 ^ |amount1| // If liquidity < 0, amount1 = -|amount1| = ~|amount1| + 1 = (-1) ^ |amount1| - (-1) From 0ae2b2795808b676962a5ba2b42e14834af78b9b Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Sun, 26 May 2024 04:49:50 -0400 Subject: [PATCH 11/13] Refactor TickMath.sol for improved readability The changes center around improving code readability in TickMath.sol. The assembly block has been condensed for simplifying the flow of code. Also added are clarifying inline comments regarding the operations involving 'ratio' and 'sqrtPriceX96' variables. --- src/TickMath.sol | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/TickMath.sol b/src/TickMath.sol index c4d231f..d61d309 100644 --- a/src/TickMath.sol +++ b/src/TickMath.sol @@ -81,17 +81,14 @@ library TickMath { if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; - // if (tick > 0) ratio = type(uint256).max / ratio; assembly { + // if (tick > 0) ratio = type(uint256).max / ratio; if sgt(tick, 0) { ratio := div(not(0), ratio) } - } - - // 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 getTickAtSqrtRatio of the output price is always consistent - assembly { + // 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 getTickAtSqrtRatio of the output price is always consistent sqrtPriceX96 := shr(32, add(ratio, sub(shl(32, 1), 1))) } } From a0d408afaaa1aeb8c655072dfe3efe92e3bb5168 Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Sun, 26 May 2024 23:43:30 -0400 Subject: [PATCH 12/13] Optimize fee pips calculation in SwapMath Refactored the SwapMath module to optimize fee pips calculation. This was achieved by caching the feePips value to prevent redundant typecasts. This reduces computational overhead and may improve performance. --- .gas-snapshot | 10 +++++----- src/SwapMath.sol | 21 ++++++++++++++------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index b235d4a..817380d 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -145,12 +145,12 @@ SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput() (gas: 303466) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput_Og() (gas: 285701) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput() (gas: 286328) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput_Og() (gas: 269021) -SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65546, μ: 27026, ~: 27110) -SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 29078, ~: 29027) -SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 28605, ~: 28507) +SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65546, μ: 27023, ~: 27110) +SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 29070, ~: 29020) +SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 28608, ~: 28507) SwapMathTest:testFuzz_getSqrtPriceTarget(bool,uint160,uint160) (runs: 65546, μ: 3503, ~: 3503) -SwapMathTest:testGas_ComputeSwapStep() (gas: 514575) -SwapMathTest:testGas_ComputeSwapStepExactIn() (gas: 534678) +SwapMathTest:testGas_ComputeSwapStep() (gas: 514269) +SwapMathTest:testGas_ComputeSwapStepExactIn() (gas: 533978) SwapMathTest:testGas_ComputeSwapStepExactIn_Og() (gas: 563266) SwapMathTest:testGas_ComputeSwapStepExactOut() (gas: 482433) SwapMathTest:testGas_ComputeSwapStepExactOut_Og() (gas: 557512) diff --git a/src/SwapMath.sol b/src/SwapMath.sol index 7c9e359..e94d377 100644 --- a/src/SwapMath.sol +++ b/src/SwapMath.sol @@ -52,19 +52,23 @@ library SwapMath { uint24 feePips ) internal pure returns (uint160 sqrtRatioNextX96, uint256 amountIn, uint256 amountOut, uint256 feeAmount) { unchecked { + uint256 _feePips = feePips; // cast once and cache bool zeroForOne = sqrtRatioCurrentX96 >= sqrtRatioTargetX96; - uint256 feeComplement = MAX_FEE_PIPS - feePips; bool exactOut = amountRemaining < 0; if (!exactOut) { - uint256 amountRemainingLessFee = FullMath.mulDiv(uint256(amountRemaining), feeComplement, MAX_FEE_PIPS); + uint256 amountRemainingLessFee = FullMath.mulDiv( + uint256(amountRemaining), + MAX_FEE_PIPS - _feePips, + MAX_FEE_PIPS + ); amountIn = zeroForOne ? SqrtPriceMath.getAmount0Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, true) : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, true); if (amountRemainingLessFee >= amountIn) { // `amountIn` is capped by the target price sqrtRatioNextX96 = sqrtRatioTargetX96; - feeAmount = FullMath.mulDivRoundingUp(amountIn, feePips, feeComplement); + feeAmount = FullMath.mulDivRoundingUp(amountIn, _feePips, MAX_FEE_PIPS - _feePips); } else { // exhaust the remaining amount amountIn = amountRemainingLessFee; @@ -100,7 +104,7 @@ library SwapMath { amountIn = zeroForOne ? SqrtPriceMath.getAmount0Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, true) : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity, true); - feeAmount = FullMath.mulDivRoundingUp(amountIn, feePips, feeComplement); + feeAmount = FullMath.mulDivRoundingUp(amountIn, _feePips, MAX_FEE_PIPS - _feePips); } } } @@ -123,8 +127,11 @@ library SwapMath { uint256 feePips ) internal pure returns (uint160 sqrtRatioNextX96, uint256 amountIn, uint256 amountOut) { bool zeroForOne = sqrtRatioCurrentX96 >= sqrtRatioTargetX96; - uint256 feeComplement = UnsafeMath.sub(MAX_FEE_PIPS, feePips); - uint256 amountRemainingLessFee = FullMath.mulDiv(amountRemaining, feeComplement, MAX_FEE_PIPS); + uint256 amountRemainingLessFee = FullMath.mulDiv( + amountRemaining, + UnsafeMath.sub(MAX_FEE_PIPS, feePips), + MAX_FEE_PIPS + ); amountIn = zeroForOne ? SqrtPriceMath.getAmount0Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, true) : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, true); @@ -132,7 +139,7 @@ library SwapMath { // `amountIn` is capped by the target price sqrtRatioNextX96 = sqrtRatioTargetX96; // add the fee amount - amountIn = FullMath.mulDivRoundingUp(amountIn, MAX_FEE_PIPS, feeComplement); + amountIn = FullMath.mulDivRoundingUp(amountIn, MAX_FEE_PIPS, UnsafeMath.sub(MAX_FEE_PIPS, feePips)); } else { // exhaust the remaining amount amountIn = amountRemaining; From a36e87d600525b1b8dd5001232f18ac546273a96 Mon Sep 17 00:00:00 2001 From: gnarlycow Date: Sun, 28 Jul 2024 21:21:19 -0700 Subject: [PATCH 13/13] Update package version and gas snapshot. --- .gas-snapshot | 259 +++++++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 141 insertions(+), 120 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 817380d..00b3685 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,142 +1,163 @@ -BitMathTest:testFuzz_LSB(uint256) (runs: 65546, μ: 17626, ~: 17625) -BitMathTest:testFuzz_MSB(uint256) (runs: 65546, μ: 17649, ~: 17643) +BitMathTest:testFuzz_LSB(uint256) (runs: 65538, μ: 17626, ~: 17625) +BitMathTest:testFuzz_MSB(uint256) (runs: 65538, μ: 17649, ~: 17643) BitMathTest:testGas_LSB() (gas: 239714) BitMathTest:testGas_LSB_Og() (gas: 305805) BitMathTest:testGas_MSB() (gas: 255269) BitMathTest:testGas_MSB_Og() (gas: 288889) -FullMathTest:testFuzz_MulDivQ128(uint256,uint256) (runs: 65544, μ: 4048, ~: 3965) -FullMathTest:testFuzz_MulDivQ96(uint256,uint256) (runs: 65544, μ: 4022, ~: 3950) -FullMathTest:testFuzz_MulDivUp_OZ(uint256,uint256,uint256) (runs: 65544, μ: 4944, ~: 4743) -FullMathTest:testFuzz_MulDivUp_Og(uint256,uint256,uint256) (runs: 65544, μ: 10031, ~: 9829) -FullMathTest:testFuzz_MulDiv_OZ(uint256,uint256,uint256) (runs: 65544, μ: 4209, ~: 4075) -FullMathTest:testFuzz_MulDiv_Og(uint256,uint256,uint256) (runs: 65544, μ: 9567, ~: 9435) -FullMathTest:testFuzz_Sqrt(uint256) (runs: 65546, μ: 4411, ~: 4411) -LiquidityAmountsTest:testFuzz_GetAmount0ForLiquidity(uint160,uint160,uint128) (runs: 65546, μ: 20519, ~: 20778) -LiquidityAmountsTest:testFuzz_GetAmount1ForLiquidity(uint160,uint160,uint128) (runs: 65546, μ: 20073, ~: 20016) -LiquidityAmountsTest:testFuzz_GetAmountsForLiquidity(uint160,uint160,uint160,uint128) (runs: 65546, μ: 23054, ~: 23154) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmount0(uint160,uint160,uint256) (runs: 65546, μ: 20601, ~: 20853) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmount1(uint160,uint160,uint256) (runs: 65546, μ: 20184, ~: 20167) -LiquidityAmountsTest:testFuzz_GetLiquidityForAmounts(uint160,uint160,uint160,uint256,uint256) (runs: 65546, μ: 22571, ~: 22643) +FullMathTest:testFuzz_MulDivQ128(uint256,uint256) (runs: 65538, μ: 4047, ~: 3965) +FullMathTest:testFuzz_MulDivQ96(uint256,uint256) (runs: 65538, μ: 4022, ~: 3950) +FullMathTest:testFuzz_MulDivUp_OZ(uint256,uint256,uint256) (runs: 65538, μ: 4945, ~: 4743) +FullMathTest:testFuzz_MulDivUp_Og(uint256,uint256,uint256) (runs: 65538, μ: 10032, ~: 9829) +FullMathTest:testFuzz_MulDiv_OZ(uint256,uint256,uint256) (runs: 65538, μ: 4209, ~: 4075) +FullMathTest:testFuzz_MulDiv_Og(uint256,uint256,uint256) (runs: 65538, μ: 9568, ~: 9435) +FullMathTest:testFuzz_Sqrt(uint256) (runs: 65538, μ: 4411, ~: 4411) +LiquidityAmountsTest:testFuzz_GetAmount0ForLiquidity(uint160,uint160,uint128) (runs: 65538, μ: 20511, ~: 20769) +LiquidityAmountsTest:testFuzz_GetAmount1ForLiquidity(uint160,uint160,uint128) (runs: 65538, μ: 20063, ~: 20007) +LiquidityAmountsTest:testFuzz_GetAmountsForLiquidity(uint160,uint160,uint160,uint128) (runs: 65538, μ: 23035, ~: 23136) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmount0(uint160,uint160,uint256) (runs: 65538, μ: 20590, ~: 20844) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmount1(uint160,uint160,uint256) (runs: 65538, μ: 20172, ~: 20158) +LiquidityAmountsTest:testFuzz_GetLiquidityForAmounts(uint160,uint160,uint160,uint256,uint256) (runs: 65538, μ: 22557, ~: 22625) LiquidityAmountsTest:testGas_GetAmountsForLiquidity() (gas: 261590) LiquidityAmountsTest:testGas_GetAmountsForLiquidity_Og() (gas: 243788) LiquidityAmountsTest:testGas_GetLiquidityForAmounts() (gas: 264457) LiquidityAmountsTest:testGas_GetLiquidityForAmounts_Og() (gas: 280733) -LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65546, μ: 11954, ~: 14751) +LiquidityMathTest:testFuzz_AddDelta(uint128,int128) (runs: 65538, μ: 11942, ~: 14751) LiquidityMathTest:testGas_AddDelta() (gas: 139593) LiquidityMathTest:testGas_AddDelta_Og() (gas: 137264) LiquidityMathTest:testRevert_LA() (gas: 8858) LiquidityMathTest:testRevert_LS() (gas: 8846) -NPMCallerPCSTest:testFuzz_BalanceOf(address) (runs: 26, μ: 17700, ~: 17700) -NPMCallerPCSTest:testFuzz_GetApproved(uint256) (runs: 26, μ: 23203, ~: 23225) -NPMCallerPCSTest:testFuzz_IsApprovedForAll(uint256) (runs: 26, μ: 30835, ~: 19549) -NPMCallerPCSTest:testFuzz_OwnerOf(uint256) (runs: 26, μ: 24204, ~: 23905) -NPMCallerPCSTest:testFuzz_Positions(uint256) (runs: 26, μ: 30905, ~: 28006) -NPMCallerPCSTest:testFuzz_PositionsFull(uint256) (runs: 26, μ: 31245, ~: 28317) -NPMCallerPCSTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 26, μ: 21809, ~: 16527) +NPMCallerPCSTest:testFuzz_BalanceOf(address) (runs: 18, μ: 17717, ~: 17717) +NPMCallerPCSTest:testFuzz_GetApproved(uint256) (runs: 18, μ: 23267, ~: 23225) +NPMCallerPCSTest:testFuzz_IsApprovedForAll(uint256) (runs: 18, μ: 32655, ~: 19549) +NPMCallerPCSTest:testFuzz_OwnerOf(uint256) (runs: 18, μ: 24318, ~: 23905) +NPMCallerPCSTest:testFuzz_Positions(uint256) (runs: 18, μ: 31468, ~: 28051) +NPMCallerPCSTest:testFuzz_PositionsFull(uint256) (runs: 18, μ: 31768, ~: 28317) +NPMCallerPCSTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 18, μ: 95789, ~: 16527) NPMCallerPCSTest:testRevert_GetApproved() (gas: 13940) NPMCallerPCSTest:testRevert_OwnerOf() (gas: 14230) -NPMCallerPCSTest:testRevert_Positions() (gas: 24315) -NPMCallerPCSTest:test_Approve() (gas: 129472) -NPMCallerPCSTest:test_Burn() (gas: 1059122) -NPMCallerPCSTest:test_Collect() (gas: 1001985) -NPMCallerPCSTest:test_DecreaseLiquidity() (gas: 921883) +NPMCallerPCSTest:testRevert_Positions() (gas: 24360) +NPMCallerPCSTest:test_Approve() (gas: 132077) +NPMCallerPCSTest:test_Burn() (gas: 1059377) +NPMCallerPCSTest:test_Collect() (gas: 1002240) +NPMCallerPCSTest:test_DecreaseLiquidity() (gas: 922161) NPMCallerPCSTest:test_Factory() (gas: 14728) -NPMCallerPCSTest:test_IncreaseLiquidity() (gas: 1242186) -NPMCallerPCSTest:test_IsApprovedForAll() (gas: 26548) -NPMCallerPCSTest:test_Mint() (gas: 731510) -NPMCallerPCSTest:test_Permit() (gas: 820007) -NPMCallerPCSTest:test_SetApprovalForAll() (gas: 61346) +NPMCallerPCSTest:test_IncreaseLiquidity() (gas: 1242443) +NPMCallerPCSTest:test_IsApprovedForAll() (gas: 29161) +NPMCallerPCSTest:test_Mint() (gas: 731743) +NPMCallerPCSTest:test_Permit() (gas: 820257) +NPMCallerPCSTest:test_SetApprovalForAll() (gas: 61318) NPMCallerPCSTest:test_TotalSupply() (gas: 16574) -NPMCallerTest:testFuzz_BalanceOf(address) (runs: 26, μ: 17726, ~: 17726) -NPMCallerTest:testFuzz_GetApproved(uint256) (runs: 26, μ: 24018, ~: 24208) -NPMCallerTest:testFuzz_IsApprovedForAll(uint256) (runs: 26, μ: 79121, ~: 79311) -NPMCallerTest:testFuzz_OwnerOf(uint256) (runs: 26, μ: 26321, ~: 26511) -NPMCallerTest:testFuzz_Positions(uint256) (runs: 26, μ: 43987, ~: 44177) -NPMCallerTest:testFuzz_PositionsFull(uint256) (runs: 26, μ: 44450, ~: 44640) -NPMCallerTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 26, μ: 94305, ~: 42884) +NPMCallerSlipStreamTest:testFuzz_BalanceOf(address) (runs: 18, μ: 17761, ~: 17761) +NPMCallerSlipStreamTest:testFuzz_GetApproved(uint256) (runs: 18, μ: 31472, ~: 31542) +NPMCallerSlipStreamTest:testFuzz_IsApprovedForAll(uint256) (runs: 18, μ: 19191, ~: 19261) +NPMCallerSlipStreamTest:testFuzz_OwnerOf(uint256) (runs: 18, μ: 23512, ~: 23582) +NPMCallerSlipStreamTest:testFuzz_Positions(uint256) (runs: 18, μ: 51614, ~: 51684) +NPMCallerSlipStreamTest:testFuzz_PositionsFull(uint256) (runs: 65538, μ: 323, ~: 323) +NPMCallerSlipStreamTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 18, μ: 16169, ~: 16239) +NPMCallerSlipStreamTest:testRevert_GetApproved() (gas: 14223) +NPMCallerSlipStreamTest:testRevert_OwnerOf() (gas: 14207) +NPMCallerSlipStreamTest:testRevert_Positions() (gas: 24752) +NPMCallerSlipStreamTest:test_Approve() (gas: 132093) +NPMCallerSlipStreamTest:test_Burn() (gas: 994507) +NPMCallerSlipStreamTest:test_Collect() (gas: 937310) +NPMCallerSlipStreamTest:test_DecreaseLiquidity() (gas: 822460) +NPMCallerSlipStreamTest:test_Factory() (gas: 14816) +NPMCallerSlipStreamTest:test_IncreaseLiquidity() (gas: 1110532) +NPMCallerSlipStreamTest:test_IsApprovedForAll() (gas: 29226) +NPMCallerSlipStreamTest:test_Mint() (gas: 606230) +NPMCallerSlipStreamTest:test_Permit() (gas: 694875) +NPMCallerSlipStreamTest:test_SetApprovalForAll() (gas: 61365) +NPMCallerSlipStreamTest:test_TotalSupply() (gas: 16574) +NPMCallerTest:testFuzz_BalanceOf(address) (runs: 18, μ: 17743, ~: 17743) +NPMCallerTest:testFuzz_GetApproved(uint256) (runs: 18, μ: 23987, ~: 24208) +NPMCallerTest:testFuzz_IsApprovedForAll(uint256) (runs: 18, μ: 79076, ~: 79297) +NPMCallerTest:testFuzz_OwnerOf(uint256) (runs: 18, μ: 26290, ~: 26511) +NPMCallerTest:testFuzz_Positions(uint256) (runs: 18, μ: 44001, ~: 44222) +NPMCallerTest:testFuzz_PositionsFull(uint256) (runs: 18, μ: 44419, ~: 44640) +NPMCallerTest:testFuzz_TokenOfOwnerByIndex(uint256) (runs: 18, μ: 48268, ~: 36576) NPMCallerTest:testRevert_GetApproved() (gas: 13940) NPMCallerTest:testRevert_OwnerOf() (gas: 14207) -NPMCallerTest:testRevert_Positions() (gas: 24315) -NPMCallerTest:test_Approve() (gas: 129461) -NPMCallerTest:test_Burn() (gas: 955424) -NPMCallerTest:test_Collect() (gas: 898281) -NPMCallerTest:test_DecreaseLiquidity() (gas: 818151) +NPMCallerTest:testRevert_Positions() (gas: 24360) +NPMCallerTest:test_Approve() (gas: 132054) +NPMCallerTest:test_Burn() (gas: 955499) +NPMCallerTest:test_Collect() (gas: 898356) +NPMCallerTest:test_DecreaseLiquidity() (gas: 818249) NPMCallerTest:test_Factory() (gas: 14728) -NPMCallerTest:test_IncreaseLiquidity() (gas: 1116322) -NPMCallerTest:test_IsApprovedForAll() (gas: 26525) -NPMCallerTest:test_Mint() (gas: 607778) -NPMCallerTest:test_Permit() (gas: 696338) -NPMCallerTest:test_SetApprovalForAll() (gas: 61346) +NPMCallerTest:test_IncreaseLiquidity() (gas: 1116399) +NPMCallerTest:test_IsApprovedForAll() (gas: 29138) +NPMCallerTest:test_Mint() (gas: 607831) +NPMCallerTest:test_Permit() (gas: 696408) +NPMCallerTest:test_SetApprovalForAll() (gas: 61318) NPMCallerTest:test_TotalSupply() (gas: 16585) -PoolAddressPCSTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65546, μ: 20454, ~: 20459) -PoolAddressPCSTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65546, μ: 15689, ~: 15694) -PoolAddressPCSTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65546, μ: 22208, ~: 22213) -PoolAddressPCSTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65546, μ: 17369, ~: 17374) -PoolAddressPCSTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65546, μ: 16038, ~: 16043) -PoolAddressPCSTest:testGas_ComputeAddress() (gas: 12229) -PoolAddressPCSTest:testGas_ComputeAddress_Og() (gas: 12774) -PoolAddressTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65546, μ: 20454, ~: 20459) -PoolAddressTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65546, μ: 15689, ~: 15694) -PoolAddressTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65546, μ: 22208, ~: 22213) -PoolAddressTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65546, μ: 17369, ~: 17374) -PoolAddressTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65546, μ: 16038, ~: 16043) -PoolAddressTest:testGas_ComputeAddress() (gas: 12229) -PoolAddressTest:testGas_ComputeAddress_Og() (gas: 12774) -PoolCallerPCSTest:testFuzz_LiquidityNet(int24) (runs: 26, μ: 22056, ~: 22056) -PoolCallerPCSTest:testFuzz_Observations(uint256) (runs: 11, μ: 278, ~: 278) -PoolCallerPCSTest:testFuzz_Positions(bytes32) (runs: 26, μ: 24548, ~: 24548) -PoolCallerPCSTest:testFuzz_Swap(bool,uint256,bytes) (runs: 26, μ: 419230, ~: 399315) -PoolCallerPCSTest:testFuzz_TickBitmap(int16) (runs: 26, μ: 14017, ~: 14017) -PoolCallerPCSTest:testFuzz_Ticks(int24) (runs: 26, μ: 27815, ~: 27815) +PoolAddressPCSTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65538, μ: 20442, ~: 20447) +PoolAddressPCSTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65538, μ: 15674, ~: 15679) +PoolAddressPCSTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65538, μ: 22202, ~: 22207) +PoolAddressPCSTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65538, μ: 17342, ~: 17347) +PoolAddressPCSTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65538, μ: 16020, ~: 16025) +PoolAddressPCSTest:testGas_ComputeAddress() (gas: 16432) +PoolAddressPCSTest:testGas_ComputeAddress_Og() (gas: 16995) +PoolAddressTest:testFuzz_ComputeAddress(address,address,uint24) (runs: 65538, μ: 20442, ~: 20447) +PoolAddressTest:testFuzz_ComputeAddressCalldata(address,address,uint24) (runs: 65538, μ: 15674, ~: 15679) +PoolAddressTest:testFuzz_ComputeAddressFromKey(address,address,uint24) (runs: 65538, μ: 22202, ~: 22207) +PoolAddressTest:testFuzz_VerifyCallback(address,address,uint24) (runs: 65538, μ: 17342, ~: 17347) +PoolAddressTest:testFuzz_VerifyCallbackCalldata(address,address,uint24) (runs: 65538, μ: 16020, ~: 16025) +PoolAddressTest:testGas_ComputeAddress() (gas: 16432) +PoolAddressTest:testGas_ComputeAddress_Og() (gas: 16995) +PoolCallerPCSTest:testFuzz_LiquidityNet(int24) (runs: 18, μ: 22062, ~: 22062) +PoolCallerPCSTest:testFuzz_Observations(uint256) (runs: 3, μ: 278, ~: 278) +PoolCallerPCSTest:testFuzz_Positions(bytes32) (runs: 18, μ: 24548, ~: 24548) +PoolCallerPCSTest:testFuzz_Swap(bool,uint256,bytes) (runs: 18, μ: 341874, ~: 316311) +PoolCallerPCSTest:testFuzz_TickBitmap(int16) (runs: 18, μ: 14023, ~: 14023) +PoolCallerPCSTest:testFuzz_Ticks(int24) (runs: 18, μ: 27809, ~: 27809) PoolCallerPCSTest:testRevert_AS_Swap() (gas: 35335) PoolCallerPCSTest:testRevert_SPL_Swap() (gas: 40056) PoolCallerPCSTest:test_Fee() (gas: 11396) PoolCallerPCSTest:test_FeeGrowthGlobal0X128() (gas: 13539) PoolCallerPCSTest:test_FeeGrowthGlobal1X128() (gas: 13541) PoolCallerPCSTest:test_Liquidity() (gas: 13720) -PoolCallerPCSTest:test_LiquidityNet() (gas: 28048) +PoolCallerPCSTest:test_LiquidityNet() (gas: 28234) PoolCallerPCSTest:test_ProtocolFees() (gas: 14768) PoolCallerPCSTest:test_Slot0() (gas: 20497) PoolCallerPCSTest:test_SqrtPriceX96AndTick() (gas: 16086) -PoolCallerPCSTest:test_Swap() (gas: 476634) +PoolCallerPCSTest:test_Swap() (gas: 476628) PoolCallerPCSTest:test_TickSpacing() (gas: 11445) -PoolCallerTest:testFuzz_LiquidityNet(int24) (runs: 26, μ: 22023, ~: 22023) -PoolCallerTest:testFuzz_Observations(uint256) (runs: 26, μ: 24376, ~: 24509) -PoolCallerTest:testFuzz_Positions(bytes32) (runs: 26, μ: 24563, ~: 24563) -PoolCallerTest:testFuzz_Swap(bool,uint256,bytes) (runs: 26, μ: 351284, ~: 352732) -PoolCallerTest:testFuzz_TickBitmap(int16) (runs: 26, μ: 14032, ~: 14032) -PoolCallerTest:testFuzz_Ticks(int24) (runs: 26, μ: 27782, ~: 27782) +PoolCallerTest:testFuzz_LiquidityNet(int24) (runs: 18, μ: 22029, ~: 22029) +PoolCallerTest:testFuzz_Observations(uint256) (runs: 18, μ: 24393, ~: 24515) +PoolCallerTest:testFuzz_Positions(bytes32) (runs: 18, μ: 24563, ~: 24563) +PoolCallerTest:testFuzz_Swap(bool,uint256,bytes) (runs: 18, μ: 289815, ~: 255679) +PoolCallerTest:testFuzz_TickBitmap(int16) (runs: 18, μ: 14038, ~: 14038) +PoolCallerTest:testFuzz_Ticks(int24) (runs: 18, μ: 27776, ~: 27776) PoolCallerTest:testRevert_AS_Swap() (gas: 35387) PoolCallerTest:testRevert_SPL_Swap() (gas: 38025) PoolCallerTest:test_Fee() (gas: 11396) PoolCallerTest:test_FeeGrowthGlobal0X128() (gas: 13539) PoolCallerTest:test_FeeGrowthGlobal1X128() (gas: 13585) PoolCallerTest:test_Liquidity() (gas: 13742) -PoolCallerTest:test_LiquidityNet() (gas: 25830) +PoolCallerTest:test_LiquidityNet() (gas: 25836) PoolCallerTest:test_ProtocolFees() (gas: 14768) PoolCallerTest:test_Slot0() (gas: 19717) PoolCallerTest:test_SqrtPriceX96AndTick() (gas: 13653) -PoolCallerTest:test_Swap() (gas: 425326) +PoolCallerTest:test_Swap() (gas: 425320) PoolCallerTest:test_TickSpacing() (gas: 11445) SafeCastTest:testRevert_ToInt128() (gas: 3099) SafeCastTest:testRevert_ToInt256() (gas: 3101) SafeCastTest:testRevert_ToUint128() (gas: 3121) SafeCastTest:testRevert_ToUint160() (gas: 3077) SafeCastTest:testToInt128() (gas: 3166) -SafeCastTest:testToInt128(int256) (runs: 65546, μ: 3328, ~: 3360) -SafeCastTest:testToInt128(uint256) (runs: 65546, μ: 3231, ~: 3257) +SafeCastTest:testToInt128(int256) (runs: 65538, μ: 3328, ~: 3360) +SafeCastTest:testToInt128(uint256) (runs: 65538, μ: 3231, ~: 3257) SafeCastTest:testToInt256() (gas: 3160) -SafeCastTest:testToInt256(uint256) (runs: 65546, μ: 3266, ~: 3270) -SafeCastTest:testToUint128(uint256) (runs: 65546, μ: 3229, ~: 3255) -SafeCastTest:testToUint160(uint256) (runs: 65546, μ: 3258, ~: 3278) -SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65546, μ: 15642, ~: 15557) -SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,uint128,bool) (runs: 65546, μ: 15743, ~: 15660) -SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,int128) (runs: 65546, μ: 15239, ~: 15183) -SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,uint128,bool) (runs: 65546, μ: 15386, ~: 15432) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65546, μ: 19138, ~: 18732) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65546, μ: 21234, ~: 21310) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65546, μ: 15568, ~: 15496) -SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65546, μ: 15384, ~: 14916) +SafeCastTest:testToInt256(uint256) (runs: 65538, μ: 3266, ~: 3270) +SafeCastTest:testToUint128(uint256) (runs: 65538, μ: 3229, ~: 3255) +SafeCastTest:testToUint160(uint256) (runs: 65538, μ: 3258, ~: 3278) +SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,int128) (runs: 65538, μ: 15626, ~: 15539) +SqrtPriceMathTest:testFuzz_GetAmount0Delta(uint160,uint160,uint128,bool) (runs: 65538, μ: 15726, ~: 15642) +SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,int128) (runs: 65538, μ: 15222, ~: 15165) +SqrtPriceMathTest:testFuzz_GetAmount1Delta(uint160,uint160,uint128,bool) (runs: 65538, μ: 15367, ~: 15414) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount0RoundingUp(uint160,uint128,uint256,bool) (runs: 65538, μ: 19127, ~: 18714) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromAmount1RoundingDown(uint160,uint128,uint256,bool) (runs: 65538, μ: 21222, ~: 21292) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromInput(uint160,uint128,uint256,bool) (runs: 65538, μ: 15553, ~: 15478) +SqrtPriceMathTest:testFuzz_GetNextSqrtPriceFromOutput(uint160,uint128,uint256,bool) (runs: 65538, μ: 15377, ~: 14907) SqrtPriceMathTest:testGas_GetAmount0Delta() (gas: 322902) SqrtPriceMathTest:testGas_GetAmount0Delta_Og() (gas: 318258) SqrtPriceMathTest:testGas_GetAmount1Delta() (gas: 281567) @@ -145,42 +166,42 @@ SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput() (gas: 303466) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromInput_Og() (gas: 285701) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput() (gas: 286328) SqrtPriceMathTest:testGas_GetNextSqrtPriceFromOutput_Og() (gas: 269021) -SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65546, μ: 27023, ~: 27110) -SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 29070, ~: 29020) -SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65546, μ: 28608, ~: 28507) -SwapMathTest:testFuzz_getSqrtPriceTarget(bool,uint160,uint160) (runs: 65546, μ: 3503, ~: 3503) +SwapMathTest:testFuzz_ComputeSwapStep(uint160,uint160,uint128,int256,uint24) (runs: 65538, μ: 27007, ~: 27092) +SwapMathTest:testFuzz_ComputeSwapStepExactIn(uint160,uint160,uint128,uint256,uint24) (runs: 65538, μ: 29063, ~: 29011) +SwapMathTest:testFuzz_ComputeSwapStepExactOut(uint160,uint160,uint128,uint256,uint24) (runs: 65538, μ: 28601, ~: 28498) +SwapMathTest:testFuzz_getSqrtPriceTarget(bool,uint160,uint160) (runs: 65538, μ: 3503, ~: 3503) SwapMathTest:testGas_ComputeSwapStep() (gas: 514269) SwapMathTest:testGas_ComputeSwapStepExactIn() (gas: 533978) SwapMathTest:testGas_ComputeSwapStepExactIn_Og() (gas: 563266) SwapMathTest:testGas_ComputeSwapStepExactOut() (gas: 482433) SwapMathTest:testGas_ComputeSwapStepExactOut_Og() (gas: 557512) SwapMathTest:testGas_ComputeSwapStep_Og() (gas: 577793) -TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65546, μ: 9280, ~: 9380) -TickBitmapPCSTest:testFuzz_FlipTick(int24) (runs: 65546, μ: 111721, ~: 112007) -TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65546, μ: 65299, ~: 65226) -TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65546, μ: 112957, ~: 112901) -TickBitmapPCSTest:testFuzz_Position(int24) (runs: 65546, μ: 3859, ~: 3859) +TickBitmapPCSTest:testFuzz_Compress(int24,int24) (runs: 65538, μ: 9285, ~: 9380) +TickBitmapPCSTest:testFuzz_FlipTick(int24) (runs: 65538, μ: 111712, ~: 112001) +TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65538, μ: 65262, ~: 65193) +TickBitmapPCSTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65538, μ: 112949, ~: 112889) +TickBitmapPCSTest:testFuzz_Position(int24) (runs: 65538, μ: 3859, ~: 3859) TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord() (gas: 12597642) TickBitmapPCSTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635537) -TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_GT() (gas: 108376) -TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 108823) -TickBitmapPCSTest:test_NextInitializedTick_GT() (gas: 119621) -TickBitmapPCSTest:test_NextInitializedTick_LTE() (gas: 124127) -TickBitmapTest:testFuzz_Compress(int24,int24) (runs: 65546, μ: 9279, ~: 9380) -TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65546, μ: 111722, ~: 112007) -TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65546, μ: 65299, ~: 65226) -TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65546, μ: 112959, ~: 112901) -TickBitmapTest:testFuzz_Position(int24) (runs: 65546, μ: 3859, ~: 3859) +TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_GT() (gas: 113437) +TickBitmapPCSTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 113884) +TickBitmapPCSTest:test_NextInitializedTick_GT() (gas: 124862) +TickBitmapPCSTest:test_NextInitializedTick_LTE() (gas: 129368) +TickBitmapTest:testFuzz_Compress(int24,int24) (runs: 65538, μ: 9285, ~: 9380) +TickBitmapTest:testFuzz_FlipTick(int24) (runs: 65538, μ: 111711, ~: 112001) +TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,int24,uint8,bool) (runs: 65538, μ: 65261, ~: 65193) +TickBitmapTest:testFuzz_NextInitializedTickWithinOneWord(int24,uint8,bool) (runs: 65538, μ: 112949, ~: 112902) +TickBitmapTest:testFuzz_Position(int24) (runs: 65538, μ: 3859, ~: 3859) TickBitmapTest:testGas_NextInitializedTickWithinOneWord() (gas: 12597642) TickBitmapTest:testGas_NextInitializedTickWithinOneWord_Og() (gas: 12635537) -TickBitmapTest:test_NextInitializedTickWithinOneWord_GT() (gas: 286334) -TickBitmapTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 298343) -TickBitmapTest:test_NextInitializedTick_GT() (gas: 491390) -TickBitmapTest:test_NextInitializedTick_LTE() (gas: 607826) -TickMathTest:testFuzzRevert_GetSqrtRatioAtTick(int24) (runs: 65546, μ: 14697, ~: 14839) -TickMathTest:testFuzzRevert_GetTickAtSqrtRatio(uint160,bool) (runs: 65546, μ: 12915, ~: 13070) -TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65546, μ: 18006, ~: 17843) -TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65546, μ: 16576, ~: 16588) +TickBitmapTest:test_NextInitializedTickWithinOneWord_GT() (gas: 291022) +TickBitmapTest:test_NextInitializedTickWithinOneWord_LTE() (gas: 303031) +TickBitmapTest:test_NextInitializedTick_GT() (gas: 496078) +TickBitmapTest:test_NextInitializedTick_LTE() (gas: 612514) +TickMathTest:testFuzzRevert_GetSqrtRatioAtTick(int24) (runs: 65538, μ: 14695, ~: 14839) +TickMathTest:testFuzzRevert_GetTickAtSqrtRatio(uint160,bool) (runs: 65538, μ: 12913, ~: 13070) +TickMathTest:testFuzz_GetSqrtRatioAtTick(int24) (runs: 65538, μ: 18008, ~: 17843) +TickMathTest:testFuzz_GetTickAtSqrtRatio(uint160) (runs: 65538, μ: 16576, ~: 16588) TickMathTest:testGas_GetSqrtRatioAtTick() (gas: 173514) TickMathTest:testGas_GetSqrtRatioAtTick_Og() (gas: 180373) TickMathTest:testGas_GetTickAtSqrtRatio() (gas: 282569) diff --git a/package.json b/package.json index 91e9b0f..c7bd1fe 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@aperture_finance/uni-v3-lib", "description": "A suite of Solidity libraries that have been imported and rewritten from Uniswap's v3-core and v3-periphery", - "version": "3.0.1", + "version": "3.0.2", "author": "Aperture Finance", "homepage": "https://aperture.finance/", "license": "GPL-2.0-or-later",