# Fractional 404 Hook for Hookr

Fractionalize an ERC-721 (or ERC-6551 backed NFT) into a tradeable ERC-20 book with locked Uniswap v4 liquidity. Integration guidelines for the Hookr team.

Status: LIVE on Robinhood Chain 4663 since 2026-10-13 (redeployed on the HK-22 partial fill fix bytecode, partner leg kept). FractionalLauncher `0xCD44629152c9a7CAc2cD68bb25A2293022F3183D`, fractional StonkFeeHook `0x8A6c104d8bc04E058Ca08282E605D42a84D6aaCc`. Unit suite 18/18 green, whole `hooks/` suite 142/142 on the deployed bytecode. Audit findings HK-10 to HK-18 were closed before the deploy (section 9). Sourcify exact match on all five contracts. The Hookr fee leg (section 3.1) is live with the recipient left at zero until Hookr supplies its contract address.

Source: `hooks/` in the StonkBrokers repository. Contracts `FractionalLauncher.sol`, `FractionToken.sol`, shared `StonkFeeHook.sol`. ABIs: `FractionalLauncher.abi.json`, `FractionToken.abi.json`, `FractionalNFT.abi.json`, `FractionalDeployer.abi.json`, `ERC6551Registry.abi.json`, `Fractional6551Account.abi.json`, `StonkFeeHook.abi.json`.

Contact: simple@clutch.market, Telegram simplefarmer69.

## 1. What the hook does

A creator deposits an NFT into the launcher (plain `transferFrom` for collections that reject `onERC721Received`, matching Anvil TBA discipline). The launcher mints a fixed supply of fractional ERC-20, opens a full range v4 pool behind `StonkFeeHook`, and locks liquidity. Fractions trade freely. Redemption / reconstitution paths are launcher gated so the NFT cannot leave without the required fractional burn.

Use cases: Anvil style NFT liquidity without a separate AMM vault, broker / intern desk fractions, collection team treasuries.

Threat model: Robinhood Chain has no public mempool. Frame mitigations as launch economics and lock discipline, not sandwich protection.

## 2. Why this is not an owned root on Hookr

Custom `StonkFeeHook` + controller. Third party hook path: Analyze / Publish / Partner Review. Swaps via Universal Router, empty hookData.

## 3. Addresses

| Item | Chain | Address |
| --- | --- | --- |
| FractionalLauncher | Robinhood Chain 4663 | 0xCD44629152c9a7CAc2cD68bb25A2293022F3183D |
| StonkFeeHook (fractional instance) | Robinhood Chain 4663 | 0x8A6c104d8bc04E058Ca08282E605D42a84D6aaCc |
| FractionalDeployer (token + NFT code deployer) | Robinhood Chain 4663 | 0x3361426DEea55e88cb04cCA5cFeB46D99eB36dfF |
| ERC6551Registry | Robinhood Chain 4663 | 0x3Df336317B73e0ce417E03488abb2B79cEe2B9E4 |
| Fractional6551Account (implementation) | Robinhood Chain 4663 | 0xb9D00C31F479B892Ae7F8F500dbf3FF3E41acC26 |
| WETH | Robinhood Chain 4663 | 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73 |
| Uniswap v4 PoolManager | Robinhood Chain 4663 | 0x8366a39CC670B4001A1121B8F6A443A643e40951 |
| Uniswap V4 Quoter | Robinhood Chain 4663 | 0x8dc178efb8111bb0973dd9d722ebeff267c98f94 |
| Universal Router 2.1.1 | Robinhood Chain 4663 | 0x8876789976dEcBfCbBbe364623C63652db8C0904 |

