Skip to content

Mosss-OS/IntentLP

Repository files navigation


██╗███╗   ██╗████████╗███████╗███╗   ██╗████████╗    ██╗     ██████╗ 
██║████╗  ██║╚══██╔══╝██╔════╝████╗  ██║╚══██╔══╝    ██║     ██╔══██╗
██║██╔██╗ ██║   ██║   █████╗  ██╔██╗ ██║   ██║       ██║     ██████╔╝
██║██║╚██╗██║   ██║   ██╔══╝  ██║╚██╗██║   ██║       ██║     ██╔═══╝ 
██║██║ ╚████║   ██║   ███████╗██║ ╚████║   ██║       ███████╗██║     
╚═╝╚═╝  ╚═══╝   ╚═╝   ╚══════╝╚═╝  ╚═══╝   ╚═╝       ╚══════╝╚═╝     

Intent-Based Liquidity Provision · Uniswap v4 Hook

Like a limit order, but for liquidity provision.

License: MIT Built with Foundry Uniswap v4 UHI9 Hookathon Deployed on Vercel Tests PRs Welcome


Launch App →


Pitch Deck

Pitch Deck
Auto-playing slides — opens in Google Slides


What is IntentLP?

IntentLP is a Uniswap v4 hook that gives liquidity providers conditional control over when their capital is actively routed through a pool.

Instead of passively sitting in a pool and absorbing every swap regardless of conditions, LPs register an intent — a set of on-chain rules that must be satisfied before a swap is allowed to flow through their position at standard fees.

When conditions are violated, a proportional penalty fee is applied, disincentivising unfavourable routing without ever hard-blocking the pool.

The Problem

Passive LPs in Uniswap v3/v4 have no say in which swaps hit their positions. A 0.01 ETH dust swap, a 500 ETH whale dump, a swap at 3am during zero-liquidity hours — all treated identically. This is the primary source of impermanent loss that the market hasn't solved at the hook layer.

The Solution

LP sets intent: "Only route through my position when:
  • Swap size is between 0.5 ETH and 50 ETH
  • Current time is between 09:00–17:00 UTC
  • Max slippage is under 1%"

The hook enforces this automatically on every beforeSwap(). No keeper. No rebalancing bot. No external protocol dependency. Pure on-chain, composable, and gas-efficient.


Project Structure

intent-lp-hook/
│
├── src/                          # Smart contracts
│   ├── IntentLPHook.sol          # Core hook — intent logic, volume tracking, fee moderation
│   └── IntentLPHookFactory.sol   # CREATE2 factory for valid hook address mining
│
├── test/
│   ├── IntentLPHook.t.sol        # 39 unit tests + fuzz suite
│   └── IntentLPHookIntegration.t.sol # 23 integration tests (forked Arbitrum Sepolia)
│
├── script/
│   └── Deploy.s.sol              # Deploy scripts: local Anvil + Unichain/Base/Arbitrum
│
├── subgraph/                     # Graph Protocol subgraph for event indexing
│
├── frontend/                     # Vite + React UI
│   ├── src/
│   │   ├── App.tsx               # Root with WagmiProvider + QueryClientProvider
│   │   ├── pages/
│   │   │   ├── HomePage.tsx      # Landing page
│   │   │   ├── AnalyticsPage.tsx # Pool analytics with TradingView charts
│   │   │   ├── DashboardPage.tsx # LP dashboard
│   │   │   ├── SwapPage.tsx      # Swap interface
│   │   │   ├── RegisterPage.tsx  # Intent registration
│   │   │   ├── BridgePage.tsx    # Cross-chain bridge
│   │   │   ├── RewardsPage.tsx   # USDC rewards
│   │   │   └── DocsPage.tsx      # Documentation
│   │   ├── components/
│   │   │   ├── Navbar.tsx        # Sticky nav, wallet connect, chain switcher
│   │   │   ├── Hero.tsx          # Landing hero with animated headline
│   │   │   ├── HowItWorks.tsx    # 4-step explainer
│   │   │   ├── Features.tsx      # Feature grid + Solidity code preview
│   │   │   ├── Dashboard.tsx     # Pool stats + my intent status + activity feed
│   │   │   ├── SwapSimulator.tsx # Live preview: will this swap violate my intent?
│   │   │   ├── IntentForm.tsx    # Register/update LP intent (wallet-connected)
│   │   │   ├── RegisterSection.tsx # Full register CTA section
│   │   │   ├── BridgeIntentSection.tsx # Cross-chain bridge form with Across
│   │   │   ├── Docs.tsx          # FAQ accordion + resource links
│   │   │   └── Footer.tsx        # Full footer with links
│   │   └── lib/
│   │       ├── contracts.ts      # ABI + deployed hook addresses per chain
│   │       └── wagmi.ts          # Wagmi config (Unichain, Base, Arbitrum, Mainnet)
│   ├── index.html
│   ├── package.json
│   ├── vite.config.ts
│   ├── tailwind.config.js
│   └── tsconfig.json
│
├── foundry.toml                  # Foundry config + remappings
├── Makefile                      # Convenience commands
└── README.md

