Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ out/
/broadcast/*/31337/
/broadcast/**/dry-run/

# Docs
docs/


# Dotenv file
.env
184 changes: 119 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,121 @@
## Foundry

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**

Foundry consists of:

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.

## Documentation

https://book.getfoundry.sh/

## Usage

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Format

```shell
$ forge fmt
# Shield Auction Hook
Mitigate Loss Versus Rebalancing (LVR) in Uniswap v4 pools by running per-block sealed-bid auctions that redirect MEV to LPs. EigenLayer operators bid to execute profitable rebalancing; proceeds are split across LPs, the winning operator (incl. gas), and the protocol.

## Table of Contents
- [Overview](#overview)
- [Architecture](#architecture)
- [Contracts](#contracts)
- [Auction Flow](#auction-flow)
- [Rewards & Fees](#rewards--fees)
- [Hook Permissions & Address Mining](#hook-permissions--address-mining)
- [Setup](#setup)
- [Building & Testing](#building--testing)
- [Deployment](#deployment)
- [Admin & Ops](#admin--ops)
- [Security Notes](#security-notes)
- [License](#license)

## Overview
- Detect LVR opportunities by comparing pool spot price to an external oracle.
- On significant swaps and sufficient deviation, start a short sealed-bid auction (12s).
- Authorized EigenLayer operators commit/reveal bids; highest bid wins.
- Winning bid proceeds are distributed: 85% LPs, 10% operator (incl. gas comp), 3% protocol fee.
- Pausable, owner-governed thresholds and operator allowlist in addition to EigenLayer registration.

## Architecture
- **Uniswap v4 Hook**: Implements `beforeSwap`, `afterSwap`, `afterAddLiquidity`, `afterRemoveLiquidity`.
- **Oracle**: Any contract implementing `IPriceOracle` supplying fresh prices and staleness checks.
- **EigenLayer AVS Directory**: Verifies operator registration status for reveal-phase authorization.
- **Sealed-bid auctions**: Commit via hash, reveal with amount+nonce; tracked per pool, one active at a time.
- **Liquidity tracking**: Simplified per-LP liquidity accounting to apportion LP rewards (placeholder; production should use precise position accounting and real token transfers).

## Contracts
- `src/ShieldAuctionHook.sol`: Core hook; triggers auctions, validates bids, finalizes, and accounts rewards.
- `src/Auction.sol` (`AuctionLib`): Auction/bid structs, commitment helpers, timing utilities.
- `src/IPriceOracle.sol`: Oracle interface for price + staleness.
- `src/IAVSDirectory.sol`: EigenLayer AVS Directory interface for operator registration checks.
- `src/HookMiner.sol`: Utility to mine a CREATE2 hook address with required permission bits.
- Tests & mocks: `test/ShieldAuctionHook.t.sol`, `test/MockAVSDirectory.sol`, `test/MockPriceOracle.sol`.

## Auction Flow
1. **Trigger** (`beforeSwap`): If swap size ≥ 0.1 ETH-equivalent and price deviation vs. oracle ≥ `lvrThreshold`, start a 12s auction for that pool (skip if one already active).
2. **Commit**: Operators call `commitBid(auctionId, commitment)` where `commitment = keccak256(bidder, amount, nonce)`.
3. **Reveal**: Authorized operators call `revealBid(auctionId, amount, nonce)`; `amount` must satisfy `MIN_BID` (0.001 ETH). Highest revealed bid tracked.
4. **Finalize** (`afterSwap`): When duration has elapsed, the next swap ends the auction, records winner, and allocates proceeds.
5. **LP Claims**: LPs call `claimRewards(poolId)` to withdraw accumulated rewards (event placeholder; wire real transfers in production).

## Rewards & Fees
- **LP reward**: 85% (`LP_REWARD_PERCENTAGE`)
- **AVS operator reward**: 10% (`AVS_REWARD_PERCENTAGE`, includes gas compensation)
- **Protocol fee**: 3% (`PROTOCOL_FEE_PERCENTAGE`)
- **Gas compensation**: 2% (`GAS_COMPENSATION_PERCENTAGE`, counted inside operator share)
- Percentages sum to `BASIS_POINTS` (10,000).

## Hook Permissions & Address Mining
Required permissions: `beforeSwap`, `afterSwap`, `afterAddLiquidity`, `afterRemoveLiquidity`. The deployed hook address must encode these flags in its low 160 bits (Uniswap v4 requirement). Mine a valid CREATE2 address with `HookMiner`:
```solidity
import { HookMiner } from "./src/HookMiner.sol";
import { Hooks } from "@uniswap/v4-core/libraries/Hooks.sol";
import { ShieldAuctionHook } from "./src/ShieldAuctionHook.sol";

