arcade β›“ on-chain

OVERVIEW

MINECAT is a 10,000-piece NFT collection of ASCII cats in 3D pixel that cannot be bought at a mint button. Every cat must be mined: your hardware grinds real keccak256 proof-of-work, and luck decides whether you claim instantly or wait for the next round. Price per mint is $0.20, settled in ETH on Robinhood Chain.

Three rigs are first-class citizens: CPU (Web Workers), GPU (a WGSL compute kernel on WebGPU), and AI agents (autopilot on the page, or any external bot speaking the same protocol).

GAME RULES

rulevalue
total supply10,000 β€” hard cap, no re-mints ever
round length~60 seconds on-chain (roundBlocks = 5 blocks)
lucky slots per round50, contested by all miners Β· tickets claimable on top
wallet cap5 mints per wallet (pending wins count toward the cap)
pricemintPriceWei β‰ˆ $0.20, paid at claim time
valid workhash < ticketTarget β€” about 1 in 100,000,000 hashes on-chain (the arcade demo uses 1 in 4,000,000 so it stays playable)
lucky odds1 in 6 valid solutions β†’ instant claim

MINING

The proof-of-work message is exactly 60 bytes:

h = keccak256( roundSeed(32) β€– minerAddress(20) β€– nonce(8, big-endian) )

Because your address is inside the hash, nobody can steal your solution from the mempool β€” a copied nonce produces a different hash for a different sender.

Targets

ticketTarget = 2²⁡⁢ / diffTicket     // any hash below = valid solution
luckyTarget  = ticketTarget / luckyDivisor   // below this = LUCKY

Rigs

LUCK & TICKETS

Every valid solution triggers the gacha moment:

Grinding extra hashes hunting a lucky one is not cheating β€” the luck roll is your own solution hash, so "more work = more luck" is the entire point of proof-of-luck.

GOING ON-CHAIN

Networks

mainnettestnet (dry-run)
chainId466346630
RPCrpc.mainnet.chain.robinhood.comrpc.testnet.chain.robinhood.com
explorerrobinhoodchain.blockscout.comexplorer.testnet.chain.robinhood.com
currencyETHtest ETH

Deploy with Remix (no toolchain)

  1. Open remix.ethereum.org, create MINECAT.sol, paste the contract from contracts/MINECAT.sol.
  2. Compile with Solidity 0.8.24.
  3. Switch MetaMask to Robinhood Chain (the mint page can add the network for you).
  4. Deploy with constructor args:
    _mintPriceWei : price of $0.20 in wei (check current ETH price)
    _diffTicket   : 100000000 (live)
    _roundBlocks  : 5 (~60 s β€” block.number tracks L1 at ~12 s on Arbitrum Orbit)
    _baseURI      : ipfs://<metadata CID>/  (or "" and set later)
  5. Verify the source on Blockscout so miners can read it.
  6. You (deployer 0x25…) are owner + 5% royalty receiver. Keys stay in your wallet, always.

⚠ Mainnet is real money. Deploy and drill the full flow on testnet first β€” same code, free gas.

MARKETPLACE

MINECAT has an official secondary market (market.html + contracts/MinecatMarket.sol) with one sacred rule:

πŸ”’ The market is sealed until all 10,000 cats are mined. On-chain, every list() and buy() checks totalMinted() >= MAX_SUPPLY β€” before sold-out the only way to own a cat is to mine it. No paper hands during the gold rush.

How it works

The demo market page mirrors all of this with fake balance β€” including the sold-out gate. It shows a locked screen with live supply progress; a dev shortcut lets you simulate sold-out to preview the exchange: floor price, listings from other miners, your sell/cancel flow, and the live activity feed.

OpenSea & enforced 5% royalty

Robinhood Chain is live on OpenSea, so MINECAT trades there out of the box: the contract speaks standard ERC-721 metadata, ERC-2981, and contractURI() for the collection page.

