From 09d479ba11139d416f061f2d95c7a4139abb3c66 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 31 Jul 2024 20:33:18 +0000 Subject: [PATCH] Update interfaces Changes: A src/lib-external/oz-v3.4-solc-0.7/contracts/introspection/IERC165.sol A src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC20/IERC20.sol A src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721.sol A src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Enumerable.sol A src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Metadata.sol A src/lib-external/oz-v4.7.0/contracts/token/ERC1155/IERC1155Receiver.sol A src/lib-external/oz-v4.7.0/contracts/token/ERC20/IERC20.sol A src/lib-external/oz-v4.7.0/contracts/token/ERC721/IERC721Receiver.sol A src/lib-external/oz-v4.7.0/contracts/utils/introspection/IERC165.sol A src/lib-external/solmate-27545b0/src/tokens/ERC20.sol A src/lib-external/solmate-8d910d8/src/tokens/ERC20.sol A src/permit2/interfaces/IAllowanceTransfer.sol A src/permit2/interfaces/IDAIPermit.sol A src/permit2/interfaces/IEIP712.sol A src/permit2/interfaces/IERC1271.sol A src/permit2/interfaces/IPermit2.sol A src/permit2/interfaces/ISignatureTransfer.sol A src/uniswapx/base/ReactorStructs.sol A src/uniswapx/interfaces/IProtocolFeeController.sol A src/uniswapx/interfaces/IReactor.sol A src/uniswapx/interfaces/IReactorCallback.sol A src/uniswapx/interfaces/IValidationCallback.sol A src/universal-router/interfaces/IRewardsCollector.sol A src/universal-router/interfaces/IUniversalRouter.sol A src/universal-router/interfaces/external/ICryptoPunksMarket.sol A src/universal-router/interfaces/external/IWETH9.sol A src/v2-core/interfaces/IERC20.sol A src/v2-core/interfaces/IUniswapV2Callee.sol A src/v2-core/interfaces/IUniswapV2ERC20.sol A src/v2-core/interfaces/IUniswapV2Factory.sol A src/v2-core/interfaces/IUniswapV2Pair.sol A src/v2-periphery/interfaces/IERC20.sol A src/v2-periphery/interfaces/IUniswapV2Migrator.sol A src/v2-periphery/interfaces/IUniswapV2Router01.sol A src/v2-periphery/interfaces/IUniswapV2Router02.sol A src/v2-periphery/interfaces/IWETH.sol A src/v2-periphery/interfaces/V1/IUniswapV1Exchange.sol A src/v2-periphery/interfaces/V1/IUniswapV1Factory.sol A src/v3-core/interfaces/IERC20Minimal.sol A src/v3-core/interfaces/IUniswapV3Factory.sol A src/v3-core/interfaces/IUniswapV3Pool.sol A src/v3-core/interfaces/IUniswapV3PoolDeployer.sol A src/v3-core/interfaces/callback/IUniswapV3FlashCallback.sol A src/v3-core/interfaces/callback/IUniswapV3MintCallback.sol A src/v3-core/interfaces/callback/IUniswapV3SwapCallback.sol A src/v3-core/interfaces/pool/IUniswapV3PoolActions.sol A src/v3-core/interfaces/pool/IUniswapV3PoolDerivedState.sol A src/v3-core/interfaces/pool/IUniswapV3PoolEvents.sol A src/v3-core/interfaces/pool/IUniswapV3PoolImmutables.sol A src/v3-core/interfaces/pool/IUniswapV3PoolOwnerActions.sol A src/v3-core/interfaces/pool/IUniswapV3PoolState.sol A src/v3-periphery/interfaces/IERC20Metadata.sol A src/v3-periphery/interfaces/IERC721Permit.sol A src/v3-periphery/interfaces/IMulticall.sol A src/v3-periphery/interfaces/INonfungiblePositionManager.sol A src/v3-periphery/interfaces/INonfungibleTokenPositionDescriptor.sol A src/v3-periphery/interfaces/IPeripheryImmutableState.sol A src/v3-periphery/interfaces/IPeripheryPayments.sol A src/v3-periphery/interfaces/IPeripheryPaymentsWithFee.sol A src/v3-periphery/interfaces/IPoolInitializer.sol A src/v3-periphery/interfaces/IQuoter.sol A src/v3-periphery/interfaces/IQuoterV2.sol A src/v3-periphery/interfaces/ISelfPermit.sol A src/v3-periphery/interfaces/ISwapRouter.sol A src/v3-periphery/interfaces/ITickLens.sol A src/v3-periphery/interfaces/IV3Migrator.sol A src/v3-periphery/interfaces/external/IERC1271.sol A src/v3-periphery/interfaces/external/IERC20PermitAllowed.sol A src/v3-periphery/interfaces/external/IWETH9.sol A src/v4-core/interfaces/IExtsload.sol A src/v4-core/interfaces/IExttload.sol A src/v4-core/interfaces/IHooks.sol A src/v4-core/interfaces/IPoolManager.sol A src/v4-core/interfaces/IProtocolFeeController.sol A src/v4-core/interfaces/IProtocolFees.sol A src/v4-core/interfaces/callback/IUnlockCallback.sol A src/v4-core/interfaces/external/IERC20Minimal.sol A src/v4-core/interfaces/external/IERC6909Claims.sol A src/v4-core/libraries/CustomRevert.sol A src/v4-core/libraries/SafeCast.sol A src/v4-core/types/BalanceDelta.sol A src/v4-core/types/BeforeSwapDelta.sol A src/v4-core/types/Currency.sol A src/v4-core/types/PoolId.sol A src/v4-core/types/PoolKey.sol A src/v4-periphery/interfaces/IERC721Permit.sol A src/v4-periphery/interfaces/IMulticall.sol A src/v4-periphery/interfaces/IPositionManager.sol A src/v4-periphery/interfaces/IQuoter.sol A src/v4-periphery/interfaces/IV4Router.sol A src/v4-periphery/interfaces/external/IERC20PermitAllowed.sol A src/v4-periphery/libraries/PathKey.sol --- .../contracts/introspection/IERC165.sol | 25 ++ .../contracts/token/ERC20/IERC20.sol | 78 +++++++ .../contracts/token/ERC721/IERC721.sol | 129 ++++++++++ .../token/ERC721/IERC721Enumerable.sol | 29 +++ .../token/ERC721/IERC721Metadata.sol | 27 +++ .../token/ERC1155/IERC1155Receiver.sol | 60 +++++ .../contracts/token/ERC20/IERC20.sol | 85 +++++++ .../token/ERC721/IERC721Receiver.sol | 30 +++ .../contracts/utils/introspection/IERC165.sol | 28 +++ .../solmate-27545b0/src/tokens/ERC20.sol | 207 ++++++++++++++++ .../solmate-8d910d8/src/tokens/ERC20.sol | 207 ++++++++++++++++ src/permit2/interfaces/IAllowanceTransfer.sol | 165 +++++++++++++ src/permit2/interfaces/IDAIPermit.sol | 24 ++ src/permit2/interfaces/IEIP712.sol | 7 + src/permit2/interfaces/IERC1271.sol | 11 + src/permit2/interfaces/IPermit2.sol | 11 + src/permit2/interfaces/ISignatureTransfer.sol | 134 +++++++++++ src/uniswapx/base/ReactorStructs.sol | 57 +++++ .../interfaces/IProtocolFeeController.sol | 13 ++ src/uniswapx/interfaces/IReactor.sol | 25 ++ src/uniswapx/interfaces/IReactorCallback.sol | 14 ++ .../interfaces/IValidationCallback.sol | 12 + .../interfaces/IRewardsCollector.sol | 12 + .../interfaces/IUniversalRouter.sol | 26 +++ .../external/ICryptoPunksMarket.sol | 12 + .../interfaces/external/IWETH9.sol | 13 ++ src/v2-core/interfaces/IERC20.sol | 18 ++ src/v2-core/interfaces/IUniswapV2Callee.sol | 6 + src/v2-core/interfaces/IUniswapV2ERC20.sol | 24 ++ src/v2-core/interfaces/IUniswapV2Factory.sol | 18 ++ src/v2-core/interfaces/IUniswapV2Pair.sol | 53 +++++ src/v2-periphery/interfaces/IERC20.sol | 18 ++ .../interfaces/IUniswapV2Migrator.sol | 6 + .../interfaces/IUniswapV2Router01.sol | 96 ++++++++ .../interfaces/IUniswapV2Router02.sol | 44 ++++ src/v2-periphery/interfaces/IWETH.sol | 8 + .../interfaces/V1/IUniswapV1Exchange.sol | 10 + .../interfaces/V1/IUniswapV1Factory.sol | 6 + src/v3-core/interfaces/IERC20Minimal.sol | 53 +++++ src/v3-core/interfaces/IUniswapV3Factory.sol | 79 +++++++ src/v3-core/interfaces/IUniswapV3Pool.sol | 24 ++ .../interfaces/IUniswapV3PoolDeployer.sol | 27 +++ .../callback/IUniswapV3FlashCallback.sol | 19 ++ .../callback/IUniswapV3MintCallback.sol | 19 ++ .../callback/IUniswapV3SwapCallback.sol | 22 ++ .../interfaces/pool/IUniswapV3PoolActions.sol | 104 +++++++++ .../pool/IUniswapV3PoolDerivedState.sol | 41 ++++ .../interfaces/pool/IUniswapV3PoolEvents.sol | 122 ++++++++++ .../pool/IUniswapV3PoolImmutables.sol | 36 +++ .../pool/IUniswapV3PoolOwnerActions.sol | 24 ++ .../interfaces/pool/IUniswapV3PoolState.sol | 117 ++++++++++ .../interfaces/IERC20Metadata.sol | 18 ++ src/v3-periphery/interfaces/IERC721Permit.sol | 32 +++ src/v3-periphery/interfaces/IMulticall.sol | 14 ++ .../INonfungiblePositionManager.sol | 179 ++++++++++++++ .../INonfungibleTokenPositionDescriptor.sol | 18 ++ .../interfaces/IPeripheryImmutableState.sol | 13 ++ .../interfaces/IPeripheryPayments.sol | 29 +++ .../interfaces/IPeripheryPaymentsWithFee.sol | 29 +++ .../interfaces/IPoolInitializer.sol | 23 ++ src/v3-periphery/interfaces/IQuoter.sol | 52 +++++ src/v3-periphery/interfaces/IQuoterV2.sol | 99 ++++++++ src/v3-periphery/interfaces/ISelfPermit.sol | 77 ++++++ src/v3-periphery/interfaces/ISwapRouter.sol | 67 ++++++ src/v3-periphery/interfaces/ITickLens.sol | 26 +++ src/v3-periphery/interfaces/IV3Migrator.sol | 34 +++ .../interfaces/external/IERC1271.sol | 17 ++ .../external/IERC20PermitAllowed.sol | 28 +++ .../interfaces/external/IWETH9.sol | 13 ++ src/v4-core/interfaces/IExtsload.sol | 22 ++ src/v4-core/interfaces/IExttload.sol | 16 ++ src/v4-core/interfaces/IHooks.sol | 157 +++++++++++++ src/v4-core/interfaces/IPoolManager.sol | 220 ++++++++++++++++++ .../interfaces/IProtocolFeeController.sol | 15 ++ src/v4-core/interfaces/IProtocolFees.sol | 51 ++++ .../interfaces/callback/IUnlockCallback.sol | 11 + .../interfaces/external/IERC20Minimal.sol | 49 ++++ .../interfaces/external/IERC6909Claims.sol | 67 ++++++ src/v4-core/libraries/CustomRevert.sol | 96 ++++++++ src/v4-core/libraries/SafeCast.sol | 52 +++++ src/v4-core/types/BalanceDelta.sol | 72 ++++++ src/v4-core/types/BeforeSwapDelta.sol | 39 ++++ src/v4-core/types/Currency.sol | 121 ++++++++++ src/v4-core/types/PoolId.sol | 16 ++ src/v4-core/types/PoolKey.sol | 19 ++ src/v4-periphery/interfaces/IERC721Permit.sol | 28 +++ src/v4-periphery/interfaces/IMulticall.sol | 13 ++ .../interfaces/IPositionManager.sol | 22 ++ src/v4-periphery/interfaces/IQuoter.sol | 105 +++++++++ src/v4-periphery/interfaces/IV4Router.sol | 51 ++++ .../external/IERC20PermitAllowed.sol | 28 +++ src/v4-periphery/libraries/PathKey.sol | 29 +++ 92 files changed, 4502 insertions(+) create mode 100644 src/lib-external/oz-v3.4-solc-0.7/contracts/introspection/IERC165.sol create mode 100644 src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC20/IERC20.sol create mode 100644 src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721.sol create mode 100644 src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Enumerable.sol create mode 100644 src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Metadata.sol create mode 100644 src/lib-external/oz-v4.7.0/contracts/token/ERC1155/IERC1155Receiver.sol create mode 100644 src/lib-external/oz-v4.7.0/contracts/token/ERC20/IERC20.sol create mode 100644 src/lib-external/oz-v4.7.0/contracts/token/ERC721/IERC721Receiver.sol create mode 100644 src/lib-external/oz-v4.7.0/contracts/utils/introspection/IERC165.sol create mode 100644 src/lib-external/solmate-27545b0/src/tokens/ERC20.sol create mode 100644 src/lib-external/solmate-8d910d8/src/tokens/ERC20.sol create mode 100644 src/permit2/interfaces/IAllowanceTransfer.sol create mode 100644 src/permit2/interfaces/IDAIPermit.sol create mode 100644 src/permit2/interfaces/IEIP712.sol create mode 100644 src/permit2/interfaces/IERC1271.sol create mode 100644 src/permit2/interfaces/IPermit2.sol create mode 100644 src/permit2/interfaces/ISignatureTransfer.sol create mode 100644 src/uniswapx/base/ReactorStructs.sol create mode 100644 src/uniswapx/interfaces/IProtocolFeeController.sol create mode 100644 src/uniswapx/interfaces/IReactor.sol create mode 100644 src/uniswapx/interfaces/IReactorCallback.sol create mode 100644 src/uniswapx/interfaces/IValidationCallback.sol create mode 100644 src/universal-router/interfaces/IRewardsCollector.sol create mode 100644 src/universal-router/interfaces/IUniversalRouter.sol create mode 100644 src/universal-router/interfaces/external/ICryptoPunksMarket.sol create mode 100644 src/universal-router/interfaces/external/IWETH9.sol create mode 100644 src/v2-core/interfaces/IERC20.sol create mode 100644 src/v2-core/interfaces/IUniswapV2Callee.sol create mode 100644 src/v2-core/interfaces/IUniswapV2ERC20.sol create mode 100644 src/v2-core/interfaces/IUniswapV2Factory.sol create mode 100644 src/v2-core/interfaces/IUniswapV2Pair.sol create mode 100644 src/v2-periphery/interfaces/IERC20.sol create mode 100644 src/v2-periphery/interfaces/IUniswapV2Migrator.sol create mode 100644 src/v2-periphery/interfaces/IUniswapV2Router01.sol create mode 100644 src/v2-periphery/interfaces/IUniswapV2Router02.sol create mode 100644 src/v2-periphery/interfaces/IWETH.sol create mode 100644 src/v2-periphery/interfaces/V1/IUniswapV1Exchange.sol create mode 100644 src/v2-periphery/interfaces/V1/IUniswapV1Factory.sol create mode 100644 src/v3-core/interfaces/IERC20Minimal.sol create mode 100644 src/v3-core/interfaces/IUniswapV3Factory.sol create mode 100644 src/v3-core/interfaces/IUniswapV3Pool.sol create mode 100644 src/v3-core/interfaces/IUniswapV3PoolDeployer.sol create mode 100644 src/v3-core/interfaces/callback/IUniswapV3FlashCallback.sol create mode 100644 src/v3-core/interfaces/callback/IUniswapV3MintCallback.sol create mode 100644 src/v3-core/interfaces/callback/IUniswapV3SwapCallback.sol create mode 100644 src/v3-core/interfaces/pool/IUniswapV3PoolActions.sol create mode 100644 src/v3-core/interfaces/pool/IUniswapV3PoolDerivedState.sol create mode 100644 src/v3-core/interfaces/pool/IUniswapV3PoolEvents.sol create mode 100644 src/v3-core/interfaces/pool/IUniswapV3PoolImmutables.sol create mode 100644 src/v3-core/interfaces/pool/IUniswapV3PoolOwnerActions.sol create mode 100644 src/v3-core/interfaces/pool/IUniswapV3PoolState.sol create mode 100644 src/v3-periphery/interfaces/IERC20Metadata.sol create mode 100644 src/v3-periphery/interfaces/IERC721Permit.sol create mode 100644 src/v3-periphery/interfaces/IMulticall.sol create mode 100644 src/v3-periphery/interfaces/INonfungiblePositionManager.sol create mode 100644 src/v3-periphery/interfaces/INonfungibleTokenPositionDescriptor.sol create mode 100644 src/v3-periphery/interfaces/IPeripheryImmutableState.sol create mode 100644 src/v3-periphery/interfaces/IPeripheryPayments.sol create mode 100644 src/v3-periphery/interfaces/IPeripheryPaymentsWithFee.sol create mode 100644 src/v3-periphery/interfaces/IPoolInitializer.sol create mode 100644 src/v3-periphery/interfaces/IQuoter.sol create mode 100644 src/v3-periphery/interfaces/IQuoterV2.sol create mode 100644 src/v3-periphery/interfaces/ISelfPermit.sol create mode 100644 src/v3-periphery/interfaces/ISwapRouter.sol create mode 100644 src/v3-periphery/interfaces/ITickLens.sol create mode 100644 src/v3-periphery/interfaces/IV3Migrator.sol create mode 100644 src/v3-periphery/interfaces/external/IERC1271.sol create mode 100644 src/v3-periphery/interfaces/external/IERC20PermitAllowed.sol create mode 100644 src/v3-periphery/interfaces/external/IWETH9.sol create mode 100644 src/v4-core/interfaces/IExtsload.sol create mode 100644 src/v4-core/interfaces/IExttload.sol create mode 100644 src/v4-core/interfaces/IHooks.sol create mode 100644 src/v4-core/interfaces/IPoolManager.sol create mode 100644 src/v4-core/interfaces/IProtocolFeeController.sol create mode 100644 src/v4-core/interfaces/IProtocolFees.sol create mode 100644 src/v4-core/interfaces/callback/IUnlockCallback.sol create mode 100644 src/v4-core/interfaces/external/IERC20Minimal.sol create mode 100644 src/v4-core/interfaces/external/IERC6909Claims.sol create mode 100644 src/v4-core/libraries/CustomRevert.sol create mode 100644 src/v4-core/libraries/SafeCast.sol create mode 100644 src/v4-core/types/BalanceDelta.sol create mode 100644 src/v4-core/types/BeforeSwapDelta.sol create mode 100644 src/v4-core/types/Currency.sol create mode 100644 src/v4-core/types/PoolId.sol create mode 100644 src/v4-core/types/PoolKey.sol create mode 100644 src/v4-periphery/interfaces/IERC721Permit.sol create mode 100644 src/v4-periphery/interfaces/IMulticall.sol create mode 100644 src/v4-periphery/interfaces/IPositionManager.sol create mode 100644 src/v4-periphery/interfaces/IQuoter.sol create mode 100644 src/v4-periphery/interfaces/IV4Router.sol create mode 100644 src/v4-periphery/interfaces/external/IERC20PermitAllowed.sol create mode 100644 src/v4-periphery/libraries/PathKey.sol diff --git a/src/lib-external/oz-v3.4-solc-0.7/contracts/introspection/IERC165.sol b/src/lib-external/oz-v3.4-solc-0.7/contracts/introspection/IERC165.sol new file mode 100644 index 0000000..e51edd9 --- /dev/null +++ b/src/lib-external/oz-v3.4-solc-0.7/contracts/introspection/IERC165.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + diff --git a/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC20/IERC20.sol b/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC20/IERC20.sol new file mode 100644 index 0000000..30281ca --- /dev/null +++ b/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC20/IERC20.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + diff --git a/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721.sol b/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721.sol new file mode 100644 index 0000000..5788329 --- /dev/null +++ b/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721.sol @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; +import {IERC165} from "../../introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; +} + diff --git a/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Enumerable.sol b/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Enumerable.sol new file mode 100644 index 0000000..2769d68 --- /dev/null +++ b/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Enumerable.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; +import {IERC721} from "./IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + diff --git a/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Metadata.sol b/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Metadata.sol new file mode 100644 index 0000000..649fda9 --- /dev/null +++ b/src/lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Metadata.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; +import {IERC721} from "./IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + diff --git a/src/lib-external/oz-v4.7.0/contracts/token/ERC1155/IERC1155Receiver.sol b/src/lib-external/oz-v4.7.0/contracts/token/ERC1155/IERC1155Receiver.sol new file mode 100644 index 0000000..ec888fa --- /dev/null +++ b/src/lib-external/oz-v4.7.0/contracts/token/ERC1155/IERC1155Receiver.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) + +pragma solidity ^0.8.0; +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) + +/** + * @dev _Available since v3.1._ + */ +interface IERC1155Receiver is IERC165 { + /** + * @dev Handles the receipt of a single ERC1155 token type. This function is + * called at the end of a `safeTransferFrom` after the balance has been updated. + * + * NOTE: To accept the transfer, this must return + * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + * (i.e. 0xf23a6e61, or its own function selector). + * + * @param operator The address which initiated the transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param id The ID of the token being transferred + * @param value The amount of tokens being transferred + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external returns (bytes4); + + /** + * @dev Handles the receipt of a multiple ERC1155 token types. This function + * is called at the end of a `safeBatchTransferFrom` after the balances have + * been updated. + * + * NOTE: To accept the transfer(s), this must return + * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + * (i.e. 0xbc197c81, or its own function selector). + * + * @param operator The address which initiated the batch transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param ids An array containing ids of each token being transferred (order and length must match values array) + * @param values An array containing amounts of each token being transferred (order and length must match ids array) + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4); +} + diff --git a/src/lib-external/oz-v4.7.0/contracts/token/ERC20/IERC20.sol b/src/lib-external/oz-v4.7.0/contracts/token/ERC20/IERC20.sol new file mode 100644 index 0000000..5673721 --- /dev/null +++ b/src/lib-external/oz-v4.7.0/contracts/token/ERC20/IERC20.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.0; + +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 amount + ) external returns (bool); +} + diff --git a/src/lib-external/oz-v4.7.0/contracts/token/ERC721/IERC721Receiver.sol b/src/lib-external/oz-v4.7.0/contracts/token/ERC721/IERC721Receiver.sol new file mode 100644 index 0000000..4566001 --- /dev/null +++ b/src/lib-external/oz-v4.7.0/contracts/token/ERC721/IERC721Receiver.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) + +pragma solidity ^0.8.0; + +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + diff --git a/src/lib-external/oz-v4.7.0/contracts/utils/introspection/IERC165.sol b/src/lib-external/oz-v4.7.0/contracts/utils/introspection/IERC165.sol new file mode 100644 index 0000000..81a871f --- /dev/null +++ b/src/lib-external/oz-v4.7.0/contracts/utils/introspection/IERC165.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + +pragma solidity ^0.8.0; + +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + diff --git a/src/lib-external/solmate-27545b0/src/tokens/ERC20.sol b/src/lib-external/solmate-27545b0/src/tokens/ERC20.sol new file mode 100644 index 0000000..70a0cd3 --- /dev/null +++ b/src/lib-external/solmate-27545b0/src/tokens/ERC20.sol @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) +/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) +/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. +abstract contract ERC20 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public name; + + string public symbol; + + uint8 public immutable decimals; + + /*////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*////////////////////////////////////////////////////////////// + EIP-2612 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 internal immutable INITIAL_CHAIN_ID; + + bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; + + mapping(address => uint256) public nonces; + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals + ) { + name = _name; + symbol = _symbol; + decimals = _decimals; + + INITIAL_CHAIN_ID = block.chainid; + INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); + } + + /*////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual returns (bool) { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + return true; + } + + function transfer(address to, uint256 amount) public virtual returns (bool) { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + + return true; + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual returns (bool) { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + + return true; + } + + /*////////////////////////////////////////////////////////////// + EIP-2612 LOGIC + //////////////////////////////////////////////////////////////*/ + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); + + // Unchecked because the only math done is incrementing + // the owner's nonce which cannot realistically overflow. + unchecked { + address recoveredAddress = ecrecover( + keccak256( + abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR(), + keccak256( + abi.encode( + keccak256( + "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" + ), + owner, + spender, + value, + nonces[owner]++, + deadline + ) + ) + ) + ), + v, + r, + s + ); + + require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); + + allowance[recoveredAddress][spender] = value; + } + + emit Approval(owner, spender, value); + } + + function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { + return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); + } + + function computeDomainSeparator() internal view virtual returns (bytes32) { + return + keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256(bytes(name)), + keccak256("1"), + block.chainid, + address(this) + ) + ); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 amount) internal virtual { + totalSupply += amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(address(0), to, amount); + } + + function _burn(address from, uint256 amount) internal virtual { + balanceOf[from] -= amount; + + // Cannot underflow because a user's balance + // will never be larger than the total supply. + unchecked { + totalSupply -= amount; + } + + emit Transfer(from, address(0), amount); + } +} + diff --git a/src/lib-external/solmate-8d910d8/src/tokens/ERC20.sol b/src/lib-external/solmate-8d910d8/src/tokens/ERC20.sol new file mode 100644 index 0000000..70a0cd3 --- /dev/null +++ b/src/lib-external/solmate-8d910d8/src/tokens/ERC20.sol @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) +/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) +/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. +abstract contract ERC20 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public name; + + string public symbol; + + uint8 public immutable decimals; + + /*////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*////////////////////////////////////////////////////////////// + EIP-2612 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 internal immutable INITIAL_CHAIN_ID; + + bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; + + mapping(address => uint256) public nonces; + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals + ) { + name = _name; + symbol = _symbol; + decimals = _decimals; + + INITIAL_CHAIN_ID = block.chainid; + INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); + } + + /*////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual returns (bool) { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + return true; + } + + function transfer(address to, uint256 amount) public virtual returns (bool) { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + + return true; + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual returns (bool) { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + + return true; + } + + /*////////////////////////////////////////////////////////////// + EIP-2612 LOGIC + //////////////////////////////////////////////////////////////*/ + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); + + // Unchecked because the only math done is incrementing + // the owner's nonce which cannot realistically overflow. + unchecked { + address recoveredAddress = ecrecover( + keccak256( + abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR(), + keccak256( + abi.encode( + keccak256( + "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" + ), + owner, + spender, + value, + nonces[owner]++, + deadline + ) + ) + ) + ), + v, + r, + s + ); + + require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); + + allowance[recoveredAddress][spender] = value; + } + + emit Approval(owner, spender, value); + } + + function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { + return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); + } + + function computeDomainSeparator() internal view virtual returns (bytes32) { + return + keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256(bytes(name)), + keccak256("1"), + block.chainid, + address(this) + ) + ); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 amount) internal virtual { + totalSupply += amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(address(0), to, amount); + } + + function _burn(address from, uint256 amount) internal virtual { + balanceOf[from] -= amount; + + // Cannot underflow because a user's balance + // will never be larger than the total supply. + unchecked { + totalSupply -= amount; + } + + emit Transfer(from, address(0), amount); + } +} + diff --git a/src/permit2/interfaces/IAllowanceTransfer.sol b/src/permit2/interfaces/IAllowanceTransfer.sol new file mode 100644 index 0000000..bc1963d --- /dev/null +++ b/src/permit2/interfaces/IAllowanceTransfer.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IEIP712} from "./IEIP712.sol"; + +/// @title AllowanceTransfer +/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts +/// @dev Requires user's token approval on the Permit2 contract +interface IAllowanceTransfer is IEIP712 { + /// @notice Thrown when an allowance on a token has expired. + /// @param deadline The timestamp at which the allowed amount is no longer valid + error AllowanceExpired(uint256 deadline); + + /// @notice Thrown when an allowance on a token has been depleted. + /// @param amount The maximum amount allowed + error InsufficientAllowance(uint256 amount); + + /// @notice Thrown when too many nonces are invalidated. + error ExcessiveInvalidation(); + + /// @notice Emits an event when the owner successfully invalidates an ordered nonce. + event NonceInvalidation( + address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce + ); + + /// @notice Emits an event when the owner successfully sets permissions on a token for the spender. + event Approval( + address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration + ); + + /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender. + event Permit( + address indexed owner, + address indexed token, + address indexed spender, + uint160 amount, + uint48 expiration, + uint48 nonce + ); + + /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function. + event Lockdown(address indexed owner, address token, address spender); + + /// @notice The permit data for a token + struct PermitDetails { + // ERC20 token address + address token; + // the maximum amount allowed to spend + uint160 amount; + // timestamp at which a spender's token allowances become invalid + uint48 expiration; + // an incrementing value indexed per owner,token,and spender for each signature + uint48 nonce; + } + + /// @notice The permit message signed for a single token allowance + struct PermitSingle { + // the permit data for a single token alownce + PermitDetails details; + // address permissioned on the allowed tokens + address spender; + // deadline on the permit signature + uint256 sigDeadline; + } + + /// @notice The permit message signed for multiple token allowances + struct PermitBatch { + // the permit data for multiple token allowances + PermitDetails[] details; + // address permissioned on the allowed tokens + address spender; + // deadline on the permit signature + uint256 sigDeadline; + } + + /// @notice The saved permissions + /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message + /// @dev Setting amount to type(uint160).max sets an unlimited approval + struct PackedAllowance { + // amount allowed + uint160 amount; + // permission expiry + uint48 expiration; + // an incrementing value indexed per owner,token,and spender for each signature + uint48 nonce; + } + + /// @notice A token spender pair. + struct TokenSpenderPair { + // the token the spender is approved + address token; + // the spender address + address spender; + } + + /// @notice Details for a token transfer. + struct AllowanceTransferDetails { + // the owner of the token + address from; + // the recipient of the token + address to; + // the amount of the token + uint160 amount; + // the token to be transferred + address token; + } + + /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval. + /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress] + /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals. + function allowance(address user, address token, address spender) + external + view + returns (uint160 amount, uint48 expiration, uint48 nonce); + + /// @notice Approves the spender to use up to amount of the specified token up until the expiration + /// @param token The token to approve + /// @param spender The spender address to approve + /// @param amount The approved amount of the token + /// @param expiration The timestamp at which the approval is no longer valid + /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve + /// @dev Setting amount to type(uint160).max sets an unlimited approval + function approve(address token, address spender, uint160 amount, uint48 expiration) external; + + /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature + /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce + /// @param owner The owner of the tokens being approved + /// @param permitSingle Data signed over by the owner specifying the terms of approval + /// @param signature The owner's signature over the permit data + function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external; + + /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature + /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce + /// @param owner The owner of the tokens being approved + /// @param permitBatch Data signed over by the owner specifying the terms of approval + /// @param signature The owner's signature over the permit data + function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external; + + /// @notice Transfer approved tokens from one address to another + /// @param from The address to transfer from + /// @param to The address of the recipient + /// @param amount The amount of the token to transfer + /// @param token The token address to transfer + /// @dev Requires the from address to have approved at least the desired amount + /// of tokens to msg.sender. + function transferFrom(address from, address to, uint160 amount, address token) external; + + /// @notice Transfer approved tokens in a batch + /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers + /// @dev Requires the from addresses to have approved at least the desired amount + /// of tokens to msg.sender. + function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external; + + /// @notice Enables performing a "lockdown" of the sender's Permit2 identity + /// by batch revoking approvals + /// @param approvals Array of approvals to revoke. + function lockdown(TokenSpenderPair[] calldata approvals) external; + + /// @notice Invalidate nonces for a given (token, spender) pair + /// @param token The token to invalidate nonces for + /// @param spender The spender to invalidate nonces for + /// @param newNonce The new nonce to set. Invalidates all nonces less than it. + /// @dev Can't invalidate more than 2**16 nonces per transaction. + function invalidateNonces(address token, address spender, uint48 newNonce) external; +} diff --git a/src/permit2/interfaces/IDAIPermit.sol b/src/permit2/interfaces/IDAIPermit.sol new file mode 100644 index 0000000..0ed0bf7 --- /dev/null +++ b/src/permit2/interfaces/IDAIPermit.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + + +interface IDAIPermit { + /// @param holder The address of the token owner. + /// @param spender The address of the token spender. + /// @param nonce The owner's nonce, increases at each call to permit. + /// @param expiry The timestamp at which the permit is no longer valid. + /// @param allowed Boolean that sets approval amount, true for type(uint256).max and false for 0. + /// @param v Must produce valid secp256k1 signature from the owner along with r and s. + /// @param r Must produce valid secp256k1 signature from the owner along with v and s. + /// @param s Must produce valid secp256k1 signature from the owner along with r and v. + function permit( + address holder, + address spender, + uint256 nonce, + uint256 expiry, + bool allowed, + uint8 v, + bytes32 r, + bytes32 s + ) external; +} diff --git a/src/permit2/interfaces/IEIP712.sol b/src/permit2/interfaces/IEIP712.sol new file mode 100644 index 0000000..4fe2704 --- /dev/null +++ b/src/permit2/interfaces/IEIP712.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + + +interface IEIP712 { + function DOMAIN_SEPARATOR() external view returns (bytes32); +} diff --git a/src/permit2/interfaces/IERC1271.sol b/src/permit2/interfaces/IERC1271.sol new file mode 100644 index 0000000..cab4875 --- /dev/null +++ b/src/permit2/interfaces/IERC1271.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + + +interface IERC1271 { + /// @dev Should return whether the signature provided is valid for the provided data + /// @param hash Hash of the data to be signed + /// @param signature Signature byte array associated with _data + /// @return magicValue The bytes4 magic value 0x1626ba7e + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); +} diff --git a/src/permit2/interfaces/IPermit2.sol b/src/permit2/interfaces/IPermit2.sol new file mode 100644 index 0000000..3276669 --- /dev/null +++ b/src/permit2/interfaces/IPermit2.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IAllowanceTransfer} from "./IAllowanceTransfer.sol"; +import {ISignatureTransfer} from "./ISignatureTransfer.sol"; + +/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer. +/// @dev Users must approve Permit2 before calling any of the transfer functions. +interface IPermit2 is ISignatureTransfer, IAllowanceTransfer { +// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval. +} diff --git a/src/permit2/interfaces/ISignatureTransfer.sol b/src/permit2/interfaces/ISignatureTransfer.sol new file mode 100644 index 0000000..6fb40e3 --- /dev/null +++ b/src/permit2/interfaces/ISignatureTransfer.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IEIP712} from "./IEIP712.sol"; + +/// @title SignatureTransfer +/// @notice Handles ERC20 token transfers through signature based actions +/// @dev Requires user's token approval on the Permit2 contract +interface ISignatureTransfer is IEIP712 { + /// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount + /// @param maxAmount The maximum amount a spender can request to transfer + error InvalidAmount(uint256 maxAmount); + + /// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred + /// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred + error LengthMismatch(); + + /// @notice Emits an event when the owner successfully invalidates an unordered nonce. + event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask); + + /// @notice The token and amount details for a transfer signed in the permit transfer signature + struct TokenPermissions { + // ERC20 token address + address token; + // the maximum amount that can be spent + uint256 amount; + } + + /// @notice The signed permit message for a single token transfer + struct PermitTransferFrom { + TokenPermissions permitted; + // a unique value for every token owner's signature to prevent signature replays + uint256 nonce; + // deadline on the permit signature + uint256 deadline; + } + + /// @notice Specifies the recipient address and amount for batched transfers. + /// @dev Recipients and amounts correspond to the index of the signed token permissions array. + /// @dev Reverts if the requested amount is greater than the permitted signed amount. + struct SignatureTransferDetails { + // recipient address + address to; + // spender requested amount + uint256 requestedAmount; + } + + /// @notice Used to reconstruct the signed permit message for multiple token transfers + /// @dev Do not need to pass in spender address as it is required that it is msg.sender + /// @dev Note that a user still signs over a spender address + struct PermitBatchTransferFrom { + // the tokens and corresponding amounts permitted for a transfer + TokenPermissions[] permitted; + // a unique value for every token owner's signature to prevent signature replays + uint256 nonce; + // deadline on the permit signature + uint256 deadline; + } + + /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection + /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order + /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce + /// @dev It returns a uint256 bitmap + /// @dev The index, or wordPosition is capped at type(uint248).max + function nonceBitmap(address, uint256) external view returns (uint256); + + /// @notice Transfers a token using a signed permit message + /// @dev Reverts if the requested amount is greater than the permitted signed amount + /// @param permit The permit data signed over by the owner + /// @param owner The owner of the tokens to transfer + /// @param transferDetails The spender's requested transfer details for the permitted token + /// @param signature The signature to verify + function permitTransferFrom( + PermitTransferFrom memory permit, + SignatureTransferDetails calldata transferDetails, + address owner, + bytes calldata signature + ) external; + + /// @notice Transfers a token using a signed permit message + /// @notice Includes extra data provided by the caller to verify signature over + /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition + /// @dev Reverts if the requested amount is greater than the permitted signed amount + /// @param permit The permit data signed over by the owner + /// @param owner The owner of the tokens to transfer + /// @param transferDetails The spender's requested transfer details for the permitted token + /// @param witness Extra data to include when checking the user signature + /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash + /// @param signature The signature to verify + function permitWitnessTransferFrom( + PermitTransferFrom memory permit, + SignatureTransferDetails calldata transferDetails, + address owner, + bytes32 witness, + string calldata witnessTypeString, + bytes calldata signature + ) external; + + /// @notice Transfers multiple tokens using a signed permit message + /// @param permit The permit data signed over by the owner + /// @param owner The owner of the tokens to transfer + /// @param transferDetails Specifies the recipient and requested amount for the token transfer + /// @param signature The signature to verify + function permitTransferFrom( + PermitBatchTransferFrom memory permit, + SignatureTransferDetails[] calldata transferDetails, + address owner, + bytes calldata signature + ) external; + + /// @notice Transfers multiple tokens using a signed permit message + /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition + /// @notice Includes extra data provided by the caller to verify signature over + /// @param permit The permit data signed over by the owner + /// @param owner The owner of the tokens to transfer + /// @param transferDetails Specifies the recipient and requested amount for the token transfer + /// @param witness Extra data to include when checking the user signature + /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash + /// @param signature The signature to verify + function permitWitnessTransferFrom( + PermitBatchTransferFrom memory permit, + SignatureTransferDetails[] calldata transferDetails, + address owner, + bytes32 witness, + string calldata witnessTypeString, + bytes calldata signature + ) external; + + /// @notice Invalidates the bits specified in mask for the bitmap at the word position + /// @dev The wordPos is maxed at type(uint248).max + /// @param wordPos A number to index the nonceBitmap at + /// @param mask A bitmap masked against msg.sender's current bitmap at the word position + function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external; +} diff --git a/src/uniswapx/base/ReactorStructs.sol b/src/uniswapx/base/ReactorStructs.sol new file mode 100644 index 0000000..57c01cd --- /dev/null +++ b/src/uniswapx/base/ReactorStructs.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +import {ERC20} from "../../lib-external/solmate-27545b0/src/tokens/ERC20.sol"; +import {IReactor} from "../interfaces/IReactor.sol"; +import {IValidationCallback} from "../interfaces/IValidationCallback.sol"; + +/// @dev generic order information +/// should be included as the first field in any concrete order types +struct OrderInfo { + // The address of the reactor that this order is targeting + // Note that this must be included in every order so the swapper + // signature commits to the specific reactor that they trust to fill their order properly + IReactor reactor; + // The address of the user which created the order + // Note that this must be included so that order hashes are unique by swapper + address swapper; + // The nonce of the order, allowing for signature replay protection and cancellation + uint256 nonce; + // The timestamp after which this order is no longer valid + uint256 deadline; + // Custom validation contract + IValidationCallback additionalValidationContract; + // Encoded validation params for additionalValidationContract + bytes additionalValidationData; +} + +/// @dev tokens that need to be sent from the swapper in order to satisfy an order +struct InputToken { + ERC20 token; + uint256 amount; + // Needed for dutch decaying inputs + uint256 maxAmount; +} + +/// @dev tokens that need to be received by the recipient in order to satisfy an order +struct OutputToken { + address token; + uint256 amount; + address recipient; +} + +/// @dev generic concrete order that specifies exact tokens which need to be sent and received +struct ResolvedOrder { + OrderInfo info; + InputToken input; + OutputToken[] outputs; + bytes sig; + bytes32 hash; +} + +/// @dev external struct including a generic encoded order and swapper signature +/// The order bytes will be parsed and mapped to a ResolvedOrder in the concrete reactor contract +struct SignedOrder { + bytes order; + bytes sig; +} + diff --git a/src/uniswapx/interfaces/IProtocolFeeController.sol b/src/uniswapx/interfaces/IProtocolFeeController.sol new file mode 100644 index 0000000..e4fd598 --- /dev/null +++ b/src/uniswapx/interfaces/IProtocolFeeController.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + +import {OutputToken} from "../base/ReactorStructs.sol"; +import {ResolvedOrder} from "../base/ReactorStructs.sol"; + +/// @notice Interface for getting fee outputs +interface IProtocolFeeController { + /// @notice Get fee outputs for the given orders + /// @param order The orders to get fee outputs for + /// @return List of fee outputs to append for each provided order + function getFeeOutputs(ResolvedOrder memory order) external view returns (OutputToken[] memory); +} diff --git a/src/uniswapx/interfaces/IReactor.sol b/src/uniswapx/interfaces/IReactor.sol new file mode 100644 index 0000000..0ad7d17 --- /dev/null +++ b/src/uniswapx/interfaces/IReactor.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + +import {SignedOrder} from "../base/ReactorStructs.sol"; + +/// @notice Interface for order execution reactors +interface IReactor { + /// @notice Execute a single order + /// @param order The order definition and valid signature to execute + function execute(SignedOrder calldata order) external payable; + + /// @notice Execute a single order using the given callback data + /// @param order The order definition and valid signature to execute + /// @param callbackData The callbackData to pass to the callback + function executeWithCallback(SignedOrder calldata order, bytes calldata callbackData) external payable; + + /// @notice Execute the given orders at once + /// @param orders The order definitions and valid signatures to execute + function executeBatch(SignedOrder[] calldata orders) external payable; + + /// @notice Execute the given orders at once using a callback with the given callback data + /// @param orders The order definitions and valid signatures to execute + /// @param callbackData The callbackData to pass to the callback + function executeBatchWithCallback(SignedOrder[] calldata orders, bytes calldata callbackData) external payable; +} diff --git a/src/uniswapx/interfaces/IReactorCallback.sol b/src/uniswapx/interfaces/IReactorCallback.sol new file mode 100644 index 0000000..b83aa1d --- /dev/null +++ b/src/uniswapx/interfaces/IReactorCallback.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + +import {ResolvedOrder} from "../base/ReactorStructs.sol"; +import {IReactor} from "./IReactor.sol"; + +/// @notice Callback for executing orders through a reactor. +interface IReactorCallback { + /// @notice Called by the reactor during the execution of an order + /// @param resolvedOrders Has inputs and outputs + /// @param callbackData The callbackData specified for an order execution + /// @dev Must have approved each token and amount in outputs to the msg.sender + function reactorCallback(ResolvedOrder[] memory resolvedOrders, bytes memory callbackData) external; +} diff --git a/src/uniswapx/interfaces/IValidationCallback.sol b/src/uniswapx/interfaces/IValidationCallback.sol new file mode 100644 index 0000000..0eb6dfa --- /dev/null +++ b/src/uniswapx/interfaces/IValidationCallback.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + +import {ResolvedOrder} from "../base/ReactorStructs.sol"; + +/// @notice Callback to validate an order +interface IValidationCallback { + /// @notice Called by the reactor for custom validation of an order. Will revert if validation fails + /// @param filler The filler of the order + /// @param resolvedOrder The resolved order to fill + function validate(address filler, ResolvedOrder calldata resolvedOrder) external view; +} diff --git a/src/universal-router/interfaces/IRewardsCollector.sol b/src/universal-router/interfaces/IRewardsCollector.sol new file mode 100644 index 0000000..884449d --- /dev/null +++ b/src/universal-router/interfaces/IRewardsCollector.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.6.2; + + +/// @title LooksRare Rewards Collector +/// @notice Implements a permissionless call to fetch LooksRare rewards earned by Universal Router users +/// and transfers them to an external rewards distributor contract +interface IRewardsCollector { + /// @notice Fetches users' LooksRare rewards and sends them to the distributor contract + /// @param looksRareClaim The data required by LooksRare to claim reward tokens + function collectRewards(bytes calldata looksRareClaim) external; +} diff --git a/src/universal-router/interfaces/IUniversalRouter.sol b/src/universal-router/interfaces/IUniversalRouter.sol new file mode 100644 index 0000000..bd769a1 --- /dev/null +++ b/src/universal-router/interfaces/IUniversalRouter.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.6.2; + +import {IERC721Receiver} from "../../lib-external/oz-v4.7.0/contracts/token/ERC721/IERC721Receiver.sol"; +import {IERC1155Receiver} from "../../lib-external/oz-v4.7.0/contracts/token/ERC1155/IERC1155Receiver.sol"; +import {IRewardsCollector} from "./IRewardsCollector.sol"; + +interface IUniversalRouter is IRewardsCollector, IERC721Receiver, IERC1155Receiver { + /// @notice Thrown when a required command has failed + error ExecutionFailed(uint256 commandIndex, bytes message); + + /// @notice Thrown when attempting to send ETH directly to the contract + error ETHNotAccepted(); + + /// @notice Thrown when executing commands with an expired deadline + error TransactionDeadlinePassed(); + + /// @notice Thrown when attempting to execute commands and an incorrect number of inputs are provided + error LengthMismatch(); + + /// @notice Executes encoded commands along with provided inputs. Reverts if deadline has expired. + /// @param commands A set of concatenated commands, each 1 byte in length + /// @param inputs An array of byte strings containing abi encoded inputs for each command + /// @param deadline The deadline by which the transaction must be executed + function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external payable; +} diff --git a/src/universal-router/interfaces/external/ICryptoPunksMarket.sol b/src/universal-router/interfaces/external/ICryptoPunksMarket.sol new file mode 100644 index 0000000..f264ce3 --- /dev/null +++ b/src/universal-router/interfaces/external/ICryptoPunksMarket.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.6.2; + + +/// @title Interface for CryptoPunksMarket +interface ICryptoPunksMarket { + /// @notice Buy a cryptopunk + function buyPunk(uint256 punkIndex) external payable; + + /// @notice Transfer a cryptopunk to another address + function transferPunk(address to, uint256 punkIndex) external; +} diff --git a/src/universal-router/interfaces/external/IWETH9.sol b/src/universal-router/interfaces/external/IWETH9.sol new file mode 100644 index 0000000..bff09b0 --- /dev/null +++ b/src/universal-router/interfaces/external/IWETH9.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.6.2; + +import {IERC20} from "../../../lib-external/oz-v4.7.0/contracts/token/ERC20/IERC20.sol"; + +/// @title Interface for WETH9 +interface IWETH9 is IERC20 { + /// @notice Deposit ether to get wrapped ether + function deposit() external payable; + + /// @notice Withdraw wrapped ether to get ether + function withdraw(uint256) external; +} diff --git a/src/v2-core/interfaces/IERC20.sol b/src/v2-core/interfaces/IERC20.sol new file mode 100644 index 0000000..62330fa --- /dev/null +++ b/src/v2-core/interfaces/IERC20.sol @@ -0,0 +1,18 @@ +pragma solidity >=0.5.0; + + +interface IERC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); +} diff --git a/src/v2-core/interfaces/IUniswapV2Callee.sol b/src/v2-core/interfaces/IUniswapV2Callee.sol new file mode 100644 index 0000000..6841eae --- /dev/null +++ b/src/v2-core/interfaces/IUniswapV2Callee.sol @@ -0,0 +1,6 @@ +pragma solidity >=0.5.0; + + +interface IUniswapV2Callee { + function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; +} diff --git a/src/v2-core/interfaces/IUniswapV2ERC20.sol b/src/v2-core/interfaces/IUniswapV2ERC20.sol new file mode 100644 index 0000000..0c772bf --- /dev/null +++ b/src/v2-core/interfaces/IUniswapV2ERC20.sol @@ -0,0 +1,24 @@ +pragma solidity >=0.5.0; + + +interface IUniswapV2ERC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + function symbol() external pure returns (string memory); + function decimals() external pure returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function PERMIT_TYPEHASH() external pure returns (bytes32); + function nonces(address owner) external view returns (uint); + + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; +} diff --git a/src/v2-core/interfaces/IUniswapV2Factory.sol b/src/v2-core/interfaces/IUniswapV2Factory.sol new file mode 100644 index 0000000..23bb61d --- /dev/null +++ b/src/v2-core/interfaces/IUniswapV2Factory.sol @@ -0,0 +1,18 @@ +pragma solidity >=0.5.0; + + +interface IUniswapV2Factory { + event PairCreated(address indexed token0, address indexed token1, address pair, uint); + + function feeTo() external view returns (address); + function feeToSetter() external view returns (address); + + function getPair(address tokenA, address tokenB) external view returns (address pair); + function allPairs(uint) external view returns (address pair); + function allPairsLength() external view returns (uint); + + function createPair(address tokenA, address tokenB) external returns (address pair); + + function setFeeTo(address) external; + function setFeeToSetter(address) external; +} diff --git a/src/v2-core/interfaces/IUniswapV2Pair.sol b/src/v2-core/interfaces/IUniswapV2Pair.sol new file mode 100644 index 0000000..67fd3dd --- /dev/null +++ b/src/v2-core/interfaces/IUniswapV2Pair.sol @@ -0,0 +1,53 @@ +pragma solidity >=0.5.0; + + +interface IUniswapV2Pair { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + function symbol() external pure returns (string memory); + function decimals() external pure returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function PERMIT_TYPEHASH() external pure returns (bytes32); + function nonces(address owner) external view returns (uint); + + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; + + event Mint(address indexed sender, uint amount0, uint amount1); + event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); + event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint); + function factory() external view returns (address); + function token0() external view returns (address); + function token1() external view returns (address); + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + function price0CumulativeLast() external view returns (uint); + function price1CumulativeLast() external view returns (uint); + function kLast() external view returns (uint); + + function mint(address to) external returns (uint liquidity); + function burn(address to) external returns (uint amount0, uint amount1); + function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; + function skim(address to) external; + function sync() external; + + function initialize(address, address) external; +} diff --git a/src/v2-periphery/interfaces/IERC20.sol b/src/v2-periphery/interfaces/IERC20.sol new file mode 100644 index 0000000..62330fa --- /dev/null +++ b/src/v2-periphery/interfaces/IERC20.sol @@ -0,0 +1,18 @@ +pragma solidity >=0.5.0; + + +interface IERC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); +} diff --git a/src/v2-periphery/interfaces/IUniswapV2Migrator.sol b/src/v2-periphery/interfaces/IUniswapV2Migrator.sol new file mode 100644 index 0000000..059a30a --- /dev/null +++ b/src/v2-periphery/interfaces/IUniswapV2Migrator.sol @@ -0,0 +1,6 @@ +pragma solidity >=0.5.0; + + +interface IUniswapV2Migrator { + function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external; +} diff --git a/src/v2-periphery/interfaces/IUniswapV2Router01.sol b/src/v2-periphery/interfaces/IUniswapV2Router01.sol new file mode 100644 index 0000000..911546b --- /dev/null +++ b/src/v2-periphery/interfaces/IUniswapV2Router01.sol @@ -0,0 +1,96 @@ +pragma solidity >=0.6.2; + + +interface IUniswapV2Router01 { + function factory() external pure returns (address); + function WETH() external pure returns (address); + + function addLiquidity( + address tokenA, + address tokenB, + uint amountADesired, + uint amountBDesired, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB, uint liquidity); + function addLiquidityETH( + address token, + uint amountTokenDesired, + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline + ) external payable returns (uint amountToken, uint amountETH, uint liquidity); + function removeLiquidity( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB); + function removeLiquidityETH( + address token, + uint liquidity, + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline + ) external returns (uint amountToken, uint amountETH); + function removeLiquidityWithPermit( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountA, uint amountB); + function removeLiquidityETHWithPermit( + address token, + uint liquidity, + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountToken, uint amountETH); + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapTokensForExactTokens( + uint amountOut, + uint amountInMax, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts); + function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) + external + returns (uint[] memory amounts); + function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) + external + returns (uint[] memory amounts); + function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) + external + payable + returns (uint[] memory amounts); + + function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); + function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); + function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); + function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); +} diff --git a/src/v2-periphery/interfaces/IUniswapV2Router02.sol b/src/v2-periphery/interfaces/IUniswapV2Router02.sol new file mode 100644 index 0000000..c62dba0 --- /dev/null +++ b/src/v2-periphery/interfaces/IUniswapV2Router02.sol @@ -0,0 +1,44 @@ +pragma solidity >=0.6.2; + +import {IUniswapV2Router01} from "./IUniswapV2Router01.sol"; + +interface IUniswapV2Router02 is IUniswapV2Router01 { + function removeLiquidityETHSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline + ) external returns (uint amountETH); + function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( + address token, + uint liquidity, + uint amountTokenMin, + uint amountETHMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountETH); + + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; + function swapExactETHForTokensSupportingFeeOnTransferTokens( + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external payable; + function swapExactTokensForETHSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; +} diff --git a/src/v2-periphery/interfaces/IWETH.sol b/src/v2-periphery/interfaces/IWETH.sol new file mode 100644 index 0000000..250b7a5 --- /dev/null +++ b/src/v2-periphery/interfaces/IWETH.sol @@ -0,0 +1,8 @@ +pragma solidity >=0.5.0; + + +interface IWETH { + function deposit() external payable; + function transfer(address to, uint value) external returns (bool); + function withdraw(uint) external; +} diff --git a/src/v2-periphery/interfaces/V1/IUniswapV1Exchange.sol b/src/v2-periphery/interfaces/V1/IUniswapV1Exchange.sol new file mode 100644 index 0000000..413d4fa --- /dev/null +++ b/src/v2-periphery/interfaces/V1/IUniswapV1Exchange.sol @@ -0,0 +1,10 @@ +pragma solidity >=0.5.0; + + +interface IUniswapV1Exchange { + function balanceOf(address owner) external view returns (uint); + function transferFrom(address from, address to, uint value) external returns (bool); + function removeLiquidity(uint, uint, uint, uint) external returns (uint, uint); + function tokenToEthSwapInput(uint, uint, uint) external returns (uint); + function ethToTokenSwapInput(uint, uint) external payable returns (uint); +} diff --git a/src/v2-periphery/interfaces/V1/IUniswapV1Factory.sol b/src/v2-periphery/interfaces/V1/IUniswapV1Factory.sol new file mode 100644 index 0000000..4ddcfd1 --- /dev/null +++ b/src/v2-periphery/interfaces/V1/IUniswapV1Factory.sol @@ -0,0 +1,6 @@ +pragma solidity >=0.5.0; + + +interface IUniswapV1Factory { + function getExchange(address) external view returns (address); +} diff --git a/src/v3-core/interfaces/IERC20Minimal.sol b/src/v3-core/interfaces/IERC20Minimal.sol new file mode 100644 index 0000000..b726bf0 --- /dev/null +++ b/src/v3-core/interfaces/IERC20Minimal.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Minimal ERC20 interface for Uniswap +/// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3 +interface IERC20Minimal { + /// @notice Returns the balance of a token + /// @param account The account for which to look up the number of tokens it has, i.e. its balance + /// @return The number of tokens held by the account + function balanceOf(address account) external view returns (uint256); + + /// @notice Transfers the amount of token from the `msg.sender` to the recipient + /// @param recipient The account that will receive the amount transferred + /// @param amount The number of tokens to send from the sender to the recipient + /// @return Returns true for a successful transfer, false for an unsuccessful transfer + function transfer(address recipient, uint256 amount) external returns (bool); + + /// @notice Returns the current allowance given to a spender by an owner + /// @param owner The account of the token owner + /// @param spender The account of the token spender + /// @return The current allowance granted by `owner` to `spender` + function allowance(address owner, address spender) external view returns (uint256); + + /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount` + /// @param spender The account which will be allowed to spend a given amount of the owners tokens + /// @param amount The amount of tokens allowed to be used by `spender` + /// @return Returns true for a successful approval, false for unsuccessful + function approve(address spender, uint256 amount) external returns (bool); + + /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender` + /// @param sender The account from which the transfer will be initiated + /// @param recipient The recipient of the transfer + /// @param amount The amount of the transfer + /// @return Returns true for a successful transfer, false for unsuccessful + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool); + + /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`. + /// @param from The account from which the tokens were sent, i.e. the balance decreased + /// @param to The account to which the tokens were sent, i.e. the balance increased + /// @param value The amount of tokens that were transferred + event Transfer(address indexed from, address indexed to, uint256 value); + + /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes. + /// @param owner The account that approved spending of its tokens + /// @param spender The account for which the spending allowance was modified + /// @param value The new allowance from the owner to the spender + event Approval(address indexed owner, address indexed spender, uint256 value); +} diff --git a/src/v3-core/interfaces/IUniswapV3Factory.sol b/src/v3-core/interfaces/IUniswapV3Factory.sol new file mode 100644 index 0000000..0e38bba --- /dev/null +++ b/src/v3-core/interfaces/IUniswapV3Factory.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title The interface for the Uniswap V3 Factory +/// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees +interface IUniswapV3Factory { + /// @notice Emitted when the owner of the factory is changed + /// @param oldOwner The owner before the owner was changed + /// @param newOwner The owner after the owner was changed + event OwnerChanged(address indexed oldOwner, address indexed newOwner); + + /// @notice Emitted when a pool is created + /// @param token0 The first token of the pool by address sort order + /// @param token1 The second token of the pool by address sort order + /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip + /// @param tickSpacing The minimum number of ticks between initialized ticks + /// @param pool The address of the created pool + event PoolCreated( + address indexed token0, + address indexed token1, + uint24 indexed fee, + int24 tickSpacing, + address pool + ); + + /// @notice Emitted when a new fee amount is enabled for pool creation via the factory + /// @param fee The enabled fee, denominated in hundredths of a bip + /// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee + event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing); + + /// @notice Returns the current owner of the factory + /// @dev Can be changed by the current owner via setOwner + /// @return The address of the factory owner + function owner() external view returns (address); + + /// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled + /// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context + /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee + /// @return The tick spacing + function feeAmountTickSpacing(uint24 fee) external view returns (int24); + + /// @notice Returns the pool address for a given pair of tokens and a fee, 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 fee The fee collected upon every swap in the pool, denominated in hundredths of a bip + /// @return pool The pool address + function getPool( + address tokenA, + address tokenB, + uint24 fee + ) external view returns (address pool); + + /// @notice Creates a pool for the given two tokens and fee + /// @param tokenA One of the two tokens in the desired pool + /// @param tokenB The other of the two tokens in the desired pool + /// @param fee The desired fee for the pool + /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved + /// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments + /// are invalid. + /// @return pool The address of the newly created pool + function createPool( + address tokenA, + address tokenB, + uint24 fee + ) external returns (address pool); + + /// @notice Updates the owner of the factory + /// @dev Must be called by the current owner + /// @param _owner The new owner of the factory + function setOwner(address _owner) external; + + /// @notice Enables a fee amount with the given tickSpacing + /// @dev Fee amounts may never be removed once enabled + /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6) + /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount + function enableFeeAmount(uint24 fee, int24 tickSpacing) external; +} diff --git a/src/v3-core/interfaces/IUniswapV3Pool.sol b/src/v3-core/interfaces/IUniswapV3Pool.sol new file mode 100644 index 0000000..0b0a376 --- /dev/null +++ b/src/v3-core/interfaces/IUniswapV3Pool.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +import {IUniswapV3PoolActions} from "./pool/IUniswapV3PoolActions.sol"; +import {IUniswapV3PoolDerivedState} from "./pool/IUniswapV3PoolDerivedState.sol"; +import {IUniswapV3PoolEvents} from "./pool/IUniswapV3PoolEvents.sol"; +import {IUniswapV3PoolImmutables} from "./pool/IUniswapV3PoolImmutables.sol"; +import {IUniswapV3PoolOwnerActions} from "./pool/IUniswapV3PoolOwnerActions.sol"; +import {IUniswapV3PoolState} from "./pool/IUniswapV3PoolState.sol"; + +/// @title The interface for a Uniswap V3 Pool +/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform +/// to the ERC20 specification +/// @dev The pool interface is broken up into many smaller pieces +interface IUniswapV3Pool is + IUniswapV3PoolImmutables, + IUniswapV3PoolState, + IUniswapV3PoolDerivedState, + IUniswapV3PoolActions, + IUniswapV3PoolOwnerActions, + IUniswapV3PoolEvents +{ + +} diff --git a/src/v3-core/interfaces/IUniswapV3PoolDeployer.sol b/src/v3-core/interfaces/IUniswapV3PoolDeployer.sol new file mode 100644 index 0000000..82ccc4e --- /dev/null +++ b/src/v3-core/interfaces/IUniswapV3PoolDeployer.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title An interface for a contract that is capable of deploying Uniswap V3 Pools +/// @notice A contract that constructs a pool must implement this to pass arguments to the pool +/// @dev This is used to avoid having constructor arguments in the pool contract, which results in the init code hash +/// of the pool being constant allowing the CREATE2 address of the pool to be cheaply computed on-chain +interface IUniswapV3PoolDeployer { + /// @notice Get the parameters to be used in constructing the pool, set transiently during pool creation. + /// @dev Called by the pool constructor to fetch the parameters of the pool + /// Returns factory The factory address + /// Returns token0 The first token of the pool by address sort order + /// Returns token1 The second token of the pool by address sort order + /// Returns fee The fee collected upon every swap in the pool, denominated in hundredths of a bip + /// Returns tickSpacing The minimum number of ticks between initialized ticks + function parameters() + external + view + returns ( + address factory, + address token0, + address token1, + uint24 fee, + int24 tickSpacing + ); +} diff --git a/src/v3-core/interfaces/callback/IUniswapV3FlashCallback.sol b/src/v3-core/interfaces/callback/IUniswapV3FlashCallback.sol new file mode 100644 index 0000000..8ff1883 --- /dev/null +++ b/src/v3-core/interfaces/callback/IUniswapV3FlashCallback.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Callback for IUniswapV3PoolActions#flash +/// @notice Any contract that calls IUniswapV3PoolActions#flash must implement this interface +interface IUniswapV3FlashCallback { + /// @notice Called to `msg.sender` after transferring to the recipient from IUniswapV3Pool#flash. + /// @dev In the implementation you must repay the pool the tokens sent by flash plus the computed fee amounts. + /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. + /// @param fee0 The fee amount in token0 due to the pool by the end of the flash + /// @param fee1 The fee amount in token1 due to the pool by the end of the flash + /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#flash call + function uniswapV3FlashCallback( + uint256 fee0, + uint256 fee1, + bytes calldata data + ) external; +} diff --git a/src/v3-core/interfaces/callback/IUniswapV3MintCallback.sol b/src/v3-core/interfaces/callback/IUniswapV3MintCallback.sol new file mode 100644 index 0000000..7f8e1c7 --- /dev/null +++ b/src/v3-core/interfaces/callback/IUniswapV3MintCallback.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Callback for IUniswapV3PoolActions#mint +/// @notice Any contract that calls IUniswapV3PoolActions#mint must implement this interface +interface IUniswapV3MintCallback { + /// @notice Called to `msg.sender` after minting liquidity to a position from IUniswapV3Pool#mint. + /// @dev In the implementation you must pay the pool tokens owed for the minted liquidity. + /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. + /// @param amount0Owed The amount of token0 due to the pool for the minted liquidity + /// @param amount1Owed The amount of token1 due to the pool for the minted liquidity + /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#mint call + function uniswapV3MintCallback( + uint256 amount0Owed, + uint256 amount1Owed, + bytes calldata data + ) external; +} diff --git a/src/v3-core/interfaces/callback/IUniswapV3SwapCallback.sol b/src/v3-core/interfaces/callback/IUniswapV3SwapCallback.sol new file mode 100644 index 0000000..3c793dd --- /dev/null +++ b/src/v3-core/interfaces/callback/IUniswapV3SwapCallback.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Callback for IUniswapV3PoolActions#swap +/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface +interface IUniswapV3SwapCallback { + /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. + /// @dev In the implementation you must pay the pool tokens owed for the swap. + /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. + /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. + /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by + /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. + /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by + /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. + /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata data + ) external; +} diff --git a/src/v3-core/interfaces/pool/IUniswapV3PoolActions.sol b/src/v3-core/interfaces/pool/IUniswapV3PoolActions.sol new file mode 100644 index 0000000..208d4ea --- /dev/null +++ b/src/v3-core/interfaces/pool/IUniswapV3PoolActions.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Permissionless pool actions +/// @notice Contains pool methods that can be called by anyone +interface IUniswapV3PoolActions { + /// @notice Sets the initial price for the pool + /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value + /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96 + function initialize(uint160 sqrtPriceX96) external; + + /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position + /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback + /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends + /// on tickLower, tickUpper, the amount of liquidity, and the current price. + /// @param recipient The address for which the liquidity will be created + /// @param tickLower The lower tick of the position in which to add liquidity + /// @param tickUpper The upper tick of the position in which to add liquidity + /// @param amount The amount of liquidity to mint + /// @param data Any data that should be passed through to the callback + /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback + /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback + function mint( + address recipient, + int24 tickLower, + int24 tickUpper, + uint128 amount, + bytes calldata data + ) external returns (uint256 amount0, uint256 amount1); + + /// @notice Collects tokens owed to a position + /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity. + /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or + /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the + /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity. + /// @param recipient The address which should receive the fees collected + /// @param tickLower The lower tick of the position for which to collect fees + /// @param tickUpper The upper tick of the position for which to collect fees + /// @param amount0Requested How much token0 should be withdrawn from the fees owed + /// @param amount1Requested How much token1 should be withdrawn from the fees owed + /// @return amount0 The amount of fees collected in token0 + /// @return amount1 The amount of fees collected in token1 + function collect( + address recipient, + int24 tickLower, + int24 tickUpper, + uint128 amount0Requested, + uint128 amount1Requested + ) external returns (uint128 amount0, uint128 amount1); + + /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position + /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0 + /// @dev Fees must be collected separately via a call to #collect + /// @param tickLower The lower tick of the position for which to burn liquidity + /// @param tickUpper The upper tick of the position for which to burn liquidity + /// @param amount How much liquidity to burn + /// @return amount0 The amount of token0 sent to the recipient + /// @return amount1 The amount of token1 sent to the recipient + function burn( + int24 tickLower, + int24 tickUpper, + uint128 amount + ) external returns (uint256 amount0, uint256 amount1); + + /// @notice Swap token0 for token1, or token1 for token0 + /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback + /// @param recipient The address to receive the output of the swap + /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0 + /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) + /// @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 + /// @param data Any data to be passed through to the callback + /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive + /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive + function swap( + address recipient, + bool zeroForOne, + int256 amountSpecified, + uint160 sqrtPriceLimitX96, + bytes calldata data + ) external returns (int256 amount0, int256 amount1); + + /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback + /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback + /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling + /// with 0 amount{0,1} and sending the donation amount(s) from the callback + /// @param recipient The address which will receive the token0 and token1 amounts + /// @param amount0 The amount of token0 to send + /// @param amount1 The amount of token1 to send + /// @param data Any data to be passed through to the callback + function flash( + address recipient, + uint256 amount0, + uint256 amount1, + bytes calldata data + ) external; + + /// @notice Increase the maximum number of price and liquidity observations that this pool will store + /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to + /// the input observationCardinalityNext. + /// @param observationCardinalityNext The desired minimum number of observations for the pool to store + function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external; +} diff --git a/src/v3-core/interfaces/pool/IUniswapV3PoolDerivedState.sol b/src/v3-core/interfaces/pool/IUniswapV3PoolDerivedState.sol new file mode 100644 index 0000000..1a0afca --- /dev/null +++ b/src/v3-core/interfaces/pool/IUniswapV3PoolDerivedState.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Pool state that is not stored +/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the +/// blockchain. The functions here may have variable gas costs. +interface IUniswapV3PoolDerivedState { + /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp + /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing + /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick, + /// you must call it with secondsAgos = [3600, 0]. + /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in + /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio. + /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned + /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp + /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block + /// timestamp + function observe(uint32[] calldata secondsAgos) + external + view + returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s); + + /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range + /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed. + /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first + /// snapshot is taken and the second snapshot is taken. + /// @param tickLower The lower tick of the range + /// @param tickUpper The upper tick of the range + /// @return tickCumulativeInside The snapshot of the tick accumulator for the range + /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range + /// @return secondsInside The snapshot of seconds per liquidity for the range + function snapshotCumulativesInside(int24 tickLower, int24 tickUpper) + external + view + returns ( + int56 tickCumulativeInside, + uint160 secondsPerLiquidityInsideX128, + uint32 secondsInside + ); +} diff --git a/src/v3-core/interfaces/pool/IUniswapV3PoolEvents.sol b/src/v3-core/interfaces/pool/IUniswapV3PoolEvents.sol new file mode 100644 index 0000000..47b5a6e --- /dev/null +++ b/src/v3-core/interfaces/pool/IUniswapV3PoolEvents.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Events emitted by a pool +/// @notice Contains all events emitted by the pool +interface IUniswapV3PoolEvents { + /// @notice Emitted exactly once by a pool when #initialize is first called on the pool + /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize + /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96 + /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool + event Initialize(uint160 sqrtPriceX96, int24 tick); + + /// @notice Emitted when liquidity is minted for a given position + /// @param sender The address that minted the liquidity + /// @param owner The owner of the position and recipient of any minted liquidity + /// @param tickLower The lower tick of the position + /// @param tickUpper The upper tick of the position + /// @param amount The amount of liquidity minted to the position range + /// @param amount0 How much token0 was required for the minted liquidity + /// @param amount1 How much token1 was required for the minted liquidity + event Mint( + address sender, + address indexed owner, + int24 indexed tickLower, + int24 indexed tickUpper, + uint128 amount, + uint256 amount0, + uint256 amount1 + ); + + /// @notice Emitted when fees are collected by the owner of a position + /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees + /// @param owner The owner of the position for which fees are collected + /// @param tickLower The lower tick of the position + /// @param tickUpper The upper tick of the position + /// @param amount0 The amount of token0 fees collected + /// @param amount1 The amount of token1 fees collected + event Collect( + address indexed owner, + address recipient, + int24 indexed tickLower, + int24 indexed tickUpper, + uint128 amount0, + uint128 amount1 + ); + + /// @notice Emitted when a position's liquidity is removed + /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect + /// @param owner The owner of the position for which liquidity is removed + /// @param tickLower The lower tick of the position + /// @param tickUpper The upper tick of the position + /// @param amount The amount of liquidity to remove + /// @param amount0 The amount of token0 withdrawn + /// @param amount1 The amount of token1 withdrawn + event Burn( + address indexed owner, + int24 indexed tickLower, + int24 indexed tickUpper, + uint128 amount, + uint256 amount0, + uint256 amount1 + ); + + /// @notice Emitted by the pool for any swaps between token0 and token1 + /// @param sender The address that initiated the swap call, and that received the callback + /// @param recipient The address that received the output of the swap + /// @param amount0 The delta of the token0 balance of the pool + /// @param amount1 The delta of the token1 balance of the pool + /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96 + /// @param liquidity The liquidity of the pool after the swap + /// @param tick The log base 1.0001 of price of the pool after the swap + event Swap( + address indexed sender, + address indexed recipient, + int256 amount0, + int256 amount1, + uint160 sqrtPriceX96, + uint128 liquidity, + int24 tick + ); + + /// @notice Emitted by the pool for any flashes of token0/token1 + /// @param sender The address that initiated the swap call, and that received the callback + /// @param recipient The address that received the tokens from flash + /// @param amount0 The amount of token0 that was flashed + /// @param amount1 The amount of token1 that was flashed + /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee + /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee + event Flash( + address indexed sender, + address indexed recipient, + uint256 amount0, + uint256 amount1, + uint256 paid0, + uint256 paid1 + ); + + /// @notice Emitted by the pool for increases to the number of observations that can be stored + /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index + /// just before a mint/swap/burn. + /// @param observationCardinalityNextOld The previous value of the next observation cardinality + /// @param observationCardinalityNextNew The updated value of the next observation cardinality + event IncreaseObservationCardinalityNext( + uint16 observationCardinalityNextOld, + uint16 observationCardinalityNextNew + ); + + /// @notice Emitted when the protocol fee is changed by the pool + /// @param feeProtocol0Old The previous value of the token0 protocol fee + /// @param feeProtocol1Old The previous value of the token1 protocol fee + /// @param feeProtocol0New The updated value of the token0 protocol fee + /// @param feeProtocol1New The updated value of the token1 protocol fee + event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New); + + /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner + /// @param sender The address that collects the protocol fees + /// @param recipient The address that receives the collected protocol fees + /// @param amount0 The amount of token0 protocol fees that is withdrawn + /// @param amount0 The amount of token1 protocol fees that is withdrawn + event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1); +} diff --git a/src/v3-core/interfaces/pool/IUniswapV3PoolImmutables.sol b/src/v3-core/interfaces/pool/IUniswapV3PoolImmutables.sol new file mode 100644 index 0000000..38d3d52 --- /dev/null +++ b/src/v3-core/interfaces/pool/IUniswapV3PoolImmutables.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Pool state that never changes +/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values +interface IUniswapV3PoolImmutables { + /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface + /// @return The contract address + function factory() external view returns (address); + + /// @notice The first of the two tokens of the pool, sorted by address + /// @return The token contract address + function token0() external view returns (address); + + /// @notice The second of the two tokens of the pool, sorted by address + /// @return The token contract address + function token1() external view returns (address); + + /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6 + /// @return The fee + function fee() external view returns (uint24); + + /// @notice The pool tick spacing + /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive + /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ... + /// This value is an int24 to avoid casting even though it is always positive. + /// @return The tick spacing + function tickSpacing() external view returns (int24); + + /// @notice The maximum amount of position liquidity that can use any tick in the range + /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and + /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool + /// @return The max amount of liquidity per tick + function maxLiquidityPerTick() external view returns (uint128); +} diff --git a/src/v3-core/interfaces/pool/IUniswapV3PoolOwnerActions.sol b/src/v3-core/interfaces/pool/IUniswapV3PoolOwnerActions.sol new file mode 100644 index 0000000..23391d2 --- /dev/null +++ b/src/v3-core/interfaces/pool/IUniswapV3PoolOwnerActions.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Permissioned pool actions +/// @notice Contains pool methods that may only be called by the factory owner +interface IUniswapV3PoolOwnerActions { + /// @notice Set the denominator of the protocol's % share of the fees + /// @param feeProtocol0 new protocol fee for token0 of the pool + /// @param feeProtocol1 new protocol fee for token1 of the pool + function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external; + + /// @notice Collect the protocol fee accrued to the pool + /// @param recipient The address to which collected protocol fees should be sent + /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1 + /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0 + /// @return amount0 The protocol fee collected in token0 + /// @return amount1 The protocol fee collected in token1 + function collectProtocol( + address recipient, + uint128 amount0Requested, + uint128 amount1Requested + ) external returns (uint128 amount0, uint128 amount1); +} diff --git a/src/v3-core/interfaces/pool/IUniswapV3PoolState.sol b/src/v3-core/interfaces/pool/IUniswapV3PoolState.sol new file mode 100644 index 0000000..395fceb --- /dev/null +++ b/src/v3-core/interfaces/pool/IUniswapV3PoolState.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Pool state that can change +/// @notice These methods compose the pool's state, and can change with any frequency including multiple times +/// per transaction +interface IUniswapV3PoolState { + /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas + /// when accessed externally. + /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value + /// tick The current tick of the pool, i.e. according to the last tick transition that was run. + /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick + /// boundary. + /// observationIndex The index of the last oracle observation that was written, + /// observationCardinality The current maximum number of observations stored in the pool, + /// observationCardinalityNext The next maximum number of observations, to be updated when the observation. + /// feeProtocol The protocol fee for both tokens of the pool. + /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0 + /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee. + /// unlocked Whether the pool is currently locked to reentrancy + function slot0() + external + view + returns ( + uint160 sqrtPriceX96, + int24 tick, + uint16 observationIndex, + uint16 observationCardinality, + uint16 observationCardinalityNext, + uint8 feeProtocol, + bool unlocked + ); + + /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool + /// @dev This value can overflow the uint256 + function feeGrowthGlobal0X128() external view returns (uint256); + + /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool + /// @dev This value can overflow the uint256 + function feeGrowthGlobal1X128() external view returns (uint256); + + /// @notice The amounts of token0 and token1 that are owed to the protocol + /// @dev Protocol fees will never exceed uint128 max in either token + function protocolFees() external view returns (uint128 token0, uint128 token1); + + /// @notice The currently in range liquidity available to the pool + /// @dev This value has no relationship to the total liquidity across all ticks + function liquidity() external view returns (uint128); + + /// @notice Look up information about a specific tick in the pool + /// @param tick The tick to look up + /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or + /// tick upper, + /// liquidityNet how much liquidity changes when the pool price crosses the tick, + /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0, + /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1, + /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick + /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick, + /// secondsOutside the seconds spent on the other side of the tick from the current tick, + /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false. + /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0. + /// In addition, these values are only relative and must be used only in comparison to previous snapshots for + /// a specific position. + function ticks(int24 tick) + external + view + returns ( + uint128 liquidityGross, + int128 liquidityNet, + uint256 feeGrowthOutside0X128, + uint256 feeGrowthOutside1X128, + int56 tickCumulativeOutside, + uint160 secondsPerLiquidityOutsideX128, + uint32 secondsOutside, + bool initialized + ); + + /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information + function tickBitmap(int16 wordPosition) external view returns (uint256); + + /// @notice Returns the information about a position by the position's key + /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper + /// @return _liquidity The amount of liquidity in the position, + /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke, + /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke, + /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke, + /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke + function positions(bytes32 key) + external + view + returns ( + uint128 _liquidity, + uint256 feeGrowthInside0LastX128, + uint256 feeGrowthInside1LastX128, + uint128 tokensOwed0, + uint128 tokensOwed1 + ); + + /// @notice Returns data about a specific observation index + /// @param index The element of the observations array to fetch + /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time + /// ago, rather than at a specific index in the array. + /// @return blockTimestamp The timestamp of the observation, + /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp, + /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp, + /// Returns initialized whether the observation has been initialized and the values are safe to use + function observations(uint256 index) + external + view + returns ( + uint32 blockTimestamp, + int56 tickCumulative, + uint160 secondsPerLiquidityCumulativeX128, + bool initialized + ); +} diff --git a/src/v3-periphery/interfaces/IERC20Metadata.sol b/src/v3-periphery/interfaces/IERC20Metadata.sol new file mode 100644 index 0000000..5db5b56 --- /dev/null +++ b/src/v3-periphery/interfaces/IERC20Metadata.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + +import {IERC20} from "../../lib-external/oz-v3.4-solc-0.7/contracts/token/ERC20/IERC20.sol"; + +/// @title IERC20Metadata +/// @title Interface for ERC20 Metadata +/// @notice Extension to IERC20 that includes token metadata +interface IERC20Metadata is IERC20 { + /// @return The name of the token + function name() external view returns (string memory); + + /// @return The symbol of the token + function symbol() external view returns (string memory); + + /// @return The number of decimal places the token has + function decimals() external view returns (uint8); +} diff --git a/src/v3-periphery/interfaces/IERC721Permit.sol b/src/v3-periphery/interfaces/IERC721Permit.sol new file mode 100644 index 0000000..db1d53f --- /dev/null +++ b/src/v3-periphery/interfaces/IERC721Permit.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + +import {IERC721} from "../../lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721.sol"; + +/// @title ERC721 with permit +/// @notice Extension to ERC721 that includes a permit function for signature based approvals +interface IERC721Permit is IERC721 { + /// @notice The permit typehash used in the permit signature + /// @return The typehash for the permit + function PERMIT_TYPEHASH() external pure returns (bytes32); + + /// @notice The domain separator used in the permit signature + /// @return The domain seperator used in encoding of permit signature + function DOMAIN_SEPARATOR() external view returns (bytes32); + + /// @notice Approve of a specific token ID for spending by spender via signature + /// @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 v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function permit( + address spender, + uint256 tokenId, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external payable; +} diff --git a/src/v3-periphery/interfaces/IMulticall.sol b/src/v3-periphery/interfaces/IMulticall.sol new file mode 100644 index 0000000..9f6a9ac --- /dev/null +++ b/src/v3-periphery/interfaces/IMulticall.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; +pragma abicoder v2; + + +/// @title Multicall interface +/// @notice Enables calling multiple methods in a single call to the contract +interface IMulticall { + /// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed + /// @dev The `msg.value` should not be trusted for any method callable from multicall. + /// @param data The encoded function data for each of the calls to make to this contract + /// @return results The results from each of the calls passed in via data + function multicall(bytes[] calldata data) external payable returns (bytes[] memory results); +} diff --git a/src/v3-periphery/interfaces/INonfungiblePositionManager.sol b/src/v3-periphery/interfaces/INonfungiblePositionManager.sol new file mode 100644 index 0000000..2698f4c --- /dev/null +++ b/src/v3-periphery/interfaces/INonfungiblePositionManager.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; +pragma abicoder v2; + +import {IPeripheryImmutableState} from "./IPeripheryImmutableState.sol"; +import {IPeripheryPayments} from "./IPeripheryPayments.sol"; +import {IPoolInitializer} from "./IPoolInitializer.sol"; +import {IERC721} from "../../lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721.sol"; +import {IERC721Enumerable} from "../../lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Enumerable.sol"; +import {IERC721Metadata} from "../../lib-external/oz-v3.4-solc-0.7/contracts/token/ERC721/IERC721Metadata.sol"; +import {IERC721Permit} from "./IERC721Permit.sol"; + +/// @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, + IPeripheryPayments, + IPeripheryImmutableState, + IERC721Metadata, + IERC721Enumerable, + IERC721Permit +{ + /// @notice Emitted when liquidity is increased for a position NFT + /// @dev Also emitted when a token is minted + /// @param tokenId The ID of the token for which liquidity was increased + /// @param liquidity The amount by which liquidity for the NFT position was increased + /// @param amount0 The amount of token0 that was paid for the increase in liquidity + /// @param amount1 The amount of token1 that was paid for the increase in liquidity + event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); + /// @notice Emitted when liquidity is decreased for a position NFT + /// @param tokenId The ID of the token for which liquidity was decreased + /// @param liquidity The amount by which liquidity for the NFT position was decreased + /// @param amount0 The amount of token0 that was accounted for the decrease in liquidity + /// @param amount1 The amount of token1 that was accounted for the decrease in liquidity + event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); + /// @notice Emitted when tokens are collected for a position NFT + /// @dev The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior + /// @param tokenId The ID of the token for which underlying tokens were collected + /// @param recipient The address of the account that received the collected tokens + /// @param amount0 The amount of token0 owed to the position that was collected + /// @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; + uint256 amount1Desired; + uint256 amount0Min; + uint256 amount1Min; + uint256 deadline; + } + + /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender` + /// @param params tokenId The ID of the token for which liquidity is being increased, + /// amount0Desired The desired amount of token0 to be spent, + /// amount1Desired The desired amount of token1 to be spent, + /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check, + /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check, + /// deadline The time by which the transaction must be included to effect the change + /// @return liquidity The new liquidity amount as a result of the increase + /// @return amount0 The amount of token0 to acheive resulting liquidity + /// @return amount1 The amount of token1 to acheive resulting liquidity + function increaseLiquidity(IncreaseLiquidityParams calldata params) + external + payable + returns ( + uint128 liquidity, + uint256 amount0, + uint256 amount1 + ); + + struct DecreaseLiquidityParams { + uint256 tokenId; + uint128 liquidity; + uint256 amount0Min; + uint256 amount1Min; + uint256 deadline; + } + + /// @notice Decreases the amount of liquidity in a position and accounts it to the position + /// @param params tokenId The ID of the token for which liquidity is being decreased, + /// amount The amount by which liquidity will be decreased, + /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity, + /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity, + /// deadline The time by which the transaction must be included to effect the change + /// @return amount0 The amount of token0 accounted to the position's tokens owed + /// @return amount1 The amount of token1 accounted to the position's tokens owed + function decreaseLiquidity(DecreaseLiquidityParams calldata params) + external + payable + returns (uint256 amount0, uint256 amount1); + + struct CollectParams { + uint256 tokenId; + address recipient; + uint128 amount0Max; + uint128 amount1Max; + } + + /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient + /// @param params tokenId The ID of the NFT for which tokens are being collected, + /// recipient The account that should receive the tokens, + /// amount0Max The maximum amount of token0 to collect, + /// amount1Max The maximum amount of token1 to collect + /// @return amount0 The amount of fees collected in token0 + /// @return amount1 The amount of fees collected in token1 + function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1); + + /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens + /// must be collected first. + /// @param tokenId The ID of the token that is being burned + function burn(uint256 tokenId) external payable; +} diff --git a/src/v3-periphery/interfaces/INonfungibleTokenPositionDescriptor.sol b/src/v3-periphery/interfaces/INonfungibleTokenPositionDescriptor.sol new file mode 100644 index 0000000..1d31f26 --- /dev/null +++ b/src/v3-periphery/interfaces/INonfungibleTokenPositionDescriptor.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; +pragma abicoder v2; + +import {INonfungiblePositionManager} from "./INonfungiblePositionManager.sol"; + +/// @title Describes position NFT tokens via URI +interface INonfungibleTokenPositionDescriptor { + /// @notice Produces the URI describing a particular token ID for a position manager + /// @dev Note this URI may be a data: URI with the JSON contents directly inlined + /// @param positionManager The position manager for which to describe the token + /// @param tokenId The ID of the token for which to produce a description, which may not be valid + /// @return The URI of the ERC721-compliant metadata + function tokenURI(INonfungiblePositionManager positionManager, uint256 tokenId) + external + view + returns (string memory); +} diff --git a/src/v3-periphery/interfaces/IPeripheryImmutableState.sol b/src/v3-periphery/interfaces/IPeripheryImmutableState.sol new file mode 100644 index 0000000..67ed345 --- /dev/null +++ b/src/v3-periphery/interfaces/IPeripheryImmutableState.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Immutable state +/// @notice Functions that return immutable state of the router +interface IPeripheryImmutableState { + /// @return Returns the address of the Uniswap V3 factory + function factory() external view returns (address); + + /// @return Returns the address of WETH9 + function WETH9() external view returns (address); +} diff --git a/src/v3-periphery/interfaces/IPeripheryPayments.sol b/src/v3-periphery/interfaces/IPeripheryPayments.sol new file mode 100644 index 0000000..8b8f5f3 --- /dev/null +++ b/src/v3-periphery/interfaces/IPeripheryPayments.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + + +/// @title Periphery Payments +/// @notice Functions to ease deposits and withdrawals of ETH +interface IPeripheryPayments { + /// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH. + /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users. + /// @param amountMinimum The minimum amount of WETH9 to unwrap + /// @param recipient The address receiving ETH + function unwrapWETH9(uint256 amountMinimum, address recipient) external payable; + + /// @notice Refunds any ETH balance held by this contract to the `msg.sender` + /// @dev Useful for bundling with mint or increase liquidity that uses ether, or exact output swaps + /// that use ether for the input amount + function refundETH() external payable; + + /// @notice Transfers the full amount of a token held by this contract to recipient + /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users + /// @param token The contract address of the token which will be transferred to `recipient` + /// @param amountMinimum The minimum amount of token required for a transfer + /// @param recipient The destination address of the token + function sweepToken( + address token, + uint256 amountMinimum, + address recipient + ) external payable; +} diff --git a/src/v3-periphery/interfaces/IPeripheryPaymentsWithFee.sol b/src/v3-periphery/interfaces/IPeripheryPaymentsWithFee.sol new file mode 100644 index 0000000..29c17bf --- /dev/null +++ b/src/v3-periphery/interfaces/IPeripheryPaymentsWithFee.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + +import {IPeripheryPayments} from "./IPeripheryPayments.sol"; + +/// @title Periphery Payments +/// @notice Functions to ease deposits and withdrawals of ETH +interface IPeripheryPaymentsWithFee is IPeripheryPayments { + /// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH, with a percentage between + /// 0 (exclusive), and 1 (inclusive) going to feeRecipient + /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users. + function unwrapWETH9WithFee( + uint256 amountMinimum, + address recipient, + uint256 feeBips, + address feeRecipient + ) external payable; + + /// @notice Transfers the full amount of a token held by this contract to recipient, with a percentage between + /// 0 (exclusive) and 1 (inclusive) going to feeRecipient + /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users + function sweepTokenWithFee( + address token, + uint256 amountMinimum, + address recipient, + uint256 feeBips, + address feeRecipient + ) external payable; +} diff --git a/src/v3-periphery/interfaces/IPoolInitializer.sol b/src/v3-periphery/interfaces/IPoolInitializer.sol new file mode 100644 index 0000000..04c015e --- /dev/null +++ b/src/v3-periphery/interfaces/IPoolInitializer.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; +pragma abicoder v2; + + +/// @title Creates and initializes V3 Pools +/// @notice Provides a method for creating and initializing a pool, if necessary, for bundling with other methods that +/// require the pool to exist. +interface IPoolInitializer { + /// @notice Creates a new pool if it does not exist, then initializes if not initialized + /// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) performed against a pool + /// @param token0 The contract address of token0 of the pool + /// @param token1 The contract address of token1 of the pool + /// @param fee The fee amount of the v3 pool for the specified token pair + /// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value + /// @return pool Returns the pool address based on the pair of tokens and fee, will return the newly created pool address if necessary + function createAndInitializePoolIfNecessary( + address token0, + address token1, + uint24 fee, + uint160 sqrtPriceX96 + ) external payable returns (address pool); +} diff --git a/src/v3-periphery/interfaces/IQuoter.sol b/src/v3-periphery/interfaces/IQuoter.sol new file mode 100644 index 0000000..16622f3 --- /dev/null +++ b/src/v3-periphery/interfaces/IQuoter.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; +pragma abicoder v2; + + +/// @title Quoter Interface +/// @notice Supports quoting the calculated amounts from exact input or exact output swaps +/// @dev These functions are not marked view because they rely on calling non-view functions and reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IQuoter { + /// @notice Returns the amount out received for a given exact input swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountIn The amount of the first token to swap + /// @return amountOut The amount of the last token that would be received + function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut); + + /// @notice Returns the amount out received for a given exact input but for a swap of a single pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountIn The desired input amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountOut The amount of `tokenOut` that would be received + function quoteExactInputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountIn, + uint160 sqrtPriceLimitX96 + ) external returns (uint256 amountOut); + + /// @notice Returns the amount in required for a given exact output swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order + /// @param amountOut The amount of the last token to receive + /// @return amountIn The amount of first token required to be paid + function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn); + + /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountOut The desired output amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` + function quoteExactOutputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountOut, + uint160 sqrtPriceLimitX96 + ) external returns (uint256 amountIn); +} diff --git a/src/v3-periphery/interfaces/IQuoterV2.sol b/src/v3-periphery/interfaces/IQuoterV2.sol new file mode 100644 index 0000000..d92d9ca --- /dev/null +++ b/src/v3-periphery/interfaces/IQuoterV2.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; +pragma abicoder v2; + + +/// @title QuoterV2 Interface +/// @notice Supports quoting the calculated amounts from exact input or exact output swaps. +/// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap. +/// @dev These functions are not marked view because they rely on calling non-view functions and reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IQuoterV2 { + /// @notice Returns the amount out received for a given exact input swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountIn The amount of the first token to swap + /// @return amountOut The amount of the last token that would be received + /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path + /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactInput(bytes memory path, uint256 amountIn) + external + returns ( + uint256 amountOut, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksCrossedList, + uint256 gasEstimate + ); + + struct QuoteExactInputSingleParams { + address tokenIn; + address tokenOut; + uint256 amountIn; + uint24 fee; + uint160 sqrtPriceLimitX96; + } + + /// @notice Returns the amount out received for a given exact input but for a swap of a single pool + /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams` + /// tokenIn The token being swapped in + /// tokenOut The token being swapped out + /// fee The fee of the token pool to consider for the pair + /// amountIn The desired input amount + /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountOut The amount of `tokenOut` that would be received + /// @return sqrtPriceX96After The sqrt price of the pool after the swap + /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactInputSingle(QuoteExactInputSingleParams memory params) + external + returns ( + uint256 amountOut, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ); + + /// @notice Returns the amount in required for a given exact output swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order + /// @param amountOut The amount of the last token to receive + /// @return amountIn The amount of first token required to be paid + /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path + /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactOutput(bytes memory path, uint256 amountOut) + external + returns ( + uint256 amountIn, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksCrossedList, + uint256 gasEstimate + ); + + struct QuoteExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint256 amount; + uint24 fee; + uint160 sqrtPriceLimitX96; + } + + /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool + /// @param params The params for the quote, encoded as `QuoteExactOutputSingleParams` + /// tokenIn The token being swapped in + /// tokenOut The token being swapped out + /// fee The fee of the token pool to consider for the pair + /// amountOut The desired output amount + /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` + /// @return sqrtPriceX96After The sqrt price of the pool after the swap + /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactOutputSingle(QuoteExactOutputSingleParams memory params) + external + returns ( + uint256 amountIn, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ); +} diff --git a/src/v3-periphery/interfaces/ISelfPermit.sol b/src/v3-periphery/interfaces/ISelfPermit.sol new file mode 100644 index 0000000..df7947c --- /dev/null +++ b/src/v3-periphery/interfaces/ISelfPermit.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + + +/// @title Self Permit +/// @notice Functionality to call permit on any EIP-2612-compliant token for use in the route +interface ISelfPermit { + /// @notice Permits this contract to spend a given token from `msg.sender` + /// @dev The `owner` is always msg.sender and the `spender` is always address(this). + /// @param token The address of the token spent + /// @param value The amount that can be spent of token + /// @param deadline A timestamp, the current blocktime must be less than or equal to this timestamp + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function selfPermit( + address token, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external payable; + + /// @notice Permits this contract to spend a given token from `msg.sender` + /// @dev The `owner` is always msg.sender and the `spender` is always address(this). + /// Can be used instead of #selfPermit to prevent calls from failing due to a frontrun of a call to #selfPermit + /// @param token The address of the token spent + /// @param value The amount that can be spent of token + /// @param deadline A timestamp, the current blocktime must be less than or equal to this timestamp + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function selfPermitIfNecessary( + address token, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external payable; + + /// @notice Permits this contract to spend the sender's tokens for permit signatures that have the `allowed` parameter + /// @dev The `owner` is always msg.sender and the `spender` is always address(this) + /// @param token The address of the token spent + /// @param nonce The current nonce of the owner + /// @param expiry The timestamp at which the permit is no longer valid + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function selfPermitAllowed( + address token, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) external payable; + + /// @notice Permits this contract to spend the sender's tokens for permit signatures that have the `allowed` parameter + /// @dev The `owner` is always msg.sender and the `spender` is always address(this) + /// Can be used instead of #selfPermitAllowed to prevent calls from failing due to a frontrun of a call to #selfPermitAllowed. + /// @param token The address of the token spent + /// @param nonce The current nonce of the owner + /// @param expiry The timestamp at which the permit is no longer valid + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function selfPermitAllowedIfNecessary( + address token, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) external payable; +} diff --git a/src/v3-periphery/interfaces/ISwapRouter.sol b/src/v3-periphery/interfaces/ISwapRouter.sol new file mode 100644 index 0000000..5ad97f6 --- /dev/null +++ b/src/v3-periphery/interfaces/ISwapRouter.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; +pragma abicoder v2; + +import {IUniswapV3SwapCallback} from "../../v3-core/interfaces/callback/IUniswapV3SwapCallback.sol"; + +/// @title Router token swapping functionality +/// @notice Functions for swapping tokens via Uniswap V3 +interface ISwapRouter is IUniswapV3SwapCallback { + struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another token + /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata + /// @return amountOut The amount of the received token + function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); + + struct ExactInputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata + /// @return amountOut The amount of the received token + function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); + + struct ExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 deadline; + uint256 amountOut; + uint256 amountInMaximum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another token + /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata + /// @return amountIn The amount of the input token + function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); + + struct ExactOutputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountOut; + uint256 amountInMaximum; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata + /// @return amountIn The amount of the input token + function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); +} diff --git a/src/v3-periphery/interfaces/ITickLens.sol b/src/v3-periphery/interfaces/ITickLens.sol new file mode 100644 index 0000000..971a52a --- /dev/null +++ b/src/v3-periphery/interfaces/ITickLens.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; +pragma abicoder v2; + + +/// @title Tick Lens +/// @notice Provides functions for fetching chunks of tick data for a pool +/// @dev This avoids the waterfall of fetching the tick bitmap, parsing the bitmap to know which ticks to fetch, and +/// then sending additional multicalls to fetch the tick data +interface ITickLens { + struct PopulatedTick { + int24 tick; + int128 liquidityNet; + uint128 liquidityGross; + } + + /// @notice Get all the tick data for the populated ticks from a word of the tick bitmap of a pool + /// @param pool The address of the pool for which to fetch populated tick data + /// @param tickBitmapIndex The index of the word in the tick bitmap for which to parse the bitmap and + /// fetch all the populated ticks + /// @return populatedTicks An array of tick data for the given word in the tick bitmap + function getPopulatedTicksInWord(address pool, int16 tickBitmapIndex) + external + view + returns (PopulatedTick[] memory populatedTicks); +} diff --git a/src/v3-periphery/interfaces/IV3Migrator.sol b/src/v3-periphery/interfaces/IV3Migrator.sol new file mode 100644 index 0000000..576e1a0 --- /dev/null +++ b/src/v3-periphery/interfaces/IV3Migrator.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; +pragma abicoder v2; + +import {IMulticall} from "./IMulticall.sol"; +import {IPoolInitializer} from "./IPoolInitializer.sol"; +import {ISelfPermit} from "./ISelfPermit.sol"; + +/// @title V3 Migrator +/// @notice Enables migration of liqudity from Uniswap v2-compatible pairs into Uniswap v3 pools +interface IV3Migrator is IMulticall, ISelfPermit, IPoolInitializer { + struct MigrateParams { + address pair; // the Uniswap v2-compatible pair + uint256 liquidityToMigrate; // expected to be balanceOf(msg.sender) + uint8 percentageToMigrate; // represented as a numerator over 100 + address token0; + address token1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint256 amount0Min; // must be discounted by percentageToMigrate + uint256 amount1Min; // must be discounted by percentageToMigrate + address recipient; + uint256 deadline; + bool refundAsETH; + } + + /// @notice Migrates liquidity to v3 by burning v2 liquidity and minting a new position for v3 + /// @dev Slippage protection is enforced via `amount{0,1}Min`, which should be a discount of the expected values of + /// the maximum amount of v3 liquidity that the v2 liquidity can get. For the special case of migrating to an + /// out-of-range position, `amount{0,1}Min` may be set to 0, enforcing that the position remains out of range + /// @param params The params necessary to migrate v2 liquidity, encoded as `MigrateParams` in calldata + function migrate(MigrateParams calldata params) external; +} diff --git a/src/v3-periphery/interfaces/external/IERC1271.sol b/src/v3-periphery/interfaces/external/IERC1271.sol new file mode 100644 index 0000000..2f3d2e3 --- /dev/null +++ b/src/v3-periphery/interfaces/external/IERC1271.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Interface for verifying contract-based account signatures +/// @notice Interface that verifies provided signature for the data +/// @dev Interface defined by EIP-1271 +interface IERC1271 { + /// @notice Returns whether the provided signature is valid for the provided data + /// @dev MUST return the bytes4 magic value 0x1626ba7e when function passes. + /// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5). + /// MUST allow external calls. + /// @param hash Hash of the data to be signed + /// @param signature Signature byte array associated with _data + /// @return magicValue The bytes4 magic value 0x1626ba7e + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); +} diff --git a/src/v3-periphery/interfaces/external/IERC20PermitAllowed.sol b/src/v3-periphery/interfaces/external/IERC20PermitAllowed.sol new file mode 100644 index 0000000..2d5dea2 --- /dev/null +++ b/src/v3-periphery/interfaces/external/IERC20PermitAllowed.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + + +/// @title Interface for permit +/// @notice Interface used by DAI/CHAI for permit +interface IERC20PermitAllowed { + /// @notice Approve the spender to spend some tokens via the holder signature + /// @dev This is the permit interface used by DAI and CHAI + /// @param holder The address of the token holder, the token owner + /// @param spender The address of the token spender + /// @param nonce The holder's nonce, increases at each call to permit + /// @param expiry The timestamp at which the permit is no longer valid + /// @param allowed Boolean that sets approval amount, true for type(uint256).max and false for 0 + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function permit( + address holder, + address spender, + uint256 nonce, + uint256 expiry, + bool allowed, + uint8 v, + bytes32 r, + bytes32 s + ) external; +} diff --git a/src/v3-periphery/interfaces/external/IWETH9.sol b/src/v3-periphery/interfaces/external/IWETH9.sol new file mode 100644 index 0000000..8311cf8 --- /dev/null +++ b/src/v3-periphery/interfaces/external/IWETH9.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + +import {IERC20} from "../../../lib-external/oz-v3.4-solc-0.7/contracts/token/ERC20/IERC20.sol"; + +/// @title Interface for WETH9 +interface IWETH9 is IERC20 { + /// @notice Deposit ether to get wrapped ether + function deposit() external payable; + + /// @notice Withdraw wrapped ether to get ether + function withdraw(uint256) external; +} diff --git a/src/v4-core/interfaces/IExtsload.sol b/src/v4-core/interfaces/IExtsload.sol new file mode 100644 index 0000000..b784f44 --- /dev/null +++ b/src/v4-core/interfaces/IExtsload.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + + +/// @notice Interface for functions to access any storage slot in a contract +interface IExtsload { + /// @notice Called by external contracts to access granular pool state + /// @param slot Key of slot to sload + /// @return value The value of the slot as bytes32 + function extsload(bytes32 slot) external view returns (bytes32 value); + + /// @notice Called by external contracts to access granular pool state + /// @param startSlot Key of slot to start sloading from + /// @param nSlots Number of slots to load into return value + /// @return values List of loaded values. + function extsload(bytes32 startSlot, uint256 nSlots) external view returns (bytes32[] memory values); + + /// @notice Called by external contracts to access sparse pool state + /// @param slots List of slots to SLOAD from. + /// @return values List of loaded values. + function extsload(bytes32[] calldata slots) external view returns (bytes32[] memory values); +} diff --git a/src/v4-core/interfaces/IExttload.sol b/src/v4-core/interfaces/IExttload.sol new file mode 100644 index 0000000..bf55100 --- /dev/null +++ b/src/v4-core/interfaces/IExttload.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + + +/// @notice Interface for functions to access any transient storage slot in a contract +interface IExttload { + /// @notice Called by external contracts to access transient storage of the contract + /// @param slot Key of slot to tload + /// @return value The value of the slot as bytes32 + function exttload(bytes32 slot) external view returns (bytes32 value); + + /// @notice Called by external contracts to access sparse transient pool state + /// @param slots List of slots to tload + /// @return values List of loaded values + function exttload(bytes32[] calldata slots) external view returns (bytes32[] memory values); +} diff --git a/src/v4-core/interfaces/IHooks.sol b/src/v4-core/interfaces/IHooks.sol new file mode 100644 index 0000000..65ecf9f --- /dev/null +++ b/src/v4-core/interfaces/IHooks.sol @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {BeforeSwapDelta} from "../types/BeforeSwapDelta.sol"; +import {BalanceDelta} from "../types/BalanceDelta.sol"; +import {IPoolManager} from "./IPoolManager.sol"; +import {PoolKey} from "../types/PoolKey.sol"; + +/// @notice The PoolManager contract decides whether to invoke specific hooks by inspecting the leading bits +/// of the hooks contract address. For example, a 1 bit in the first bit of the address will +/// cause the 'before swap' hook to be invoked. See the Hooks library for the full spec. +/// @dev Should only be callable by the v4 PoolManager. +interface IHooks { + /// @notice The hook called before the state of a pool is initialized + /// @param sender The initial msg.sender for the initialize call + /// @param key The key for the pool being initialized + /// @param sqrtPriceX96 The sqrt(price) of the pool as a Q64.96 + /// @param hookData Arbitrary data handed into the PoolManager by the initializer to be be passed on to the hook + /// @return bytes4 The function selector for the hook + function beforeInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96, bytes calldata hookData) + external + returns (bytes4); + + /// @notice The hook called after the state of a pool is initialized + /// @param sender The initial msg.sender for the initialize call + /// @param key The key for the pool being initialized + /// @param sqrtPriceX96 The sqrt(price) of the pool as a Q64.96 + /// @param tick The current tick after the state of a pool is initialized + /// @param hookData Arbitrary data handed into the PoolManager by the initializer to be be passed on to the hook + /// @return bytes4 The function selector for the hook + function afterInitialize( + address sender, + PoolKey calldata key, + uint160 sqrtPriceX96, + int24 tick, + bytes calldata hookData + ) external returns (bytes4); + + /// @notice The hook called before liquidity is added + /// @param sender The initial msg.sender for the add liquidity call + /// @param key The key for the pool + /// @param params The parameters for adding liquidity + /// @param hookData Arbitrary data handed into the PoolManager by the liquidity provider to be passed on to the hook + /// @return bytes4 The function selector for the hook + function beforeAddLiquidity( + address sender, + PoolKey calldata key, + IPoolManager.ModifyLiquidityParams calldata params, + bytes calldata hookData + ) external returns (bytes4); + + /// @notice The hook called after liquidity is added + /// @param sender The initial msg.sender for the add liquidity call + /// @param key The key for the pool + /// @param params The parameters for adding liquidity + /// @param delta The caller's balance delta after adding liquidity + /// @param hookData Arbitrary data handed into the PoolManager by the liquidity provider to be passed on to the hook + /// @return bytes4 The function selector for the hook + /// @return BalanceDelta The hook's delta in token0 and token1. Positive: the hook is owed/took currency, negative: the hook owes/sent currency + function afterAddLiquidity( + address sender, + PoolKey calldata key, + IPoolManager.ModifyLiquidityParams calldata params, + BalanceDelta delta, + bytes calldata hookData + ) external returns (bytes4, BalanceDelta); + + /// @notice The hook called before liquidity is removed + /// @param sender The initial msg.sender for the remove liquidity call + /// @param key The key for the pool + /// @param params The parameters for removing liquidity + /// @param hookData Arbitrary data handed into the PoolManager by the liquidty provider to be be passed on to the hook + /// @return bytes4 The function selector for the hook + function beforeRemoveLiquidity( + address sender, + PoolKey calldata key, + IPoolManager.ModifyLiquidityParams calldata params, + bytes calldata hookData + ) external returns (bytes4); + + /// @notice The hook called after liquidity is removed + /// @param sender The initial msg.sender for the remove liquidity call + /// @param key The key for the pool + /// @param params The parameters for removing liquidity + /// @param delta The caller's balance delta after removing liquidity + /// @param hookData Arbitrary data handed into the PoolManager by the liquidty provider to be be passed on to the hook + /// @return bytes4 The function selector for the hook + /// @return BalanceDelta The hook's delta in token0 and token1. Positive: the hook is owed/took currency, negative: the hook owes/sent currency + function afterRemoveLiquidity( + address sender, + PoolKey calldata key, + IPoolManager.ModifyLiquidityParams calldata params, + BalanceDelta delta, + bytes calldata hookData + ) external returns (bytes4, BalanceDelta); + + /// @notice The hook called before a swap + /// @param sender The initial msg.sender for the swap call + /// @param key The key for the pool + /// @param params The parameters for the swap + /// @param hookData Arbitrary data handed into the PoolManager by the swapper to be be passed on to the hook + /// @return bytes4 The function selector for the hook + /// @return BeforeSwapDelta The hook's delta in specified and unspecified currencies. Positive: the hook is owed/took currency, negative: the hook owes/sent currency + /// @return uint24 Optionally override the lp fee, only used if three conditions are met: 1. the Pool has a dynamic fee, 2. the value's 2nd highest bit is set (23rd bit, 0x400000), and 3. the value is less than or equal to the maximum fee (1 million) + function beforeSwap( + address sender, + PoolKey calldata key, + IPoolManager.SwapParams calldata params, + bytes calldata hookData + ) external returns (bytes4, BeforeSwapDelta, uint24); + + /// @notice The hook called after a swap + /// @param sender The initial msg.sender for the swap call + /// @param key The key for the pool + /// @param params The parameters for the swap + /// @param delta The amount owed to the caller (positive) or owed to the pool (negative) + /// @param hookData Arbitrary data handed into the PoolManager by the swapper to be be passed on to the hook + /// @return bytes4 The function selector for the hook + /// @return int128 The hook's delta in unspecified currency. Positive: the hook is owed/took currency, negative: the hook owes/sent currency + function afterSwap( + address sender, + PoolKey calldata key, + IPoolManager.SwapParams calldata params, + BalanceDelta delta, + bytes calldata hookData + ) external returns (bytes4, int128); + + /// @notice The hook called before donate + /// @param sender The initial msg.sender for the donate call + /// @param key The key for the pool + /// @param amount0 The amount of token0 being donated + /// @param amount1 The amount of token1 being donated + /// @param hookData Arbitrary data handed into the PoolManager by the donor to be be passed on to the hook + /// @return bytes4 The function selector for the hook + function beforeDonate( + address sender, + PoolKey calldata key, + uint256 amount0, + uint256 amount1, + bytes calldata hookData + ) external returns (bytes4); + + /// @notice The hook called after donate + /// @param sender The initial msg.sender for the donate call + /// @param key The key for the pool + /// @param amount0 The amount of token0 being donated + /// @param amount1 The amount of token1 being donated + /// @param hookData Arbitrary data handed into the PoolManager by the donor to be be passed on to the hook + /// @return bytes4 The function selector for the hook + function afterDonate( + address sender, + PoolKey calldata key, + uint256 amount0, + uint256 amount1, + bytes calldata hookData + ) external returns (bytes4); +} diff --git a/src/v4-core/interfaces/IPoolManager.sol b/src/v4-core/interfaces/IPoolManager.sol new file mode 100644 index 0000000..1af480e --- /dev/null +++ b/src/v4-core/interfaces/IPoolManager.sol @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {IExtsload} from "./IExtsload.sol"; +import {IExttload} from "./IExttload.sol"; +import {IERC6909Claims} from "./external/IERC6909Claims.sol"; +import {BalanceDelta} from "../types/BalanceDelta.sol"; +import {Currency} from "../types/Currency.sol"; +import {IHooks} from "./IHooks.sol"; +import {IProtocolFees} from "./IProtocolFees.sol"; +import {PoolId} from "../types/PoolId.sol"; +import {PoolKey} from "../types/PoolKey.sol"; + +/// @notice Interface for the PoolManager +interface IPoolManager is IProtocolFees, IERC6909Claims, IExtsload, IExttload { + /// @notice Thrown when a currency is not netted out after the contract is unlocked + error CurrencyNotSettled(); + + /// @notice Thrown when trying to interact with a non-initialized pool + error PoolNotInitialized(); + + /// @notice Thrown when unlock is called, but the contract is already unlocked + error AlreadyUnlocked(); + + /// @notice Thrown when a function is called that requires the contract to be unlocked, but it is not + error ManagerLocked(); + + /// @notice Pools are limited to type(int16).max tickSpacing in #initialize, to prevent overflow + error TickSpacingTooLarge(int24 tickSpacing); + + /// @notice Pools must have a positive non-zero tickSpacing passed to #initialize + error TickSpacingTooSmall(int24 tickSpacing); + + /// @notice PoolKey must have currencies where address(currency0) < address(currency1) + error CurrenciesOutOfOrderOrEqual(address currency0, address currency1); + + /// @notice Thrown when a call to updateDynamicLPFee is made by an address that is not the hook, + /// or on a pool that does not have a dynamic swap fee. + error UnauthorizedDynamicLPFeeUpdate(); + + /// @notice Thrown when trying to swap amount of 0 + error SwapAmountCannotBeZero(); + + ///@notice Thrown when native currency is passed to a non native settlement + error NonZeroNativeValue(); + + /// @notice Thrown when `clear` is called with an amount that is not exactly equal to the open currency delta. + error MustClearExactPositiveDelta(); + + /// @notice Emitted when a new pool is initialized + /// @param id The abi encoded hash of the pool key struct for the new pool + /// @param currency0 The first currency of the pool by address sort order + /// @param currency1 The second currency of the pool by address sort order + /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip + /// @param tickSpacing The minimum number of ticks between initialized ticks + /// @param hooks The hooks contract address for the pool, or address(0) if none + /// @param sqrtPriceX96 The price of the pool on initialization + /// @param tick The initial tick of the pool corresponding to the intialized price + event Initialize( + PoolId indexed id, + Currency indexed currency0, + Currency indexed currency1, + uint24 fee, + int24 tickSpacing, + IHooks hooks, + uint160 sqrtPriceX96, + int24 tick + ); + + /// @notice Emitted when a liquidity position is modified + /// @param id The abi encoded hash of the pool key struct for the pool that was modified + /// @param sender The address that modified the pool + /// @param tickLower The lower tick of the position + /// @param tickUpper The upper tick of the position + /// @param liquidityDelta The amount of liquidity that was added or removed + event ModifyLiquidity( + PoolId indexed id, address indexed sender, int24 tickLower, int24 tickUpper, int256 liquidityDelta + ); + + /// @notice Emitted for swaps between currency0 and currency1 + /// @param id The abi encoded hash of the pool key struct for the pool that was modified + /// @param sender The address that initiated the swap call, and that received the callback + /// @param amount0 The delta of the currency0 balance of the pool + /// @param amount1 The delta of the currency1 balance of the pool + /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96 + /// @param liquidity The liquidity of the pool after the swap + /// @param tick The log base 1.0001 of the price of the pool after the swap + /// @param fee The swap fee in hundredths of a bip + event Swap( + PoolId indexed id, + address indexed sender, + int128 amount0, + int128 amount1, + uint160 sqrtPriceX96, + uint128 liquidity, + int24 tick, + uint24 fee + ); + + /// @return int24 the constant representing the maximum tickSpacing for an initialized pool key + function MAX_TICK_SPACING() external view returns (int24); + + /// @return int24 the constant representing the minimum tickSpacing for an initialized pool key + function MIN_TICK_SPACING() external view returns (int24); + + /// @notice All interactions on the contract that account deltas require unlocking. A caller that calls `unlock` must implement + /// `IUnlockCallback(msg.sender).unlockCallback(data)`, where they interact with the remaining functions on this contract. + /// @dev The only functions callable without an unlocking are `initialize` and `updateDynamicLPFee` + /// @param data Any data to pass to the callback, via `IUnlockCallback(msg.sender).unlockCallback(data)` + /// @return The data returned by the call to `IUnlockCallback(msg.sender).unlockCallback(data)` + function unlock(bytes calldata data) external returns (bytes memory); + + /// @notice Initialize the state for a given pool ID + /// @param key The pool key for the pool to initialize + /// @param sqrtPriceX96 The initial square root price + /// @param hookData The data to pass through to the initialize hooks + /// @return tick The initial tick of the pool + function initialize(PoolKey memory key, uint160 sqrtPriceX96, bytes calldata hookData) + external + returns (int24 tick); + + struct ModifyLiquidityParams { + // the lower and upper tick of the position + int24 tickLower; + int24 tickUpper; + // how to modify the liquidity + int256 liquidityDelta; + // a value to set if you want unique liquidity positions at the same range + bytes32 salt; + } + + /// @notice Modify the liquidity for the given pool + /// @dev Poke by calling with a zero liquidityDelta + /// @param key The pool to modify liquidity in + /// @param params The parameters for modifying the liquidity + /// @param hookData The data to pass through to the add/removeLiquidity hooks + /// @return callerDelta The balance delta of the caller of modifyLiquidity. This is the total of both principal and fee deltas. + /// @return feeDelta The balance delta of the fees generated in the liquidity range. Returned for informational purposes. + function modifyLiquidity(PoolKey memory key, ModifyLiquidityParams memory params, bytes calldata hookData) + external + returns (BalanceDelta callerDelta, BalanceDelta feeDelta); + + struct SwapParams { + bool zeroForOne; + int256 amountSpecified; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swap against the given pool + /// @param key The pool to swap in + /// @param params The parameters for swapping + /// @param hookData The data to pass through to the swap hooks + /// @return swapDelta The balance delta of the address swapping + /// @dev Swapping on low liquidity pools may cause unexpected swap amounts when liquidity available is less than amountSpecified. + /// Additionally note that if interacting with hooks that have the BEFORE_SWAP_RETURNS_DELTA_FLAG or AFTER_SWAP_RETURNS_DELTA_FLAG + /// the hook may alter the swap input/output. Integrators should perform checks on the returned swapDelta. + function swap(PoolKey memory key, SwapParams memory params, bytes calldata hookData) + external + returns (BalanceDelta swapDelta); + + /// @notice Donate the given currency amounts to the pool with the given pool key + /// @param key The key of the pool to donate to + /// @param amount0 The amount of currency0 to donate + /// @param amount1 The amount of currency1 to donate + /// @param hookData The data to pass through to the donate hooks + /// @return BalanceDelta The delta of the caller after the donate + function donate(PoolKey memory key, uint256 amount0, uint256 amount1, bytes calldata hookData) + external + returns (BalanceDelta); + + /// @notice Writes the current ERC20 balance of the specified currency to transient storage + /// This is used to checkpoint balances for the manager and derive deltas for the caller. + /// @dev This MUST be called before any ERC20 tokens are sent into the contract, but can be skipped + /// for native tokens because the amount to settle is determined by the sent value. + /// @param currency The currency whose balance to sync + function sync(Currency currency) external; + + /// @notice Called by the user to net out some value owed to the user + /// @dev Can also be used as a mechanism for _free_ flash loans + /// @param currency The currency to withdraw from the pool manager + /// @param to The address to withdraw to + /// @param amount The amount of currency to withdraw + function take(Currency currency, address to, uint256 amount) external; + + /// @notice Called by the user to pay what is owed + /// @return paid The amount of currency settled + function settle() external payable returns (uint256 paid); + + /// @notice Called by the user to pay on behalf of another address + /// @param recipient The address to credit for the payment + /// @return paid The amount of currency settled + function settleFor(address recipient) external payable returns (uint256 paid); + + /// @notice WARNING - Any currency that is cleared, will be non-retreivable, and locked in the contract permanently. + /// A call to clear will zero out a positive balance WITHOUT a corresponding transfer. + /// @dev This could be used to clear a balance that is considered dust. + /// Additionally, the amount must be the exact positive balance. This is to enforce that the caller is aware of the amount being cleared. + function clear(Currency currency, uint256 amount) external; + + /// @notice Called by the user to move value into ERC6909 balance + /// @param to The address to mint the tokens to + /// @param id The currency address to mint to ERC6909s, as a uint256 + /// @param amount The amount of currency to mint + /// @dev The id is converted to a uint160 to correspond to a currency address + /// If the upper 12 bytes are not 0, they will be 0-ed out + function mint(address to, uint256 id, uint256 amount) external; + + /// @notice Called by the user to move value from ERC6909 balance + /// @param from The address to burn the tokens from + /// @param id The currency address to burn from ERC6909s, as a uint256 + /// @param amount The amount of currency to burn + /// @dev The id is converted to a uint160 to correspond to a currency address + /// If the upper 12 bytes are not 0, they will be 0-ed out + function burn(address from, uint256 id, uint256 amount) external; + + /// @notice Updates the pools lp fees for the a pool that has enabled dynamic lp fees. + /// @param key The key of the pool to update dynamic LP fees for + /// @param newDynamicLPFee The new dynamic pool LP fee + function updateDynamicLPFee(PoolKey memory key, uint24 newDynamicLPFee) external; +} diff --git a/src/v4-core/interfaces/IProtocolFeeController.sol b/src/v4-core/interfaces/IProtocolFeeController.sol new file mode 100644 index 0000000..6233572 --- /dev/null +++ b/src/v4-core/interfaces/IProtocolFeeController.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {PoolKey} from "../types/PoolKey.sol"; + +/// @notice Interface to fetch the protocol fees for a pool from the protocol fee controller +interface IProtocolFeeController { + /// @notice Returns the protocol fees for a pool given the conditions of this contract + /// @param poolKey The pool key to identify the pool. The controller may want to use attributes on the pool + /// to determine the protocol fee, hence the entire key is needed. + /// @return protocolFee The pool's protocol fee, expressed in hundredths of a bip. The upper 12 bits are for 1->0 + /// and the lower 12 are for 0->1. The maximum is 1000 - meaning the maximum protocol fee is 0.1%. + /// the protocolFee is taken from the input first, then the lpFee is taken from the remaining input + function protocolFeeForPool(PoolKey memory poolKey) external view returns (uint24 protocolFee); +} diff --git a/src/v4-core/interfaces/IProtocolFees.sol b/src/v4-core/interfaces/IProtocolFees.sol new file mode 100644 index 0000000..82c400a --- /dev/null +++ b/src/v4-core/interfaces/IProtocolFees.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import {Currency} from "../types/Currency.sol"; +import {IProtocolFeeController} from "./IProtocolFeeController.sol"; +import {PoolId} from "../types/PoolId.sol"; +import {PoolKey} from "../types/PoolKey.sol"; + +/// @notice Interface for all protocol-fee related functions in the pool manager +interface IProtocolFees { + /// @notice Thrown when not enough gas is provided to look up the protocol fee + error ProtocolFeeCannotBeFetched(); + /// @notice Thrown when protocol fee is set too high + error ProtocolFeeTooLarge(uint24 fee); + + /// @notice Thrown when collectProtocolFees or setProtocolFee is not called by the controller. + error InvalidCaller(); + + /// @notice Emitted when the protocol fee controller address is updated in setProtocolFeeController. + event ProtocolFeeControllerUpdated(address indexed protocolFeeController); + + /// @notice Emitted when the protocol fee is updated for a pool. + event ProtocolFeeUpdated(PoolId indexed id, uint24 protocolFee); + + /// @notice Given a currency address, returns the protocol fees accrued in that currency + /// @param currency The currency to check + /// @return amount The amount of protocol fees accrued in the currency + function protocolFeesAccrued(Currency currency) external view returns (uint256 amount); + + /// @notice Sets the protocol fee for the given pool + /// @param key The key of the pool to set a protocol fee for + /// @param newProtocolFee The fee to set + function setProtocolFee(PoolKey memory key, uint24 newProtocolFee) external; + + /// @notice Sets the protocol fee controller + /// @param controller The new protocol fee controller + function setProtocolFeeController(IProtocolFeeController controller) external; + + /// @notice Collects the protocol fees for a given recipient and currency, returning the amount collected + /// @param recipient The address to receive the protocol fees + /// @param currency The currency to withdraw + /// @param amount The amount of currency to withdraw + /// @return amountCollected The amount of currency successfully withdrawn + function collectProtocolFees(address recipient, Currency currency, uint256 amount) + external + returns (uint256 amountCollected); + + /// @notice Returns the current protocol fee controller address + /// @return IProtocolFeeController The currency protocol fee controller + function protocolFeeController() external view returns (IProtocolFeeController); +} diff --git a/src/v4-core/interfaces/callback/IUnlockCallback.sol b/src/v4-core/interfaces/callback/IUnlockCallback.sol new file mode 100644 index 0000000..52abe5f --- /dev/null +++ b/src/v4-core/interfaces/callback/IUnlockCallback.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + + +/// @notice Interface for the callback executed when an address unlocks the pool manager +interface IUnlockCallback { + /// @notice Called by the pool manager on `msg.sender` when the manager is unlocked + /// @param data The data that was passed to the call to unlock + /// @return Any data that you want to be returned from the unlock call + function unlockCallback(bytes calldata data) external returns (bytes memory); +} diff --git a/src/v4-core/interfaces/external/IERC20Minimal.sol b/src/v4-core/interfaces/external/IERC20Minimal.sol new file mode 100644 index 0000000..3889536 --- /dev/null +++ b/src/v4-core/interfaces/external/IERC20Minimal.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + + +/// @title Minimal ERC20 interface for Uniswap +/// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3 +interface IERC20Minimal { + /// @notice Returns an account's balance in the token + /// @param account The account for which to look up the number of tokens it has, i.e. its balance + /// @return The number of tokens held by the account + function balanceOf(address account) external view returns (uint256); + + /// @notice Transfers the amount of token from the `msg.sender` to the recipient + /// @param recipient The account that will receive the amount transferred + /// @param amount The number of tokens to send from the sender to the recipient + /// @return Returns true for a successful transfer, false for an unsuccessful transfer + function transfer(address recipient, uint256 amount) external returns (bool); + + /// @notice Returns the current allowance given to a spender by an owner + /// @param owner The account of the token owner + /// @param spender The account of the token spender + /// @return The current allowance granted by `owner` to `spender` + function allowance(address owner, address spender) external view returns (uint256); + + /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount` + /// @param spender The account which will be allowed to spend a given amount of the owners tokens + /// @param amount The amount of tokens allowed to be used by `spender` + /// @return Returns true for a successful approval, false for unsuccessful + function approve(address spender, uint256 amount) external returns (bool); + + /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender` + /// @param sender The account from which the transfer will be initiated + /// @param recipient The recipient of the transfer + /// @param amount The amount of the transfer + /// @return Returns true for a successful transfer, false for unsuccessful + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`. + /// @param from The account from which the tokens were sent, i.e. the balance decreased + /// @param to The account to which the tokens were sent, i.e. the balance increased + /// @param value The amount of tokens that were transferred + event Transfer(address indexed from, address indexed to, uint256 value); + + /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes. + /// @param owner The account that approved spending of its tokens + /// @param spender The account for which the spending allowance was modified + /// @param value The new allowance from the owner to the spender + event Approval(address indexed owner, address indexed spender, uint256 value); +} diff --git a/src/v4-core/interfaces/external/IERC6909Claims.sol b/src/v4-core/interfaces/external/IERC6909Claims.sol new file mode 100644 index 0000000..6dd382b --- /dev/null +++ b/src/v4-core/interfaces/external/IERC6909Claims.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + + +/// @notice Interface for claims over a contract balance, wrapped as a ERC6909 +interface IERC6909Claims { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event OperatorSet(address indexed owner, address indexed operator, bool approved); + + event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount); + + event Transfer(address caller, address indexed from, address indexed to, uint256 indexed id, uint256 amount); + + /*////////////////////////////////////////////////////////////// + FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @notice Owner balance of an id. + /// @param owner The address of the owner. + /// @param id The id of the token. + /// @return amount The balance of the token. + function balanceOf(address owner, uint256 id) external view returns (uint256 amount); + + /// @notice Spender allowance of an id. + /// @param owner The address of the owner. + /// @param spender The address of the spender. + /// @param id The id of the token. + /// @return amount The allowance of the token. + function allowance(address owner, address spender, uint256 id) external view returns (uint256 amount); + + /// @notice Checks if a spender is approved by an owner as an operator + /// @param owner The address of the owner. + /// @param spender The address of the spender. + /// @return approved The approval status. + function isOperator(address owner, address spender) external view returns (bool approved); + + /// @notice Transfers an amount of an id from the caller to a receiver. + /// @param receiver The address of the receiver. + /// @param id The id of the token. + /// @param amount The amount of the token. + /// @return bool True, always, unless the function reverts + function transfer(address receiver, uint256 id, uint256 amount) external returns (bool); + + /// @notice Transfers an amount of an id from a sender to a receiver. + /// @param sender The address of the sender. + /// @param receiver The address of the receiver. + /// @param id The id of the token. + /// @param amount The amount of the token. + /// @return bool True, always, unless the function reverts + function transferFrom(address sender, address receiver, uint256 id, uint256 amount) external returns (bool); + + /// @notice Approves an amount of an id to a spender. + /// @param spender The address of the spender. + /// @param id The id of the token. + /// @param amount The amount of the token. + /// @return bool True, always + function approve(address spender, uint256 id, uint256 amount) external returns (bool); + + /// @notice Sets or removes an operator for the caller. + /// @param operator The address of the operator. + /// @param approved The approval status. + /// @return bool True, always + function setOperator(address operator, bool approved) external returns (bool); +} diff --git a/src/v4-core/libraries/CustomRevert.sol b/src/v4-core/libraries/CustomRevert.sol new file mode 100644 index 0000000..0274de2 --- /dev/null +++ b/src/v4-core/libraries/CustomRevert.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title Library for reverting with custom errors efficiently +/// @notice Contains functions for reverting with custom errors with different argument types efficiently +/// @dev To use this library, declare `using CustomRevert for bytes4;` and replace `revert CustomError()` with +/// `CustomError.selector.revertWith()` +/// @dev The functions may tamper with the free memory pointer but it is fine since the call context is exited immediately +library CustomRevert { + /// @dev Reverts with the selector of a custom error in the scratch space + function revertWith(bytes4 selector) internal pure { + assembly ("memory-safe") { + mstore(0, selector) + revert(0, 0x04) + } + } + + /// @dev Reverts with a custom error with an address argument in the scratch space + function revertWith(bytes4 selector, address addr) internal pure { + assembly ("memory-safe") { + mstore(0, selector) + mstore(0x04, and(addr, 0xffffffffffffffffffffffffffffffffffffffff)) + revert(0, 0x24) + } + } + + /// @dev Reverts with a custom error with an int24 argument in the scratch space + function revertWith(bytes4 selector, int24 value) internal pure { + assembly ("memory-safe") { + mstore(0, selector) + mstore(0x04, signextend(2, value)) + revert(0, 0x24) + } + } + + /// @dev Reverts with a custom error with a uint160 argument in the scratch space + function revertWith(bytes4 selector, uint160 value) internal pure { + assembly ("memory-safe") { + mstore(0, selector) + mstore(0x04, and(value, 0xffffffffffffffffffffffffffffffffffffffff)) + revert(0, 0x24) + } + } + + /// @dev Reverts with a custom error with two int24 arguments + function revertWith(bytes4 selector, int24 value1, int24 value2) internal pure { + assembly ("memory-safe") { + let fmp := mload(0x40) + mstore(fmp, selector) + mstore(add(fmp, 0x04), signextend(2, value1)) + mstore(add(fmp, 0x24), signextend(2, value2)) + revert(fmp, 0x44) + } + } + + /// @dev Reverts with a custom error with two uint160 arguments + function revertWith(bytes4 selector, uint160 value1, uint160 value2) internal pure { + assembly ("memory-safe") { + let fmp := mload(0x40) + mstore(fmp, selector) + mstore(add(fmp, 0x04), and(value1, 0xffffffffffffffffffffffffffffffffffffffff)) + mstore(add(fmp, 0x24), and(value2, 0xffffffffffffffffffffffffffffffffffffffff)) + revert(fmp, 0x44) + } + } + + /// @dev Reverts with a custom error with two address arguments + function revertWith(bytes4 selector, address value1, address value2) internal pure { + assembly ("memory-safe") { + mstore(0, selector) + mstore(0x04, and(value1, 0xffffffffffffffffffffffffffffffffffffffff)) + mstore(0x24, and(value2, 0xffffffffffffffffffffffffffffffffffffffff)) + revert(0, 0x44) + } + } + + /// @notice bubble up the revert message returned by a call and revert with the selector provided + /// @dev this function should only be used with custom errors of the type `CustomError(bytes revertReason)` + function bubbleUpAndRevertWith(bytes4 selector) internal pure { + assembly ("memory-safe") { + let size := returndatasize() + let fmp := mload(0x40) + + // Encode selector, offset, size, data + mstore(fmp, selector) + mstore(add(fmp, 0x04), 0x20) + mstore(add(fmp, 0x24), size) + returndatacopy(add(fmp, 0x44), 0, size) + + // Ensure the size is a multiple of 32 bytes + let encodedSize := add(0x44, mul(div(add(size, 31), 32), 32)) + revert(fmp, encodedSize) + } + } +} + diff --git a/src/v4-core/libraries/SafeCast.sol b/src/v4-core/libraries/SafeCast.sol new file mode 100644 index 0000000..e5df1f1 --- /dev/null +++ b/src/v4-core/libraries/SafeCast.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +import {CustomRevert} from "./CustomRevert.sol"; + +/// @title Safe casting methods +/// @notice Contains methods for safely casting between types +library SafeCast { + using CustomRevert for bytes4; + + error SafeCastOverflow(); + + /// @notice Cast a uint256 to a uint160, revert on overflow + /// @param x The uint256 to be downcasted + /// @return y The downcasted integer, now type uint160 + function toUint160(uint256 x) internal pure returns (uint160 y) { + y = uint160(x); + if (y != x) SafeCastOverflow.selector.revertWith(); + } + + /// @notice Cast a uint256 to a uint128, revert on overflow + /// @param x The uint256 to be downcasted + /// @return y The downcasted integer, now type uint128 + function toUint128(uint256 x) internal pure returns (uint128 y) { + y = uint128(x); + if (x != y) SafeCastOverflow.selector.revertWith(); + } + + /// @notice Cast a int256 to a int128, revert on overflow or underflow + /// @param x The int256 to be downcasted + /// @return y The downcasted integer, now type int128 + function toInt128(int256 x) internal pure returns (int128 y) { + y = int128(x); + if (y != x) SafeCastOverflow.selector.revertWith(); + } + + /// @notice Cast a uint256 to a int256, revert on overflow + /// @param x The uint256 to be casted + /// @return y The casted integer, now type int256 + function toInt256(uint256 x) internal pure returns (int256 y) { + y = int256(x); + if (y < 0) SafeCastOverflow.selector.revertWith(); + } + + /// @notice Cast a uint256 to a int128, revert on overflow + /// @param x The uint256 to be downcasted + /// @return The downcasted integer, now type int128 + function toInt128(uint256 x) internal pure returns (int128) { + if (x >= 1 << 127) SafeCastOverflow.selector.revertWith(); + return int128(int256(x)); + } +} + diff --git a/src/v4-core/types/BalanceDelta.sol b/src/v4-core/types/BalanceDelta.sol new file mode 100644 index 0000000..c57fe97 --- /dev/null +++ b/src/v4-core/types/BalanceDelta.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import {SafeCast} from "../libraries/SafeCast.sol"; + +/// @dev Two `int128` values packed into a single `int256` where the upper 128 bits represent the amount0 +/// and the lower 128 bits represent the amount1. +type BalanceDelta is int256; + +using {add as +, sub as -, eq as ==, neq as !=} for BalanceDelta global; +using BalanceDeltaLibrary for BalanceDelta global; +using SafeCast for int256; + +function toBalanceDelta(int128 _amount0, int128 _amount1) pure returns (BalanceDelta balanceDelta) { + assembly ("memory-safe") { + balanceDelta := or(shl(128, _amount0), and(sub(shl(128, 1), 1), _amount1)) + } +} + +function add(BalanceDelta a, BalanceDelta b) pure returns (BalanceDelta) { + int256 res0; + int256 res1; + assembly ("memory-safe") { + let a0 := sar(128, a) + let a1 := signextend(15, a) + let b0 := sar(128, b) + let b1 := signextend(15, b) + res0 := add(a0, b0) + res1 := add(a1, b1) + } + return toBalanceDelta(res0.toInt128(), res1.toInt128()); +} + +function sub(BalanceDelta a, BalanceDelta b) pure returns (BalanceDelta) { + int256 res0; + int256 res1; + assembly ("memory-safe") { + let a0 := sar(128, a) + let a1 := signextend(15, a) + let b0 := sar(128, b) + let b1 := signextend(15, b) + res0 := sub(a0, b0) + res1 := sub(a1, b1) + } + return toBalanceDelta(res0.toInt128(), res1.toInt128()); +} + +function eq(BalanceDelta a, BalanceDelta b) pure returns (bool) { + return BalanceDelta.unwrap(a) == BalanceDelta.unwrap(b); +} + +function neq(BalanceDelta a, BalanceDelta b) pure returns (bool) { + return BalanceDelta.unwrap(a) != BalanceDelta.unwrap(b); +} + +/// @notice Library for getting the amount0 and amount1 deltas from the BalanceDelta type +library BalanceDeltaLibrary { + /// @notice A BalanceDelta of 0 + BalanceDelta public constant ZERO_DELTA = BalanceDelta.wrap(0); + + function amount0(BalanceDelta balanceDelta) internal pure returns (int128 _amount0) { + assembly ("memory-safe") { + _amount0 := sar(128, balanceDelta) + } + } + + function amount1(BalanceDelta balanceDelta) internal pure returns (int128 _amount1) { + assembly ("memory-safe") { + _amount1 := signextend(15, balanceDelta) + } + } +} + diff --git a/src/v4-core/types/BeforeSwapDelta.sol b/src/v4-core/types/BeforeSwapDelta.sol new file mode 100644 index 0000000..c3b45ca --- /dev/null +++ b/src/v4-core/types/BeforeSwapDelta.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// Return type of the beforeSwap hook. +// Upper 128 bits is the delta in specified tokens. Lower 128 bits is delta in unspecified tokens (to match the afterSwap hook) +type BeforeSwapDelta is int256; + +// Creates a BeforeSwapDelta from specified and unspecified +function toBeforeSwapDelta(int128 deltaSpecified, int128 deltaUnspecified) + pure + returns (BeforeSwapDelta beforeSwapDelta) +{ + assembly ("memory-safe") { + beforeSwapDelta := or(shl(128, deltaSpecified), and(sub(shl(128, 1), 1), deltaUnspecified)) + } +} + +/// @notice Library for getting the specified and unspecified deltas from the BeforeSwapDelta type +library BeforeSwapDeltaLibrary { + /// @notice A BeforeSwapDelta of 0 + BeforeSwapDelta public constant ZERO_DELTA = BeforeSwapDelta.wrap(0); + + /// extracts int128 from the upper 128 bits of the BeforeSwapDelta + /// returned by beforeSwap + function getSpecifiedDelta(BeforeSwapDelta delta) internal pure returns (int128 deltaSpecified) { + assembly ("memory-safe") { + deltaSpecified := sar(128, delta) + } + } + + /// extracts int128 from the lower 128 bits of the BeforeSwapDelta + /// returned by beforeSwap and afterSwap + function getUnspecifiedDelta(BeforeSwapDelta delta) internal pure returns (int128 deltaUnspecified) { + assembly ("memory-safe") { + deltaUnspecified := signextend(15, delta) + } + } +} + diff --git a/src/v4-core/types/Currency.sol b/src/v4-core/types/Currency.sol new file mode 100644 index 0000000..62de612 --- /dev/null +++ b/src/v4-core/types/Currency.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import {IERC20Minimal} from "../interfaces/external/IERC20Minimal.sol"; +import {CustomRevert} from "../libraries/CustomRevert.sol"; + +type Currency is address; + +using {greaterThan as >, lessThan as <, greaterThanOrEqualTo as >=, equals as ==} for Currency global; +using CurrencyLibrary for Currency global; + +function equals(Currency currency, Currency other) pure returns (bool) { + return Currency.unwrap(currency) == Currency.unwrap(other); +} + +function greaterThan(Currency currency, Currency other) pure returns (bool) { + return Currency.unwrap(currency) > Currency.unwrap(other); +} + +function lessThan(Currency currency, Currency other) pure returns (bool) { + return Currency.unwrap(currency) < Currency.unwrap(other); +} + +function greaterThanOrEqualTo(Currency currency, Currency other) pure returns (bool) { + return Currency.unwrap(currency) >= Currency.unwrap(other); +} + +/// @title CurrencyLibrary +/// @dev This library allows for transferring and holding native tokens and ERC20 tokens +library CurrencyLibrary { + using CustomRevert for bytes4; + + /// @notice Thrown when a native transfer fails + /// @param revertReason bubbled up revert reason + error NativeTransferFailed(bytes revertReason); + + /// @notice Thrown when an ERC20 transfer fails + /// @param revertReason bubbled up revert reason + error ERC20TransferFailed(bytes revertReason); + + /// @notice A constant to represent the native currency + Currency public constant NATIVE = Currency.wrap(address(0)); + + function transfer(Currency currency, address to, uint256 amount) internal { + // altered from https://github.com/transmissions11/solmate/blob/44a9963d4c78111f77caa0e65d677b8b46d6f2e6/src/utils/SafeTransferLib.sol + // modified custom error selectors + + bool success; + if (currency.isNative()) { + assembly ("memory-safe") { + // Transfer the ETH and revert if it fails. + success := call(gas(), to, amount, 0, 0, 0, 0) + } + // revert with NativeTransferFailed, containing the bubbled up error as an argument + if (!success) NativeTransferFailed.selector.bubbleUpAndRevertWith(); + } else { + assembly ("memory-safe") { + // Get a pointer to some free memory. + let fmp := mload(0x40) + + // Write the abi-encoded calldata into memory, beginning with the function selector. + mstore(fmp, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) + mstore(add(fmp, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. + mstore(add(fmp, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. + + success := + and( + // Set success to whether the call reverted, if not we check it either + // returned exactly 1 (can't just be non-zero data), or had no return data. + or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), + // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. + // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. + // Counterintuitively, this call must be positioned second to the or() call in the + // surrounding and() call or else returndatasize() will be zero during the computation. + call(gas(), currency, 0, fmp, 68, 0, 32) + ) + + // Now clean the memory we used + mstore(fmp, 0) // 4 byte `selector` and 28 bytes of `to` were stored here + mstore(add(fmp, 0x20), 0) // 4 bytes of `to` and 28 bytes of `amount` were stored here + mstore(add(fmp, 0x40), 0) // 4 bytes of `amount` were stored here + } + // revert with ERC20TransferFailed, containing the bubbled up error as an argument + if (!success) ERC20TransferFailed.selector.bubbleUpAndRevertWith(); + } + } + + function balanceOfSelf(Currency currency) internal view returns (uint256) { + if (currency.isNative()) { + return address(this).balance; + } else { + return IERC20Minimal(Currency.unwrap(currency)).balanceOf(address(this)); + } + } + + function balanceOf(Currency currency, address owner) internal view returns (uint256) { + if (currency.isNative()) { + return owner.balance; + } else { + return IERC20Minimal(Currency.unwrap(currency)).balanceOf(owner); + } + } + + function isNative(Currency currency) internal pure returns (bool) { + return Currency.unwrap(currency) == Currency.unwrap(NATIVE); + } + + function isZero(Currency currency) internal pure returns (bool) { + return isNative(currency); + } + + function toId(Currency currency) internal pure returns (uint256) { + return uint160(Currency.unwrap(currency)); + } + + // If the upper 12 bytes are non-zero, they will be zero-ed out + // Therefore, fromId() and toId() are not inverses of each other + function fromId(uint256 id) internal pure returns (Currency) { + return Currency.wrap(address(uint160(id))); + } +} + diff --git a/src/v4-core/types/PoolId.sol b/src/v4-core/types/PoolId.sol new file mode 100644 index 0000000..912c342 --- /dev/null +++ b/src/v4-core/types/PoolId.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import {PoolKey} from "./PoolKey.sol"; + +type PoolId is bytes32; + +/// @notice Library for computing the ID of a pool +library PoolIdLibrary { + /// @notice Returns value equal to keccak256(abi.encode(poolKey)) + function toId(PoolKey memory poolKey) internal pure returns (PoolId poolId) { + assembly ("memory-safe") { + poolId := keccak256(poolKey, mul(32, 5)) + } + } +} + diff --git a/src/v4-core/types/PoolKey.sol b/src/v4-core/types/PoolKey.sol new file mode 100644 index 0000000..714c263 --- /dev/null +++ b/src/v4-core/types/PoolKey.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import {Currency} from "./Currency.sol"; +import {IHooks} from "../interfaces/IHooks.sol"; + +/// @notice Returns the key for identifying a pool +struct PoolKey { + /// @notice The lower currency of the pool, sorted numerically + Currency currency0; + /// @notice The higher currency of the pool, sorted numerically + Currency currency1; + /// @notice The pool swap fee, capped at 1_000_000. If the highest bit is 1, the pool has a dynamic fee and must be exactly equal to 0x800000 + uint24 fee; + /// @notice Ticks that involve positions must be a multiple of tick spacing + int24 tickSpacing; + /// @notice The hooks of the pool + IHooks hooks; +} + diff --git a/src/v4-periphery/interfaces/IERC721Permit.sol b/src/v4-periphery/interfaces/IERC721Permit.sol new file mode 100644 index 0000000..52a08e9 --- /dev/null +++ b/src/v4-periphery/interfaces/IERC721Permit.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + + +/// @title ERC721 with permit +/// @notice Extension to ERC721 that includes a permit function for signature based approvals +interface IERC721Permit { + error NonceAlreadyUsed(); + + /// @notice The permit typehash used in the permit signature + /// @return The typehash for the permit + function PERMIT_TYPEHASH() external pure returns (bytes32); + + /// @notice The domain separator used in the permit signature + /// @return The domain seperator used in encoding of permit signature + function DOMAIN_SEPARATOR() external view returns (bytes32); + + /// @notice Approve of a specific token ID for spending by spender via signature + /// @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 v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function permit(address spender, uint256 tokenId, uint256 deadline, uint256 nonce, uint8 v, bytes32 r, bytes32 s) + external + payable; +} diff --git a/src/v4-periphery/interfaces/IMulticall.sol b/src/v4-periphery/interfaces/IMulticall.sol new file mode 100644 index 0000000..636d038 --- /dev/null +++ b/src/v4-periphery/interfaces/IMulticall.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.2; + + +/// @title Multicall interface +/// @notice Enables calling multiple methods in a single call to the contract +interface IMulticall { + /// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed + /// @dev The `msg.value` should not be trusted for any method callable from multicall. + /// @param data The encoded function data for each of the calls to make to this contract + /// @return results The results from each of the calls passed in via data + function multicall(bytes[] calldata data) external payable returns (bytes[] memory results); +} diff --git a/src/v4-periphery/interfaces/IPositionManager.sol b/src/v4-periphery/interfaces/IPositionManager.sol new file mode 100644 index 0000000..11a227f --- /dev/null +++ b/src/v4-periphery/interfaces/IPositionManager.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.2; + + +interface IPositionManager { + error NotApproved(address caller); + error DeadlinePassed(); + error IncorrectPositionConfigForTokenId(uint256 tokenId); + + /// @notice Maps the ERC721 tokenId to a configId, which is a keccak256 hash of the position's pool key, and range (tickLower, tickUpper) + /// Enforces that a minted ERC721 token is tied to one range on one pool. + /// @param tokenId the ERC721 tokenId, assigned at mint + /// @return configId the hash of the position's poolkey, tickLower, and tickUpper + function positionConfigs(uint256 tokenId) external view returns (bytes32 configId); + + /// @notice Batches many liquidity modification calls to pool manager + /// @param payload is an encoding of actions, and parameters for those actions + /// @param deadline is the deadline for the batched actions to be executed + function modifyLiquidities(bytes calldata payload, uint256 deadline) external payable; + + function nextTokenId() external view returns (uint256); +} diff --git a/src/v4-periphery/interfaces/IQuoter.sol b/src/v4-periphery/interfaces/IQuoter.sol new file mode 100644 index 0000000..734f1e5 --- /dev/null +++ b/src/v4-periphery/interfaces/IQuoter.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.6.2; + +import {Currency} from "../../v4-core/types/Currency.sol"; +import {PoolKey} from "../../v4-core/types/PoolKey.sol"; +import {PathKey} from "../libraries/PathKey.sol"; + +/// @title Quoter Interface +/// @notice Supports quoting the delta amounts from exact input or exact output swaps. +/// @notice For each pool also tells you the number of initialized ticks loaded and the sqrt price of the pool after the swap. +/// @dev These functions are not marked view because they rely on calling non-view functions and reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IQuoter { + error InvalidLockCaller(); + error InvalidQuoteBatchParams(); + error InsufficientAmountOut(); + error LockFailure(); + error NotSelf(); + error UnexpectedRevertBytes(bytes revertData); + + struct PoolDeltas { + int128 currency0Delta; + int128 currency1Delta; + } + + struct QuoteExactSingleParams { + PoolKey poolKey; + bool zeroForOne; + address recipient; + uint128 exactAmount; + uint160 sqrtPriceLimitX96; + bytes hookData; + } + + struct QuoteExactParams { + Currency exactCurrency; + PathKey[] path; + address recipient; + uint128 exactAmount; + } + + /// @notice Returns the delta amounts for a given exact input swap of a single pool + /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams` + /// poolKey The key for identifying a V4 pool + /// zeroForOne If the swap is from currency0 to currency1 + /// recipient The intended recipient of the output tokens + /// exactAmount The desired input amount + /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// hookData arbitrary hookData to pass into the associated hooks + /// @return deltaAmounts Delta amounts resulted from the swap + /// @return sqrtPriceX96After The sqrt price of the pool after the swap + /// @return initializedTicksLoaded The number of initialized ticks that the swap loaded + function quoteExactInputSingle(QuoteExactSingleParams calldata params) + external + returns (int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint32 initializedTicksLoaded); + + /// @notice Returns the delta amounts along the swap path for a given exact input swap + /// @param params the params for the quote, encoded as 'QuoteExactInputParams' + /// currencyIn The input currency of the swap + /// path The path of the swap encoded as PathKeys that contains currency, fee, tickSpacing, and hook info + /// recipient The intended recipient of the output tokens + /// exactAmount The desired input amount + /// @return deltaAmounts Delta amounts along the path resulted from the swap + /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path + /// @return initializedTicksLoadedList List of the initialized ticks that the swap loaded for each pool in the path + function quoteExactInput(QuoteExactParams memory params) + external + returns ( + int128[] memory deltaAmounts, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksLoadedList + ); + + /// @notice Returns the delta amounts for a given exact output swap of a single pool + /// @param params The params for the quote, encoded as `QuoteExactOutputSingleParams` + /// poolKey The key for identifying a V4 pool + /// zeroForOne If the swap is from currency0 to currency1 + /// recipient The intended recipient of the output tokens + /// exactAmount The desired input amount + /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// hookData arbitrary hookData to pass into the associated hooks + /// @return deltaAmounts Delta amounts resulted from the swap + /// @return sqrtPriceX96After The sqrt price of the pool after the swap + /// @return initializedTicksLoaded The number of initialized ticks that the swap loaded + function quoteExactOutputSingle(QuoteExactSingleParams calldata params) + external + returns (int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint32 initializedTicksLoaded); + + /// @notice Returns the delta amounts along the swap path for a given exact output swap + /// @param params the params for the quote, encoded as 'QuoteExactOutputParams' + /// currencyOut The output currency of the swap + /// path The path of the swap encoded as PathKeys that contains currency, fee, tickSpacing, and hook info + /// recipient The intended recipient of the output tokens + /// exactAmount The desired output amount + /// @return deltaAmounts Delta amounts along the path resulted from the swap + /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path + /// @return initializedTicksLoadedList List of the initialized ticks that the swap loaded for each pool in the path + function quoteExactOutput(QuoteExactParams memory params) + external + returns ( + int128[] memory deltaAmounts, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksLoadedList + ); +} diff --git a/src/v4-periphery/interfaces/IV4Router.sol b/src/v4-periphery/interfaces/IV4Router.sol new file mode 100644 index 0000000..75d599c --- /dev/null +++ b/src/v4-periphery/interfaces/IV4Router.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.2; + +import {Currency} from "../../v4-core/types/Currency.sol"; +import {PoolKey} from "../../v4-core/types/PoolKey.sol"; +import {PathKey} from "../libraries/PathKey.sol"; + +/// @title IV4Router +/// @notice Interface containing all the structs and errors for different v4 swap types +interface IV4Router { + /// @notice Emitted when an exactInput swap does not receive its minAmountOut + error TooLittleReceived(); + /// @notice Emitted when an exactOutput is asked for more than its maxAmountIn + error TooMuchRequested(); + + /// @notice Parameters for a single-hop exact-input swap + struct ExactInputSingleParams { + PoolKey poolKey; + bool zeroForOne; + uint128 amountIn; + uint128 amountOutMinimum; + uint160 sqrtPriceLimitX96; + bytes hookData; + } + + /// @notice Parameters for a multi-hop exact-input swap + struct ExactInputParams { + Currency currencyIn; + PathKey[] path; + uint128 amountIn; + uint128 amountOutMinimum; + } + + /// @notice Parameters for a single-hop exact-output swap + struct ExactOutputSingleParams { + PoolKey poolKey; + bool zeroForOne; + uint128 amountOut; + uint128 amountInMaximum; + uint160 sqrtPriceLimitX96; + bytes hookData; + } + + /// @notice Parameters for a multi-hop exact-output swap + struct ExactOutputParams { + Currency currencyOut; + PathKey[] path; + uint128 amountOut; + uint128 amountInMaximum; + } +} diff --git a/src/v4-periphery/interfaces/external/IERC20PermitAllowed.sol b/src/v4-periphery/interfaces/external/IERC20PermitAllowed.sol new file mode 100644 index 0000000..98d1e1a --- /dev/null +++ b/src/v4-periphery/interfaces/external/IERC20PermitAllowed.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.5.0; + + +/// @title Interface for permit +/// @notice Interface used by DAI/CHAI for permit +interface IERC20PermitAllowed { + /// @notice Approve the spender to spend some tokens via the holder signature + /// @dev This is the permit interface used by DAI and CHAI + /// @param holder The address of the token holder, the token owner + /// @param spender The address of the token spender + /// @param nonce The holder's nonce, increases at each call to permit + /// @param expiry The timestamp at which the permit is no longer valid + /// @param allowed Boolean that sets approval amount, true for type(uint256).max and false for 0 + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function permit( + address holder, + address spender, + uint256 nonce, + uint256 expiry, + bool allowed, + uint8 v, + bytes32 r, + bytes32 s + ) external; +} diff --git a/src/v4-periphery/libraries/PathKey.sol b/src/v4-periphery/libraries/PathKey.sol new file mode 100644 index 0000000..ba49010 --- /dev/null +++ b/src/v4-periphery/libraries/PathKey.sol @@ -0,0 +1,29 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; +import {Currency} from "../../v4-core/types/Currency.sol"; +import {IHooks} from "../../v4-core/interfaces/IHooks.sol"; +import {PoolKey} from "../../v4-core/types/PoolKey.sol"; + +struct PathKey { + Currency intermediateCurrency; + uint24 fee; + int24 tickSpacing; + IHooks hooks; + bytes hookData; +} + +library PathKeyLib { + function getPoolAndSwapDirection(PathKey memory params, Currency currencyIn) + internal + pure + returns (PoolKey memory poolKey, bool zeroForOne) + { + Currency currencyOut = params.intermediateCurrency; + (Currency currency0, Currency currency1) = + currencyIn < currencyOut ? (currencyIn, currencyOut) : (currencyOut, currencyIn); + + zeroForOne = currencyIn == currency0; + poolKey = PoolKey(currency0, currency1, params.fee, params.tickSpacing, params.hooks); + } +} +