uint160 flags = Hooks.BEFORE_SWAP_FLAG
| Hooks.AFTER_SWAP_FLAG
| Hooks.AFTER_ADD_LIQUIDITY_FLAG
| Hooks.AFTER_REMOVE_LIQUIDITY_FLAG;

(address hookAddress, bytes32 salt) = HookMiner.find(
deployer,
flags,
type(ShieldAuctionHook).creationCode,
abi.encode(poolManager, avsDirectory, avsAddress, priceOracle, feeRecipient, lvrThreshold)
);
// Deploy with CREATE2 to hookAddress using the mined salt.
```

### Gas Snapshots

```shell
$ forge snapshot
```

### Anvil

```shell
$ anvil
```

### Deploy

```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```

### Cast

```shell
$ cast <subcommand>
```

### Help

```shell
$ forge --help
$ anvil --help
$ cast --help
```
# Shield-Auction-Hook
## Setup
1. Install Foundry: `curl -L https://foundry.paradigm.xyz | bash` then `foundryup`.
2. Fetch deps (if using submodules): `git submodule update --init --recursive`.
3. Ensure Uniswap v4 core/periphery, EigenLayer interfaces, and OZ are available (already vendored under `lib/`).

## Building & Testing
- Build: `forge build`
- Test (verbose): `forge test -vvv`
- Format: `forge fmt`
- Gas report: `forge snapshot`
- Local node: `anvil`

Key tests: `test/ShieldAuctionHook.t.sol` covers deployment, permission mask correctness, auction lifecycle, bidding/reveal, reward math, LVR detection, admin controls, and pause behavior.

## Deployment
Constructor args (ShieldAuctionHook):
- `IPoolManager poolManager`
- `IAVSDirectory avsDirectory`
- `address avsAddress`
- `IPriceOracle priceOracle`
- `address feeRecipient`
- `uint256 lvrThreshold` (basis points; e.g., 100 = 1%)

Deployment outline:
1. Mine hook address with required permission flags (see above).
2. Deploy via CREATE2 with mined salt and constructor args.
3. Create pool using `PoolKey` pointing `hooks` to the deployed hook address, then `initialize`.
4. Seed liquidity so swaps can occur.
5. Register operators in EigenLayer for your AVS and/or owner-allowlist them via `setOperatorAuthorization`.

## Admin & Ops
- `setOperatorAuthorization(operator, bool)`: owner allowlist override in addition to AVS registration.
- `setLVRThreshold(newBps)`: adjust deviation trigger.
- `setFeeRecipient(addr)`: update protocol fee sink.
- `pause()` / `unpause()`: halt or resume swap hooks and auction triggering.
- View helpers: `activeAuctions(poolId)`, `auctions(auctionId)`, `bidCommitments`, `revealedBids`, `poolRewards`, `lpRewards`, `lpLiquidity`, `totalLiquidity`.

## Security Notes
- Hook is pausable and uses `ReentrancyGuard`, but production deployments must:
- Replace placeholder reward transfers with real token/native payouts.
- Use robust multi-source oracles and strict staleness windows.
- Harden liquidity accounting (current version is simplified).
- Monitor events (`AuctionStarted`, `AuctionEnded`, `MEVDistributed`, etc.) for operations and alerting.
- Deploying to an address without correct permission bits will brick the hook; always validate mined address before use.

## License
MIT
92 changes: 92 additions & 0 deletions docs/integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Shield Auction Hook – Integration Guide

This guide explains how to deploy and wire Shield Auction Hook into a Uniswap v4 pool, connect EigenLayer operators, and operate the sealed-bid auction flow.

## Prerequisites
- Foundry toolchain (`forge`, `anvil`), Uniswap v4 core/periphery libraries available at compile time.
- Access to a price oracle implementing `IPriceOracle` that returns fresh, non-stale prices for the traded pair.
- Access to EigenLayer AVS Directory (`IAVSDirectory`) and an AVS address that operators register against.
- A deployer capable of CREATE2 address mining (see `HookMiner`) so the hook address encodes required permissions.

## Required Hook Permissions
The hook uses `beforeSwap`, `afterSwap`, `afterAddLiquidity`, and `afterRemoveLiquidity`. The deployed address must have the corresponding permission bits set in its low 160 bits. If the address does not satisfy the mask, the PoolManager will reject the hook.

