Uniswap Hook Incubator — Building your first hook #3

Zuhaib Mohammed
2 min readSep 10, 2024

--

When we are new to Solidity, one of the first examples we encounter is the Counter.sol, where we set a variable to a value and retrieve it using a getter function. The repository below demonstrates a similar concept but utilizes Uniswap V4 hooks as an example.

https://github.com/uniswapfoundation/v4-template

A similar example was used in the lessons, where users earned points for swapping tokens and adding liquidity. This basic example helped to understand how each hook has its own function parameters and values to be passed. One example to understand this is shown below.

Let’s explore the differences between beforeSwap & afterSwap

beforeSwap(
address sender,
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
bytes calldata hookData
)

afterSwap(
address sender,
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
BalanceDelta delta,
bytes calldata hookData
)

There’s an additional parameter called BalanceDelta that tracks how much tokens the user and the pool need to exchange. Essentially, a negative value indicates that funds are leaving the user’s wallet, while a positive value means funds are being sent to the user’s wallet.

Types of swaps

  1. Exact Input for Output: The user specifies an exact amount of input tokens to swap for a calculated amount of output tokens. Example, “I want to sell exactly 1 ETH for some amount of USDC.”

2. Exact Output for Input: The user specifies an exact amount of output tokens they want, with a calculated input token amount (up to a limit). For example, “I want exactly 4000 USDC and can spend up to 1.5 ETH for that.

Hook Contract Address

The PoolManager determines which hook functions to call based on a bitmap encoded directly into the hook’s address. Each hook function — such as afterSwap — is represented by a true/false value at a specific bit within the hook’s address. For local testing, we can use the deployCodeTo cheat code available in Foundry.

When determining the correct address, the key constraint is that the bits we care about must be set to 1 in the address, while the rest are irrelevant.

Example where in the afterAddLiquidity and afterSwap needs to be enabled for the custom hook.

    // Deploy hook to an address that has the proper flags set
uint160 flags = uint160(
Hooks.AFTER_ADD_LIQUIDITY_FLAG | Hooks.AFTER_SWAP_FLAG
);
deployCodeTo(
"PointsHook.sol",
abi.encode(manager, "Points Token", "TEST_POINTS"),
address(flags)
);

Thanks for Reading ! Stay Tuned for the next blog !

Connect with me: https://linktr.ee/zuhaib44

--

--