Quickstart

Prerequisites

# Install Foundry
curl -L https://foundry.paradigm.xyz | bash && foundryup

# Install Node.js 18+ (for frontend)
node --version  # should be >= 18

1 · Smart Contracts

# Install Solidity dependencies
make install

# Build
make build

# Run full test suite
make test-v

# Run fuzz tests (10k iterations)
make test-fuzz

# Gas report
make test-gas

2 · Frontend

cd frontend

# Install JS dependencies
npm install

# Start dev server at http://localhost:5173
npm run dev

# Production build
npm run build

# Preview production build
npm run preview

3 · Deploy Locally (Anvil)

# Terminal 1
anvil

# Terminal 2
make deploy-local

4 · Deploy to Testnet / Mainnet

cp .env.example .env
# Fill in your RPC URLs and private key

make deploy-unichain-sepolia   # Unichain Sepolia
make deploy-base-sepolia       # Base Sepolia
make deploy-arbitrum-sepolia   # Arbitrum Sepolia

5 · Verify on Arbiscan

# Requires ARBISCAN_API_KEY in .env
forge verify-contract <DEPLOYED_ADDRESS> src/IntentLPHook.sol:IntentLPHook \
  --chain 421614 \
  --constructor-args $(cast abi-encode "constructor(address,address)" \
    <POOL_MANAGER_ADDR> <USDC_ADDR>)

After deploying, update HOOK_ADDRESSES in frontend/src/lib/contracts.ts with your deployed address.

Current Arbitrum Sepolia deployment: 0x8BFBAA48cB579600FBDe29aAAf04965C3FDBDac0 (verified)
Base Sepolia deployment: 0xbB76a401b1381C501703008c34ef58C6e5701Ac0 (verified)

Live App

The frontend is deployed on Vercel:

https://intent-lp-hook.vercel.app

Connect your wallet on Arbitrum Sepolia to interact with the live hook contract. Supported chains: Arbitrum Sepolia, Base Sepolia, Unichain Sepolia, Ethereum Sepolia.


How the Hook Works

Permissions

Permission Purpose
afterInitialize Sets up rolling volume tracker for new pool
beforeAddLiquidity Accepts inline intent registration via hookData
beforeRemoveLiquidity Deactivates intent if LP removes all liquidity
beforeSwap Core enforcement — evaluates all active intents, applies penalty fee
afterSwap Finalises volume tracking, emits indexer events

Fee Override Mechanism

penaltyFee = (violatedIntents / totalActiveIntents) × 3000 bps

Returned with the 0x400000 flag to signal Uniswap v4's PoolManager to apply the override.

Rolling Volume Formula

if elapsed >= 1 hour:
  rollingVolume = (previousVolume × (24 - hoursElapsed) / 24) + newSwapVolume
else:
  rollingVolume += newSwapVolume

A 24-hour exponential decay approximation — no oracle dependency, all on-chain.


LP Intent Parameters

Field Type Description
minSwapVolume uint256 Minimum swap size (in token0 units, e.g. wei for ETH)
maxSwapVolume uint256 Maximum swap size
maxSlippageBps uint256 Max slippage tolerance in basis points (reserved for oracle integration)
activeHourStart uint8 UTC hour when intent activates (0–23)
activeHourEnd uint8 UTC hour when intent deactivates (0–23)
active bool Pause/resume toggle
owner address Set automatically to msg.sender

