Build your own hook
Whenever starting on a new project, it is always a good idea to use a framework which can assist in development and that can make the setup process easier. Similarly, when building your own hooks, will would want to use a few utilities to 1) Mining the correct salt for your hook address 2) Using a router which acquire the lock and then call various functions on the pool manager 3) Deploying the hook to a deterministic address
Many of these steps are already taken care by a few template repositories which are listed here
Hooks Template
One of the most popular templates is the v4-template which is created by Sauce.
You can clone the repository and then follow the instructions in the README to get started.
Getting Started
- Installation: The template requires Foundry. Install dependencies using:
 
forge install
- Testing: Run tests with:
 
forge test
Counter Hook
The template includes an example hook (Counter.sol), a test for it, and scripts for deploying hooks.
Here are some of the things to note about the Counter hook:
- It extends the 
BaseHookcontract which is defined in the v4-periphery repository. 
import {BaseHook} from "v4-periphery/BaseHook.sol";
contract Counter is BaseHook {
     // ... hook code here
}
- The hook gets called before and after every swap and modify position call. This is done as part of 
getHookPermissionsfunction 
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,
        noOp: false,
        accessLock: false
    });
}
- Corresponding to the hooks calls, the hook implements the following functions:
 
 function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata, bytes calldata)
     external
     override
     returns (bytes4)
 {
     beforeSwapCount[key.toId()]++;
     return BaseHook.beforeSwap.selector;
 }
 function afterSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata, BalanceDelta, bytes calldata)
     external
     override
     returns (bytes4)
 {
     afterSwapCount[key.toId()]++;
     return BaseHook.afterSwap.selector;
 }
 function beforeAddLiquidity(
     address,
     PoolKey calldata key,
     IPoolManager.ModifyLiquidityParams calldata,
     bytes calldata
 ) external override returns (bytes4) {
     beforeAddLiquidityCount[key.toId()]++;
     return BaseHook.beforeAddLiquidity.selector;
 }
 function beforeRemoveLiquidity(
     address,
     PoolKey calldata key,
     IPoolManager.ModifyLiquidityParams calldata,
     bytes calldata
 ) external override returns (bytes4) {
     beforeRemoveLiquidityCount[key.toId()]++;
     return BaseHook.beforeRemoveLiquidity.selector;
 }
- In each of these functions, Counter hook increments a counter. You can see this in the 
beforeSwapfunction: 
function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata, bytes calldata)
    external
    override
    returns (bytes4)
{
    beforeSwapCount[key.toId()]++;
    return BaseHook.beforeSwap.selector;
}
Additional Resources
- v4-periphery: For advanced hook implementations.
 - v4-core: The core repository for Uniswap v4.