Search projects, hackathons, sponsors and tech

    ← All projects

    usufruct

    Sell a fixed window of your Uniswap fees upfront. Keep the position, get the same NFT back.

    Demo

    About

    Three things are deliberately decoupled, and that's the core of the design. Capture happens after the end block, so it collects more than the sold period; the contract reserves the actual USDC received rather than trusting any projection. The residual owner can retrieve the NFT before allocation is resolved at all — that withdrawal cannot touch the protected fee reserve. And settlement is authenticated against historical chain state, with allocation bounded by what was captured. Holders then redeem independently, so one recipient failing cannot block anyone else. Payouts use the immutable original claim count, never the remaining token supply, so somebody else redeeming never changes your fraction. This ran end to end in public. Series 1 on Sepolia: position NFT 39216 activated at block 11696226, end block N at 11696317, 10,000 claims issued against a 0.25 USDC upfront payment for 2,500 of them. A teammate bought 1,000 claims across three real Aqua trades. Capture collected 1.499999 USDC. The NFT returned at 11696393 while allocation was still unresolved. Allocation at 11696450 separated 0.999999 USDC earned by N from 0.500000 USDC earned after it. 9,010 claims have since been redeemed for 0.900996 USDC across four independent holders. Every figure shown before allocation is an estimate. Estimates never authorise a payout.

    How it's made

    Contracts are Solidity built with Foundry 1.5.1 (Cancun) and run through Slither. Four first-party contracts: FeeStrip.sol escrows the canonical Uniswap v4 NFT for a fixed window, FeeClaim.sol issues the transferable claims against that window's unpaid native USDC fee income, and market/FeeStripMarket.sol with market/FeeStripRouter.sol provide the claim/USDC market. Coverage is 20 protocol tests plus two invariant campaigns totalling 16,384 calls with zero unexpected reverts, with separate proof and market suites on top. Uniswap v4 is the substrate rather than a dependency. We work against canonical position NFTs with a native v4 lifecycle, freezing the fixed range for the window. Series 1 ran the complete lifecycle in public on Sepolia against NFT 39216: activation at 11696226, end block N at 11696317, capture, NFT return at 11696393 before allocation resolved, then allocation at 11696450 costing 4,396,570 gas. Settlement authenticates the historical block header, position manager account and pool storage, and an independent native-endpoint oracle on an isolated fork produces 999999 USDC micros matching the authenticated witness. The claim market runs on official source-pinned Aqua and SwapVM sources from 1inch, extended with a custom two-instruction dispatcher so a fee claim is a first-class position inside Aqua rather than a token bolted on beside it. That's the hackiest and most useful thing we did. In series 1 a teammate bought 1,000 claims across three real public trades of 189, 63 and 748 — genuine FeeClaim and USDC transfers on Sepolia, not a fork. Tests cover both directions, unavailable and shared maker capital, stale lifecycle state, and adversarial callback ordering. That teammate's redemption of 1,000 claims for 0.099999 USDC cost 122,011 gas. Buyer analytics compose two Graph products. Hosted Substreams joins Subgraph Studio series 1 instrument state at finalized block 11696247, with 22 of 22 observed blocks covered and in range, at zero indexing lag relative to finalized history. packages/data/src/compose.mjs does the join with identity, common-block and hash checks, packages/data/src/store.mjs handles cursor persistence and reorg recovery, and packages/core/src/economics.mjs computes range occupancy and break-even. The snapshot is partial-period and carries no exact-fee or forecast authority. Analytics inform buyers; they never authorise settlement. The repo is a pnpm 12 workspace on Node 24. The web app in apps/web deploys to Vercel; an operations service runs from Dockerfile.operations on Railway with an api/ surface. The complete browser lifecycle — sale, trade, capture, return, settlement, redemption — runs end to end against a real local chain and reproduces in hosted CI via `pnpm test:browser:chain`. Endpoint durability is handled by a dedicated keeper that saved N at N+2. Exact proof was then restored from two remote GETs into a fresh local database and two authenticated copies, with zero remote writes, no RPC witness fallback and no hosted failover. An operations service runs from Dockerfile.operations on Railway; the web app deploys to Vercel; the repo is a pnpm 12 workspace on Node 24.