Royalty is hardcoded at 5% (no setter exists) and enforced on-chain with an operator allowlist: while royaltyEnforced is on, approve/setApprovalForAll and operator-driven transfers only work for venues the owner has allowlisted via setOperator(). A marketplace that refuses to pay royalties simply cannot move your cats.

  1. After deploying, allowlist your venues: setOperator(minecatMarket, true) and setOperator(openSeaSeaportConduit, true) (grab the Seaport conduit address for Robinhood Chain from OpenSea's docs/explorer).
  2. Set setContractURI("ipfs://…/collection.json") β€” include "seller_fee_basis_points": 500 and "fee_recipient" so OpenSea displays the fee.
  3. Holders can always transfer their own tokens directly (gifts, wallet moves) β€” enforcement targets marketplace flows. OTC hand-offs are the one hole no NFT contract can close.
  4. Escape hatch: setRoyaltyEnforced(false) if a future venue breaks; flip it back anytime.

USING THE MINT PAGE

  1. Open mint.html β†’ CONNECT WALLET (adds/switches to Robinhood Chain).
  2. Paste the deployed contract address β†’ load contract.
  3. If the round seed says NOT OPENED YET, hit OPEN ROUND (tiny tx, anyone may do it β€” the seed anchors to a blockhash so it can't be pre-mined).
  4. Pick CPU or GPU β†’ START MINING. The page grinds against the live seed with your address.
  5. On a solution you review it first, then SUBMIT WORK (tx). Lucky = voucher; bust = ticket.
  6. CLAIM (tx, sends mintPriceWei) β†’ cat minted. Your on-chain cats render at the bottom.

Every transaction pops in your wallet for approval. The page holds no keys and can spend nothing on its own.

CONTRACT REFERENCE

Miner-facing

functionwhat it does
openRound()sets the seed for the current round (once per round, anyone)
submitWork(uint64 nonce)verifies your PoW; lucky→voucher (slot locked), else→ticket
claim() payablepays mintPriceWei, mints from voucher or matured ticket
currentRound() / roundSeed(r)round index (block-based) and its seed
ticketTarget() / luckyTarget()the two difficulty thresholds
roundMinted(r) / totalMintedslots used this round / global supply
mintedBy(a) / voucher(a) / ticketFromRound(a)your caps & pending wins

Owner-only

functionpurpose
setMintPrice(wei)keep the price pegged near $0.20
setDifficulty(diff, luckyDiv)tune for real network hashrate
setBaseURI(uri) / setRoyaltyReceiver(a)metadata + ERC-2981 (5%)
withdraw()pull mint proceeds to the owner wallet

Events

RoundOpened(round, seed)
WorkSubmitted(miner, round, nonce, hash, lucky)
Claimed(miner, tokenId, viaTicket)
Transfer / Approval / ApprovalForAll (ERC-721)

AGENT API

External AI agents mine through window.MINECAT on the arcade page, or straight against the contract. Full protocol with an ethers.js sketch lives in agent/AGENT.md.

πŸ€– Agents get their own skill file: skills/minecat-miner/SKILL.md β€” a drop-in agent skill (YAML frontmatter + instructions) containing the PoW spec, the proven decision loop, a revert decoder, and non-negotiable key-safety rules. Point your agent at it, or install it as a Claude Code skill (~/.claude/skills/minecat-miner/) and it will know how to mine the moment MINECAT comes up.

MINECAT.job()        // { round, seed, address, diffTicket, luckyDiv }
MINECAT.state()      // slots, supply, wallet, hashrate, pendingHoki
MINECAT.start('gpu') // 'cpu' | 'gpu' | 'agent'
MINECAT.claim()      // lucky win or matured ticket
MINECAT.submitNonce(hiHex, loHex)  // bring-your-own-miner

ART & METADATA

FAQ & SECURITY

Can someone steal my solution from the mempool?

No. The hash commits to your address; a stolen nonce is worthless to anyone else.

Can the team pre-mine lucky rounds?

No. Seeds derive from a blockhash at openRound() time β€” unknowable in advance, for us too.

Is grinding for lucky hashes an exploit?

It's the game. Luck is priced in work.

What does the site do with my keys?

Nothing β€” it never sees them. All signing happens inside your wallet extension. No seed phrases, no key input fields, ever. Anyone asking you to paste a private key "to mine faster" is robbing you.

Why did my submitWork revert?

Usual suspects: the round rolled over (new seed β†’ old solution invalid), the 50 slots were already gone (lucky path), you already hold a ticket, or the wallet cap (5, counting pending wins) is reached.

Demo mode on the arcade page is a 1:1 simulation with fake balance β€” perfect for feeling the game before spending real gas.

Mine from a terminal (CLI miner)

The website miner runs in your browser. If you would rather mine from a shell β€” on Windows, Linux, macOS or a VPS β€” use the CLI miner. Same proof-of-work, same contract, multi-core CPU or WebGPU, and it submits and claims for you.

⬇ download minecat-miner.zip

Quick start

# 1. unpack, then inside the miner folder:
npm install

# 2. benchmark first β€” no key needed, costs nothing
node minecat-miner.js --bench

# 3. give it a funded burner key
#    Linux/macOS:
export MINECAT_PRIVATE_KEY=0xyour_key
#    Windows PowerShell:
$env:MINECAT_PRIVATE_KEY="0xyour_key"

# 4. mine
node minecat-miner.js
node minecat-miner.js --mode gpu        # WebGPU via headless Chrome
node minecat-miner.js --threads 8       # pick core count

Run it 24/7

# systemd
sudo systemctl enable --now minecat-miner
sudo journalctl -u minecat-miner -f

# pm2
MINECAT_PRIVATE_KEY=0xkey pm2 start minecat-miner.js --name minecat -- --threads 3

Prove it computes the same hash as the contract

node verify-preimage.js

Cross-checks the miner against keccak256(abi.encodePacked(bytes32,address,uint64)) computed independently β€” including uint64 max and the 232 boundary. If it fails, do not mine: every solution would be rejected on-chain.

Full docs, systemd/pm2/screen recipes and a troubleshooting table are in README.md inside the zip. Your private key never leaves your machine β€” it signs locally and is never transmitted.