### Mining a Valid Address
Use `HookMiner` to compute a CREATE2 salt that yields a valid address:
```solidity
import { HookMiner } from "../src/HookMiner.sol";
import { Hooks } from "@uniswap/v4-core/libraries/Hooks.sol";

uint160 flags = Hooks.BEFORE_SWAP_FLAG
| Hooks.AFTER_SWAP_FLAG
| Hooks.AFTER_ADD_LIQUIDITY_FLAG
| Hooks.AFTER_REMOVE_LIQUIDITY_FLAG;

(address hookAddress, bytes32 salt) = HookMiner.find(
deployer,
flags,
type(ShieldAuctionHook).creationCode,
abi.encode(poolManager, avsDirectory, avsAddress, priceOracle, feeRecipient, lvrThreshold)
);
```
Deploy with CREATE2 using the mined `hookAddress` and `salt`.

## Deployment Steps
1. **Collect dependencies**:
- `poolManager`: deployed Uniswap v4 `PoolManager`.
- `avsDirectory`: EigenLayer AVS directory address.
- `avsAddress`: your AVS identifier.
- `priceOracle`: contract implementing `IPriceOracle`.
- `feeRecipient`: protocol fee sink.
- `lvrThreshold`: deviation threshold in basis points (1% = 100).
2. **Mine hook address** with the permission flags (above) and constructor args.
3. **Deploy hook** via CREATE2 to the mined address.
4. **Create / initialize pool** with `PoolKey` pointing `hooks` to the deployed address:
```solidity
PoolKey memory key = PoolKey({
currency0: token0,
currency1: token1,
fee: 3000,
tickSpacing: 60,
hooks: IHooks(hookAddress)
});
poolManager.initialize(key, initSqrtPriceX96);
```
5. **Seed liquidity** so swaps can execute and auctions can be triggered.
6. **Authorize operators**:
- Register operators in EigenLayer for your AVS (`avsOperatorStatus` must be `REGISTERED`), **and/or**
- Owner calls `setOperatorAuthorization(operator, true)` for an allowlist override.
7. **Configure threshold/fees** as needed via owner functions (`setLVRThreshold`, `setFeeRecipient`).

## Runtime Behavior
- **Triggering**: On `beforeSwap`, if swap size ≥ 0.1 ETH-equivalent and price deviation vs. oracle ≥ `lvrThreshold`, a 12s auction is started for that pool (one at a time).
- **Commit phase**: Operators call `commitBid(auctionId, commitment)` with `commitment = keccak256(bidder, amount, nonce)`; `amount` must be ≥ `MIN_BID` (0.001 ETH).
- **Reveal phase**: Authorized operators call `revealBid(auctionId, amount, nonce)`. Highest revealed bid wins; bid counts recorded.
- **Finalize**: When duration elapses, the next `afterSwap` call auto-finalizes (`_endAuction`), splits proceeds (85% LPs / 10% operator incl. gas / 3% protocol), and emits `AuctionEnded` + `MEVDistributed`.
- **LP claims**: LPs call `claimRewards(poolId)` to withdraw their share (simplified event placeholder for now).
- **Pausing**: Owner can pause/unpause; when paused, swap hooks revert and no auctions start.

## Oracle Expectations
- `getPrice(token0, token1)` returns token1/token0 price in 18 decimals.
- `isPriceStale` must return `true` when data is outdated; stale prices suppress auctions.
- Returning zero prices disables triggers for that pair.

## Operator UX Tips
- Pre-compute commitments off-chain using `AuctionLib.generateCommitment(bidder, amount, nonce)`.
- Track auctions via `AuctionStarted`/`AuctionEnded` events per `poolId`.
- Use `auctions(auctionId)` view to read state; `getTimeRemaining` helper is available in `AuctionLib`.

## Testing Locally
- Build: `forge build`
- Run tests: `forge test -vvv`
- Gas snapshot: `forge snapshot`
The test suite (`test/ShieldAuctionHook.t.sol`) demonstrates end-to-end setup, permissioned deployment, auction triggers, bidding, reveals, and admin controls; use it as reference for your own scripts.

## Production Hardening Notes
- Replace placeholder reward transfers with real token payouts (native/ ERC20) and accurate per-position accounting.
- Consider slashing/penalty mechanisms for failing operators.
- Use robust, multi-source oracle data and tighter staleness windows.
- Tune `MIN_BID`, `MAX_AUCTION_DURATION`, and swap-size thresholds for target chain conditions.
- Monitor events for operational alerts and invariant checks.


56 changes: 56 additions & 0 deletions docs/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Shield Auction Hook – Overview

Shield Auction Hook is a Uniswap v4 hook that mitigates Loss Versus Rebalancing (LVR) by running short sealed-bid auctions whenever pool price deviates materially from an external oracle price. EigenLayer operators compete to capture MEV; proceeds are redistributed to LPs, operators, and the protocol.

