# Custom hook

## Overview

The `CustomHook` contract is a Uniswap V4 hook deployed and attached to the official TITHE/ETH pool. It is the active component of the system — every swap on the pool triggers its callbacks, and every fee TITHE generates flows through it.

The hook has three jobs:

1. **Skim 5% of the ETH side of every swap** (regardless of direction).
2. **Route 4% to the `RewardDistributor` and 1% to the treasury multisig.**
3. **Enforce permanent liquidity lock** by blocking modification of the initial LP position.

## V4 hooks, briefly

In Uniswap V4, every pool can optionally have an associated hook contract. The pool calls into the hook at specific lifecycle moments — before/after `initialize`, before/after `addLiquidity`, before/after `removeLiquidity`, before/after `swap`, and before/after `donate`. The hook can perform arbitrary logic at each of these points and, with the right permissions flags, can modify the swap's input/output amounts (the "delta").

The set of callbacks a hook participates in is encoded in the hook's deployment address itself — specific bits of the address indicate which permissions the hook holds. This is a security feature: a pool can verify at initialization that the hook claims only the permissions encoded in its address, and the hook cannot be tricked into executing privileged callbacks that weren't part of its declared interface.

## CustomHook permissions

The CustomHook deploys with the following permissions encoded:

| Flag                           | Status               | Used for                                                                             |
| ------------------------------ | -------------------- | ------------------------------------------------------------------------------------ |
| `beforeInitialize`             | Enabled              | Validate the pool is being initialized with TITHE/ETH and no other configuration.    |
| `afterInitialize`              | Disabled             | —                                                                                    |
| `beforeAddLiquidity`           | Enabled              | Allow initial LP add by deployer; block all subsequent adds to the initial position. |
| `afterAddLiquidity`            | Disabled             | —                                                                                    |
| `beforeRemoveLiquidity`        | **Enabled (revert)** | Block all liquidity removal attempts. This is the LP lock.                           |
| `afterRemoveLiquidity`         | Disabled             | —                                                                                    |
| `beforeSwap`                   | Enabled              | Skim fee on buy direction (ETH → TITHE).                                             |
| `beforeSwapReturnsDelta`       | **Enabled**          | Required to modify the input delta and take fee in ETH.                              |
| `afterSwap`                    | Enabled              | Skim fee on sell direction (TITHE → ETH).                                            |
| `afterSwapReturnsDelta`        | **Enabled**          | Required to modify the output delta and take fee in ETH.                             |
| `beforeDonate` / `afterDonate` | Disabled             | No donate logic.                                                                     |

All other permissions are disabled. The hook cannot mint, cannot pause, cannot upgrade, cannot freeze. Its surface area is precisely four lifecycle callbacks plus initialization validation.

## Fee mechanics — buy direction

When a user swaps ETH → TITHE (buying):

{% stepper %}
{% step %}

### User submits swap

zeroForOne = true, amountSpecified = X ETH (input)
{% endstep %}

{% step %}

### PoolManager invokes CustomHook.beforeSwap(...)

{% endstep %}

{% step %}

### Hook computes fee

fee = X \* 5% = X \* 500 / 10000
{% endstep %}

{% step %}

### Hook returns a BeforeSwapDelta

It indicates it has claimed `fee` ETH from input.
{% endstep %}

{% step %}

### Pool executes the swap

Effective input is (X - fee), producing TITHE output.
{% endstep %}

{% step %}

### Hook splits the claimed fee

* Transfers (fee \* 4 / 5) ETH to RewardDistributor
* Transfers (fee \* 1 / 5) ETH to treasury multisig
  {% endstep %}

{% step %}

### User receives TITHE

The user receives TITHE corresponding to (X - fee) ETH at the pool's price.
{% endstep %}
{% endstepper %}

The fee is taken **before** the swap. The user effectively pays the fee in ETH and then receives less TITHE than they would on a vanilla pool. The hook never holds TITHE during this flow.

## Fee mechanics — sell direction

When a user swaps TITHE → ETH (selling):

