From 4899de7fdeb7e9be90d6b42657c5709f68ff4aac Mon Sep 17 00:00:00 2001 From: saucepoint <98790946+saucepoint@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:13:01 -0400 Subject: [PATCH] OZ-L13: Docstrings n cleanup (#335) * oz-L13: natspec for action constants * oz-L13: natspec for BaseHook * oz-N05: rename ERC721PermitHashLibrary -> ERC721PermitHash * oz-L13: natspec for ERC721PermitHash * sb-i69: (nice), natspec for IERC721Permit_v4 * oz-L13: IPositionManager natspec * oz-L13: natspec immutable state, notifier, permit2forwarder, poolinitializer, pathkey, pooltickscounter * oz-N09: permit2 forwarder natspec * rename PathKeyLib for consistency * oz-L13: natspec for safecallback * forge fmt --- src/V4Router.sol | 4 ++-- src/base/ERC721Permit_v4.sol | 7 ++++--- src/base/ImmutableState.sol | 3 +++ src/base/Notifier.sol | 9 ++++++++ src/base/Permit2Forwarder.sol | 7 +++++++ src/base/PoolInitializer.sol | 7 +++++++ src/base/SafeCallback.sol | 6 ++++++ src/base/hooks/BaseHook.sol | 21 ++++++++++++++++--- src/interfaces/IERC721Permit_v4.sol | 3 ++- src/interfaces/IPositionManager.sol | 6 ++++++ src/lens/Quoter.sol | 6 +++--- src/libraries/ActionConstants.sol | 7 ++++++- src/libraries/ERC721PermitHash.sol | 14 ++++++++++++- src/libraries/PathKey.sol | 9 +++++++- src/libraries/PoolTicksCounter.sol | 10 +++++++++ test/erc721Permit/ERC721Permit.permit.t.sol | 10 ++++----- .../ERC721Permit.permitForAll.t.sol | 14 ++++++------- test/shared/PosmTestSetup.sol | 4 ++-- 18 files changed, 117 insertions(+), 30 deletions(-) diff --git a/src/V4Router.sol b/src/V4Router.sol index c14ad76a7..f9faffed3 100644 --- a/src/V4Router.sol +++ b/src/V4Router.sol @@ -8,7 +8,7 @@ import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol"; import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; -import {PathKey, PathKeyLib} from "./libraries/PathKey.sol"; +import {PathKey, PathKeyLibrary} from "./libraries/PathKey.sol"; import {CalldataDecoder} from "./libraries/CalldataDecoder.sol"; import {BipsLibrary} from "./libraries/BipsLibrary.sol"; import {IV4Router} from "./interfaces/IV4Router.sol"; @@ -25,7 +25,7 @@ import {ActionConstants} from "./libraries/ActionConstants.sol"; abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver { using SafeCastTemp for *; using SafeCast for *; - using PathKeyLib for PathKey; + using PathKeyLibrary for PathKey; using CalldataDecoder for bytes; using BipsLibrary for uint256; diff --git a/src/base/ERC721Permit_v4.sol b/src/base/ERC721Permit_v4.sol index aab76f7c2..b700db89d 100644 --- a/src/base/ERC721Permit_v4.sol +++ b/src/base/ERC721Permit_v4.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.0; import {ERC721} from "solmate/src/tokens/ERC721.sol"; import {EIP712_v4} from "./EIP712_v4.sol"; -import {ERC721PermitHashLibrary} from "../libraries/ERC721PermitHash.sol"; +import {ERC721PermitHash} from "../libraries/ERC721PermitHash.sol"; import {SignatureVerification} from "permit2/src/libraries/SignatureVerification.sol"; import {IERC721Permit_v4} from "../interfaces/IERC721Permit_v4.sol"; @@ -17,6 +17,7 @@ abstract contract ERC721Permit_v4 is ERC721, IERC721Permit_v4, EIP712_v4, Unorde /// @notice Computes the nameHash and versionHash constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) EIP712_v4(name_) {} + /// @notice Checks if the block's timestamp is before a signature's deadline modifier checkSignatureDeadline(uint256 deadline) { if (block.timestamp > deadline) revert SignatureDeadlineExpired(); _; @@ -31,7 +32,7 @@ abstract contract ERC721Permit_v4 is ERC721, IERC721Permit_v4, EIP712_v4, Unorde // the .verify function checks the owner is non-0 address owner = _ownerOf[tokenId]; - bytes32 digest = ERC721PermitHashLibrary.hashPermit(spender, tokenId, nonce, deadline); + bytes32 digest = ERC721PermitHash.hashPermit(spender, tokenId, nonce, deadline); signature.verify(_hashTypedData(digest), owner); _useUnorderedNonce(owner, nonce); @@ -47,7 +48,7 @@ abstract contract ERC721Permit_v4 is ERC721, IERC721Permit_v4, EIP712_v4, Unorde uint256 nonce, bytes calldata signature ) external payable checkSignatureDeadline(deadline) { - bytes32 digest = ERC721PermitHashLibrary.hashPermitForAll(operator, approved, nonce, deadline); + bytes32 digest = ERC721PermitHash.hashPermitForAll(operator, approved, nonce, deadline); signature.verify(_hashTypedData(digest), owner); _useUnorderedNonce(owner, nonce); diff --git a/src/base/ImmutableState.sol b/src/base/ImmutableState.sol index 70992aa1d..8e30f1a4b 100644 --- a/src/base/ImmutableState.sol +++ b/src/base/ImmutableState.sol @@ -3,7 +3,10 @@ pragma solidity ^0.8.0; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; +/// @title Immutable State +/// @notice A collection of immutable state variables, commonly used across multiple contracts contract ImmutableState { + /// @notice The Uniswap v4 PoolManager contract IPoolManager public immutable poolManager; constructor(IPoolManager _poolManager) { diff --git a/src/base/Notifier.sol b/src/base/Notifier.sol index 2992b6a8b..0b7d1d716 100644 --- a/src/base/Notifier.sol +++ b/src/base/Notifier.sol @@ -24,7 +24,16 @@ abstract contract Notifier is INotifier { /// @inheritdoc INotifier mapping(uint256 tokenId => ISubscriber subscriber) public subscriber; + /// @notice Only allow callers that are approved as spenders or operators of the tokenId + /// @dev to be implemented by the parent contract (PositionManager) + /// @param caller the address of the caller + /// @param tokenId the tokenId of the position modifier onlyIfApproved(address caller, uint256 tokenId) virtual; + + /// @notice Only allow callers that provide the correct config for the tokenId + /// @dev to be implemented by the parent contract (PositionManager) + /// @param tokenId the tokenId of the position + /// @param config the config of the tokenId modifier onlyValidConfig(uint256 tokenId, PositionConfig calldata config) virtual; function _positionConfigs(uint256 tokenId) internal view virtual returns (PositionConfigId storage); diff --git a/src/base/Permit2Forwarder.sol b/src/base/Permit2Forwarder.sol index 12e378aae..b7c678683 100644 --- a/src/base/Permit2Forwarder.sol +++ b/src/base/Permit2Forwarder.sol @@ -6,6 +6,7 @@ import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol" /// @notice PermitForwarder allows permitting this contract as a spender on permit2 /// @dev This contract does not enforce the spender to be this contract, but that is the intended use case contract Permit2Forwarder { + /// @notice the Permit2 contract to forward approvals IAllowanceTransfer public immutable permit2; error Wrap__Permit2Reverted(address _permit2, bytes reason); @@ -16,6 +17,9 @@ contract Permit2Forwarder { /// @notice allows forwarding a single permit to permit2 /// @dev this function is payable to allow multicall with NATIVE based actions + /// @param owner the owner of the tokens + /// @param permitSingle the permit data + /// @param signature the signature of the permit; abi.encodePacked(r, s, v) function permit(address owner, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature) external payable @@ -30,6 +34,9 @@ contract Permit2Forwarder { /// @notice allows forwarding batch permits to permit2 /// @dev this function is payable to allow multicall with NATIVE based actions + /// @param owner the owner of the tokens + /// @param _permitBatch a batch of approvals + /// @param signature the signature of the permit; abi.encodePacked(r, s, v) function permitBatch(address owner, IAllowanceTransfer.PermitBatch calldata _permitBatch, bytes calldata signature) external payable diff --git a/src/base/PoolInitializer.sol b/src/base/PoolInitializer.sol index 2e0918985..1f42ab1ff 100644 --- a/src/base/PoolInitializer.sol +++ b/src/base/PoolInitializer.sol @@ -5,7 +5,14 @@ import {ImmutableState} from "./ImmutableState.sol"; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; +/// @title Pool Initializer +/// @notice Initializes a Uniswap v4 Pool +/// @dev Enables create pool + mint liquidity in a single transaction with multicall abstract contract PoolInitializer is ImmutableState { + /// @notice Initialize a Uniswap v4 Pool + /// @param key the PoolKey of the pool to initialize + /// @param sqrtPriceX96 the initial sqrtPriceX96 of the pool + /// @param hookData the optional data passed to the hook's initialize functions function initializePool(PoolKey calldata key, uint160 sqrtPriceX96, bytes calldata hookData) external payable diff --git a/src/base/SafeCallback.sol b/src/base/SafeCallback.sol index ab80cd845..cda2b4a04 100644 --- a/src/base/SafeCallback.sol +++ b/src/base/SafeCallback.sol @@ -5,20 +5,26 @@ import {IUnlockCallback} from "@uniswap/v4-core/src/interfaces/callback/IUnlockC import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {ImmutableState} from "./ImmutableState.sol"; +/// @title Safe Callback +/// @notice A contract that only allows the Uniswap v4 PoolManager to call the unlockCallback abstract contract SafeCallback is ImmutableState, IUnlockCallback { + /// @notice Thrown when calling unlockCallback where the caller is not PoolManager error NotPoolManager(); constructor(IPoolManager _poolManager) ImmutableState(_poolManager) {} + /// @notice Only allow calls from the PoolManager contract modifier onlyPoolManager() { if (msg.sender != address(poolManager)) revert NotPoolManager(); _; } + /// @inheritdoc IUnlockCallback /// @dev We force the onlyPoolManager modifier by exposing a virtual function after the onlyPoolManager check. function unlockCallback(bytes calldata data) external onlyPoolManager returns (bytes memory) { return _unlockCallback(data); } + /// @dev to be implemented by the child contract, to safely guarantee the logic is only executed by the PoolManager function _unlockCallback(bytes calldata data) internal virtual returns (bytes memory); } diff --git a/src/base/hooks/BaseHook.sol b/src/base/hooks/BaseHook.sol index c4c0c6b16..331d513c6 100644 --- a/src/base/hooks/BaseHook.sol +++ b/src/base/hooks/BaseHook.sol @@ -9,6 +9,8 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {BeforeSwapDelta} from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol"; import {SafeCallback} from "../SafeCallback.sol"; +/// @title Base Hook +/// @notice abstract contract for hook implementations abstract contract BaseHook is IHooks, SafeCallback { error NotSelf(); error InvalidPool(); @@ -31,11 +33,14 @@ abstract contract BaseHook is IHooks, SafeCallback { _; } + /// @notice Returns a struct of permissions to signal which hook functions are to be implemented + /// @dev Used at deployment to validate the address correctly represents the expected permissions function getHookPermissions() public pure virtual returns (Hooks.Permissions memory); - // this function is virtual so that we can override it during testing, - // which allows us to deploy an implementation to any address - // and then etch the bytecode into the correct address + /// @notice Validates the deployed hook address agrees with the expected permissions of the hook + /// @dev this function is virtual so that we can override it during testing, + /// which allows us to deploy an implementation to any address + /// and then etch the bytecode into the correct address function validateHookAddress(BaseHook _this) internal pure virtual { Hooks.validateHookPermissions(_this, getHookPermissions()); } @@ -50,10 +55,12 @@ abstract contract BaseHook is IHooks, SafeCallback { } } + /// @inheritdoc IHooks function beforeInitialize(address, PoolKey calldata, uint160, bytes calldata) external virtual returns (bytes4) { revert HookNotImplemented(); } + /// @inheritdoc IHooks function afterInitialize(address, PoolKey calldata, uint160, int24, bytes calldata) external virtual @@ -62,6 +69,7 @@ abstract contract BaseHook is IHooks, SafeCallback { revert HookNotImplemented(); } + /// @inheritdoc IHooks function beforeAddLiquidity(address, PoolKey calldata, IPoolManager.ModifyLiquidityParams calldata, bytes calldata) external virtual @@ -70,6 +78,7 @@ abstract contract BaseHook is IHooks, SafeCallback { revert HookNotImplemented(); } + /// @inheritdoc IHooks function beforeRemoveLiquidity( address, PoolKey calldata, @@ -79,6 +88,7 @@ abstract contract BaseHook is IHooks, SafeCallback { revert HookNotImplemented(); } + /// @inheritdoc IHooks function afterAddLiquidity( address, PoolKey calldata, @@ -89,6 +99,7 @@ abstract contract BaseHook is IHooks, SafeCallback { revert HookNotImplemented(); } + /// @inheritdoc IHooks function afterRemoveLiquidity( address, PoolKey calldata, @@ -99,6 +110,7 @@ abstract contract BaseHook is IHooks, SafeCallback { revert HookNotImplemented(); } + /// @inheritdoc IHooks function beforeSwap(address, PoolKey calldata, IPoolManager.SwapParams calldata, bytes calldata) external virtual @@ -107,6 +119,7 @@ abstract contract BaseHook is IHooks, SafeCallback { revert HookNotImplemented(); } + /// @inheritdoc IHooks function afterSwap(address, PoolKey calldata, IPoolManager.SwapParams calldata, BalanceDelta, bytes calldata) external virtual @@ -115,6 +128,7 @@ abstract contract BaseHook is IHooks, SafeCallback { revert HookNotImplemented(); } + /// @inheritdoc IHooks function beforeDonate(address, PoolKey calldata, uint256, uint256, bytes calldata) external virtual @@ -123,6 +137,7 @@ abstract contract BaseHook is IHooks, SafeCallback { revert HookNotImplemented(); } + /// @inheritdoc IHooks function afterDonate(address, PoolKey calldata, uint256, uint256, bytes calldata) external virtual diff --git a/src/interfaces/IERC721Permit_v4.sol b/src/interfaces/IERC721Permit_v4.sol index eab4d1285..bc4c7aa06 100644 --- a/src/interfaces/IERC721Permit_v4.sol +++ b/src/interfaces/IERC721Permit_v4.sol @@ -12,6 +12,7 @@ interface IERC721Permit_v4 { /// @param spender The account that is being approved /// @param tokenId The ID of the token that is being approved for spending /// @param deadline The deadline timestamp by which the call must be mined for the approve to work + /// @param nonce a unique value, for an owner, to prevent replay attacks; an unordered nonce where the top 248 bits correspond to a word and the bottom 8 bits calculate the bit position of the word /// @param signature Concatenated data from a valid secp256k1 signature from the holder, i.e. abi.encodePacked(r, s, v) /// @dev payable so it can be multicalled with NATIVE related actions function permit(address spender, uint256 tokenId, uint256 deadline, uint256 nonce, bytes calldata signature) @@ -23,7 +24,7 @@ interface IERC721Permit_v4 { /// @param operator The address that will be set as an operator for the owner /// @param approved The permission to set on the operator /// @param deadline The deadline timestamp by which the call must be mined for the approve to work - /// @param nonce The nonce of the owner's permit + /// @param nonce a unique value, for an owner, to prevent replay attacks; an unordered nonce where the top 248 bits correspond to a word and the bottom 8 bits calculate the bit position of the word /// @param signature Concatenated data from a valid secp256k1 signature from the holder, i.e. abi.encodePacked(r, s, v) /// @dev payable so it can be multicalled with NATIVE related actions function permitForAll( diff --git a/src/interfaces/IPositionManager.sol b/src/interfaces/IPositionManager.sol index 8f7a59c63..ff0e03fde 100644 --- a/src/interfaces/IPositionManager.sol +++ b/src/interfaces/IPositionManager.sol @@ -5,11 +5,17 @@ import {PositionConfig} from "../libraries/PositionConfig.sol"; import {INotifier} from "./INotifier.sol"; +/// @title IPositionManager +/// @notice Interface for the PositionManager contract interface IPositionManager is INotifier { + /// @notice Thrown when the caller is not approved to modify a position error NotApproved(address caller); + /// @notice Thrown when the block.timestamp exceeds the user-provided deadline error DeadlinePassed(uint256 deadline); + /// @notice Thrown when the caller provides the incorrect PositionConfig for a corresponding tokenId when modifying liquidity error IncorrectPositionConfigForTokenId(uint256 tokenId); + /// @notice Emitted when a new liquidity position is minted event MintPosition(uint256 indexed tokenId, PositionConfig config); /// @notice Unlocks Uniswap v4 PoolManager and batches actions for modifying liquidity diff --git a/src/lens/Quoter.sol b/src/lens/Quoter.sol index ee996043c..4f9741943 100644 --- a/src/lens/Quoter.sol +++ b/src/lens/Quoter.sol @@ -9,13 +9,13 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol"; import {IQuoter} from "../interfaces/IQuoter.sol"; import {PoolTicksCounter} from "../libraries/PoolTicksCounter.sol"; -import {PathKey, PathKeyLib} from "../libraries/PathKey.sol"; +import {PathKey, PathKeyLibrary} from "../libraries/PathKey.sol"; import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; import {SafeCallback} from "../base/SafeCallback.sol"; contract Quoter is IQuoter, SafeCallback { using PoolIdLibrary for PoolKey; - using PathKeyLib for PathKey; + using PathKeyLibrary for PathKey; using StateLibrary for IPoolManager; /// @dev cache used to check a safety condition in exact output swaps. @@ -231,7 +231,7 @@ contract Quoter is IQuoter, SafeCallback { curAmountOut = i == pathLength ? params.exactAmount : cache.prevAmount; amountOutCached = curAmountOut; - (PoolKey memory poolKey, bool oneForZero) = PathKeyLib.getPoolAndSwapDirection( + (PoolKey memory poolKey, bool oneForZero) = PathKeyLibrary.getPoolAndSwapDirection( params.path[i - 1], i == pathLength ? params.exactCurrency : cache.prevCurrency ); diff --git a/src/libraries/ActionConstants.sol b/src/libraries/ActionConstants.sol index f51b9600d..914528b02 100644 --- a/src/libraries/ActionConstants.sol +++ b/src/libraries/ActionConstants.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; +/// @title Action Constants +/// @notice Common constants used in actions +/// @dev Constants are gas efficient alternatives to their literal values library ActionConstants { /// @notice used to signal that an action should use the input value of the open delta on the pool manager /// or of the balance that the contract holds @@ -9,7 +12,9 @@ library ActionConstants { /// This value is equivalent to 1<<255, i.e. a singular 1 in the most significant bit. uint256 internal constant CONTRACT_BALANCE = 0x8000000000000000000000000000000000000000000000000000000000000000; - /// @notice used to signal that the recipient of an action should be the msgSender or address(this) + /// @notice used to signal that the recipient of an action should be the msgSender address internal constant MSG_SENDER = address(1); + + /// @notice used to signal that the recipient of an action should be the address(this) address internal constant ADDRESS_THIS = address(2); } diff --git a/src/libraries/ERC721PermitHash.sol b/src/libraries/ERC721PermitHash.sol index 1ed5c2baa..a8c9cfc87 100644 --- a/src/libraries/ERC721PermitHash.sol +++ b/src/libraries/ERC721PermitHash.sol @@ -1,13 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -library ERC721PermitHashLibrary { +library ERC721PermitHash { /// @dev Value is equal to keccak256("Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)"); bytes32 constant PERMIT_TYPEHASH = 0x49ecf333e5b8c95c40fdafc95c1ad136e8914a8fb55e9dc8bb01eaa83a2df9ad; /// @dev Value is equal to keccak256("PermitForAll(address operator,bool approved,uint256 nonce,uint256 deadline)"); bytes32 constant PERMIT_FOR_ALL_TYPEHASH = 0x6673cb397ee2a50b6b8401653d3638b4ac8b3db9c28aa6870ffceb7574ec2f76; + /// @notice Hashes the data that will be signed for IERC721Permit_v4.permit() + /// @param spender The address which may spend the tokenId + /// @param tokenId The tokenId of the owner, which may be spent by spender + /// @param nonce A unique non-ordered value for each signature to prevent replay attacks + /// @param deadline The time at which the signature expires + /// @return digest The hash of the data to be signed; the equivalent to keccak256(abi.encode(PERMIT_TYPEHASH, spender, tokenId, nonce, deadline)); function hashPermit(address spender, uint256 tokenId, uint256 nonce, uint256 deadline) internal pure @@ -32,6 +38,12 @@ library ERC721PermitHashLibrary { } } + /// @notice Hashes the data that will be signed for IERC721Permit_v4.permit() + /// @param operator The address which may spend any of the owner's tokenIds + /// @param approved true if the operator is to have full permission over the owner's tokenIds; false otherwise + /// @param nonce A unique non-ordered value for each signature to prevent replay attacks + /// @param deadline The time at which the signature expires + /// @return digest The hash of the data to be signed; the equivalent to keccak256(abi.encode(PERMIT_FOR_ALL_TYPEHASH, operator, approved, nonce, deadline)); function hashPermitForAll(address operator, bool approved, uint256 nonce, uint256 deadline) internal pure diff --git a/src/libraries/PathKey.sol b/src/libraries/PathKey.sol index b46fb8b59..b3fa1e7f8 100644 --- a/src/libraries/PathKey.sol +++ b/src/libraries/PathKey.sol @@ -13,7 +13,14 @@ struct PathKey { bytes hookData; } -library PathKeyLib { +/// @title PathKey Library +/// @notice Functions for working with PathKeys +library PathKeyLibrary { + /// @notice Get the pool and swap direction for a given PathKey + /// @param params the given PathKey + /// @param currencyIn the input currency + /// @return poolKey the pool key of the swap + /// @return zeroForOne the direction of the swap, true if currency0 is being swapped for currency1 function getPoolAndSwapDirection(PathKey calldata params, Currency currencyIn) internal pure diff --git a/src/libraries/PoolTicksCounter.sol b/src/libraries/PoolTicksCounter.sol index f808e61ca..c101a22fa 100644 --- a/src/libraries/PoolTicksCounter.sol +++ b/src/libraries/PoolTicksCounter.sol @@ -6,6 +6,8 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol"; import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; +/// @title Pool Ticks Counter +/// @notice Functions for counting the number of initialized ticks between two ticks library PoolTicksCounter { using PoolIdLibrary for PoolKey; using StateLibrary for IPoolManager; @@ -19,10 +21,16 @@ library PoolTicksCounter { bool tickAfterInitialized; } + /// @notice Count the number of initialized ticks between two ticks /// @dev This function counts the number of initialized ticks that would incur a gas cost between tickBefore and tickAfter. /// When tickBefore and/or tickAfter themselves are initialized, the logic over whether we should count them depends on the /// direction of the swap. If we are swapping upwards (tickAfter > tickBefore) we don't want to count tickBefore but we do /// want to count tickAfter. The opposite is true if we are swapping downwards. + /// @param self the IPoolManager + /// @param key the PoolKey of the pool + /// @param tickBefore the tick before the swap + /// @param tickAfter the tick after the swap + /// @return initializedTicksLoaded the number of initialized ticks loaded function countInitializedTicksLoaded(IPoolManager self, PoolKey memory key, int24 tickBefore, int24 tickAfter) internal view @@ -94,6 +102,8 @@ library PoolTicksCounter { return initializedTicksLoaded; } + /// @notice Count the number of set bits in a uint256 + /// @param x the uint256 to count the bits of function countOneBits(uint256 x) private pure returns (uint16) { uint16 bits = 0; while (x != 0) { diff --git a/test/erc721Permit/ERC721Permit.permit.t.sol b/test/erc721Permit/ERC721Permit.permit.t.sol index 654c20c93..e567d08f6 100644 --- a/test/erc721Permit/ERC721Permit.permit.t.sol +++ b/test/erc721Permit/ERC721Permit.permit.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.24; import "forge-std/Test.sol"; import {SignatureVerification} from "permit2/src/libraries/SignatureVerification.sol"; -import {ERC721PermitHashLibrary} from "../../src/libraries/ERC721PermitHash.sol"; +import {ERC721PermitHash} from "../../src/libraries/ERC721PermitHash.sol"; import {MockERC721Permit} from "../mocks/MockERC721Permit.sol"; import {IERC721Permit_v4} from "../../src/interfaces/IERC721Permit_v4.sol"; import {IERC721} from "forge-std/interfaces/IERC721.sol"; @@ -61,15 +61,15 @@ contract ERC721PermitTest is Test { // --- Test the signature-based approvals (permit) --- function test_permitTypeHash() public pure { assertEq( - ERC721PermitHashLibrary.PERMIT_TYPEHASH, + ERC721PermitHash.PERMIT_TYPEHASH, keccak256("Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)") ); } function test_fuzz_permitHash(address spender, uint256 tokenId, uint256 nonce, uint256 deadline) public pure { bytes32 expectedHash = - keccak256(abi.encode(ERC721PermitHashLibrary.PERMIT_TYPEHASH, spender, tokenId, nonce, deadline)); - assertEq(expectedHash, ERC721PermitHashLibrary.hashPermit(spender, tokenId, nonce, deadline)); + keccak256(abi.encode(ERC721PermitHash.PERMIT_TYPEHASH, spender, tokenId, nonce, deadline)); + assertEq(expectedHash, ERC721PermitHash.hashPermit(spender, tokenId, nonce, deadline)); } function test_domainSeparator() public view { @@ -284,7 +284,7 @@ contract ERC721PermitTest is Test { abi.encodePacked( "\x19\x01", erc721Permit.DOMAIN_SEPARATOR(), - keccak256(abi.encode(ERC721PermitHashLibrary.PERMIT_TYPEHASH, spender, tokenId, nonce, deadline)) + keccak256(abi.encode(ERC721PermitHash.PERMIT_TYPEHASH, spender, tokenId, nonce, deadline)) ) ); } diff --git a/test/erc721Permit/ERC721Permit.permitForAll.t.sol b/test/erc721Permit/ERC721Permit.permitForAll.t.sol index 26c97a463..63e99ad31 100644 --- a/test/erc721Permit/ERC721Permit.permitForAll.t.sol +++ b/test/erc721Permit/ERC721Permit.permitForAll.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.24; import "forge-std/Test.sol"; import {SignatureVerification} from "permit2/src/libraries/SignatureVerification.sol"; -import {ERC721PermitHashLibrary} from "../../src/libraries/ERC721PermitHash.sol"; +import {ERC721PermitHash} from "../../src/libraries/ERC721PermitHash.sol"; import {MockERC721Permit} from "../mocks/MockERC721Permit.sol"; import {IERC721Permit_v4} from "../../src/interfaces/IERC721Permit_v4.sol"; import {IERC721} from "forge-std/interfaces/IERC721.sol"; @@ -51,15 +51,15 @@ contract ERC721PermitForAllTest is Test { // --- Test the signature-based approvals (permitForAll) --- function test_permitForAllTypeHash() public pure { assertEq( - ERC721PermitHashLibrary.PERMIT_FOR_ALL_TYPEHASH, + ERC721PermitHash.PERMIT_FOR_ALL_TYPEHASH, keccak256("PermitForAll(address operator,bool approved,uint256 nonce,uint256 deadline)") ); } function test_fuzz_permitForAllHash(address operator, bool approved, uint256 nonce, uint256 deadline) public pure { bytes32 expectedHash = - keccak256(abi.encode(ERC721PermitHashLibrary.PERMIT_FOR_ALL_TYPEHASH, operator, approved, nonce, deadline)); - assertEq(expectedHash, ERC721PermitHashLibrary.hashPermitForAll(operator, approved, nonce, deadline)); + keccak256(abi.encode(ERC721PermitHash.PERMIT_FOR_ALL_TYPEHASH, operator, approved, nonce, deadline)); + assertEq(expectedHash, ERC721PermitHash.hashPermitForAll(operator, approved, nonce, deadline)); } /// @dev operator uses alice's signature to approve itself @@ -338,9 +338,7 @@ contract ERC721PermitForAllTest is Test { abi.encodePacked( "\x19\x01", erc721Permit.DOMAIN_SEPARATOR(), - keccak256( - abi.encode(ERC721PermitHashLibrary.PERMIT_FOR_ALL_TYPEHASH, operator, approved, nonce, deadline) - ) + keccak256(abi.encode(ERC721PermitHash.PERMIT_FOR_ALL_TYPEHASH, operator, approved, nonce, deadline)) ) ); } @@ -354,7 +352,7 @@ contract ERC721PermitForAllTest is Test { abi.encodePacked( "\x19\x01", erc721Permit.DOMAIN_SEPARATOR(), - keccak256(abi.encode(ERC721PermitHashLibrary.PERMIT_TYPEHASH, spender, tokenId, nonce, deadline)) + keccak256(abi.encode(ERC721PermitHash.PERMIT_TYPEHASH, spender, tokenId, nonce, deadline)) ) ); } diff --git a/test/shared/PosmTestSetup.sol b/test/shared/PosmTestSetup.sol index 345726c4d..5c35c316f 100644 --- a/test/shared/PosmTestSetup.sol +++ b/test/shared/PosmTestSetup.sol @@ -15,7 +15,7 @@ import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol" import {DeployPermit2} from "permit2/test/utils/DeployPermit2.sol"; import {HookSavesDelta} from "./HookSavesDelta.sol"; import {HookModifyLiquidities} from "./HookModifyLiquidities.sol"; -import {ERC721PermitHashLibrary} from "../../src/libraries/ERC721PermitHash.sol"; +import {ERC721PermitHash} from "../../src/libraries/ERC721PermitHash.sol"; /// @notice A shared test contract that wraps the v4-core deployers contract and exposes basic liquidity operations on posm. contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations { @@ -104,7 +104,7 @@ contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations { abi.encodePacked( "\x19\x01", lpm.DOMAIN_SEPARATOR(), - keccak256(abi.encode(ERC721PermitHashLibrary.PERMIT_TYPEHASH, spender, tokenId, nonce, deadline)) + keccak256(abi.encode(ERC721PermitHash.PERMIT_TYPEHASH, spender, tokenId, nonce, deadline)) ) ); }