# Hooks Overview (/docs/protocols/v4/guides/hooks/getting-started)

Start here to understand Uniswap v4 hooks and set up a local workflow for building and testing them.

## Set Up Your Local Environment
Before writing the hook, first configure a local environment (for example deploying `PoolManager`, utility routers, and test tokens).

At the end of this guide a development environment will be set up to be used to build the rest of the examples in the Guides section of the docs.

To get started quickly with Uniswap v4 hooks, use the `Getting Started` section below to clone a boilerplate and begin building. To start from scratch and learn the underlying concepts, jump to the `Start from Scratch` section.

## Getting Started
The Uniswap [v4-template repo](https://github.com/uniswapfoundation/v4-template) provides a basic foundry environment with required imports already pre-loaded. Click on [`Use this template`](https://github.com/new?template_name=v4-template\&template_owner=uniswapfoundation) to create a new repository with it.

Or simply clone it and install the dependencies:

```bash
git clone https://github.com/uniswapfoundation/v4-template.git
cd v4-template
# requires foundry
forge install
forge test
```

Then hop to the [Local Node via Anvil](#local-node-via-anvil) to complete the set up and start developing.

## Start from Scratch
In the following sections, let's walk through the steps to create the same environment set up as the boilerplate from scratch and learn the underlying concepts.

## Setting up Foundry
First thing is to set up a new Foundry project.

If there is no Foundry installed - follow the [Foundry Book](https://book.getfoundry.sh/getting-started/installation) for installation.

Once Foundry is setup, initialize a new project:

```bash
forge init counter-hook
cd counter-hook
```

Then install the Uniswap `v4-core` and `v4-periphery` contracts as dependencies:

```bash
forge install Uniswap/v4-core && forge install Uniswap/v4-periphery
```

Next, set up the remappings so that the shorthand syntax for importing contracts from the dependencies work nicely:

```bash
forge remappings > remappings.txt
```

> [!NOTE]
> If there is something wrong with the inferred remappings, please replace with the following in `remappings.txt`:

```
@uniswap/v4-core/=lib/v4-core/
forge-gas-snapshot/=lib/v4-core/lib/forge-gas-snapshot/src/
forge-std/=lib/v4-core/lib/forge-std/src/
permit2/=lib/v4-periphery/lib/permit2/
solmate/=lib/v4-core/lib/solmate/
v4-core/=lib/v4-core/
v4-periphery/=lib/v4-periphery/
```

After that, remove the default Counter contract and its associated test and script file that Foundry initially set up. To do that, either manually delete those files, or just run the following:

```bash
rm ./**/Counter*.sol
```

Finally, since v4 uses transient storage which is only available after Ethereum's cancun hard fork and on Solidity versions >= 0.8.24 - some config must be set in `foundry.toml` config file.

To do that, add the following lines to `foundry.toml`:

```toml
# foundry.toml

solc_version = "0.8.26"
evm_version = "cancun"
ffi = true
```

Awesome! Now it's all set to start building the hook! Let’s run a quick test to confirm everything is set up properly.

## Compile a basic hook contract
To confirm that the environment is configured correctly let's write a basic Counter Hook contract. Create a new file, `./src/CounterHook.sol` and paste the following code into it:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {BaseHook} from "v4-periphery/src/utils/BaseHook.sol";

import {Hooks} from "v4-core/src/libraries/Hooks.sol";
import {IPoolManager} from "v4-core/src/interfaces/IPoolManager.sol";
import {SwapParams, ModifyLiquidityParams} from "v4-core/src/types/PoolOperation.sol";
import {PoolKey} from "v4-core/src/types/PoolKey.sol";
import {PoolId, PoolIdLibrary} from "v4-core/src/types/PoolId.sol";
import {BalanceDelta} from "v4-core/src/types/BalanceDelta.sol";
import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "v4-core/src/types/BeforeSwapDelta.sol";

contract CounterHook is BaseHook {
    using PoolIdLibrary for PoolKey;

    // NOTE: ---------------------------------------------------------
    // state variables should typically be unique to a pool
    // a single hook contract should be able to service multiple pools
    // ---------------------------------------------------------------

    mapping(PoolId => uint256 count) public beforeSwapCount;
    mapping(PoolId => uint256 count) public afterSwapCount;

    mapping(PoolId => uint256 count) public beforeAddLiquidityCount;
    mapping(PoolId => uint256 count) public beforeRemoveLiquidityCount;

    constructor(IPoolManager _poolManager) BaseHook(_poolManager) {}

    function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
        return Hooks.Permissions({
            beforeInitialize: false,
            afterInitialize: false,
            beforeAddLiquidity: true,
            afterAddLiquidity: false,
            beforeRemoveLiquidity: true,
            afterRemoveLiquidity: false,
            beforeSwap: true,
            afterSwap: true,
            beforeDonate: false,
            afterDonate: false,
            beforeSwapReturnDelta: false,
            afterSwapReturnDelta: false,
            afterAddLiquidityReturnDelta: false,
            afterRemoveLiquidityReturnDelta: false
        });
    }

    // -----------------------------------------------
    // NOTE: see IHooks.sol for function documentation
    // -----------------------------------------------

    function _beforeSwap(address, PoolKey calldata key, SwapParams calldata, bytes calldata)
        internal
        override
        returns (bytes4, BeforeSwapDelta, uint24)
    {
        beforeSwapCount[key.toId()]++;
        return (BaseHook.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, 0);
    }

    function _afterSwap(address, PoolKey calldata key, SwapParams calldata, BalanceDelta, bytes calldata)
        internal
        override
        returns (bytes4, int128)
    {
        afterSwapCount[key.toId()]++;
        return (BaseHook.afterSwap.selector, 0);
    }

    function _beforeAddLiquidity(
        address,
        PoolKey calldata key,
        ModifyLiquidityParams calldata,
        bytes calldata
    ) internal override returns (bytes4) {
        beforeAddLiquidityCount[key.toId()]++;
        return BaseHook.beforeAddLiquidity.selector;
    }

    function _beforeRemoveLiquidity(
        address,
        PoolKey calldata key,
        ModifyLiquidityParams calldata,
        bytes calldata
    ) internal override returns (bytes4) {
        beforeRemoveLiquidityCount[key.toId()]++;
        return BaseHook.beforeRemoveLiquidity.selector;
    }
}
```

To compile the Counter Hook contracts in the `./src` folder, use the foundry build command:

```bash
forge build
```

If the environment is compiled correctly it will display a message:

```
Compiler run successful!
```

## Local node via Anvil
Other than writing unit tests, [Anvil](https://book.getfoundry.sh/anvil/) can be used to deploy and test hooks.

With the local node up and running, use the `--rpc-url 127.0.0.1:8545` flag in tests to point the Foundry testing suite to that local node:

```bash
# start anvil, a local EVM chain
anvil

# in a new terminal
# foundry script for deploying v4 & hooks to anvil
forge script script/Anvil.s.sol \
    --rpc-url http://localhost:8545 \
    --private-key <test_wallet_private_key> \
    --broadcast

# test on the anvil local node
forge test --rpc-url 127.0.0.1:8545
```

With the environment set up ready to be built on. Jump over to the guides section to learn about the Uniswap functions that can be integrated with Hook. Remember to add all contracts (.sol files) to the `./src` folder and their subsequent tests to the `./test` folder. Then test them against the local anvil node by running:

```bash
forge test --rpc-url 127.0.0.1:8545
```

## Appendix: OpenZeppelin Hooks Library
> [!NOTE]
> [OpenZeppelin Hooks Library](https://docs.openzeppelin.com/uniswap-hooks/1.x/), included in [v4-template](https://github.com/uniswapfoundation/v4-template), provides secure and modular reference implementations for Uniswap v4 hooks.

If you're starting from scratch, you can install the OpenZeppelin Hooks library:

```bash
$ forge install OpenZeppelin/uniswap-hooks
```

The library includes:

* **BaseHook**: Core scaffolding with security checks and permission management
* **BaseCustomAccounting**: For implementing hook-owned liquidity and custom token accounting
* **BaseCustomCurve**: For replacing default concentrated liquidity math with custom swap logic
* **BaseAsyncSwap**: For implementing non-atomic and asynchronous swaps
* **BaseDynamicFee**: For implementing dynamic fee pools
* **BaseOverrideFee**: For implementing dynamic fees on every swap
* **BaseDynamicAfterFee**: For implementing post-swap fee adjustments based on actual swap output

## Where to Go Next
* [Swap Hooks](/docs/protocols/v4/guides/hooks/swap-hooks)
* [Liquidity Hooks](/docs/protocols/v4/guides/hooks/liquidity-hooks)
* [AsyncSwap Hooks](/docs/protocols/v4/guides/hooks/async-swap)
* [Access msg.sender Inside a Hook](/docs/protocols/v4/guides/hooks/accessing-msg.sender)
* [Hook Deployment](/docs/protocols/v4/guides/hooks/hook-deployment)