{% stepper %}
{% step %}

### User submits swap

zeroForOne = false, amountSpecified = Y TITHE (input)
{% endstep %}

{% step %}

### PoolManager invokes CustomHook.beforeSwap(...)

No-op for sells.
{% endstep %}

{% step %}

### Pool executes the swap

Producing Z ETH output.
{% endstep %}

{% step %}

### PoolManager invokes CustomHook.afterSwap(...)

{% endstep %}

{% step %}

### Hook computes fee

fee = Z \* 5% = Z \* 500 / 10000
{% endstep %}

{% step %}

### Hook returns an AfterSwapDelta

It indicates it has claimed `fee` ETH from output.
{% endstep %}

{% step %}

### Hook splits the claimed fee

* Transfers (fee \* 4 / 5) ETH to RewardDistributor
* Transfers (fee \* 1 / 5) ETH to treasury multisig
  {% endstep %}

{% step %}

### User receives ETH

The user receives (Z - fee) ETH.
{% endstep %}
{% endstepper %}

The fee is taken **after** the swap, from the output. The user sells their TITHE at the pool's price and then has 5% of the resulting ETH skimmed.

## Why the asymmetry (beforeSwap for buys, afterSwap for sells)

Both directions could in principle use either callback, but the chosen approach has a clear logic:

* **For buys**, the input is ETH. Taking the fee in `beforeSwap` means the user's ETH input is reduced before it hits the pool. The fee is denominated in the asset being supplied.
* **For sells**, the input is TITHE. Taking the fee in `beforeSwap` would require collecting TITHE, then selling it for ETH within the hook — adding internal sell pressure on the token and creating MEV opportunities. Taking the fee in `afterSwap` from the ETH output avoids this entirely.

In both cases, **the hook only ever touches ETH**. This is the central design property. The hook has no TITHE balance, ever. It needs no token approvals. It creates no token-side selling pressure.

## LP lock enforcement

The initial LP position is added by the deployer in a single transaction at launch. After that transaction, the `beforeRemoveLiquidity` callback reverts unconditionally for that position. There is no `unlock()` function, no time-based unlock, no caller-based exception.

The lock is enforced at the hook level, which means:

* **No external locker contract is required.** Unicrypt, Team.Finance, or any other lock service is unnecessary — the lock is part of the pool's behavior, not a separate timelock.
* **No address can bypass it.** The check is on the position itself (identified by the position's `salt`/owner), not on the caller. Even the deployer, even a multisig, even a privileged caller reverts.
* **It is permanent.** There is no path through the hook that allows removal. The function literally reverts.

For non-initial positions (anyone else's LP), the hook permits adds and removes normally. Anyone is welcome to JIT liquidity or run a market-making strategy on top of the pool; only the initial 730M TITHE / paired-ETH position is locked.

## What the hook cannot do

To be explicit:

* It **cannot mint TITHE.** The token contract has no mint function exposed.
* It **cannot adjust the fee rate.** The 5% is a constant, set at deployment.
* It **cannot adjust the fee split.** The 4:1 ratio is a constant.
* It **cannot drain the RewardDistributor.** The hook can only deposit; the distributor has no privileged caller.
* It **cannot pause swaps.** No pause logic exists.
* It **cannot upgrade.** Not deployed behind a proxy.
* It **cannot be redeployed and re-attached.** Once the pool is initialized with this hook address, the pool's hook is permanent for that pool.

## Source verification

Post-deploy, the hook contract is verified on Etherscan with full source. The verification should show:

1. No `Ownable` or access-control imports.
2. The exact constants for fee rate (500 basis points) and split (400 / 100 basis points).
3. No `payable` functions that accept ETH without routing it to distributor or treasury.
4. No `selfdestruct` or `delegatecall`.
5. Hook permissions matching the deployed address bits.

The address itself encodes the permissions — anyone can compute the expected permissions byte from the hook's deployment address and confirm it matches the declared interface.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tithe-coin.gitbook.io/tithe-coin/custom-hook.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
