Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

OZ-L13: Docstrings n cleanup #335

Merged
merged 12 commits into from
Sep 4, 2024
4 changes: 2 additions & 2 deletions src/V4Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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;

Expand Down
7 changes: 4 additions & 3 deletions src/base/ERC721Permit_v4.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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();
_;
Expand All @@ -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);
Expand All @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src/base/ImmutableState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
9 changes: 9 additions & 0 deletions src/base/Notifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions src/base/Permit2Forwarder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions src/base/PoolInitializer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions src/base/SafeCallback.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
21 changes: 18 additions & 3 deletions src/base/hooks/BaseHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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());
}
Expand All @@ -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
Expand All @@ -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
Expand All @@ -70,6 +78,7 @@ abstract contract BaseHook is IHooks, SafeCallback {
revert HookNotImplemented();
}

/// @inheritdoc IHooks
function beforeRemoveLiquidity(
address,
PoolKey calldata,
Expand All @@ -79,6 +88,7 @@ abstract contract BaseHook is IHooks, SafeCallback {
revert HookNotImplemented();
}

/// @inheritdoc IHooks
function afterAddLiquidity(
address,
PoolKey calldata,
Expand All @@ -89,6 +99,7 @@ abstract contract BaseHook is IHooks, SafeCallback {
revert HookNotImplemented();
}

/// @inheritdoc IHooks
function afterRemoveLiquidity(
address,
PoolKey calldata,
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/interfaces/IERC721Permit_v4.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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(
Expand Down
6 changes: 6 additions & 0 deletions src/interfaces/IPositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/lens/Quoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
);

Expand Down
7 changes: 6 additions & 1 deletion src/libraries/ActionConstants.sol
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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);
}
14 changes: 13 additions & 1 deletion src/libraries/ERC721PermitHash.sol
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
9 changes: 8 additions & 1 deletion src/libraries/PathKey.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading