whitepaper - v1 - 2026

UNI404: an ERC-404 with Uniswap-style pool NFTs

Seven sections: design, contract, art, risks, why Uniswap, FAQ. Read it before buying.

Contents
  1. Abstract
  2. Design
  3. Contract surface
  4. On-chain art
  5. Risks
  6. Why Uniswap V4
  7. FAQ

01Abstract

UNI404 is the first ERC-404 token to launch directly on Uniswap V4 with a custom Hook attached to its pool. ERC-404 is a non-standard pattern that pairs an ERC-20 fungible balance with an ERC-721 NFT layer on the same contract. Each whole token (1.0 UNI404, 18 decimals) corresponds to exactly one Pool NFT in the same wallet. Whole-unit boundaries are the trigger: cross one upward, an NFT is minted; cross one downward, an NFT is burned.

The pool sits on Uniswap V4 paired with WETH. A companion UNI404Hook contract is attached at pool initialization. The protocol charges 0% on transfers, 0% on swaps. Instead, the hook captures pool yield from V4 LP fees and redistributes it to UNI404 holders, weighted by NFT count and rarity. Hold a Legendary, earn 50x what a Common holder earns per share. UNI404's NFTs are deterministic on-chain art - the SVG, traits and color all derived from the tokenId via keccak256 and rendered at view time. 10,000 supply, hard-capped, no mint after deploy.

02Design

The contract in three pillars

The whole design fits in three sentences before we get to the gory bits.

01 - Fungible layer
02 - NFT layer
03 - Boundary math
  1. Fungible layer. 10,000 UNI404 with 18 decimals. Trades through a Uniswap V4 pool with our custom Hook attached. 0% protocol fee on transfers and swaps. The hook is a yield redistributor: it captures V4 LP fees and pays them out to UNI404 holders weighted by their NFT count and rarity.
  2. NFT layer. One NFT per whole token. Hold 3.7 UNI404, you also hold 3 Pool NFTs in the same wallet. Each NFT is a unique on-chain SVG of an AMM-style pool: token pair, fee tier, rarity, color. Drawn from the contract bytecode, never off-chain.
  3. Boundary math. Cross a whole number, the NFT moves. Spend down past a whole-unit boundary, the lowest-id NFT in your wallet burns. Cross upward, a fresh NFT mints to you (or a previously-burned id is recycled). LP and vault contracts can be whitelisted so the LP doesn't accumulate worthless NFTs.

Two surfaces, one balance

Internally the contract has standard ERC-20 storage (balance per address, allowance per pair) and standard ERC-721 storage (ownerOf per tokenId, owned-tokens list per address). The two stay synced through a single rule applied on every transfer:

burn = max(0, floor(balanceBefore / 1e18) - floor(balanceAfter / 1e18))
mint = max(0, floor(balanceAfter / 1e18) - floor(balanceBefore / 1e18))

burn pops the youngest NFT in the sender's wallet and pushes its tokenId onto a recycling stack. mint pops a tokenId from the recycling stack first (so id-space stays compact), or increments a counter for fresh ones, then assigns it to the receiver.

Whitelist for LPs

Liquidity pools, vaults and bridges hold ERC-20 balances they'd never use the NFT side of. The owner can mark such addresses as whitelisted: they hold the ERC-20 balance, but boundary crossings don't mint or burn NFTs for them. Without this, every Uniswap LP pool would slowly accumulate dead Pool NFTs that nobody wanted.

transferFrom is overloaded

One quirk worth knowing: the third argument of transferFrom(from, to, amountOrId) is interpreted as a tokenId (ERC-721 path) when it falls in [1, TOTAL_NFTS] AND that id is owned by from. Otherwise it's treated as an ERC-20 amount. This is the standard ERC-404 trick, kept for compatibility with bridge and aggregator code. approve(spender, amount) follows the same rule.

03Contract surface

ERC-20 reads

ERC-721 reads

User actions

Owner actions

That's the whole owner surface. There is no pause, no mint, no fee setter. Yield distribution lives in the separate UNI404Hook contract and is also non-tunable - the rarity weights are hard-coded.

Yield distribution (the V4 hook)

The V4 Hook is what makes UNI404 different from a vanilla ERC-404. Pool fees on Uniswap V4 normally go to liquidity providers; our hook intercepts a portion and accumulates it for UNI404 NFT holders. The math is straightforward:

  1. Each NFT carries a weight based on its rarity: Common 1, Uncommon 3, Rare 8, Epic 20, Legendary 50.
  2. A user's shares = sum of weights across every UNI404 they hold.
  3. The hook tracks a global yieldIndex that increments every time pool fees flow in, scaled by the total weighted shares in circulation.
  4. A user's claimable = shares * (yieldIndex - userLastIndex).
  5. Calling claim() sends the user their accrued yield in WETH and updates their lastIndex.

