# Weighted Hook Index: Technical Specifications
## Project Overview
The Weighted Hook Index is an on-chain, self-balancing crypto index built using Uniswap v4 hooks. It replicates a constant-mean market-maker invariant across a fixed basket of assets. A lightweight IndexCoordinator contract (inheriting ERC-6909) manages global state for multiple indices, enabling permissionless index LP tokens that rebalance continuously through arbitrage incentives—without governance, off-chain oracles.
### Key Features
- **Multi-Index Support**: ERC-6909-based tokens where each ID represents a unique index (basket) with its own assets, weights, and pools.
- **Hub-Star Topology**: For a basket of N assets in an index (ID), deploy N-1 Uniswap v4 pools pairing each asset with a designated hub asset (e.g., USDC), dramatically reducing deployment costs from \binom{N}{2} to N-1 pools.
- **Invariant Enforcement**: Each WeightedHook completely overrides Uniswap v4 pricing using global index state, maintaining the per-index constant-mean invariant (∏ (reserve_i ^ weight_i) >= invariant) across all N assets.
- **Rebalancing**: Purely arbitrage-driven; weighted curve pricing automatically creates incentives for traders to restore target weights without any liquidity management.
- **LP Tokens**: Permissionless ERC-6909 tokens minted by depositing proportional assets, which are held as reserves in the IndexCoordinator and made available through hub-paired WeightedHook pools.
- **On-Chain Only**: No external oracles; all logic uses aggregated reserves and fixed weights.
- **Efficient Routing**: Non-hub pairs trade via 2-hop routes through the hub asset, with periphery contracts handling optimal path execution.
- **Fixed Baskets**: Assets and weights are set at index creation (immutable per ID), including designation of the hub asset.
This hub-star design dramatically reduces gas costs (from O(N²) to O(N) pools), simplifies index management, improves capital efficiency, and leverages Uniswap v4 for routing infrastructure. Each WeightedHook manages a 2-asset Uniswap pool but prices using global N-asset index state, enabling efficient arbitrage and rebalancing while maintaining the constant-mean invariant.
## Architecture and Flow Diagrams
The following Mermaid charts illustrate the key flows in the protocol. Each chart focuses on a specific process, showing interactions between users, the IndexCoordinator, pools, and supporting libraries. For clarity, we've omitted optional monitoring elements like events.
### Hub-Star Topology Comparison
This chart compares the all-pairs topology with the optimized hub-star design:
```mermaid
graph LR
subgraph "All-Pairs Topology (5 assets = 10 pools)"
A1[Asset A] --- B1[Asset B]
A1 --- C1[Asset C]
A1 --- D1[Asset D]
A1 --- E1[Asset E]
B1 --- C1
B1 --- D1
B1 --- E1
C1 --- D1
C1 --- E1
D1 --- E1
end
subgraph "Hub-Star Topology (5 assets = 4 pools)"
HUB[USDC<br/>Hub]
A2[Asset A] --- HUB
B2[Asset B] --- HUB
C2[Asset C] --- HUB
D2[Asset D] --- HUB
A2 -.->|Virtual Pair<br/>via Hub| B2
A2 -.->|Virtual Pair<br/>via Hub| C2
B2 -.->|Virtual Pair<br/>via Hub| D2
end
style HUB fill:#f9f,stroke:#333,stroke-width:4px
```
**Key Benefits:**
- **Pool Reduction**: From N(N-1)/2 to N-1 pools (10→4 for 5 assets, 45→9 for 10 assets)
- **Gas Savings**: ~60-80% reduction in deployment and management costs
- **Simplified Arbitrage**: All assets have direct liquidity to stable hub
- **Maintained Invariant**: Virtual reserves calculated through hub preserve the constant-mean
### Complete Hub-Star Architecture
This diagram shows the full system with multiple indices using different hub assets:
```mermaid
graph TB
subgraph "IndexCoordinator (Central Hub)"
IC[IndexCoordinator<br/>ERC-6909]
subgraph "Index Registry"
ID1[Index ID: 1<br/>Tech Basket<br/>Hub: USDC]
ID2[Index ID: 2<br/>DeFi Index<br/>Hub: WETH]
ID3[Index ID: 3<br/>Stables<br/>Hub: USDC]
end
end
subgraph "Index 1: Tech Basket (USDC Hub)"
USDC1[USDC]
AAPL[AAPL]
GOOGL[GOOGL]
MSFT[MSFT]
USDC1 ---|Pool 1.1| AAPL
USDC1 ---|Pool 1.2| GOOGL
USDC1 ---|Pool 1.3| MSFT
AAPL -.->|Virtual: AAPL/GOOGL<br/>via USDC| GOOGL
AAPL -.->|Virtual: AAPL/MSFT<br/>via USDC| MSFT
GOOGL -.->|Virtual: GOOGL/MSFT<br/>via USDC| MSFT
end
subgraph "Index 2: DeFi Index (WETH Hub)"
WETH[WETH]
UNI[UNI]
AAVE[AAVE]
CRV[CRV]
COMP[COMP]
WETH ---|Pool 2.1| UNI
WETH ---|Pool 2.2| AAVE
WETH ---|Pool 2.3| CRV
WETH ---|Pool 2.4| COMP
end
subgraph "Index 3: Stablecoin Index (USDC Hub)"
USDC2[USDC]
USDT[USDT]
DAI[DAI]
FRAX[FRAX]
USDC2 ---|Pool 3.1| USDT
USDC2 ---|Pool 3.2| DAI
USDC2 ---|Pool 3.3| FRAX
end
IC --> ID1
IC --> ID2
IC --> ID3
ID1 -->|Manages| USDC1
ID2 -->|Manages| WETH
ID3 -->|Manages| USDC2
User1[User] -->|Mint/Burn/Swap| IC
Arb[Arbitrageur] -->|Rebalance| USDC1
Arb -->|Rebalance| WETH
style IC fill:#f9f,stroke:#333,stroke-width:4px
style USDC1 fill:#9ff,stroke:#333,stroke-width:3px
style WETH fill:#9ff,stroke:#333,stroke-width:3px
style USDC2 fill:#9ff,stroke:#333,stroke-width:3px
```
**Architecture Highlights:**
- Each index can choose its optimal hub asset (stablecoins typically use USDC, DeFi tokens might use WETH)
- Each WeightedHook manages one 2-asset Uniswap pool but queries global N-asset state for pricing
- Virtual pairs (dotted lines) are calculated through 2-hop routing, each hop using global context
- Arbitrageurs focus on hub pairs for efficient rebalancing
- Cross-index arbitrage possible when indices share common assets
### N-Asset Index via 2-Asset Hooks Pattern
This diagram shows how a 4-asset index is implemented using 3 separate WeightedHook instances:
```mermaid
graph TB
subgraph "4-Asset Index (ID: 1)"
IC[IndexCoordinator<br/>Hook + State Manager<br/>USDC: 40%<br/>ETH: 30%<br/>BTC: 20%<br/>LINK: 10%]
subgraph "Uniswap Pools (IC as hook)"
P1[USDC-ETH Pool]
P2[USDC-BTC Pool]
P3[USDC-LINK Pool]
end
end
subgraph "User Interactions"
U1[User swaps ETH→USDC]
U2[User swaps ETH→BTC<br/>via Router: ETH→USDC→BTC]
end
U1 -->|Swap| P1
P1 -->|beforeSwap| IC
IC -->|Weighted pricing| P1
U2 -->|Route through| P1
U2 -->|Route through| P2
P1 -->|beforeSwap| IC
P2 -->|beforeSwap| IC
style IC fill:#f9f,stroke:#333,stroke-width:4px
style P1 fill:#bfb,stroke:#333,stroke-width:2px
style P2 fill:#bfb,stroke:#333,stroke-width:2px
style P3 fill:#bfb,stroke:#333,stroke-width:2px
```
**Key Properties:**
- **3 Uniswap Pools**: Each uses IndexCoordinator as its hook
- **1 Contract**: IndexCoordinator manages state AND acts as hook for all pools
- **Pool Identification**: Uses PoolKey to determine which index and assets
- **Global Pricing**: Every swap considers ALL 4 assets' weights and reserves
- **Virtual Pairs**: ETH↔BTC routed through hub, maintaining weighted pricing
### Chart 1: Index Creation and Deployment
This chart shows how a user creates a new index with hub-star topology:
```mermaid
graph TD
User -->|Calls createIndex assets weights hubAsset| IC[IndexCoordinator<br/>ERC-6909]
IC -->|Assigns unique token ID| IC
IC -->|Validates hub asset in basket| IC
IC -->|Deploys N-1 hub-paired pools for ID| Pools[Hub-Paired Pools<br/>with WeightedHooks]
IC -->|Sets immutable weights/assets/hub for ID| IC
subgraph "Example: 4-asset index with USDC hub"
USDC[USDC Hub]
USDC ---|Pool 1| ETH[ETH]
USDC ---|Pool 2| BTC[wBTC]
USDC ---|Pool 3| LINK[LINK]
end
```
### Chart 2: Minting LP Tokens
This chart depicts the process of minting LP shares for an existing index (ID), including asset distribution to pools.
```mermaid
graph TD
User -->|Deposits proportional assets for ID| IC[IndexCoordinator<br/>ERC-6909]
IC -->|Validates proportions for ID| IC
IC -->|Holds reserves for index access| IC
IC -->|Makes available via WeightedHooks| Pools[Hub-Paired WeightedHooks]
IC -->|Mints shares token ID| User
IC -->|Updates reserves/invariant for ID| IC
```
### Chart 3: Swapping and Rebalancing
This chart illustrates swapping with hub-star routing:
```mermaid
graph TD
Trader[Trader/Arbitrageur] -->|Swap request A→B| PR[Periphery Router]
PR -->|Routes via hub: A→USDC→B| Pools
subgraph "Two-Hop Execution"
P1[WeightedHook A-USDC] -->|Query global state| IC[IndexCoordinator]
P1 -->|Execute swap with global pricing| P1
P2[WeightedHook USDC-B] -->|Query global state| IC
P2 -->|Execute swap with global pricing| P2
end
IC -->|Validate composite invariant| IC
IC -->|Update global reserves| IC
P1 -->|Update reserves| IC
P2 -->|Update reserves| IC
PR -->|Return B tokens| Trader
Trader -.->|Direct arbitrage<br/>on hub pairs| Pools
```
### Chart 4: Burning LP Tokens
This chart shows the redemption process, where LP shares are burned to withdraw proportional assets.
```mermaid
graph TD
User -->|Burns shares for ID| IC[IndexCoordinator<br/>ERC-6909]
IC -->|Validates shares for ID| IC
IC -->|Calculates proportional withdrawal| IC
IC -->|Releases reserves directly| IC
IC -->|Returns assets| User
IC -->|Updates reserves/invariant for ID| IC
```
## Key Components
### IndexCoordinator Contract (`IndexCoordinator.sol`)
- **Role**: Central contract that combines index management, ERC-6909 tokens, AND acts as the universal Uniswap v4 hook for ALL pools across ALL indices.
- **Inheritance**: `IndexCoordinator is ERC6909, BaseHook`
- **Key Properties**:
- Single hook address for all pools across all indices
- Maps PoolKey (currency pair) to index ID and asset positions
- Permissionless index creation with auto-assigned IDs
- Per-ID immutables: Assets, normalized weights, hub asset
- Per-ID dynamic state: Reserves, invariants
- ERC-6909 balances track LP shares per ID
- **Key Functions**:
- `createIndex(address[] assets, uint256[] weights, address hubAsset)`:
```solidity
function createIndex(address[] assets, uint256[] weights, address hub) {
uint256 indexId = nextIndexId++;
// Store index configuration
indices[indexId] = IndexConfig({
assets: assets,
weights: weights,
hubAsset: hub,
// ...
});
// For each non-hub asset, create Uniswap pool
for (uint i = 0; i < assets.length; i++) {
if (assets[i] == hub) continue;
PoolKey memory key = PoolKey({
currency0: Currency.wrap(hub < assets[i] ? hub : assets[i]),
currency1: Currency.wrap(hub < assets[i] ? assets[i] : hub),
fee: 3000,
tickSpacing: 60,
hooks: IHooks(address(this)) // THIS contract is the hook
});
// Store mapping from pool to index
bytes32 poolId = PoolIdLibrary.toId(key);
poolToIndex[poolId] = indexId;
poolToAssetIndex[poolId] = i;
// Initialize Uniswap pool
poolManager.initialize(key, calculateStartPrice());
}
}
```
- `getTargetWeight(uint256 id, address asset)`: Returns the fixed weight for an asset in the index (ID).
- `getGlobalReserves(uint256 id, address asset)`: Returns reserves for an asset from its hub-paired pool (or hub's total reserves across all pairs).
- `getVirtualReserves(uint256 id, address asset0, address asset1)`: Calculates virtual reserves for non-hub pairs using the product of their hub ratios.
- `computeInvariant(uint256 id)`: Calculates the per-index constant-mean invariant: ∏ (reserve_i ^ weight_i) using fixed-point math, where reserves include both direct hub-paired and calculated virtual reserves.
- `getWeightDrift(uint256 id, address asset)`: Computes current weight (reserve_i / total reserves) vs. target for the index; emits `WeightDrift` event if drift exceeds a threshold (e.g., 5%).
- `mint(uint256 id, address to, uint256 shares)`: User deposits assets proportional to the index's weights; validates proportions; adds to global reserves; mints ERC-6909 shares for the ID.
- `burn(uint256 id, address from, uint256 shares)`: Burns ERC-6909 shares for the ID; calculates proportional withdrawal; transfers assets from global reserves to user.
- `totalValueLocked(uint256 id)`: Computes TVL for the index based on aggregated reserves.
- **Storage**: Mappings for per-ID data (ID → assets/weights/hubAsset/pools/reserves); routing cache for virtual pairs; standard ERC-6909 storage (balances, totalSupply per ID).
- **Rationale**: Single contract acts as both index manager AND universal hook for all pools, eliminating the need for separate WeightedHook instances. Uses PoolKey to identify which index/pool is being swapped.
- `beforeSwap(address sender, PoolKey key, SwapParams params, bytes data)`: Acts as universal hook for all pools
- `getHookPermissions()`: Returns permissions to block liquidity operations and enable custom pricing
### Hook Implementation in IndexCoordinator
Since IndexCoordinator inherits BaseHook, it implements the hook functions for ALL pools:
```solidity
function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata)
external
override
returns (bytes4, BeforeSwapDelta, uint24)
{
// 1. Identify which index and assets from PoolKey
bytes32 poolId = PoolIdLibrary.toId(key);
uint256 indexId = poolToIndex[poolId];
uint256 assetIndex = poolToAssetIndex[poolId];
// 2. Get index configuration
IndexConfig memory config = indices[indexId];
// 3. Determine tokens involved
address tokenIn = params.zeroForOne ?
Currency.unwrap(key.currency0) : Currency.unwrap(key.currency1);
address tokenOut = params.zeroForOne ?
Currency.unwrap(key.currency1) : Currency.unwrap(key.currency0);
// 4. Calculate swap amounts using global weighted math
bool isExactInput = params.amountSpecified < 0;
uint256 amountIn;
uint256 amountOut;
if (isExactInput) {
amountIn = uint256(-params.amountSpecified);
amountOut = calculateWeightedOutput(
indexId,
tokenIn,
tokenOut,
amountIn
);
} else {
amountOut = uint256(params.amountSpecified);
amountIn = calculateWeightedInput(
indexId,
tokenIn,
tokenOut,
amountOut
);
}
// 5. Handle token transfers
poolManager.take(params.zeroForOne ? key.currency0 : key.currency1, address(this), amountIn);
// Update internal reserves
reserves[indexId][tokenIn] += amountIn;
reserves[indexId][tokenOut] -= amountOut;
// Pay out
IERC20(tokenOut).transfer(address(poolManager), amountOut);
poolManager.settle();
// 6. Validate invariant
require(validateInvariant(indexId), "Invariant violation");
// 7. Return delta to override Uniswap pricing
BeforeSwapDelta delta = isExactInput ?
toBeforeSwapDelta(int128(amountIn), -int128(amountOut)) :
toBeforeSwapDelta(-int128(amountOut), int128(amountIn));
return (BaseHook.beforeSwap.selector, delta, 0);
}
```
### Libraries
- **QuoteLib** (`QuoteLib.sol`): Computes swap quotes based on the weighted invariant (e.g., outAmount = reserveOut * (1 - (reserveIn / (reserveIn + amountIn)) ^ (weightIn / weightOut))).
- **CurveLib** (`CurveLib.sol`): Core math for the constant-mean invariant (e.g., computeInvariant, verifyPostSwap).
## Weighted Curve Mathematics
### Core Invariant Formula
The fundamental invariant for our weighted index pools follows the Balancer constant-mean market maker model:
```
V = ∏(B_i^W_i) = constant
```
Where:
- `B_i` = balance of token i in the index
- `W_i` = normalized weight of token i (all weights sum to 1)
- `V` = invariant constant that must be preserved
### Multi-Asset Swap Formula
For swapping token `i` to token `o` within an index:
```
A_o = B_o * (1 - (B_i / (B_i + A_i))^(W_i/W_o))
```
**Key Properties:**
- The ratio `W_i/W_o` determines swap curvature between any two assets
- When an asset is underweight, its effective price increases across ALL pairs
- When an asset is overweight, it becomes cheaper in ALL pairs
- The formula inherently accounts for the entire pool state, not just the pair being swapped
### Rebalancing Through Price Incentives
The curve automatically creates arbitrage opportunities when weights drift from targets:
```solidity
// Effective pricing considers weight deviation
effectivePrice = spotPrice * (currentWeight / targetWeight)^α
// Spot price between any two assets
spotPrice = (B_i/W_i) / (B_o/W_o)
```
**Example Rebalancing Scenario:**
- Target: Hub 40%, Asset A 40%, Asset B 20%
- Current: Hub 40%, Asset A 30%, Asset B 30%
- Result: A becomes expensive (underweight), B becomes cheap (overweight)
- Arbitrage: Buy A externally → sell to pool, Buy B from pool → sell externally
### Hub-Star Virtual Pricing
For non-hub pairs in our topology, prices are calculated through the hub:
```solidity
function getVirtualPrice(tokenA, tokenB) {
priceA_hub = (B_A/W_A) / (B_hub/W_hub);
priceHub_B = (B_hub/W_hub) / (B_B/W_B);
return priceA_hub * priceHub_B;
}
```
**Benefits:**
- **Global State Awareness**: Each swap considers the entire index composition
- **Automatic Rebalancing**: Price deviations create natural arbitrage incentives
- **Capital Efficiency**: All liquidity is always active, no out-of-range positions
- **Gas Optimization**: No tick management or position updates required
This mathematical foundation ensures that our weighted indices self-balance through market forces while maintaining capital efficiency and gas optimization.
### Architecture Benefits
1. **Simplicity**: One contract instead of multiple hook instances
2. **Gas Efficiency**: No external calls between hook and coordinator
3. **Atomic Operations**: Direct access to reserves and state
4. **Easier Upgrades**: Single contract to maintain and upgrade
5. **Security**: Centralized access control and invariant enforcement
### Supporting Contracts
- **Periphery** (`IndexPeriphery.sol`): User-friendly wrappers handling:
- **Smart Routing**: Automatic path selection (direct hub pair or 2-hop route)
- **Batch Operations**: Multi-asset swaps optimized for hub topology
- **Quote Aggregation**: Accurate quotes for virtual pairs
## Technical Flow
1. **Index Creation**: User calls `createIndex` with hub asset → IndexCoordinator validates hub → for each non-hub asset: creates PoolKey with IndexCoordinator as hook → stores pool-to-index mapping → calls `poolManager.initialize()` → Uniswap pool created → assigns ID, sets weights.
2. **Minting LP Tokens**: User deposits proportional assets → IndexCoordinator adds to reserves for specific index → mints ERC-6909 shares for that index ID.
3. **Direct Hub Swaps**: Trader swaps on hub pair → Uniswap routes to IndexCoordinator.beforeSwap → IndexCoordinator identifies index from PoolKey → calculates weighted price using ALL N assets → updates reserves → validates invariant.
4. **Routed Swaps**: Trader swaps non-hub pair (A→B) → Periphery routes A→Hub→B → each swap hits IndexCoordinator with different PoolKey → global weighted pricing maintained.
5. **Rebalancing**: Hub concentration enables efficient arbitrage → traders exploit price gaps on hub pairs → weights restored with minimal hops.
6. **Burning LP Tokens**: User burns shares → IndexCoordinator calculates proportional withdrawal → transfers assets from global reserves.
7. **Monitoring**: Enhanced events track both direct and virtual reserves, hub utilization, and routing efficiency.
## Security and Edge Cases
- **Invariant Checks**: All swaps (direct and routed) validate per-index invariant to prevent drainage.
- **Hub Dependency**: Hub asset failure/depeg risks mitigated by:
- Allowing hub migration via governance (future enhancement)
- Using highly liquid, stable assets (USDC, WETH)
- Monitoring hub pair health
- **Virtual Reserve Accuracy**: Composite calculations maintain precision through careful fixed-point math.
- **Routing Attacks**: Periphery validates optimal paths; sandwich attacks minimized by invariant constraints.
- **Gas Efficiency**: Hub-star reduces deployment by ~80%; ERC-6909 minimizes storage; no liquidity management overhead.
- **Reserve Management**: All reserves stored directly in IndexCoordinator, accessed during swaps.
## Hub-Star Benefits Summary
| Metric | All-Pairs | Hub-Star | Improvement |
|--------|-----------|----------|--------------|
| Pools (10 assets) | 45 | 9 | 80% reduction |
| Deployment Gas | O(N²) | O(N) | Quadratic → Linear |
| Max Swap Hops | 1 | 2 | Acceptable tradeoff |
| Arbitrage Paths | Complex | Simple | Via hub asset |
| Liquidity Depth | Fragmented | Concentrated | Better execution |
## Hook-Based Architecture: N-Asset Indices via 2-Asset Pools
### Core Innovation
A single IndexCoordinator contract acts as the universal hook for ALL pools across ALL indices. It uses the PoolKey to identify which index and assets are being swapped, then applies global weighted pricing.
### Simplified Architecture
```mermaid
graph TB
subgraph "Single IndexCoordinator Contract"
IC[IndexCoordinator<br/>ERC-6909 + BaseHook]
subgraph "Index Registry"
I1[Index 1: USDC/ETH/BTC]
I2[Index 2: WETH/UNI/AAVE]
end
subgraph "Pool Mappings"
PM[PoolKey → IndexID]
end
end
subgraph "Uniswap v4 Pools"
P1[USDC-ETH Pool]
P2[USDC-BTC Pool]
P3[WETH-UNI Pool]
P4[WETH-AAVE Pool]
end
P1 -->|beforeSwap| IC
P2 -->|beforeSwap| IC
P3 -->|beforeSwap| IC
P4 -->|beforeSwap| IC
IC -->|Uses PoolKey to identify| PM
PM -->|Maps to| I1
PM -->|Maps to| I2
```
### Pool Initialization Flow
```mermaid
sequenceDiagram
participant User
participant IC as IndexCoordinator<br/>(ERC-6909 + Hook)
participant PM as PoolManager
User->>IC: createIndex([USDC, ETH, BTC], [40%, 30%, 30%], USDC)
IC->>IC: Assign indexId = 1
loop For each non-hub asset
IC->>IC: Create PoolKey with IC as hook
IC->>IC: Store poolId → indexId mapping
IC->>PM: initialize(PoolKey, startPrice)
PM->>PM: Create Uniswap pool
end
IC->>IC: Store index config
IC->>User: Return indexId
```
### Weighted Pricing Calculation
The core pricing formula adapts Balancer's weighted math to our hub-star topology:
```solidity
function calculateWeightedOutput(
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256[] memory weights,
uint256[] memory reserves
) returns (uint256) {
// Get indices for tokens
uint256 inIdx = getTokenIndex(tokenIn);
uint256 outIdx = getTokenIndex(tokenOut);
// Apply Balancer weighted formula
// A_out = B_out * (1 - (B_in / (B_in + A_in))^(W_in/W_out))
uint256 weightRatio = (weights[inIdx] * 1e18) / weights[outIdx];
uint256 adjustedReserveIn = reserves[inIdx] + amountIn;
uint256 base = (reserves[inIdx] * 1e18) / adjustedReserveIn;
uint256 power = rpow(base, weightRatio, 1e18);
return reserves[outIdx] * (1e18 - power) / 1e18;
}
```
### Why This Architecture Works
1. **Unified Architecture**:
- **Uniswap**: Handles routing, interfaces, and token accounting
- **IndexCoordinator**: Acts as universal hook AND maintains all state
- **Pool Identification**: PoolKey mappings determine index and asset context
2. **Token Flow**:
```
User → Uniswap Router → PoolManager → IndexCoordinator (as Hook)
↓ (internal reserve update)
User ← Uniswap Router ← PoolManager ← IndexCoordinator (as Hook)
```
3. **Global State Coherence**:
- Single contract maintains all state
- Reserves updated directly within same transaction
- Invariant validated immediately with direct access
4. **Rebalancing Mechanism**:
- Underweight assets become expensive across ALL pools
- Overweight assets become cheap across ALL pools
- Arbitrageurs naturally restore balance
### Implementation Considerations
1. **Reentrancy Protection**: Hooks must be non-reentrant
2. **Decimal Handling**: Normalize all tokens to 18 decimals internally
3. **Fee Integration**: Protocol fees applied in weighted calculation
4. **Slippage Protection**: Handled by Uniswap's existing mechanisms
5. **Oracle Resistance**: No external price feeds needed
This architecture elegantly combines Uniswap's battle-tested infrastructure with sophisticated weighted index mathematics, making indices with 10+ assets both practical and efficient.
### Additional Hook Considerations
#### Edge Cases to Handle
1. **Zero Liquidity**:
```solidity
if (reserves[tokenIndex] == 0) {
// Initial liquidity case - use target weights for pricing
return calculateInitialPrice(amountIn, weights);
}
```
2. **Minimum Trade Size**:
```solidity
require(amountIn >= MIN_TRADE_SIZE, "Trade too small");
```
3. **Maximum Impact**:
```solidity
uint256 priceImpact = calculatePriceImpact(amountIn, reserves);
require(priceImpact <= MAX_PRICE_IMPACT, "Excessive price impact");
```
4. **Pause Mechanism**:
```solidity
modifier notPaused() {
require(!coordinator.isIndexPaused(indexId), "Index paused");
_;
}
```
#### Hook Functions Summary
| Hook | Purpose | Implementation |
|------|---------|----------------|
| `beforeInitialize` | Prevent unauthorized pools | Revert unless called by IndexCoordinator |
| `beforeSwap` | Core pricing logic | Calculate weighted price, handle transfers |
| `beforeAddLiquidity` | Block traditional liquidity | Always revert with custom error |
| `beforeRemoveLiquidity` | Block traditional liquidity | Always revert with custom error |
| `beforeDonate` | Prevent donations | Always revert to avoid locked funds |
| `afterSwap` | Not needed | All logic in beforeSwap |
| `beforeSwapReturnDelta` | Override pricing | Return true to use custom delta |
#### Gas Optimizations
1. **Cache frequently used values**:
```solidity
uint256 cachedHubIndex = hubIndex; // Avoid repeated SLOAD
```
2. **Pack struct data**:
```solidity
struct SwapCache {
uint128 amountIn;
uint128 amountOut;
uint8 tokenInIndex;
uint8 tokenOutIndex;
}
```
3. **Use unchecked math where safe**:
```solidity
unchecked {
newReserve = oldReserve + amountIn; // After overflow check
}
```
### Key Design Insights
1. **Single Contract Architecture**: IndexCoordinator inherits BaseHook, acting as both the index manager AND the universal hook for all pools across all indices.
2. **Pool Identification**: Uses PoolKey to map each swap to its corresponding index and asset positions, enabling one contract to handle unlimited pools.
3. **Global Pricing**: Although each Uniswap pool is 2-asset, the hook calculates prices using ALL N asset weights and reserves from the index.
4. **No Traditional Liquidity**: Completely bypasses Uniswap's tick system. All "liquidity" is the index's reserves managed internally by IndexCoordinator.
5. **Automatic Rebalancing**: The weighted formula naturally creates arbitrage opportunities by making underweight assets expensive and overweight assets cheap.
This elegant design achieves N-asset weighted indices using Uniswap v4's 2-asset pools, with a single contract managing everything - dramatically simpler than deploying multiple hook instances!