Skip to content

Cache-Atelier/patron-hook

Repository files navigation

Patron Pools

A Uniswap v4 hook that redirects LP trading fees to a beneficiary. LPs provide liquidity through the standard Uniswap interface — no custom frontend, no approvals, no extra transactions. Every swap that passes through a Patron Pool automatically accrues fees for the designated cause.

How It Works

Each Patron Pool is a standard Uniswap v4 liquidity pool with a hook that intercepts the fee mechanism:

  1. beforeSwap overrides the LP fee to zero — no fees accrue to LP positions.
  2. afterSwap computes a hook fee on the swap output, extracts the tokens via poolManager.take(), and records them in an internal ledger.
  3. The beneficiary (or anyone) calls collectFees() to withdraw accumulated fees at any time.

From the trader's perspective, the pool behaves like any other Uniswap v4 pool. From the LP's perspective, they are providing liquidity knowing their fee revenue goes to a cause instead of to themselves.

Architecture

Each hook contract is deployed with an immutable beneficiary address and immutable fee percentage. A hook address represents a specific (beneficiary, fee tier) combination.

PatronPoolFactory
    │
    ├── deploy(beneficiary, fee, salt) → PatronPoolHook @ 0xabc...
    │       beneficiary = 0xBEEF (immutable)
    │       fee = 500 (0.05%, immutable)
    │
    └── deploy(beneficiary, fee, salt) → PatronPoolHook @ 0xdef...
            beneficiary = 0xBEEF (immutable)
            fee = 3000 (0.30%, immutable)

The factory deploys hooks via CREATE2 with a mined salt that produces an address with the correct v4 permission flag bits.

Why Per-Beneficiary Hooks?

Uniswap v4's PoolManager.initialize() does not accept a hookData parameter — there is no way to pass configuration to a hook during pool creation. By baking the beneficiary and fee into the contract as immutables, pool creation on the Uniswap UI requires zero extra steps: just paste the hook address and go.

Pull-Based Fee Collection

Fees are not transferred on every swap. They accumulate in the hook contract and the beneficiary calls collectFees(currency) to withdraw. This eliminates reentrancy risk during swap execution and reduces per-swap gas.

Contracts

Contract Purpose
PatronPoolHook Core hook — overrides LP fees to zero, charges hook fee, accrues for beneficiary
PatronPoolFactory Deploys hooks via CREATE2, maintains on-chain registry

PatronPoolHook

Constructor:

constructor(IPoolManager poolManager, address beneficiary, uint24 fee)
  • beneficiary — address that receives accrued fees (immutable, cannot be zero)
  • fee — fee in hundredths of a bip (3000 = 0.30%, max 10000 = 1.00%)

Hook Permissions:

Permission Purpose
beforeInitialize Validates pool uses dynamic fee flag (0x800000)
beforeSwap Overrides LP fee to zero
afterSwap Computes fee, calls take(), records accrual
afterSwapReturnDelta Returns delta to charge fee to swapper

External Functions:

  • collectFees(Currency currency) — transfers all accrued fees in the given currency to the beneficiary. Permissionless (anyone can call it).

Events:

  • FeesRedirected(PoolId poolId, Currency currency, uint256 amount) — emitted on every swap
  • FeesCollected(Currency currency, uint256 amount) — emitted on fee collection

PatronPoolFactory

Functions:

  • deploy(address beneficiary, uint24 fee, bytes32 salt) — deploys a new hook via CREATE2
  • computeAddress(address beneficiary, uint24 fee, bytes32 salt) — predicts deployment address
  • isPatronHook(address hook) — checks if an address was deployed by this factory
  • hooks(address) — returns (beneficiary, fee) for a deployed hook

User Flows

Beneficiary Setup (one-time)

  1. Call factory.deploy(beneficiaryAddress, fee, salt) — via a frontend, Etherscan, or script.
  2. Receive the hook address. Share it publicly.

Pool Creation

  1. Go to the Uniswap web app.
  2. Select Pool → New, choose a token pair.
  3. Select "Add a hook" and paste the Patron Pool hook address.
  4. Create the pool (it will be a dynamic fee pool).

Adding Liquidity

  1. Find the pool on Uniswap.
  2. Add liquidity at any tick range.
  3. That's it — standard Uniswap v4 position, standard NFT.

Fee Collection

Call hook.collectFees(currency) on the hook contract — via Etherscan, a frontend, or a script. Anyone can trigger collection; fees always go to the beneficiary.

Fee Tier Selection

The fee is set at hook deployment and cannot be changed. Recommended tiers:

Pair Type Recommended Fee Value
Stablecoin / stablecoin 0.01% 100
Blue-chip majors (ETH/USDC) 0.05% 500
Mid-cap altcoins 0.30% 3000
Exotic / long-tail 1.00% 10000

Uniswap's smart order router splits volume across pools proportional to liquidity. A Patron Pool doesn't need to undercut other pools — it just needs to match the standard fee tier for its pair type.

Development

Prerequisites

  • Foundry
  • Node.js (for dependency management)

Setup

git clone <repo-url>
cd patron-hook
npm install
forge build

Test

forge test

Deploy

forge script script/DeployPatronPool.s.sol \
  --rpc-url <RPC_URL> \
  --broadcast \
  --sig "run(address,address,uint24)" \
  <POOL_MANAGER_ADDRESS> <BENEFICIARY_ADDRESS> <FEE>

Security

Trust Model

  • Immutable — no admin functions, no upgrades, no mutable configuration.
  • No beforeSwapReturnDelta — the critical NoOp rug pull attack vector is not enabled.
  • No beforeRemoveLiquidity — LP funds cannot be trapped.
  • Pull-based collectionafterSwap makes no external calls to unknown addresses.
  • Reentrancy guard on collectFees().
  • Fee cap — constructor enforces fee <= 10000 (1%).

Known Limitations

  • Fee-on-transfer tokens: If a pool's tokens charge transfer fees, accruedFees may overstate the actual hook balance. collectFees() handles this gracefully by transferring min(owed, actualBalance).
  • Exact-output swaps: Supported — fee is charged on the unspecified (input) side. Both swap directions are handled for both exact-input and exact-output.

Audit Status

This code has not been audited. Use at your own risk.

License

MIT

About

The Patron Hook is a Uniswap v4 hook that allows Liquidity Providers to become Liquidity Patrons by automatically donating their fees to a beneficiary.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors