================================================================================
STONKERS
multi-deck meme-hand NFTs on Robinhood Chain
whitepaper.txt
================================================================================
Status: living document · product + protocol overview
Chain: Robinhood Chain
Mint: native ETH only · up to 5 hands per transaction
--------------------------------------------------------------------------------
1. ONE-LINE SUMMARY
--------------------------------------------------------------------------------
You pay ETH to mint a Hand NFT. The protocol deals a leverage-weighted hand
from a fair multi-deck shoe (sum of leverages always equals 5), spends 75%
of the mint on those memecoins in proportion to each card's leverage, stores
purchase-backed claims on the NFT (~90.9% of tokens bought; 10% vault
buffer), and sends 25% as a protocol fee.
When you burn the NFT, those stored claims pay out in-kind: Memecoins
transfer to your wallet and the NFT is destroyed.
--------------------------------------------------------------------------------
2. WHAT YOU OWN
--------------------------------------------------------------------------------
Hand NFT (ERC-721)
· Represents a random hand drawn from the active shoe.
· Cards are (meme, leverage) pairs: 1× spot, 2×, or 3×.
· Hand size is variable: the dealer draws until sum(leverage) = 5
(HAND_WEIGHT). Examples: five 1× cards, 2×+2×+1×, 3×+2×, 3×+1×+1×, …
· On burn you redeem handClaims[i] of each card's Memecoin — the
exact purchase-backed amount stored at mint (and any secondary royalty
top-ups). NOT a fixed unitTokenAmount × leverage formula.
Memecoins
· CASHCAT, STONKBROKER, PONS, MANCER, MOTION, HALT, TENDIES, SNAT, SUSHICAT, FRONG, SWAPPY, HMM.
· Custody lives in StockVault until burn redemption.
--------------------------------------------------------------------------------
3. GENESIS DECK (TEMPLATE)
--------------------------------------------------------------------------------
The shoe is built from a fixed 52-card template:
20 × 1× cards
20 × 2× cards
12 × 3× cards
────────────────
52 cards · total weight = 20·1 + 20·2 + 12·3 = 96
Asset count follows the live pool (see §2 Memecoins). Every name appears
at least once at 1×, 2×, and 3×; extra 1×/2× copies keep slot counts at
20/20/12 when needed.
Multi-deck shoe: by default N = 6 decks → 6 × 52 = 312 cards shuffled
together (operator-configurable via ProtocolConfig.decksN).
--------------------------------------------------------------------------------
4. FAIRNESS: COMMIT → OPEN → AUDIT REVEAL
--------------------------------------------------------------------------------
Before anyone can mint, an operator runs a multi-step shoe:
1) commitShoe(commitment)
commitment = keccak256(seed || salt)
Locks the future shuffle without revealing the seed.
2) Wait revealDelaySecs (default 60s; shorter on local Anvil).
3) openShoe(seed, salt)
Verifies the commitment, runs Fisher–Yates over decksN copies of
the 52-card template, and enables dealing. Seed is used on-chain
to build the shoe but is NOT emitted and NOT stored as
revealedSeed — so there is no official public seed during the sale.
4) Users mint until the shoe cannot fill another hand (exhausted).
5) revealShoe(seed, salt)
Public audit only after mint-out / exhaust. Publishes seed + salt
so anyone can re-derive the shuffle and match the original
commitment. Blocked while the shoe can still deal (anti card-mining).
Dealing is sequential from the shuffled array. For each hand the shoe draws
consecutive cards until sum(leverage) == HAND_WEIGHT (5), skipping a card
only when adding it would overshoot. When remaining cards fall below
handSize or penetrationCards, the shoe is exhausted and a new shoe must be
committed/opened.
Users never pick cards. Randomness is fixed at open and cannot be
reordered after the fact without invalidating the commitment. Undealt
peeks are hidden until the public audit reveal.
--------------------------------------------------------------------------------
5. MINT (ETH ONLY)
--------------------------------------------------------------------------------
Two-step mint (pay + reserve → deal on a later block):
1) commitMint(quantity) payable
Pays full mintPrice × quantity; ETH locked on controller.
RESERVES worst-case shoe cards (HAND_WEIGHT × qty, with penetration
floor) so the shoe cannot be overbooked. No cards dealt yet.
availableForMint = remaining − sum(unrevealed reservations).
No mint salt: card fairness is the shoe shuffle (separate seed).
2) revealMint(commitId)
Callable by the commit buyer or the protocol operator/owner.
Deals the reserved hands, buys memes, mints NFTs, releases the
reservation. Must be a later block than commitMint (same-block
commit+reveal reverts). Capacity was locked at commit so reveals
cannot be overbooked. Reverting reveal does NOT refund commit ETH.
Constraints
· quantity ∈ {1, 2, 3, 4, 5}
· msg.value == mintPrice × quantity at commit (exact)
· mint not paused; availableForMint ≥ need at commit
· reveal bound to shoeId from commit
Mint proceeds split (per hand, at reveal):
· 25% (MINT_FEE_BPS = 2500) → ProtocolConfig.mintFeeRecipient
· 75% = meme budget, split by LEVERAGE across the dealt cards:
share_i = floor(stockBudget × leverage_i / HAND_WEIGHT)
last card gets the remainder so the full budget is allocated
Example (stockBudget = 0.0075 ETH, HAND_WEIGHT = 5):
3× card → 3/5 of budget
2× card → 2/5 of budget
1× card → 1/5 of budget
A 3×+2× hand spends the same total as five 1× cards — but weights
the buys toward the higher-leverage stickers.
For each hand on reveal:
a) Deal cards until sum(leverage) = 5.
b) For each card i with token T_i and leverage-weighted share s_i:
spend s_i on T_i via BuyAdapter (Uniswap etc.)
minOut = quote(s_i) × (10000 − buySlippageBps) / 10000
(default buySlippageBps = 500 → 5% max slippage vs quote)
amountOut_i = tokens actually received
claim_i = amountOut_i × 10000 / 11000 // user share (~90.9%)
buffer = amountOut_i − claim_i // ~9.1% vault surplus (10% buffer)
liability[T_i] += claim_i
store claim_i on the NFT (handClaims)
c) Mint Hand NFT with cards[] + claims[]; emit Minted / HandMinted /
StockClaimFunded.
Burn:
· Redeem handClaims[i] of each card's Memecoin (purchase-backed).
· Vault already holds amountOut ≥ claim (buffer stays as surplus).
Residual ETH (usually zero or dust from floor division):
· Rare when last-card remainder absorbs allocation dust.
· withdrawMintEscrow / optional settleMintEscrow (full-template basket
surplus buy) for any leftover mintEscrowWei.
Off-chain: indexer DB stores buyer, qty, salt, shoeId, nonce for recovery and
admin/keeper reveal (no protocol timeout — keeper eventually reveals).
Why NOT a full 52-card basket on mint?
Primary mints buy only the hand's cards, leverage-weighted, so vault
inventory matches claims. Surplus comes from the 10% buffer on every buy
and from optional fee recycling (see §7), not from buying names the hand
does not hold.
--------------------------------------------------------------------------------
6. BURN / REDEEM
--------------------------------------------------------------------------------
Entry: StonkersController.burn(uint256 tokenId)
· Caller must be the NFT owner.
· Read handClaims[]; for each slot redeem that exact token amount of the
corresponding Memecoin to the owner (StockVault.redeemInKind).
· Decrease liabilities; transfer ERC-20s out of the vault.
· Destroy the NFT (controller-authorized burn).
· Emit Burned(burner, tokenId, cards).
No cash settlement: you get the memecoins themselves.
No fixed unit size: two hands with the same cards can hold different
claim amounts if their fills (amountOut) differed.
--------------------------------------------------------------------------------
7. TREASURY, FEES & SECONDARY ROYALTIES
--------------------------------------------------------------------------------
StockVault
· Holds Memecoin balances bought on mint and fee/royalty paths.
· Tracks liability[token] = outstanding burn claims.
· Invariant enforced on redeem: balance ≥ liability.
· surplus[token] = balance − liability (overcollateral).
Primary mint ETH
· Does NOT sit as idle ETH treasury by design.
· 25% fee → mintFeeRecipient; 75% immediately converted into the hand's
memes and deposited to the vault (see §5).
Secondary royalties (ERC-2981)
· HandNFT royalties (default royaltyBps, e.g. 5%) point at feeRecipient.
· feeRecipient is set to FeeSink on deploy.
· FeeSink address (this network): 0x026dcE14a134997Bf61Fc24af0c3fBfD693b20ed
Royalty applier bot (ProtocolConfig.royaltyApplier)
· Address (this network): 0x7130D4405251Bf7C44e01e43C4f5F527257f5f2d
· After a secondary marketplace sale (e.g. Seaport), royalty ETH lands in
FeeSink. A small automated bot — the royalty applier — watches sales and
calls FeeSink.applyToHand(tokenId, amount) for the sold hand.
· That spends the royalty on more of the memes already on that NFT (same
leverage-weighted buy path as mint), then boosts the hand's burn claims.
In plain terms: the bot buys more "memecoins" / pool stocks for the card
that just traded.
· Timing is not instant. The watcher polls on a short interval; if FeeSink
balance, gas, or RPC is slow, or an apply reverts, the job is queued and
retried (on the order of minutes, not seconds). A successful sale does
not guarantee an immediate claim top-up.
· Transparency: open /search, look up the token ID. Under that NFT you get
a "royalty top-ups" table — each sale, whether apply succeeded or is
still queued/failed, which assets were bought into the hand, and links
to the sale + apply transactions.
FeeSink — two paths
A) applyToHand(tokenId, amount) [secondary sale royalty processing]
Normally called by the royalty applier bot (or operator/owner).
Forwards royalty ETH to StonkersController.applySecondaryRoyalty:
· 25% (MINT_FEE_BPS) → mintFeeRecipient
· 75% → leverage-weighted buys of THIS hand's cards only
· claim_i increases by amountOut_i × 10000/11000 (same 10% buffer)
· handNft.boostClaims(tokenId, deltas)
Economic effect: marketplace royalty tops up that NFT's burn claims
and vault inventory for those memes. Requires royalty ETH on FeeSink
(marketplace consideration / ERC-2981 to feeRecipient), then applyToHand
— not raw ERC-2981 alone.
B) sweepNative / sweepToken [residual / orphan only — not sale royalties]
Recycle dust or leftover ETH/tokens after all known royalties have
been applyToHand'd. Buys the full 52-slot leverage-weighted basket
→ StockVault surplus only (no per-hand claim boost).
Primary mint's 25% fee never sits in FeeSink — it goes straight to
mintFeeRecipient at mint/reveal.
Diagram (simplified):
User ETH ──mint──► hand memes (lev-weighted) ──► StockVault
▲ │
│ liability ↑
secondary ──► royalty applier bot │
sale applyToHand (this hand) │
royalty ETH + mintFee share │
▲ on burn: tokens → user
FeeSink liability ↓
│
sweepNative → full basket (surplus only)
--------------------------------------------------------------------------------
8. ART & METADATA
--------------------------------------------------------------------------------
Artwork is assigned deterministically off-chain (server seed) at tokenId:
· Mapping is fixed for a given STONKERS_ART_SEED + art pool.
· Pre-mint: images/traits are not served (mint-gated).
· Post-mint: tokenURI → /api/stonkers/{id} · image → /api/stonkers/{id}/image
· Traits (hair, suit, rare flags, …) come from the same assignment.
This is independent of the meme hand (cards), which is fully on-chain.
--------------------------------------------------------------------------------
9. ROLES
--------------------------------------------------------------------------------
ProtocolConfig.owner
· Retune mintPrice, decksN, delays, buySlippageBps, pause mint, set
operator / feeRecipient (royalties) / mintFeeRecipient (25% primary
mint and secondary royalty fee share).
ProtocolConfig.operator
· Commit / open / audit-reveal shoes; may sweep FeeSink.
ProtocolConfig.royaltyApplier
· Hot wallet for the royalty applier bot (FeeSink.applyToHand after sales).
· Address: 0x7130D4405251Bf7C44e01e43C4f5F527257f5f2d
· Operator/owner may still call applyToHand manually.
Public
· commitMint + revealMint with ETH; burn owned hands (when vault funded).
· Operator may revealMint(commitId) for pending commits (no salt).
· Operator settleMintEscrow (optional residual → full-template basket).
· Anyone can inspect royalty apply history for a hand on /search.
--------------------------------------------------------------------------------
10. RISKS & DISCLAIMERS
--------------------------------------------------------------------------------
· Not financial advice. Memecoins and regulatory packaging are separate
from this open protocol description.
· Solvency depends on adapter execution quality and the 10% buy buffer
relative to market impact / slippage (buySlippageBps caps adverse fills).
· Claims are purchase-backed: bad fills mean smaller handClaims for that
mint, not a protocol guarantee of a fixed token amount.
· Fairness assumes operator opens with the committed seed and later publishes
a valid audit reveal after mint-out; users should verify commitments when
auditing a shoe.
· Secondary royalty claim top-ups only apply when royalty ETH is routed
through FeeSink.applyToHand (usually by the royalty applier bot); plain
ERC-2981 transfers alone do not boost claims. Apply can lag minutes after
a marketplace sale — check /search for that token's royalty top-ups table.
· Demo USD prices in the app UI are play numbers until live oracles are
wired end-to-end. On-chain hands display DexScreener marks over stored
claims when available.
--------------------------------------------------------------------------------
11. FURTHER READING
--------------------------------------------------------------------------------
/boardroom live mints, burns, vault balances
/activity your wallet's mint / burn / transfer history
/verify recompute shoe shuffle from commit + public reveal
/search look up any revealed hand — claims, owner, and royalty
top-ups (applier bot history: assets bought, tx links,
success / queued / failed)
================================================================================
end of whitepaper.txt
stonkers.finance
================================================================================