## Design Goals
- Detect LVR opportunities using an external price oracle.
- Trigger per-pool, per-block sealed-bid auctions on significant swaps.
- Pay auction proceeds to LPs (85%), AVS operator (10% incl. gas), and protocol (3%).
- Keep integration minimal: only hook permissions and oracle/AVS wiring are required.
- Remain pausible and admin-configurable for safety.

## Key Contracts
- `ShieldAuctionHook`: main hook; intercepts `beforeSwap`/`afterSwap`, tracks liquidity, orchestrates auctions and reward accounting.
- `AuctionLib`: data structures and helpers for auctions, bid commitments, and time calculations.
- `IPriceOracle`: interface for external price feed used to detect price deviation and staleness.
- `IAVSDirectory`: interface to EigenLayer AVS Directory for operator registration checks.
- `HookMiner`: helper to mine a CREATE2 hook address that satisfies Uniswap v4 permission bits.

## Hook Permissions
`ShieldAuctionHook` requires these permissions: `beforeSwap`, `afterSwap`, `afterAddLiquidity`, `afterRemoveLiquidity`. The deployed address must embed these flags in its low 160 bits (standard v4 hook requirement). Use `HookMiner` or equivalent address mining to find a valid address for deployment.

## Flow Summary
1. **Liquidity tracking** (`afterAddLiquidity` / `afterRemoveLiquidity`): track per-pool LP liquidity to simplify proportional reward accounting.
2. **Swap interception** (`beforeSwap`): if swap size is meaningful and price deviation from oracle meets `lvrThreshold`, start a new sealed-bid auction for the pool (one active auction per pool).
3. **Auction lifecycle**:
- Start: create `AuctionLib.Auction` with 12s duration (`MAX_AUCTION_DURATION`), store active auction id per pool.
- Commit: authorized operators submit bid commitments (`commitBid`), counted toward `totalBids`.
- Reveal: only authorized operators (`onlyAuthorizedOperator`) reveal bids; highest revealed bid tracked as winner.
- End: when duration elapses, `afterSwap` finalizes (`_endAuction`), records winner, and moves proceeds to reward buckets.
4. **Reward distribution** (`_distributeRewards`): split winning bid into LP rewards (85%), operator reward (10% incl. gas comp), protocol fee (3%), gas compensation (2% counted within operator share). LP rewards are currently pooled and claimable per pool.
5. **Claims** (`claimRewards`): LPs withdraw accumulated rewards for a pool (simplified event-based transfer placeholder).
6. **Admin controls**: owner may pause/unpause, set LVR threshold, fee recipient, and authorize/deauthorize operators in addition to AVS registration.

## Auction Mechanics
- **Trigger**: price deviation in basis points between pool spot and oracle price >= `lvrThreshold` (configurable, e.g., 100 = 1%) and swap size >= 0.1 ETH equivalent.
- **Duration**: 12 seconds (approx. one block); only one active auction per pool.
- **Sealed-bid**: commitments are `keccak256(bidder, amount, nonce)` (see `AuctionLib.generateCommitment`). Reveal validates commitment and enforces `MIN_BID` (0.001 ETH).
- **Winning**: highest revealed bid becomes winner; auction is idempotently finalized once ended.

## External Dependencies
- **Uniswap v4 Core/Periphery**: hook ABI and permission bits; hook must be deployed to a mined address.
- **Price Oracle**: must implement `IPriceOracle`, provide fresh prices, and expose staleness checks.
- **EigenLayer AVS Directory**: used to verify operator registration (`avsOperatorStatus`) in addition to owner-managed allowlist.

## Events and Observability
- `AuctionStarted`, `AuctionEnded`, `BidCommitted`, `BidRevealed`, `MEVDistributed`, `RewardsClaimed`, `LiquidityTracked`, `OperatorAuthorized/Deauthorized`, `LVRThresholdUpdated`.
- Useful for off-chain indexers and operator UIs to track auction lifecycle and rewards.

## Safety Considerations
- **Reentrancy**: guarded via `ReentrancyGuard` on external entry points.
- **Pause switch**: all swap hooks respect `whenNotPaused`.
- **Oracle risk**: stale/zero prices skip auction triggers; integrators must ensure robust oracle feeds.
- **Accounting simplification**: liquidity tracking is simplified; production deployments should replace with precise per-position accounting and real token transfers.
- **Permissions correctness**: deploying to an address without proper hook flags will brick the pool; always validate mined address before deployment.


Loading