-
Notifications
You must be signed in to change notification settings - Fork 549
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8aa3062
commit 1a77926
Showing
32 changed files
with
1,281 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
{ | ||
"label": "Permit2", | ||
"position": 3, | ||
"position": 4, | ||
"collapsed": true | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
{ | ||
"label": "UniswapX", | ||
"position": 2, | ||
"position": 3, | ||
"collapsed": true | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
{ | ||
"label": "Universal Router", | ||
"position": 2, | ||
"position": 3, | ||
"collapsed": true | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
{ | ||
"label": "V1 Protocol", | ||
"position": 5, | ||
"position": 6, | ||
"collapsed": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
{ | ||
"label": "V2 Protocol", | ||
"position": 4, | ||
"position": 5, | ||
"collapsed": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
{ | ||
"label": "V3 Protocol", | ||
"position": 1, | ||
"position": 2, | ||
"collapsed": false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"label": "V4 Protocol", | ||
"position": 1, | ||
"collapsed": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
--- | ||
id: intro-to-v4 | ||
title: Introduction to Uniswap V4 | ||
sidebar_position: 0.5 | ||
--- | ||
|
||
Uniswap V4, the latest iteration of the Uniswap protocol, is a significant advancement in decentralized | ||
exchanges (DEXs) and automated market makers (AMMs). Here are the key features of Uniswap V4: | ||
|
||
**Customizability with Hooks:** Uniswap V4 introduces a new feature called "hooks", which are essentially smart | ||
contracts that can be attached to liquidity pools. These hooks enable a high degree of customization, allowing | ||
developers to implement specific functionalities at different points in a pool's lifecycle, such as before or after | ||
swaps and liquidity modifications. | ||
|
||
For example, hooks can enable order types (i.e. limit order), specially-tailored oracles, or custom AMM curves. The | ||
flexibility of hooks allows for a broad range of innovations while maintaining the core efficiency of the platform. | ||
|
||
**Singleton Contract for Efficiency:** A significant architectural change in Uniswap V4 is the introduction of a | ||
Singleton contract. In previous versions, each token pair required a separate smart contract, leading to higher gas | ||
costs, especially in multi-hop trades. The Singleton contract model consolidates all pools into a single contract, | ||
significantly reducing gas costs for both trading and pool creation. This model allows for more efficient multi-hop | ||
trades as tokens do not need to be transferred between multiple contracts. Additionally, creating a new pool in | ||
V4 is 99% cheaper in gas costs compared to V3, lowering barriers for setting up new pools. | ||
|
||
**Flash Accounting System:** Another innovative feature in Uniswap V4 is the "flash accounting" system. This system | ||
allows users to efficiently chain together multiple actions in a single transaction, such as swap-and-add-liquidity. | ||
The system tracks the net balances of inbound and outbound tokens; at the end of the transaction, | ||
the contract verifies all debts have been settled. If the user hasn’t settled their debts, the entire transaction reverts, | ||
ensuring security and efficiency. This system is similar to flash loans in concept and is part of the effort to | ||
reduce gas costs and enhance transaction efficiency on the platform. | ||
|
||
**Unlimited Fee Tiers:** Uniswap V4 allows unlimited fee tiers for various liquidity pools. This flexibility allows | ||
for a more tailored approach in catering to a diverse range of assets and trading strategies. Each pool can have its | ||
own unique fee tiers, optimizing the platform's appeal to a wider spectrum of users and market needs. | ||
|
||
**Native ETH Support**: Uniswap V4 enhances user experience by enabling direct trading pairs with native ETH, | ||
eliminating the need for WETH (Wrapped ETH). This simplification streamlines the trading process and lowers transaction | ||
costs. | ||
|
||
**Community-Driven Development and Innovation:** Uniswap V4 emphasizes a community-driven approach to development | ||
and innovation. Since its code release, there has been active community engagement, with many issues, pull requests, | ||
and unique feature ideas contributed by users. The protocol is | ||
designed to encourage innovation, allowing the global community to shape the future of AMMs. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
--- | ||
id: v4-architecture-overview | ||
title: V4 Architecture Overview | ||
sidebar_position: 1 | ||
--- | ||
|
||
# Architecture | ||
In Uniswap V3, each pool has its own contract instance, which makes initializing pools and performing swaps in multiple pools costly. | ||
Whereas, in V4, all pools are kept in a single contract to provide substantial gas savings. | ||
|
||
![High Level Architecture](./images/01_Pool_Initialization/v3_high_level_architecture.png) | ||
|
||
![High Level Architecture](./images/01_Pool_Initialization/v4_high_level_architecture.png) | ||
|
||
Early calculations say that V4 will | ||
make the gas cost of creating pools 99% less. Hooks offer unlimited choices and the single contract lets you easily | ||
move through all these choices. | ||
|
||
This Singleton design is improved by a new "flash accounting" method. Instead of moving assets in and out of pools | ||
after each swap in V3, this method only moves the net balances. This means the system is a lot more efficient and | ||
saves even more gas in Uniswap V4. | ||
|
||
![V3 Detailed Architecture](./images/01_Pool_Initialization/v3_detailed_architecture.png) | ||
|
||
![V4 Detailed Architecture](./images/01_Pool_Initialization/v4_detailed_architecture.png) | ||
|
||
Because of the efficiency of the Singleton contract and flash accounting, there is no need to limit fee tiers. People | ||
who create pools can choose them to be most competitive or change them with a dynamic fee hook. V4 also supports | ||
native ETH again, which helps save more gas. |
195 changes: 195 additions & 0 deletions
195
docs/contracts/v4/concepts/02-2-pool-manager-and-initialization.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
--- | ||
id: pool-manager-and-pool-initialization | ||
title: Pool Manager and Pool Initialization | ||
sidebar_position: 1 | ||
--- | ||
|
||
# PoolManager | ||
To understand the major parts of the PoolManager, let's look at the the main interface: `IPoolManager.sol`. | ||
|
||
https://github.com/Uniswap/v4-core/blob/main/src/interfaces/IPoolManager.sol | ||
|
||
### Lifecycle Functions | ||
|
||
1. **initialize**: This function initializes a new pool with specified parameters such as pool key, initial price, and | ||
optional hook data, setting up the fundamental characteristics of the pool. | ||
|
||
2. **swap**: Allows users to exchange one type of currency for another within a specified pool, adhering to set limits | ||
and conditions, and adjusting the pool's state accordingly. | ||
|
||
3. **modifyLiquidity**: Enables users to change the amount of liquidity they've provided to a pool, either by adding or | ||
removing it, based on specified upper and lower tick limits. | ||
|
||
### Balance Functions | ||
1. **mint (related to ERC6909 claims)**: Used for creating new claim tokens (as per ERC6909 standards) for a user, | ||
denoting specific rights or entitlements, but not representing liquidity provider (LP) receipt tokens. | ||
|
||
2. **burn (related to ERC6909 claims)**: Allows users to destroy their claim tokens (compliant with ERC6909), | ||
effectively relinquishing the rights or entitlements those tokens represented. | ||
|
||
3. **take**: This function allows users to withdraw or "net out" a specified amount of a currency, which could be seen | ||
as a mechanism for zero-cost flash loans under certain conditions. | ||
|
||
4. **settle**: Used by users to pay off any outstanding amounts they owe, potentially in a different currency, with | ||
the function returning the amount paid. | ||
|
||
The `mint` and `burn` functions are specifically related to handling ERC6909 claims, which are distinct from liquidity | ||
provider receipt tokens. These functions deal with specific claims or entitlements rather than the representation of a | ||
user's share in the liquidity pool. | ||
|
||
|
||
# Pool Initialization | ||
The `initialize` function sets up a new liquidity pool in Uniswap. It takes necessary information such as currencies | ||
and pricing info, and hook information as inputs, checks various conditions to ensure that the pool is set up correctly, | ||
and sets initial values for the pool. | ||
|
||
https://github.com/Uniswap/v4-core/blob/main/src/PoolManager.sol | ||
```solidity | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity ^0.8.20; | ||
// ... [other imports and contract definitions] | ||
/// @notice Holds the state for all pools | ||
contract PoolManager is IPoolManager, Fees, NoDelegateCall, ERC6909Claims { | ||
// ... [other definitions and functions] | ||
/// @inheritdoc IPoolManager | ||
function initialize(PoolKey memory key, uint160 sqrtPriceX96, bytes calldata hookData) | ||
external | ||
override | ||
onlyByLocker // Modifier ensures only the current locker can call this function | ||
returns (int24 tick) | ||
{ | ||
// Check if the fee specified in the key is too large | ||
if (key.fee.isStaticFeeTooLarge()) revert FeeTooLarge(); | ||
// Validate tick spacing - it must be within defined min and max limits | ||
if (key.tickSpacing > MAX_TICK_SPACING) revert TickSpacingTooLarge(); | ||
if (key.tickSpacing < MIN_TICK_SPACING) revert TickSpacingTooSmall(); | ||
// Ensure the currency order is correct (currency0 < currency1) | ||
if (key.currency0 >= key.currency1) revert CurrenciesOutOfOrderOrEqual(); | ||
// Validate the hooks contract address | ||
if (!key.hooks.isValidHookAddress(key.fee)) revert Hooks.HookAddressNotValid(address(key.hooks)); | ||
// Call before initialization hook with provided data | ||
key.hooks.beforeInitialize(key, sqrtPriceX96, hookData); | ||
// Convert the PoolKey to a PoolId | ||
PoolId id = key.toId(); | ||
// Fetch protocol fee and dynamic swap fee if applicable | ||
(, uint16 protocolFee) = _fetchProtocolFee(key); | ||
uint24 swapFee = key.fee.isDynamicFee() ? _fetchDynamicSwapFee(key) : key.fee.getStaticFee(); | ||
// Initialize the pool with the given parameters and receive the current tick | ||
tick = pools[id].initialize(sqrtPriceX96, protocolFee, swapFee); | ||
// Call after initialization hook with the resulting data | ||
key.hooks.afterInitialize(key, sqrtPriceX96, tick, hookData); | ||
// Emit an event to signal the initialization of the pool with key details | ||
emit Initialize(id, key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks); | ||
} | ||
// ... [other functions] | ||
} | ||
``` | ||
Upon success, the transaction announces a new pool was created by emitting an `Initialize` event. | ||
|
||
# PoolKey | ||
|
||
The `PoolKey` is a structure that uniquely identifies a liquidity pool by storing its details -- the two | ||
currencies involved (sorted numerically), the swap fee, tick spacing, and hooks (extra functionalities) of the pool. | ||
|
||
It acts as a unique identifier, ensuring that each pool can be precisely specified and accessed within the code. | ||
|
||
The liquidity for a PoolKey is unique to that pool alone | ||
|
||
```solidity | ||
/// @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. The upper 4 bits determine if the hook sets any fees. | ||
uint24 fee; | ||
/// @notice Ticks that involve positions must be a multiple of tick spacing | ||
int24 tickSpacing; | ||
/// @notice The hooks of the pool | ||
IHooks hooks; | ||
} | ||
``` | ||
|
||
Since we create and pass the `PoolKey` to the `initialize` function, and as part of the PoolKey we pass the `hooks` we | ||
want to use for the pool. | ||
|
||
We can use the `hooks` to customize the pool to our liking. | ||
|
||
# Initialization Code | ||
Here are the important parts of the initialization code from the `PoolManagerInitializeTest` contract. | ||
|
||
https://github.com/Uniswap/v4-core/blob/main/test/PoolManagerInitialize.t.sol | ||
```solidity | ||
contract Deployers { | ||
function deployFreshManager() internal { | ||
manager = new PoolManager(500000); | ||
} | ||
function deployFreshManagerAndRouters() internal { | ||
deployFreshManager(); | ||
// Initialize various routers with the deployed manager. These routers likely handle | ||
// different aspects of the pool's functionality, such as swapping, liquidity modification, etc. | ||
swapRouter = new PoolSwapTest(manager); | ||
modifyLiquidityRouter = new PoolModifyLiquidityTest(manager); | ||
donateRouter = new PoolDonateTest(manager); | ||
takeRouter = new PoolTakeTest(manager); | ||
initializeRouter = new PoolInitializeTest(manager); // This is the router that is used to initialize the pool | ||
// ... [other routers] | ||
} | ||
} | ||
contract PoolManagerInitializeTest is Test, Deployers, GasSnapshot { | ||
function setUp() public { | ||
deployFreshManagerAndRouters(); | ||
(currency0, currency1) = deployMintAndApprove2Currencies(); | ||
uninitializedKey = PoolKey({ | ||
currency0: currency0, | ||
currency1: currency1, | ||
fee: 3000, | ||
hooks: IHooks(ADDRESS_ZERO), | ||
tickSpacing: 60 | ||
}); | ||
} | ||
function test_initialize_succeedsWithHooks(uint160 sqrtPriceX96) public { | ||
// Assumptions tested in Pool.t.sol | ||
sqrtPriceX96 = uint160(bound(sqrtPriceX96, TickMath.MIN_SQRT_RATIO, TickMath.MAX_SQRT_RATIO - 1)); | ||
address payable mockAddr = payable(address(uint160(Hooks.BEFORE_INITIALIZE_FLAG | Hooks.AFTER_INITIALIZE_FLAG))); | ||
address payable hookAddr = payable(MOCK_HOOKS); | ||
vm.etch(hookAddr, vm.getDeployedCode("EmptyTestHooks.sol:EmptyTestHooks")); | ||
MockContract mockContract = new MockContract(); | ||
vm.etch(mockAddr, address(mockContract).code); | ||
MockContract(mockAddr).setImplementation(hookAddr); | ||
uninitializedKey.hooks = IHooks(mockAddr); | ||
// Call initialize function with the uninitialized key and the specified sqrtPriceX96 | ||
int24 tick = initializeRouter.initialize(uninitializedKey, sqrtPriceX96, ZERO_BYTES); | ||
(Pool.Slot0 memory slot0,,,) = manager.pools(uninitializedKey.toId()); | ||
assertEq(slot0.sqrtPriceX96, sqrtPriceX96, "sqrtPrice"); | ||
} | ||
} | ||
``` |
Oops, something went wrong.
1a77926
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
docs – ./
docs-uniswap.vercel.app
docs.uniswap.org
docs-git-main-uniswap.vercel.app