A pooled, market-cap-weighted index vault for Ethereum mainnet. Holders deposit and redeem in a single asset, USDC, and receive an ERC-20 share that represents a pro-rata claim on the underlying basket. The vault computes its own target weights on-chain from float-adjusted market cap, applies real index-provider methodology (iterative capping, a minimum-weight floor, and reconstitution buffering), and rebalances through CoW Swap batch auctions rather than naive DEX swaps.
The differentiator is not the vault plumbing, which is commodity. It is the on-chain methodology engine, the honesty of the supply-oracle trust model that makes autonomous weighting safe to rely on, and a rebalancer that routes around a stale feed instead of halting on it.
Most on-chain indices get the finance wrong in one of three ways.
They let a human or a governor set the target weights. That is a discretionary fund wearing an index label, and it carries exactly the trust and key-person risk an index is supposed to remove.
They weight by raw market cap with no cap. A pure market-cap weighting of the top crypto assets is roughly seventy percent Bitcoin plus Ether, which is not diversification, it is a leveraged bet on two names with extra steps. Real index providers apply a per-asset cap and redistribute the overflow, iterated to convergence. Few on-chain indices do this correctly.
They weight by total or fully-diluted supply rather than free float, so locked, vesting, treasury, and foundation tokens inflate the weight of names whose tradable supply is a fraction of the headline number.
And they conflate rebalancing with reconstitution. Recomputing the weights of the existing members is a different event from changing which assets are members, and treating them as one produces needless turnover at the membership boundary.
This protocol takes the index methodology seriously and moves the discretionary surface off-chain only where it genuinely cannot live on-chain, then names that residual trust precisely rather than pretending it away.
IndexVault is an ERC-7540 asynchronous vault, a superset of ERC-4626. Net asset value is computed from the oracle USD value of the basket constituents plus the idle USDC buffer, expressed in USDC units, and any stale price feed makes value-sensitive operations revert rather than transact on bad data.
The vault holds a target idle buffer of USDC, sized as a band around five percent of NAV, so that ordinary retail flow does not force a trade on every interaction. Liquidity then runs in two lanes:
- A synchronous lane for flows small enough to keep the buffer inside its band. These settle immediately at the current NAV per share, exactly like a standard ERC-4626 deposit or redeem.
- An asynchronous lane for flows that would push the buffer outside its band. These route through ERC-7540 request and claim. Requests queue into a settlement epoch, a keeper batch-settles the epoch at one NAV, and users claim their shares or USDC afterwards.
Pending value sits in an isolated PendingSilo so that unsettled deposits, escrowed redemption shares, and claimable balances never contaminate the vault's NAV. The exclusion is structural, not a bookkeeping subtraction.
Two protections matter. Pending redemptions are priced at settlement time, not request time, which is fairer to the holders who remain in the vault. And a request can never be settled in the same block it was created, which closes the flash-loan and same-block oracle-manipulation vector.
MarketCapMethodology maps a constituent set to target weights behind a pluggable IMethodology interface, so the weighting scheme can be swapped without touching the vault or the rebalancer. It composes three standard index stages, all of which live in the pure WeightMath library with exact, enforced invariants.
- Float-adjusted market cap. Each constituent's weight starts from
freeFloatSupply * price, using free-float circulating supply rather than total or fully-diluted supply. - Iterative capping. A hard per-asset cap (twenty-five percent by default) is applied, the overflow is redistributed pro-rata across the uncapped names, and the process iterates because redistribution can push a previously-uncapped name over the cap. The library guarantees the output sums to exactly 1e18, that no weight exceeds the cap, and that an infeasible configuration reverts rather than silently degrading.
- A minimum-weight floor. Positions too small to justify their rebalance gas and slippage are pruned to zero and their weight is redistributed across the survivors.
A separate cap trigger sits above the cap target. The methodology caps target weights to the target, but exposes a higher trigger the rebalancer reads, so a name that appreciates past the trigger is brought back to the cap off-cycle rather than only at the next scheduled reweight. This is the Nasdaq-100 hysteresis: cap to the target, trigger higher.
Membership uses a buffer rule that keeps reconstitution distinct from reweighting. An incumbent is dropped only when it falls below rank N plus a buffer, and a non-member is added only when it rises above rank N minus that buffer, so the index does not churn its membership on every transient crossing of the boundary rank.
Autonomous market-cap weighting is only as trustworthy as its circulating-supply input. Whoever controls that number can move the target weights and front-run the resulting rebalance. Circulating supply also cannot be made fully trustless, because for most tokens it is an off-chain fact that does not entirely exist on-chain. So the goal is not to pretend otherwise. The goal is to minimize the off-chain surface to its smallest core, secure that residual, and contain the damage if it is ever corrupted. The design leans on one structural fact: supply is slow-moving, which means security can be bought with latency in a way that would be impossible for a price feed.
The oracle is built in three layers behind the ISupplyOracle seam.
- Minimize (
ExcludedAddressRegistry). Circulating supply is derived directly on-chain astotalSupply - Σ balanceOf(excludedAddress). This converts "trust a number" into "trust a list of addresses," where every excluded entry is a falsifiable public claim (this is a vesting contract, this is the team multisig, this is a burn sink) that anyone can audit.totalSupplyitself is a free, trustless upper bound. Every change to the excluded set is timelocked, so it is visible on-chain before it can take effect. - Secure (
SupplyOracle). The irreducible residual, the share of on-chain-circulating supply whose lock status is not on-chain visible, is expressed as a free-float factor in the range zero to one. Independent reporters push factor values, and a commit takes their median and requires a quorum to agree within tolerance. If the sources diverge, the constituent freezes at its last-good value rather than acting on disputed data. Because the factor is capped at one, free-float can never exceed the on-chain floor by construction. - Contain (
SupplyOracle). A committed factor moves toward the median by at most a bounded step per commit, so a correct-but-large change is approached gradually over several commits and a malicious spike cannot move the index more than one step before a human can react. A hard staleness ceiling fails reads closed if every reporter goes silent for too long, and a guardian can pause all reads outright.
The interface is shaped so that an optimistic oracle can later replace the reporter-median residual on a per-constituent basis without the methodology engine ever noticing.
Rebalancer executes reweights through CoW Swap. It opens a rebalance epoch that freezes each constituent's target USD value at weight times deployable NAV, then expresses the resulting sells and buys as orders that CoW solvers settle in batch auctions, which gives uniform clearing prices, batch-auction MEV resistance, and moves settlement gas off the vault and onto the solver. The vault is the order owner and delegates validation to the rebalancer through ERC-1271, so every solver fill is checked against the frozen epoch: the order must be a routed leg through USDC, its receiver must be the vault, and its minimum-out is anchored to the oracle price with a slippage haircut, so a solver can never fill the vault at an arbitrarily bad price. Orders are partially fillable, and NAV is always read from actual current balances rather than intended post-rebalance balances, so a partial fill simply leaves the vault closer to target.
Triggers sit under one anti-churn floor. A scheduled reweight is keeper-gated and requires the drift and cadence thresholds to be met. An emergency open is permissionless when drift crosses the large band or when a constituent breaches the methodology's cap trigger, so a runaway name is brought back to the cap off-cycle rather than waiting on the schedule. The rebalance target is buffer-aware: it holds back the vault's operating buffer, plus any USDC reserve needed to fund pending redemptions the idle buffer cannot cover, then weights the constituents over the deployable remainder, so a redemption-heavy epoch raises the USDC it needs from the basket before settlement pays it out.
Rebalancing routes around trouble rather than halting on it. A constituent whose feed has gone stale is quarantined and excluded from the epoch, and the healthy names reweight over the fresh subset instead of the whole rebalance reverting. A mainnet-fork test proves the rebalancer reconstructs the exact EIP-712 digest the live GPv2Settlement contract verifies against, so the order encoding matches what CoW checks on-chain byte-for-byte.
Three protections backstop the value-sensitive paths.
- Constituent quarantine. When a constituent's price feed goes stale, its holding is marked down on a decaying haircut and the constituent is excluded from weighting and trading rather than priced on stale data. Mints fail closed while any constituent is quarantined, so no one can enter at a NAV that ignores a name the vault cannot currently price.
- NAV-per-share circuit breaker. Settlement compares the new NAV per share against the last-good reference, and a move beyond the configured band pauses the vault and returns rather than reverting, so a collective mispricing that slips past every per-feed check cannot settle on bad data. The owner reviews and either accepts the new reference on unpause or keeps the vault paused.
- Guardian pause. A guardian can pause all value movement immediately, while unpause is owner-only. Paused blocks entry, exit, settlement, and order validation, but an already-settled claim still pays out.
ConstituentGovernor governs membership on a shared timelocked-proposals base. Adding a constituent, and removing one, are separate timelocked acts, and removal distinguishes a forced exit (a failed or delisted name, gated by an on-chain failure check) from a discretionary one (a methodology decision). Removal is a wind-down, not a dump: the constituent is marked winding-down so its full holding reads as drift, and the rebalancer sells it back toward zero at the oracle-anchored minimum-out over normal epochs rather than dumping it in a single trade. A guardian can veto a pending proposal.
- Settle-time pricing for pending redemptions. Valuing escrowed redemption shares at the settlement NAV rather than the request NAV is fairer to remaining holders, who would otherwise absorb the difference if the basket moved between request and settlement.
- The cap does security work, not only diversification. A constituent pinned at the cap has a weight that is independent of its exact supply, so supply-oracle precision is irrelevant for the largest names and matters only for the mid and long tail, where both the dollar amounts and the value at risk from manipulation are smaller.
- Freeze versus revert. Because supply is the slow input and price the fast one, a quiet or diverging supply source freezes the constituent at its last-good value rather than halting the index. A revert is reserved for genuine hard failures: a paused oracle, an uninitialized constituent, or a value past the hard staleness ceiling.
- The supply rate-limit clamps rather than rejects. Rejecting a too-large commit would never converge, because every commit re-sees the full target. Clamping the move toward the target by one step per commit is what actually realizes "approached gradually."
- Adding risk is gated, removing risk is open. A scheduled reweight is keeper-gated, but an emergency open and a stale-feed quarantine need no permission, and a guardian pause is always available, so the paths that de-risk the vault never wait on a privileged actor being awake.
- No role can move funds to an arbitrary address. The only asset outflows are user redemptions at NAV and solver-settled trades bounded by a per-order minimum-out with the vault as the fixed receiver. The guardian's powers are pause-only.
Supply is a bounded trust assumption, not a trustless one, and the protocol is designed to state that precisely rather than overclaim. The on-chain derivation and the timelocked excluded-address registry shrink the trusted surface to a residual free-float factor; the multi-source median, divergence freeze, rate-limit, staleness ceiling, and guardian pause bound what a corrupted residual can do. Price feeds are trusted Chainlink oracles with per-feed heartbeats and round-health checks. The execution venue depends on CoW's solver network being live and liquid on mainnet, which is the reason the protocol targets mainnet rather than an L2.
This is a research-stage codebase. It is not audited and it is not deployed. The vault, methodology engine, supply oracle, CoW rebalancer, safety layer, and constituent governance are implemented and tested, including a mainnet-fork check that the rebalancer's order digest matches the live CoW settlement contract. A curator-managed yield layer that puts idle constituent balances to work through vetted strategies, a fee module, and a full deployment and audit path are the planned next phase and are not yet built.
src/
IndexVault.sol ERC-7540 two-lane vault, NAV, settlement, curated constituents
PendingSilo.sol isolated holder of in-flight value
AssetRegistry.sol shared asset catalog and health-checked Chainlink feeds
methodology/
MarketCapMethodology.sol float-adjusted capped market-cap weighting, cap trigger
rebalancer/
Rebalancer.sol CoW Swap epochs, triggers, oracle-anchored orders, ERC-1271 validation
governance/
ConstituentGovernor.sol timelocked add, forced and discretionary removal, wind-down
TimelockedProposals.sol shared timelock base for governance proposals
libraries/
WeightMath.sol pure capping, floor, and buffer-rule math
GPv2Order.sol CoW order struct and EIP-712 digest
oracle/
ExcludedAddressRegistry.sol Layer 1 on-chain circulating derivation
SupplyOracle.sol Layers 2 and 3 residual, freeze, containment
interfaces/
IERC7540.sol IMethodology.sol ISupplyOracle.sol IRebalancer.sol
test/
Built with Foundry on Solidity 0.8.28 and OpenZeppelin v5.
forge build
forge test
The suite is 162 tests across 14 files. It covers the full asynchronous request, settle, and claim lifecycle, buffer-band gating of the synchronous lanes, oracle fail-closed behavior, settlement liveness and flash-loan guards, property fuzzing of the capping algorithm against its exact invariants, and adversarial supply-oracle scenarios including the divergence freeze, rate-limit convergence, timelocked exclusions, and guardian pause. It also drives the rebalancer end to end, the dual-threshold and cap triggers, the buffer-aware target, basket-funded redemptions, rebalancing around a quarantined constituent, the NAV circuit breaker, the guardian pause, and constituent governance. Three of the tests fork mainnet to prove the rebalancer's CoW order digest matches the live GPv2Settlement contract, and need a mainnet RPC configured under the mainnet endpoint to run.