TLISHook (Time-Locked Intent System Hook) is a Uniswap V4 hook that eliminates MEV attacks using a combination of time-locked encryption and verifiable randomness.
THE PROBLEM: Standard Uniswap V4 pools are still vulnerable to sandwich attacks, front-running, and other MEV exploitation. Traders lose 2-5% of their swap value to sophisticated bots that scan the mempool and manipulate transaction ordering.
THE SOLUTION: TLISHook introduces a novel two-layer defense mechanism:
-
PRIVACY LAYER: Users submit encrypted swap intents that are XOR-encrypted with future Drand randomness. These intents remain completely unreadable for a 5-minute collection window, preventing bots from seeing trade flow before execution.
-
RANDOMNESS LAYER: At execution time, each swap executes at a "surprise price" - the market price plus or minus a random offset (±1% in sqrtPriceX96 space). This randomness is derived from Drand (a decentralized randomness beacon), making it verifiable and unpredictable.
KEY FEATURES:
- Temporal privacy through time-locked encryption (5-minute batches)
- Surprise pricing that makes front-running unprofitable
- User-defined safety bounds ensure you never get worse than your specified limits
- Atomic batch execution prevents partial manipulation
- Decentralized coordination via timestamp-based batch IDs
- Escrow-based settlement for autonomous execution
THE INNOVATION: Beyond security, TLISHook gamifies trading. Users might get lucky and receive better-than-market prices, or unlucky and pay slightly more - but always within their safety bounds. This transforms boring swaps into engaging, strategic experiences while providing stronger MEV protection than traditional approaches.
TECHNICAL ARCHITECTURE:
- Built on Uniswap V4's hooks system
- Integrates Drand quicknet (3-second rounds) for randomness
- Uses poolManager.unlock() → unlockCallback() for atomic settlement
- Keeper network executes batches after time-lock expires (60-second priority window)
- All user funds held in hook's escrow (s_userBalances mapping)
IMPACT: Trading becomes both MORE secure (MEV-resistant) AND more fun (gamified with provably fair randomness). Users maintain control via price bounds while potentially benefiting from lucky random outcomes.
TECH STACK:
- Solidity ^0.8.26 for smart contracts
- Foundry (forge, anvil) for development and testing
- Uniswap V4 core & periphery libraries
- Drand quicknet API for decentralized randomness
- Sepolia testnet for deployment
CORE ARCHITECTURE:
- HOOK IMPLEMENTATION (TLISHookV5.sol)
Built as a Uniswap V4 hook implementing beforeSwap() lifecycle. The hook intercepts normal swaps and redirects them through our time-locked intent system. Key challenges:
- Calculating correct hook permissions bitmap (0x4000 for beforeSwap only)
- Managing hook-owned liquidity positions for swap execution
- Handling delta accounting with poolManager.unlock() → unlockCallback() pattern
- ENCRYPTION MECHANISM
Used simple XOR encryption (post hackathon AES/complex crypto encryption) for gas efficiency:
encryptedData = intentData XOR drand_randomness
This works because:
- XOR is reversible: encrypted XOR same_key = original
- Drand randomness is 32 bytes, perfect for uint256 packing
- Super cheap on-chain (just one XOR operation per intent)
HACKY PART: Pack all intent parameters (zeroForOne, amount, minSqrtPrice, maxSqrtPrice) into a single bytes32, then XOR it with drand. This saves massive gas vs encrypting each field separately.
- BATCH TIMING COORDINATION
No centralized scheduler! Batches self-organize via deterministic timestamp math:
batchId = block.timestamp / 300 // 5-minute windows
unlockTime = (batchId + 1) * 300 + 60 // Close + 60s lock
- SURPRISE PRICING ALGORITHM
The trickiest part was implementing ±1% randomness in sqrtPriceX96 space (Uniswap's price format). can't just do
price * 1.01 because prices are stored as sqrt(price) * 2^96:
// Extract random percentage from drand (0-10000 basis points)
uint256 randomBps = (randomness % 10000);
// Apply ±1% offset in sqrtPrice space
uint160 surprisePrice = applySqrtPriceOffset(marketPrice, randomBps);
// Clamp to user bounds
finalPrice = clamp(surprisePrice, minSqrtPrice, maxSqrtPrice);
MORE: Instead of complex sqrt calculations, used linear interpolation in sqrt space.
- DRAND INTEGRATION
Integrated Drand's quicknet (3-second rounds) as our randomness source:
- On intent submission: Calculate target drandRound = (unlockTime / 3) + 1
- At execution: Keeper fetches drand randomness from HTTP API
- Contract verifies randomness via signature check (BLS12-381)
- Use verified randomness for both decryption AND surprise pricing
- Post hackathon more robust solution to implement.
CHALLENGE: Drand verification is expensive (~500k gas for BLS verification). optimized by:
- Caching verified randomness in DrandOracle contract
- Reusing same randomness for entire batch
- Keeper pre-verifies off-chain before submission
- ESCROW SYSTEM
Users deposit tokens into
mapping(address => mapping(Currency => uint256)) s_userBalances. This escrow approach:
- Eliminates need for per-intent approvals (would fail with encryption)
- Enables autonomous execution without user signatures
- Gas-efficient: only 2 storage updates per intent (debit input, credit output)
HACKY OPTIMIZATION: used Uniswap V4's Currency type (address cast) to support both ERC20 and native ETH with same code path.
WHAT IMPROVE WITH MORE TIME:
- BLS verification in Solidity (currently gas prohibitive, could use precompile)
- Multi-pool support (currently hardcoded single ETH/USDC pool)
- Advanced pricing strategies (TWAP-based, volatility-adjusted)
- Keeper profitability calculator (automated gas vs reward analysis)
- AI agent to automatically execute batch, to avoid any execution batch window wastage.