# 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!