When NFTs move (transfers crossing whole-unit boundaries mint/burn NFTs), the hook updates both wallets' shares atomically. Selling all your UNI404 zeroes your shares; you keep whatever you accrued before the sell, claimable forever.

04On-chain art

Every Pool NFT's image is generated by the contract at view time. There's no pinned IPFS hash, no off-chain metadata server, no team key signing the image. The recipe:

  1. Hash the tokenId: h = keccak256("UNI404", tokenId).
  2. Pick a token symbol from the 16-token shipping list using h[0]. The pair is always TOKEN/WETH.
  3. Pick a fee tier (0.01% / 0.05% / 0.10% / 0.30% / 1.00%) from h[2], weighted to mirror Uniswap's real V3+V4 tier distribution.
  4. Pick a rarity (Common / Uncommon / Rare / Epic / Legendary) from h[3], weighted 50 / 25 / 15 / 8 / 2.
  5. Pick a pool type (V2 / V3 / V4 / Stable / Exotic) from h[4], weighted 25 / 30 / 20 / 15 / 10.
  6. Derive an HSL hue from h[5] for the non-WETH token blob; WETH always renders pink-violet.
  7. Derive a TVL flavor number ($50k - $500M) from h[6:8] for display only, plus its 5-bucket categorical bracket (Bag / Steady / Deep / Whale / Beast).
  8. Compose an SVG with the pool-type header pill, the pair label, two colored token blobs, an AMM curve squiggle, three bottom pills (fee / TVL bracket / rarity), and the tokenId footer.
  9. Wrap the SVG in JSON with attributes, base64-encode the lot, return as data:application/json;base64,....

The recipe is deterministic. The same tokenId always produces the same NFT. Re-mints (burned-id recycling) preserve the id, so the art also stays the same.

05Risks

// honest risk disclosure

UNI404 is experimental. ERC-404 is a non-standard pattern that breaks edge cases of both ERC-20 and ERC-721 wallets if they don't know about it. Read this list before buying.

06Why Uniswap?

Of all the things you could build a 10,000-supply ERC-404 around, why picture Uniswap-style pools? Three reasons.

  1. Pools have natural variation. Pair, fee tier, depth, type. That's a 4-trait NFT before you make anything up. Add rarity for the cherry on top and you have a five-trait card without forcing it.
  2. The brand fits the math. Uniswap shipped the AMM that defined the genre and the V4 hook that made it programmable. ERC-404 is, in spirit, a hook on standard ERC-20 transfers - mint or burn an NFT every time the fungible balance crosses a whole-unit line.
  3. The art writes itself. Two tokens, an AMM curve, a fee, a frame color for rarity. The SVG is short. The result is recognizable from a thumbnail. No need to commission art or run an AI through 10,000 prompts.

07FAQ

Why ERC-404?

Because tying NFTs to whole-unit balances is a real-feeling mechanic. You buy 1.5 tokens, you get 1 NFT. Buy half a token more, the second NFT shows up. It makes the fungible balance feel meaningful.

Why pools as the NFT subject?

Pools have natural variation (pair, fee, depth, age) and the brand fits the Uniswap-themed contract. No need to invent traits or commission art.

Can I move just one NFT without moving any tokens?

No. Transferring a tokenId always moves 1 whole UNI404 of fungible balance with it. The two layers are tied at the boundary; you can't desync them.

What happens to the NFT layer when I list on Uniswap?

Selling tokens to the LP transfers the fungible balance to the pool address (whitelisted), which doesn't trigger an NFT mint there. On your side, your fungible balance drops below a whole-unit boundary, your NFT burns. The opposite happens when you buy back.

Is the LP a single-sided pool?

No. UNI404 trades against WETH on a single Uniswap V4 pool with our companion UNI404Hook attached. The Position Manager (the V4 contract holding LP positions) is whitelisted so it doesn't accumulate NFTs. The pool can be created via standard V4 tools - Universal Router 2 routes through it automatically.

Is the art random?

Deterministic from tokenId. Not random. You can predict any NFT's traits just from its id by running the recipe in section 4.

Will there be a v2?

No plans. UNI404 is one contract, fully on-chain, ownership renounceable. v2 would be a different contract.