# Create a Pool on Uniswap v4 (/docs/protocols/v4/guides/create-pool)

Create a Uniswap v4 pool and optionally initialize it with liquidity in one flow.

## Context
Creating a pool on Uniswap v4 is permissionless and enables the trading of an asset. Uniswap v4 is a popular destination for creating markets due to its:

* Proven track record and battle-tested codebase
* Concentrated liquidity, unlocking capital efficiency
* Flexibile pool design through dynamic fees and hooks
* Gas-efficient architecture
* Integrations with alternative trading venues

For more information, developers should see [Uniswap v4 Overview](/docs/protocols/v4/overview)

The guide covers two approaches to creating a pool:

1. Create a pool only
2. Create a pool and add initial liquidity, with one transaction

## Setup
Developing with Uniswap v4 *requires [foundry](https://book.getfoundry.sh)*

Install the dependencies:

```bash
forge install uniswap/v4-core
forge install uniswap/v4-periphery
```

## Guide: Create a Pool Only
To initialize a Uniswap v4 Pool *without initial liquidity*, developers should call `PoolManager.initialize()`

Creating a pool without liquidity may be useful for "reserving" a pool for future use, when initial liquidity is not available, or when external market makers would provide the starting liquidity

## 1. Configure the pool
```solidity
import {PoolKey} from "v4-core/src/types/PoolKey.sol";

PoolKey memory pool = PoolKey({
    currency0: currency0,
    currency1: currency1,
    fee: lpFee,
    tickSpacing: tickSpacing,
    hooks: hookContract
});
```

> For native token pairs (Ether), use `CurrencyLibrary.ADDRESS_ZERO` as `currency0`

`PoolKey` uniquely identifies a pool

* *Currencies* should be sorted, `uint160(currency0) < uint160(currency1)`
* *lpFee* is the fee expressed in pips, i.e. 3000 = 0.30%
* *tickSpacing* is the granularity of the pool. Lower values are more precise but may be more expensive to trade on
* *hookContract* is the address of the hook contract

A note on `tickSpacing`:

Lower tick spacing provides improved price precision; however, smaller tick spaces will cause swaps to cross ticks more often, incurring higher gas costs

As a reference, Uniswap v3 pools are configured with:

| Fee   | Fee Value | Tick Spacing |
| ----- | --------- | ------------ |
| 0.01% | 100       | 1            |
| 0.05% | 500       | 10           |
| 0.30% | 3000      | 60           |
| 1.00% | 10\_000   | 200          |

## 2. Call initialize
Pools are initialized with a starting price

```solidity
IPoolManager(manager).initialize(pool, startingPrice);
```

* the *startingPrice* is expressed as sqrtPriceX96: `floor(sqrt(token1 / token0) * 2^96)`
  * i.e. `79228162514264337593543950336` is the starting price for a 1:1 pool

## Guide: Create a Pool and Add Liquidity
Uniswap v4's `PositionManager` supports atomic creation of a pool and initial liquidity using *multicall*. Developers can create a trading pool, with liquidity, in a single transaction:

## 1. Initialize the parameters provided to multicall()
```solidity
bytes[] memory params = new bytes[](2);
```

* The first call, `params[0]`, will encode `initializePool` parameters
* The second call, `params[1]`, will encode a *mint* operation for `modifyLiquidities`

## 2. Configure the pool
```solidity
PoolKey memory pool = PoolKey({
    currency0: currency0,
    currency1: currency1,
    fee: lpFee,
    tickSpacing: tickSpacing,
    hooks: hookContract
});
```

> For native token pairs (Ether), use `CurrencyLibrary.ADDRESS_ZERO` as `currency0`

`PoolKey` uniquely identifies a pool

* *Currencies* should be sorted, `uint160(currency0) < uint160(currency1)`
* *lpFee* is the fee expressed in pips, i.e. 3000 = 0.30%
* *tickSpacing* is the granularity of the pool. Lower values are more precise but more expensive to trade
* *hookContract* is the address of the hook contract

## 3. Encode the initializePool parameters
Pools are initialized with a starting price

```solidity
import {IPoolInitializer_v4} from "v4-periphery/src/interfaces/IPoolInitializer_v4.sol";

params[0] = abi.encodeWithSelector(
    IPoolInitializer_v4.initializePool.selector,
    pool,
    startingPrice
);
```

* the *startingPrice* is expressed as *sqrtPriceX96*: `floor(sqrt(token1 / token0) * 2^96)`
  * `79228162514264337593543950336` is the starting price for a 1:1 pool

## 4. Initialize the mint-liquidity parameters
PositionManager's `modifyLiquidities` uses an encoded command system

```solidity
bytes memory actions = abi.encodePacked(uint8(Actions.MINT_POSITION), uint8(Actions.SETTLE_PAIR));
```

* The first command `MINT_POSITION` creates a new liquidity position
* The second command `SETTLE_PAIR` indicates that tokens are to be paid by the caller, to create the position

## Guide: Encode Liquidity Operations
5. Encode the MINT_POSITION parameters [#5-encode-the-mint_position-parameters]

```solidity
bytes[] memory mintParams = new bytes[](2);
mintParams[0] = abi.encode(pool, tickLower, tickUpper, liquidity, amount0Max, amount1Max, recipient, hookData);
```

* *pool* the same `PoolKey` defined above, in pool-creation
* *tickLower* and *tickUpper* are the range of the position, must be a multiple of `pool.tickSpacing`
* *liquidity* is the amount of liquidity units to add, see `LiquidityAmounts` for converting token amounts to liquidity units
* *amount0Max* and *amount1Max* are the maximum amounts of token0 and token1 the caller is willing to transfer
* *recipient* is the address that will receive the liquidity position (ERC-721)
* *hookData* is the optional hook data

6. Encode the SETTLE_PAIR parameters [#6-encode-the-settle_pair-parameters]

Creating a position on a pool requires the caller to transfer `currency0` and `currency1` tokens

```solidity
mintParams[1] = abi.encode(pool.currency0, pool.currency1);
```

## 7. Encode the modifyLiquidities call
```solidity
// Note: In production, deadlines should be calculated offchain using real time
// For example: uint256 deadline = block.timestamp + 3600; // 1 hour from now
uint256 deadline = block.timestamp + 3600; // 1 hour deadline
params[1] = abi.encodeWithSelector(
    posm.modifyLiquidities.selector, abi.encode(actions, mintParams), deadline
);
```

## Guide: Approve and Execute
## 8. Approve the tokens
`PositionManager` uses `Permit2` for token transfers

* Repeat for both tokens

```solidity
// approve permit2 as a spender
IERC20(token).approve(address(permit2), type(uint256).max);

// approve `PositionManager` as a spender
IAllowanceTransfer(address(permit2)).approve(token, address(positionManager), type(uint160).max, type(uint48).max);
```

## 9. Execute the multicall
The `multicall` is used to execute multiple calls in a single transaction

```solidity
PositionManager(posm).multicall(params);
```

For pools paired with native tokens (Ether), provide `value` in the contract call

```solidity
PositionManager(posm).multicall{value: ethToSend}(params);
```

> Excess Ether is **NOT** refunded unless developers encoded `SWEEP` in the `actions` parameter

For a full end-to-end script, developers should see [v4-template's scripts](https://github.com/uniswapfoundation/v4-template/tree/main/script)
