The TreasuryManagementHook
contract is built on Uniswap V4’s hook system, leveraging several key components for efficient treasury management:
contract TreasuryManagementHook is BaseHook {
using PoolIdLibrary for PoolKey;
using CurrencyLibrary for Currency;
BaseHook Inheritance: Provides the foundational hook infrastructure, handling the complex lifecycle management and integration with Uniswap V4’s PoolManager. This eliminates the need to implement low-level hook mechanics manually.
Library Usage:
PoolIdLibrary
: Enables type-safe pool identification through thetoId()
method, ensuring consistent pool referencing across the systemCurrencyLibrary
: Handles currency operations and type conversions, abstracting away the complexity of different token standards
Core Type Imports: The contract utilizes essential Uniswap V4 types like BalanceDelta
, PoolKey
, and BeforeSwapDelta
for handling swap data and pool configuration.
The contract’s storage design prioritizes gas efficiency while maintaining treasury functionality:
address public treasury; // Treasury controller address
uint24 public treasuryFeeRate; // Fee rate in basis points
uint24 public constant MAX_FEE_RATE = 1000; // 10% maximum fee cap
uint256 public constant BASIS_POINTS = 10000; // Precision denominator
Design Rationale:
uint24
for fee rates provides sufficient range (0- 16,777,215) while using minimal storage slots- The basis points system (10,000) enables precise fee calculations with 0.01% precision
- Hard-coded maximum fee rate of 10% prevents excessive fee collection that could harm trading
mapping(PoolId => bool) public isPoolManaged; // Pool participation tracking
mapping(Currency => uint256) public accumulatedFees; // Fee balances by token
Storage Efficiency:
- Separate mappings optimize gas costs for different query patterns
isPoolManaged
enables quick pool status checks during swapsaccumulatedFees
tracks balances per token type for flexible withdrawals
constructor(
IPoolManager _poolManager,
address _treasury,
uint24 _treasuryFeeRate
) BaseHook(_poolManager) {
if (_treasury == address(0)) revert InvalidTreasuryAddress();
if (_treasuryFeeRate > MAX_FEE_RATE) revert FeeRateTooHigh();treasury = _treasury;
treasuryFeeRate = _treasuryFeeRate;
}
Zero Address Protection: Prevents deployment with an invalid treasury address, which would lock the contract’s functionality permanently.
Fee Rate Validation: Ensures the initial fee rate complies with the 10% maximum limit, preventing deployment with excessive fees.
Early Validation Strategy: Performing all validation in the constructor prevents invalid contract states and saves gas on failed deployments.
The hook’s capabilities are precisely defined through the permissions structure:
function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
return Hooks.Permissions({
beforeInitialize: false,
afterInitialize: true, // Pool registration
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: true, // Pool validation
afterSwap: true, // Fee collection
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
});
}
Minimal Permissions Approach: Only enables necessary hooks to reduce gas costs and minimize attack surface. The contract specifically needs:
afterInitialize
: Automatically registers new pools for fee collectionbeforeSwap
: Validates whether the pool should be processed for feesafterSwap
: Executes the actual fee collection logic
Gas Optimization: By avoiding unnecessary hook permissions, the contract reduces the overhead of hook processing for operations that don’t require treasury intervention.
The contract implements a straightforward but effective access control system:
function setTreasury(address _newTreasury) external {
if (msg.sender != treasury) revert OnlyTreasuryAllowed();
if (_newTreasury == address(0)) revert InvalidTreasuryAddress();address oldTreasury = treasury;
treasury = _newTreasury;
emit TreasuryAddressChanged(oldTreasury, _newTreasury);
}
Direct Address Comparison: Uses simple msg.sender
comparison for gas-efficient access control, avoiding complex role-based systems that could introduce vulnerabilities.
Input Validation: Prevents transition to invalid states by validating the new treasury address before making changes.
Event Emission: Provides complete transparency for governance changes, enabling off-chain monitoring and audit trails.
Atomic Updates: All changes occur within a single transaction, ensuring state consistency.
The contract defines custom errors for gas-efficient and user-friendly error handling:
error InvalidTreasuryAddress();
error FeeRateTooHigh();
error OnlyTreasuryAllowed();
error InsufficientFees();
Gas Efficiency: Custom errors consume significantly less gas than require
statements with string messages, especially important for functions called frequently during swaps.
Type Safety: Enables specific error handling in client applications and testing frameworks.
Clear Communication: Descriptive names improve debugging experience and help developers understand failure conditions.
The contract provides secure methods to update treasury parameters during operation:
function setTreasuryFeeRate(uint24 _newFeeRate) external {
if (msg.sender != treasury) revert OnlyTreasuryAllowed();
if (_newFeeRate > MAX_FEE_RATE) revert FeeRateTooHigh();uint24 oldRate = treasuryFeeRate;
treasuryFeeRate = _newFeeRate;
emit TreasuryFeeRateChanged(oldRate, _newFeeRate);
}
Access Control: Only the treasury address can modify fee rates, preventing unauthorized changes that could affect trading economics.
Rate Limiting: Enforces the maximum 10% fee rate even for runtime changes, maintaining system safety bounds.
Audit Trail: Event emission creates a permanent record of all fee rate changes for governance tracking.
Immediate Effect: Changes take effect immediately for all subsequent swaps, enabling responsive treasury management.
The contract includes specific features to support testing and development:
function validateHookAddress(BaseHook) internal pure override {
// Skip validation in tests
}function setPoolManaged(PoolKey calldata key, bool managed) external {
isPoolManaged[key.toId()] = managed;
}
Validation Override: The validateHookAddress
override simplifies testing by bypassing complex address validation requirements.
Manual Pool Control: setPoolManaged
allows direct manipulation of pool management status for controlled testing scenarios.
Unrestricted Testing: Testing functions intentionally bypass normal access controls to enable test coverage.
This design provides several key advantages:
Modularity: Clear separation between configuration, fee collection, and withdrawal logic enables independent testing and upgrades.
Gas Efficiency: Optimized storage layout and minimal hook permissions reduce operational costs.
Security: Simple access control model reduces complexity while maintaining effective protection.
Flexibility: Configurable fee rates and selective pool management support diverse treasury strategies.
Transparency: Event logging enables complete auditability of treasury operations.