Note: Set both activeHourStart and activeHourEnd to 0 to allow all hours.


Example Usage

Solidity

// Register intent directly
IntentLPHook.LPIntent memory intent = IntentLPHook.LPIntent({
    minSwapVolume: 0.5 ether,
    maxSwapVolume: 50 ether,
    maxSlippageBps: 100,      // 1%
    activeHourStart: 9,
    activeHourEnd: 17,
    active: true,
    owner: address(0)         // set by hook
});
hook.registerIntent(poolKey, intent);

// Deactivate without removing liquidity
hook.deactivateIntent(poolKey);

// Preview: would a 3 ETH swap violate my intent?
(bool violated, uint256 count) = hook.previewSwap(poolKey, 3 ether);

Frontend (React + wagmi)

import { useWriteContract } from 'wagmi'
import { parseEther } from 'viem'
import { INTENT_LP_HOOK_ABI, HOOK_ADDRESSES } from './lib/contracts'

const { writeContract } = useWriteContract()

writeContract({
  address: HOOK_ADDRESSES[chainId],
  abi: INTENT_LP_HOOK_ABI,
  functionName: 'registerIntent',
  args: [poolKey, intent],
})

Design Decisions

Why penalty fees instead of hard blocks? Hard-blocking swaps can strand liquidity if intent conditions are too strict. Penalty fees keep the pool always accessible while making unfavourable routing economically unattractive.

Why no external oracle for volume? Volume tracking is fully on-chain — no oracle required. maxSlippageBps is enforced via a configurable Chainlink price feed per pool for oracle-backed slippage protection.

Why rolling volume vs. per-block tracking? LPs care about aggregate market conditions, not individual swap context. The 24h decay approximation is a single SLOAD + arithmetic — minimal gas, meaningful signal.


Gas Estimates

| Operation | Estimated Gas | |---|---|---| | registerIntent (new) | ~85,000 | | registerIntent (update) | ~40,000 | | deactivateIntent | ~25,000 | | beforeSwap (0 intents) | ~5,000 | | beforeSwap (5 intents) | ~10,000 | | beforeSwap (10 intents) | ~37,000 | | _updateRollingVolume | moved to afterSwap — hot path no longer pays this cost |


Roadmap

  • Chainlink integration — enforce maxSlippageBps with real-time price feeds
  • USDC streaming rewards — Circle reward pool for active LPs
  • Emergency pause — owner-controlled enforcement bypass
  • Gas optimization — ~25K gas saved in hot path
  • SwapSimulator — live on-chain preview connected to deployed contract
  • Subgraph — Graph Protocol indexer for all contract events
  • Across Protocol — cross-chain intent sync via ERC-7683
  • EigenLayer AVS — shared intent state & LVR reduction auction
  • Intent Marketplace — publish and subscribe to community intent templates
  • Formal Audit — engage a security firm before TVL exceeds safe thresholds
  • Intent NFTs — make intents transferable ERC-721 tokens (sellable strategies)

Security

IntentLP has not been audited. It was built for the Atrium Academy UHI9 Hookathon.

  • The test suite covers 63 tests (41 unit + 22 integration) including fuzz tests
  • The hook does not hold user funds; it only adjusts fees in real time
  • Intents are stored per-LP per-pool and cannot be modified by anyone other than the intent owner
  • No upgradeable proxy — deterministic CREATE2 deployment

Do not deploy significant capital without a professional security audit.


Contributing

We welcome contributions from the community! Whether you're fixing a bug, adding a feature, or improving documentation, please read our Contributing Guide first.

git clone https://github.com/Mosss-OS/IntentLP.git
cd IntentLP
make install
make build
make test

Quick Links

Please run forge fmt before submitting PRs.


License

MIT — see LICENSE


Built with ♥ for the Atrium Academy UHI9 Hookathon

atrium.academy · Uniswap v4 Docs · Foundry

About

IntentLP — Intent-Based Liquidity Provision for Uniswap v4. A Uniswap v4 hook that lets liquidity providers define conditional rules (min/max volume, time windows, slippage) for when their capital is active in a pool. Built for the Atrium Academy UHI9 Hookathon.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors