Search projects, hackathons, sponsors and tech

    ← All projects

    Air Index

    Create and own your index fund as an ENS name — composition lives entirely in the ENSv2 namespace.

    Demo

    About

    Index products today are opaque and locked in. The composition of an ETF lives in a provider's database, you cannot verify it, you cannot fork it, and you cannot take it anywhere. Air Index makes the index itself a name. In Air Index, an index IS an ENS name. Create defi-blue.airindex.eth and you own an index. Each constituent is a subname: weth.defi-blue.airindex.eth resolves to the token's contract address, and its weight is stored as a data record on that same name. There is no backend database. The entire composition of an index is the namespace, so any wallet, app, or agent can read a full index with a stock ENS library — no Air Index SDK required. Resolving weth.defi-blue.airindex.eth in viem returns the token address directly. ENSv2's Enhanced Access Control lets us split an index into the two things it actually is: rules and numbers. The methodology is pinned to IPFS and written to the name's contenthash, then permanently locked by revoking both the role and its admin role — after that, nobody can change the rules, not even the creator. The weights, meanwhile, can be delegated to a rebalancer with a permission scoped to a single record key, so the rebalancer can adjust allocations but cannot swap in a different token, add a constituent, or touch the methodology. Firing the rebalancer is one transaction. That rebalancer can be an AI agent, and it gets its own namespace: rebalancer.defi-blue.airindex.eth holds the agent's address, and its mandate — cadence, maximum drift, allowed asset classes — is published as text records on its own name. The agent's on-chain permissions are exactly its published mandate, so what it is allowed to do is publicly verifiable rather than a matter of trust. Two more things fall out of the namespace model. Short tickers work like they do for real ETFs: dfbl.airindex.eth is a resolver-level alias of defi-blue.airindex.eth, sharing one set of records with no duplication, the same way IBIT and "iShares Bitcoin Trust ETF" are one product. And indexes are forkable: pointing a new name's subregistry at an existing index's registry produces a fork that tracks the original, or you can branch and diverge. Forking an index becomes as cheap as forking a repo.

    How it's made

    Everything runs on the ENSv2 beta deployment on Sepolia. https://explorer.ens.dev/airindex.eth Structure. airindex.eth has a subregistry; every index is a subname token in it, so an index is an ERC1155 the creator genuinely owns and can transfer or sell. Each index name then has its own registry holding its constituents. We lean on ENSv2's longest-suffix resolution: constituents inherit the nearest ancestor's resolver, so a constituent resolves off the parent's resolver without needing its own, which keeps creating an index cheap. Constituent data uses the standard profile — addr(60) for the token contract, a data record for the weight — specifically so that nothing about reading an index requires our code. Permissions. This is where ENSv2 does the heavy lifting. Resolvers in ENSv2 are per account rather than per name, so we deploy one protocol-owned Permissioned Resolver through the Verifiable Factory and scope each creator to their own index with authorizeNameRoles. Rebalancer delegation uses authorizeDataRoles against a single record key, which grants ROLE_SET_DATA for that key only — a name-level grant would have been a superset and too broad. Locking the methodology calls revokeRootRoles with ROLE_SET_CONTENTHASH OR'd with ROLE_SET_CONTENTHASH_ADMIN in one call; without the admin role there is no path to granting it back, which is what makes the immutability real rather than a promise. None of this was expressible in ENSv1 without the Name Wrapper's coarse fuses. Aliasing. Tickers use setAlias at the resolver level, which required both names to sit on the same resolver instance — one reason we went with a shared protocol resolver. Worth noting for anyone building on this: aliases only resolve through the Universal Resolver's resolve() path, so calling text() or addr() directly on the resolver with an aliased namehash silently returns empty. That cost us an hour. Forking is the other kind of aliasing — namespace-level — done by pointing a new index's subregistry at an existing one, which is a tree operation that simply has no ENSv1 equivalent. Gotchas. ENSv2 token IDs are mutable and regenerate when roles change, so we never cache them and always resolve to the current ID at transaction time via findTokenId. We also never hardcode a resolver address, since a name's configured resolver is now its owner's own deployment. Stack. Solidity with Foundry for the registrar and registry, viem plus ENSjs v4.2.3+ for all ENS reads and writes, wagmi and Next.js on the frontend, and a public price API mapped by symbol for portfolio valuation — prices are the only off-chain component, and index composition is read live from Sepolia on every load, never from local state.