Deploy parameters (state file `hooks/deployments/fractional-hook.4663.json`): owner `0xD4aF10Bc56b08f8fc2990a3ADeeD4b757ae6A26C`, protocolTo = treasury `0xb668382cF44038a3E8140E789060F6A809787CDa`, protocolBps 1000, partnerTo `0x0` (pending the Hookr CA), partnerBps 5000, minSeedQuote 0.05 WETH, hook flags 10956. Deploy txs: code deployer `0x081322d407ff979b6a47053ee9b7f77c6742c6af52eb55c158c1badadaff4207`, registry `0xb7f577831ab5df4552c2d98e2b9a1556d73b05f79fa297952e6aaaa4926c082d`, account implementation `0xff32e342932f08133a8d2c20c9a97636cce9ee95451e9a5a179ad26f52d0587e`, launcher `0x6a921386571e7a35cc9a4de3d631c6a6de90c1ad912d8df4ca08539b22857778`, setLauncher `0x20c6b9c69fa59f75abe1037fc5ee7795d05584d8dee49f08073600886c909efd`, hook `0x2fd5bd031f6cb90d5a1a05a2b09a5d7f880874741906b25c3a6203b1c3a93201`, setHook `0x642d9726f013db70c60f8610c6ffc46901024b9e2f477ac949988c3f7bbb6ec4`, setPartner `0xb28a1ee617cab5aa28af1a37951d8940e21809022e07b38cd793f2f035340e07`. Verified: Sourcify exact match on all five contracts (https://sourcify.dev/server/v2/contract/4663/0xCD44629152c9a7CAc2cD68bb25A2293022F3183D).

Deployed size: FractionalLauncher 17,336 B (70.5% of EIP-170), FractionalDeployer 14,806 B, StonkFeeHook 5,596 B, FractionToken 5,198 B, FractionalNFT 4,899 B, ERC6551Registry 820 B, Fractional6551Account 1,765 B.

### 3.1 Hookr fee leg

Same split as the Battle Token Hook: `protocolCut = fee x protocolBps / 10000`, then `partnerCut = protocolCut x partnerBps / 10000` is carved out of the protocol cut for Hookr (5000 bps = half of the protocol cut). The StonkBrokers treasury keeps the other half, the remainder streams to fraction holders through `FractionToken.notify`. While `partnerTo` is zero the hook books the carve under `partnerAccrued[quote]`; once the owner runs `FractionalLauncher.setPartner(<hookrCA>, 5000)` anyone releases it with `StonkFeeHook.flushPartner(<quote>)` and later swaps pay Hookr directly inside the swap. Events: `PartnerFeeTaken`, `PartnerFlushed`, `PartnerSet`.

## 4. Hook identity and hooklist entry

Flags match `StonkFeeHook`.

```json
{
  "name": "Fractional 404 Hook",
  "author": "StonkBrokers",
  "address": "0x8A6c104d8bc04E058Ca08282E605D42a84D6aaCc",
  "chainId": 4663,
  "dynamicFee": false,
  "upgradeable": false,
  "requiresCustomSwapData": false,
  "vanillaSwap": true,
  "beforeSwapReturnsDelta": true,
  "afterSwapReturnsDelta": true,
  "source": "https://github.com/Clutch-L4bs/stonkbrokers/tree/main/hooks",
  "docs": "StonkBrokers-Fractional-404-Hook-Hookr-Integration.pdf",
  "tags": ["fractional", "nft", "404", "robinhood-chain"]
}
```

## 5. Pool keys

| Field | Value |
| --- | --- |
| currencies | fractional token and quote (WETH), sorted |
| fee | 10000 (1%) typical |
| tickSpacing | 200 |
| hooks | StonkFeeHook (fractional instance) |

## 6. NFT deposit note

Collections without `onERC721Received` must use plain `transferFrom` into the launcher (same rule as StonkBroker TBA deposits). SafeTransferFrom may revert `ERC721InvalidReceiver`.

## 7. Swapping

Vanilla. Quote with V4 Quoter, empty hookData. Outside LP blocked while the fraction is live.

## 8. Contract functions

What each public surface does. Arguments match the shipped ABIs (`FractionalLauncher.abi.json`, `FractionToken.abi.json`, `FractionalNFT.abi.json`, `Fractional6551Account.abi.json`, `ERC6551Registry.abi.json`, `StonkFeeHook.abi.json`).

### 8.1 FractionalLauncher

Launch and 404 bridge:

| Function | Who | What it does |
| --- | --- | --- |
| `createCollection(params)` | creator | Pulls `seedQuote`, deploys `FractionalNFT` + `FractionToken` via the deployer, keeps `creatorKeep` highest NFT ids with the creator, mints `pooled * 666666` fractions into a locked full range v4 pool, pages the first TBA batch. Returns `(collectionId, nft, token)`. Reverts `HookMismatch`, `NativeNotSupported`, `SeedTooSmall`, `BadParams`. Emits `CollectionCreated`. |
| `deposit(collectionId, tokenId)` | holder | Vaults an NFT via plain `transferFrom` and mints 666,666 fractions to the caller. Reverts `UnknownCollection`, `BadTokenId`. Emits `Deposited`. |
| `redeem(collectionId, tokenId)` | holder | Burns 666,666 fractions and returns a vaulted NFT. Reverts `NotVaulted` if that id is not in the launcher. Emits `Redeemed`. |
| `deployAccounts(collectionId, n)` | anyone | Permissionless paging: deploys the next `n` ERC-6551 token bound accounts. Addresses are deterministic before deploy. Emits `AccountsDeployed`. Reverts `AccountsComplete` when done. |
| `withdrawLiquidity(collectionId)` | creator | After `lpUnlockAt`, pulls the whole locked position once. Emits `LiquidityWithdrawn`. |

Read surface:

| Function | Who | What it does |
| --- | --- | --- |
| `collection(id)` | anyone | Full `Collection` struct: creator, nft, token, quote, pool, fees, snipe schedule, nftCount, accountsDeployed, unlock clocks, totalFees, liquidityPulled. |
| `accountOf(collectionId, tokenId)` | anyone | Deterministic TBA address whether or not the clone is deployed. |
| `vaulted(collectionId)` | anyone | Count of NFTs currently sitting in the launcher (redeemable). |
| `currentSnipeBps(id)` | anyone | Live decaying snipe tax from launch. |
| `collectionOf(poolId)` / `collectionOfNft(nft)` | anyone | Reverse lookups. |
| `feeTerms(poolId)` / `onSwap(...)` | StonkFeeHook | Controller callbacks. Fee remainder after creator cut streams into FractionToken via `notify`. Emits `FeeStreamed`. |

Owner (no path to vaulted NFTs, fractions in the pool, or streamed fees):

| Function | Who | What it does |
| --- | --- | --- |
| `setProtocol(to, bps)` / `setMinSeedQuote(v)` | owner | Protocol cut and launch floor. |
| `setPartner(to, bps)` | owner | Hookr partner leg: `bps` of the PROTOCOL cut for `to` (default `0x0` / 5000 at deploy). Reverts `PartnerBpsTooHigh` above 10000. Emits `PartnerSet`. |
| `protocolTo` / `protocolBps` / `partnerTo` / `partnerBps` | anyone | The two fee destinations. |
| `setHook(hook)` | owner | Wire the fractional `StonkFeeHook`. |
| `transferOwnership` / `acceptOwnership` | owner / pending | Two step Ownable. |

### 8.2 FractionToken

Share ERC-20 (666,666 per vaulted NFT). Streams quote fees to holders.

| Function | Who | What it does |
| --- | --- | --- |
| ERC-20 surface | anyone | Standard transfer / approve surface. |
| `claimable(holder)` / `claim()` / `claimTo(to)` | anyone / holder | Unclaimed quote drip and payout. |
| `burn(amount)` | holder | Burns fractions (used on redeem). |
| `mint(to, amount)` / `notify(amount)` / `setExcluded(...)` | launcher only | Mint on deposit / create, credit drip after swap fees, exclude PoolManager. |

### 8.3 FractionalNFT + ERC-6551

| Contract / function | Who | What it does |
| --- | --- | --- |
| `FractionalNFT.totalSupply()` / `setBaseURI` | anyone / deployer | Consecutive id ERC-721. Base URI set at deploy time. |
| `ERC6551Registry.createAccount` / `account` | launcher / anyone | CREATE2 clones of `Fractional6551Account`. |
| `Fractional6551Account.owner()` | anyone | NFT owner (follows transfers). |
| `executeCall(to, value, data)` / `executeTokenTransfer(token, to, amount)` | TBA owner | Owner gated calls from the token bound wallet. |
| `isValidSignature(hash, sig)` | anyone | EIP-1271 against the NFT owner. |

### 8.4 StonkFeeHook (fractional instance)

Same shared hook as Battle (BattleTokenHook-Hookr-Integration.md section 7.3, including `flushPartner(quote)` and `partnerAccrued(quote)`). Controller is the FractionalLauncher. Outside LP blocked while the collection is live.

## 9. Proofs

Unit suite `hooks/test/Fractional.t.sol` 18/18 on the deployed bytecode: deposit, mint fractions, trade, lock, redeem / reconstitute, outside LP blocked, owner bounds, plus the audit regressions `test_buy_creatorCutFoldsIntoStreamWhenBlocked` and `test_create_badParamsMatrix`. Partner leg pinned by `hooks/test/Partner.t.sol`. Whole `hooks/` suite 142/142 including the mainnet fork tests.

Audit closure (2026-10-10, fixed before deploy, report `docs/Hashlock-Certified-Audit-StonkBrokers-Hooks.pdf`):

- HK-10: the `ExactOutputWhileTaxed` guard in the shared `StonkFeeHook.beforeSwap` sat below the zero fee early return, so an exact output swap on a zero fee pool slipped past it. The check now runs first.
- HK-13: `snipeStartBps + max(buyFeeBps, sellFeeBps) >= 10000` is rejected at collection creation (`BadParams`), a 100% tax can no longer be configured.
- HK-17 (was H-1 / H-2): a fee push while `totalEarningSupply == 0` used to strand the quote. `FractionToken` now parks it in `pendingReward` and `_materializePending` folds it into the reward index on the first earning balance.
- HK-18 (was H-3): the creator cut was a hard `_safeTransfer`, so a reverting creator wallet could brick every taxed swap. `onSwap` now uses the tolerant `_tryTransfer` and folds a failed creator leg into the holder stream (`FeeStreamed(collectionId, streamed, paidCreator)` reports which path landed).

## 10. Go live status

1. FractionalLauncher, FractionalDeployer, ERC6551Registry, Fractional6551Account and StonkFeeHook deployed 2026-10-10 via `hooks/script/FractionalHookDeploy.s.sol` on the audit fixed, partner leg bytecode (PHASE=deploy, then PHASE=verify readbacks). Two earlier same day generations with zero launches are superseded and archived: launcher `0x59c6...3B13` / hook `0x277c...2acc` (`fractional-hook.4663.superseded-2026-10-10.json`) and launcher `0xC7E9...4238` / hook `0x7750...2AcC` (`fractional-hook.4663.superseded-2026-10-10b.json`).
4. Hookr CA: owner `setPartner(<hookrCA>, 5000)` on the launcher, then anyone `flushPartner(<quote>)` on the hook. Pending on Hookr.
2. Addresses above are final; the hooklist entry is live. Pool keys come from `CollectionCreated` events.
3. Depositing a collection and trading fractions is permissionless; the owner only tunes bounded fee knobs.
