This repository is a monorepo for the Uniswap V4 Hooks workshop. It includes smart contracts, V4 SDK integration, Indexer, and Dashboard.
In this workshop, you'll deploy and test Uniswap V4's innovative "Hooks" feature, experiencing the complete Hook development lifecycle (development β deployment β testing β analysis).
Duration: 35-55 minutes
Target Audience: Developers with basic Solidity knowledge
This workshop will help you achieve:
- Understanding how Uniswap V4 Hooks work
- Experiencing proper address deployment using HookMiner
- Mastering pool operations with V4 SDK
- Verifying JIT attack prevention with LiquidityPenaltyHook
- Learning analysis methods using Envio indexer
| Time | Section | Content |
|---|---|---|
| 0-5 min | Environment Setup | Clone repository, install dependencies, configure environment variables |
| 5-15 min | Hook Deployment | Deploy LiquidityPenaltyHook using HookMiner |
| 15-25 min | Pool Creation | Create pool with deployed Hook |
| 25-40 min | Hands-on Operations | Add/remove liquidity and swap using V4 SDK |
| 40-45 min | Analysis & Summary | Check results with Indexer and Dashboard, Q&A |
π Full Workshop Script: See workshop-50min-script.md for a detailed 50-minute workshop guide with complete explanations and code examples.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Blockchain (Unichain) β
β γ»Hooks (LiquidityPenaltyHook, etc.) β
β γ»PoolManager, PositionManager β
β γ»Universal Router β
βββββββββββββββββββββββ¬βββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β β
β β
Event Monitoring Transaction Execution
β β
βΌ βΌ
βββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββ
β INDEXER (Envio) β β V4 SDK Scripts β
β http://localhost:8080 β β γ»04-add-liquidity.ts β
β γ»Event Collection β β γ»05-swap-universal-router.ts β
β γ»Data Persistence β β γ»06-remove-liquidity.ts β
β (PostgreSQL) β β γ»check-pool-state.ts β
β γ»GraphQL API β β β
ββββββββββββββββ¬βββββββββββββββ βββββββββββββββββββ¬ββββββββββββββββββ
β β
β GraphQL API β Operations
β β
βΌ β
βββββββββββββββββββββββββββββββ β
β DASHBOARD APP β β
β http://localhost:3000 β β
β γ»Display Statistics β β
β γ»TVL Analysis β β
β γ»Hook Behavior β β
β Visualization β β
ββββββββββββββββ¬βββββββββββββββ β
β β
β Read-only β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Users β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The smart contract deployment process uses Foundry's scripting capabilities:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Developer Machine β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Foundry Scripts β β
β β 01_DeployAndSave.s.sol β Deploy hooks with HookMiner β β
β β 02_CreatePool.s.sol β Create pools with deployed hooks β β
β β 03_ShowPoolInfo.s.sol β Display deployment information β β
β ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββ β
β β HookMiner β β
β β γ»Calculate deterministic addresses based on permissions β β
β β γ»Find salt for CREATE2 deployment β β
β β γ»Encode hook flags in address (last 20 bits) β β
β ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββ β
β β CREATE2 Deployer β β
β β γ»Deploy hooks at calculated addresses β β
β β γ»Ensure permission bits match address β β
β β γ»Save deployment info to .env files β β
β ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββ
β Deploy & Initialize
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Unichain Blockchain β
β γ»Deployed Hooks at deterministic addresses β
β γ»Initialized Pools with hook integration β
β γ»Ready for V4 SDK interaction β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key Deployment Steps:
-
Environment Setup
cd contracts source .env export ETH_FROM=$(cast wallet address --private-key $PK)d
-
Hook Deployment (01_DeployAndSave.s.sol)
- Uses HookMiner to calculate addresses
- Deploys via CREATE2 for deterministic addresses
- Saves addresses to
scripts/.deployment.env
-
Pool Creation (02_CreatePool.s.sol)
- Reads deployed hook addresses
- Creates pools with proper hook integration
- Saves pool info to
scripts/.pool.env
-
Verification (03_ShowPoolInfo.s.sol)
- Displays all deployment information
- Confirms hook permissions and pool configuration
Uniswap V4 adopts a "singleton" architecture where all pools are managed by a single PoolManager contract. This enables:
- Improved Gas Efficiency: Optimized multi-hop swaps between pools
- Customizability: Free extension of pool behavior through Hooks
- Capital Efficiency: Temporary borrowing via flash accounting
Hooks are custom logic executed at specific points in a pool's lifecycle:
βββββββββββββββββββ
β User Action β
ββββββββββ¬βββββββββ
β
ββββββΌββββββ ββββββββββββββββ
β Pool ββββββΊβ Hook Contractβ
β Manager βββββββ€ (Your Logic) β
ββββββββββββ ββββββββββββββββ
14 Extension Points:
beforeInitialize/afterInitializebeforeAddLiquidity/afterAddLiquiditybeforeRemoveLiquidity/afterRemoveLiquiditybeforeSwap/afterSwapbeforeDonate/afterDonate- Delta return flags (for fee and swap amount adjustments)
Problem: Just-In-Time (JIT) Attacks
- Attackers add liquidity just before large swaps
- They immediately remove liquidity after capturing swap fees
- This steals revenue from long-term liquidity providers
Solution: Time-based Penalty
penalty = fees * (1 - (currentBlock - lastAddedBlock) / blockNumberOffset)Imposes penalties on early liquidity removal, decreasing over time (0% after 10 blocks).
Prevents sandwich attacks by limiting price manipulation within blocks. Checkpoints prices at the start of each block and prevents trades at advantageous prices within the same block.
Enables on-chain limit orders that automatically execute when specific prices are reached.
# Or manually create each .env file
cp contracts/.env.example contracts/.env
cp apps/indexer/.env.example apps/indexer/.envRequired settings for contracts/.env:
PK: Private key for deployment (never commit this!)ETHERSCAN_API_KEY: For contract verification
Required settings for apps/indexer/.env:
ENVIO_API_TOKEN: Envio API token (optional)- Not required for local development only
- Required for production or when using the development console (https://envio.dev/console)
- Create tokens at https://envio.dev/app/api-tokens
# Install using Bun
bun install# Setup indexer
cd apps/indexer
pnpm install # Indexer requires pnpm
bun run codegen
bun run dev# In a new terminal, start Dashboard (http://localhost:3000)
cd apps/dashboard
pnpm install
bun run devNote:
- The indexer requires Docker Desktop to be running
- GraphQL endpoint will be available at http://localhost:8080/v1/graphql once the indexer is ready
- For subsequent runs, you can simply use
bun run devin the indexer directory
uniswap-v4-workshop/
βββ contracts/ # Uniswap V4 Hooks smart contracts
β βββ src/ # Hook implementations (LiquidityPenaltyHook, etc.)
β βββ script/ # Deployment and operation scripts
βββ scripts/ # V4 SDK integration scripts
β βββ utils/ # Common utilities
β βββ 04-add-liquidity.ts # Add liquidity
β βββ 05-swap-universal-router.ts # Execute swaps
β βββ 06-remove-liquidity.ts # Remove liquidity
βββ apps/
β βββ indexer/ # Blockchain indexer (Envio)
β βββ dashboard/ # Analytics dashboard (Next.js)
βββ deployments/ # Contract addresses by network
βββ docs/ # Workshop documentation
# Contract-related
bun run contracts:build # Build contracts
bun run v4:deploy # Deploy hooks with HookMiner
bun run v4:pool # Create pool with deployed hook
bun run v4:info # Show pool information
# V4 SDK operations
bun run v4:check # Check pool state
bun run v4:add # Add liquidity (create Position NFT)
bun run v4:swap # Execute swap via Universal Router
bun run v4:remove # Remove liquidity
# Application startup
bun run indexer # Start indexer (requires Docker)
bun run dashboard # Start dashboardFoundry Scripts:
// v4:deploy (01_DeployAndSave.s.sol) - Hook Deployment
- Deploy at proper address using HookMiner
- Deterministic address generation via CREATE2
- Save deployment results to .deployment.env
// v4:pool (02_CreatePool.s.sol) - Pool Creation
- Create pool using deployed Hook
- ETH/USDC pair, 0.3% fee setting
- Save pool information to .pool.env
// v4:info (03_ShowPoolInfo.s.sol) - Display Pool Information
- Display Hook address and enabled permissions
- Pool ID and current price
- Generate explorer linksV4 SDK Scripts:
// v4:check (check-pool-state.ts) - Check Pool State
- Display current price, liquidity, and fees
- Verify Hook address and settings
// v4:add (04-add-liquidity.ts) - Add Liquidity
- Create Position NFT
- Gasless approval via Permit2
- Provide liquidity to specified price range
// v4:swap (05-swap-universal-router.ts) - Execute Swap
- Quote via V4 Quoter (revert data processing)
- Build actions with V4Planner
- Execute via Universal Router
// v4:remove (06-remove-liquidity.ts) - Remove Liquidity
- Withdraw liquidity from Position NFT
- Handle LiquidityPenaltyHook penalties
- Support partial or complete removalThe most unique aspect of V4 Hooks is that permission information is encoded in the address itself:
Hook Address: 0x0050E651C7b8662f4E17C589B6387db8f7488503
^^^^
Lowest bits (right side) represent permissions
Example: Lowest 14 bits of 0x...8503
- Binary:
1000 0101 0000 0011 - This indicates the following permissions:
- bit 0 (0x1): AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA
- bit 1 (0x2): AFTER_ADD_LIQUIDITY_RETURNS_DELTA
- bit 8 (0x100): AFTER_REMOVE_LIQUIDITY
- bit 10 (0x400): AFTER_ADD_LIQUIDITY
- Permission Declaration:
function getHookPermissions() public pure returns (Hooks.Permissions memory) {
return Hooks.Permissions({
afterAddLiquidity: true,
afterRemoveLiquidity: true,
afterAddLiquidityReturnDelta: true,
afterRemoveLiquidityReturnDelta: true,
// ... all others false
});
}- Address Calculation:
// HookMiner finds the proper address using CREATE2
uint160 flags = Hooks.AFTER_ADD_LIQUIDITY_FLAG |
Hooks.AFTER_REMOVE_LIQUIDITY_FLAG | ...;
(address hookAddress, bytes32 salt) = HookMiner.find(
CREATE2_DEPLOYER,
flags,
bytecode,
constructorArgs
);- Validation: Permissions are validated with validateHookAddress().
PoolManager β Event Emitted β Envio Indexer β PostgreSQL β GraphQL β Dashboard
- Initialize: Pool creation (including Hook address)
- Swap: Trade execution and Hook intervention
- ModifyLiquidity: LP operations and penalty application
- Donate: Fee donations
- Workshop 45min Guide (ζ₯ζ¬θͺ) - Complete workshop guide
- Architecture Details
- Contracts README
After completing the workshop, consider applying for the Unichain Hook Grant!
- Organizers: Uniswap Foundation & Atrium
- Target: Innovative Hooks running on Unichain
- Categories: DeFi Innovation, Liquidity Optimization, MEV Protection, New AMM Designs
- Grants Info
- Workshop 50-minute Script - Complete workshop guide with detailed explanations and code examples
- Workshop Overview (Japanese) - Workshop goals and structure in Japanese
- Uniswap V4 Implementation Patterns - Comprehensive patterns and best practices
- Uniswap V4 Documentation
- V4 SDK Documentation
- V4 Core Repository
- OpenZeppelin Hooks
- Hooks Audit Report
- Hook Data Standards Guide
- Unichain Documentation
- Envio HyperSync Documentation
- Envio Uniswap V3 Analytics
- Envio Uniswap V4 Indexer
- Japanese Community
- Uniswap V4 Dojo
Building the Future of DeFi with Uniswap V4