A Uniswap V4 hook implementation that enables flash swap-like functionality for liquidations in lending protocols. This hook allows liquidators to execute liquidations without requiring upfront capital.
Traditional liquidations in DeFi lending protocols require liquidators to have the debt token on hand to repay the borrower's debt and claim the collateral. This creates a capital requirement that limits participation in the liquidation market.
This Flash Liquidation Hook leverages Uniswap V4's hook system and flash accounting to enable capital-efficient liquidations similar to Uniswap V2's flash swaps but with improved architecture.
- A liquidator identifies an underwater position in a lending protocol
- The liquidator calls
flashLiquidate()on the hook, specifying:- The debt token (token to borrow for liquidation)
- The collateral token (token that will be seized)
- The borrower's address
- The amount of debt to liquidate
- Minimum profit requirement (optional)
- The hook executes a swap to borrow the debt token
- Within the same transaction, it liquidates the position, sells the collateral, repays the debt, and sends any profit to the liquidator
- Initial Call: Liquidator calls
flashLiquidate() - Flash Swap: Hook performs a swap to obtain the debt tokens
- afterSwap Hook: The hook's
afterSwapfunction is triggered automatically - Liquidation: Inside
afterSwap, the hook:- Identifies the underwater position
- Calls the lending protocol's
liquidate()function - Receives collateral from the liquidation
- Swaps the collateral for the debt token in another Uniswap pool
- Settles the debt to the original pool
- Sends any profit to the liquidator
- Transaction Completion: The entire process happens atomically in a single transaction
The main hook contract that implements the flash liquidation logic.
- Implements:
afterSwaphook from Uniswap V4 - Key Functions:
flashLiquidate(): Entry point for liquidatorsafterSwap(): Handles the liquidation logiccheckLiquidationProfitability(): Helper to check if a liquidation would be profitable
Interface for interacting with the lending protocol.
- Key Functions:
liquidate(): Liquidates a borrower's positionisLiquidatable(): Checks if a position can be liquidated
A mock implementation of the lending protocol for testing and demonstration purposes.
This is a convenience layer on top of the FlashLiquidationHook. It doesn't have a direct connection to the hook in the sense of ownership or permissions - it's simply a contract that calls the hook's functions. The Orchestrator provides several benefits compared to direct hook interactions:
- Abstraction: It abstracts away some of the complexity of calling the hook directly
- Batch Processing: It can handle batched liquidations across multiple positions
- Monitoring: It helps track token pairs for liquidation opportunities
- Safety Features: It includes profit checks and emergency functions
- Permissions: It can implement access controls for certain functions
Think of the Orchestrator as a "bot manager" that makes it easier for liquidation bots to interact with the hook, but it's not a required component.
Uniswap V4 introduces a new architecture where hooks are directly associated with pools. Here's how to create a pool with the FlashLiquidationHook:
First, deploy the FlashLiquidationHook contract:
// Deploy the hook with the PoolManager and LiquidationProtocol addresses
FlashLiquidationHook hook = new FlashLiquidationHook(
IPoolManager(poolManagerAddress),
ILiquidationProtocol(liquidationProtocolAddress)
);To create pools with hooks, you'll need a factory contract that interacts with the Uniswap V4 PoolManager:
// Create a pool factory that can create pools with hooks
PoolFactory factory = new PoolFactory(IPoolManager(poolManagerAddress));Using the factory, initialize a new pool with the hook:
// Create a pool key with the hook address
PoolKey memory poolKey = PoolKey({
currency0: Currency.wrap(address(token0)),
currency1: Currency.wrap(address(token1)),
fee: 3000, // 0.3% fee tier
tickSpacing: 60,
hooks: IHooks(address(hook))
});
// Initialize the pool
factory.createAndInitializePool(poolKey, initialSqrtPriceX96);After creating the pool, you can add liquidity:
// Add liquidity to the pool
factory.addLiquidity(
poolKey,
IPoolManager.ModifyLiquidityParams({
tickLower: lowerTick,
tickUpper: upperTick,
liquidityDelta: liquidityAmount
})
);Once the pool is created with the hook, the hook's logic is automatically executed whenever a swap occurs in the pool. For our FlashLiquidationHook, the afterSwap function will be called after every swap in the pool.
- Hook Address Must Be Whitelisted: In Uniswap V4, hook addresses must be whitelisted as part of the factory contract (for security reasons)
- Hooks Are Immutable: Once a pool is created with a hook, the hook cannot be changed
- Multiple Pools Can Share the Same Hook: You can create many pools that all use the same hook instance
- Hooks Must Be Gas-Efficient: Since hooks are called automatically on various operations, they need to be gas-efficient to keep transaction costs reasonable
- Flash Accounting: Uniswap V4's flash accounting allows the hook to handle debt that must be repaid by the end of the transaction, which is what enables our flash liquidation mechanism
- Capital Efficiency: Liquidators don't need to hold debt tokens beforehand
- Atomic Execution: The entire liquidation happens in a single transaction
- Risk Reduction: If the liquidation doesn't yield enough to repay the flash loan, the transaction reverts
- Gas Efficiency: Uses V4's singleton architecture and flash accounting
- Accessibility: Lowers the barrier to entry for liquidators
- Uniswap V4 deployed on your network
- Access to a lending protocol that supports liquidations
- Foundry for development and deployment
# Clone the repository
git clone https://github.com/yourusername/liquidation-hook.git
cd liquidation-hook
# Install dependencies
forge install-
Install dependencies:
bash setup.sh
-
Build the project:
forge build --via-ir
-
Edit the deployment script (
script/Deploy.s.sol) with appropriate addresses. -
Deploy the contract:
forge script script/Deploy.s.sol:DeployScript --rpc-url [your_rpc_url] --broadcast
// Query the hook to check if a position is liquidatable and potentially profitable
(bool liquidatable, uint256 maxDebtAmount, uint256 estimatedProfit) =
flashLiquidationHook.checkLiquidationProfitability(
debtToken,
collateralToken,
borrower
);// Execute the liquidation if profitable
flashLiquidationHook.flashLiquidate(
debtToken, // Token to borrow (e.g., USDC)
collateralToken, // Token used as collateral (e.g., WETH)
borrower, // Address of the underwater position
debtAmount, // Amount of debt to liquidate
minProfitAmount // Minimum profit required (optional)
);While you can interact directly with the FlashLiquidationHook, the LiquidationOrchestrator provides several advantages:
- Convenience: Abstracts away complexities of direct hook interaction
- Batch Processing: Can execute multiple liquidations in a single transaction
- Profit Optimization: Includes logic to check profitability before executing
- Monitoring: Tracks token pairs for liquidation opportunities
- Safety Features: Includes emergency functions and better error handling
For simple use cases, direct interaction with the hook is sufficient. For production use or automated bots, the Orchestrator provides a more robust interface.
$ forge build --via-ir$ forge script script/Deploy.s.sol:DeployScript --rpc-url <your_rpc_url> --private-key <your_private_key>To integrate with a specific lending protocol:
- Implement the
ILiquidationProtocolinterface for your target protocol - Deploy the
FlashLiquidationHookwith the appropriate protocol implementation - Create pools with the hook attached
- Develop liquidation bots that monitor for liquidation opportunities and call the hook
- Reentrancy: The hook uses a state variable to prevent reentrancy attacks
- Minimum Profit: Optional parameter to ensure liquidations are profitable enough
- Slippage Protection: Could be extended to include more advanced slippage protection
- Gas Optimization: The implementation is designed to be gas-efficient
- Multi-Collateral Support: Extend to handle positions with multiple collateral types
- Oracle Integration: Add price feeds to validate liquidation values
- Fee Distribution: Share liquidation profits with protocol or affected LPs
- Partial Liquidations: Enable liquidating only a portion of a position
- MEV Protection: Add mechanisms to prevent liquidation front-running
This project is licensed under MIT - see the LICENSE file for details.
- Uniswap V4 - For the hook system and flash accounting
- Foundry - For the development framework