What MORO does
The contracts could not be reached, so the figures below come from the source rather than from a chain, and are marked accordingly. Treat them as our intent, not as a reading.
01 — How it works
There are 999unverified birds. A minted bird is asleep, and a sleeping bird is a picture: it holds nothing and earns nothing. Waking one burns 50,000unverified $MORO, permanently, and from then on it earns tokenized stock into a store inside the token called its Nest.
The stock comes from trading fees on the $MORO/NVDA pair. Every hour, whatever arrived is divided: 85% across awake birds by weight, 15% to the treasury. Nobody has to be watching for this to be correct — the hours are settled by anyone calling poke(), and a bird is credited for the hours it was awake at the weight it held during them, whenever that settlement happens.
A bird that is not fed loses weight over time, and one that is sold falls asleep. Neither takes anything away from what it has already earned.
02 — $MORO
$MORO exists to be destroyed. It is spent to wake a bird and spent again to feed one, and in both cases it is burned rather than collected — no address receives it, including ours. Waking costs 50,000unverified and one feed costs 10,000unverified.
The entire supply was minted once, at deployment, to the treasury, which seeds the trading pair. There is no mint function and no owner who could add one.
03 — The Nest
The Nest is tokenized stock held inside the NFT, not a claim you redeem against us. It travels with the token: sell the bird and the buyer gets the hoard. We tested this on a real chain — a bird holding 141.67 NVDA was transferred and the balance did not move.
Withdrawal is free. Not free as a policy we are promising to keep — there is no fee variable anywhere in the distributor, so there is no number for a future admin to change and no admin to change it. A withdrawal on testnet paid out the balance exactly, to the wei.
Hours are settled by poke(), which anyone may call, takes no argument and pays its caller nothing. At most 720unverified hours close per call, so a long-neglected accumulator catches up over several calls rather than exceeding the block limit and wedging permanently.
04 — Iridescence and decay
A bird holds full weight for the first 28unverified days after its last feed. After that it steps down: to until day 42unverified, then to until day 56unverified, after which it is dormant and earns nothing until fed again.
The steps happen on a schedule with no transaction behind them. The contract does not discover a bird has decayed when someone touches it — the drops are written into the accumulator as dated changes at the moment the bird is fed, so an unattended bird is valued correctly for every hour whether or not anyone was watching. We tested this on a real chain by waking a bird during an unsettled backlog: it was credited nothing for the hour it had slept through.
The first 24unverified birds ever woken are the Tiding, and they never decay at all. A Tiding bird keeps the mark permanently, including through a sale — the flag is claimed on a token’s first waking, so re-waking after a sale cannot take a further slot.
05 — Tiers
Feeding past the wake threshold raises a bird’s weight permanently. The ladder is cumulative — the totals below are lifetime $MORO burned by that bird, not per-feed costs.
| Tier | Burned · $MORO | Weight |
|---|---|---|
| Woken | 50,000unverified | 1×unverified |
| Polished | 150,000unverified | 1.5×unverified |
| Burnished | 400,000unverified | 2×unverified |
| Hoarder | 1,000,000unverified | 3×unverified |
06 — The Gilded
8unverified birds out of the full 999unverified are Gilded. Each token maps to an art index through a permutation that is a bijection, so precisely the eight tokens landing below the threshold are Gilded — across the whole collection there is no draw that could produce seven or nine.
Read this before minting
Exactly eight Gilded exist only if the collection sells out. The eight are drawn across all 999unverified token ids, but minting stops permanently when the mint window closes, and any Gilded id above the final supply is never minted and therefore never exists.
A partial mint of n birds contains roughly 8 × n / 999 Gilded — and only roughly, because it depends entirely on where the seed happened to put them. Sell half and you might get five, or three. It is entirely possible for a partial mint to contain no Gilded at all.
This is not hypothetical. On our testnet deployment 12 of 999 were minted and revealed, and isGilded() returns false for every one of them. That collection contains zero Gilded.
The live count is shown on the mint page and in the explorer, read from the chain. If you are minting for the chance at a Gilded bird, that number — not the number eight — is the one that applies to you.
Which eight depends on a seed committed on chain before the first sale and published after the last. Until the reveal nobody can know, including us; after it, anyone can derive the set and check it against isGilded(tokenId).
07 — Claiming without gas
A bird’s owner can withdraw its Nest themselves with withdraw, which requires them to send a transaction and therefore to hold gas. Somebody holding a bird and no ETH would otherwise be unable to reach their own stock, so there is a second path: withdrawFor(tokenId, to, deadline, signature). The owner signs; anyone at all may submit it and pay the gas.
The relay is trusted with nothing. That is worth being exact about, because “relay” usually implies a component you have to trust. There is nothing here it could betray. A relay — ours, a compromised one, or a hostile stranger — can do exactly three things: submit a signature it was given, submit it late, or not submit it at all.
It cannot redirect the funds: the recipient is inside what the owner signed, so submitting with a different destination produces a different digest, which recovers a different address, which is not the owner. It cannot claim twice: each token carries a counter that is spent when a signature is used. It cannot use a signature after the bird is sold, because ownership is read when the transaction executes and never taken from the signature — a seller’s old signature recovers to the seller, who no longer owns it. And it cannot hold a signature indefinitely, because the owner signs a deadline.
There is no trusted forwarder, and that is deliberate. A forwarder would be an address that gets believed about who it is acting for, which then becomes an address that must never be compromised. Here nothing is believed. The signature is the only authority in the system.
08 — Checking the collection yourself
The art is not stored on chain, so “the collection is what we say it is” would otherwise be a matter of trust. It is not. Every bird is a pure function of the revealed seed, so the whole collection can be regenerated from scratch and compared against a checksum published after the reveal.
The manifest hashes every token’s traits and all four of its state images, then hashes that list into a single root. Reproduce it with:
MORO_SEED=$(cast call <MORO> 'seed()(bytes32)') \
node art/engine/cli.ts manifestThe seed comes off the chain, not from us. If the root you get differs from the published one, the published collection is not the one the seed produces, and you should say so loudly.
Published root (Robinhood Chain (4663)): 6f552fff1c926a08ed6af67f6ee00b8a01261fa5fe55eea20b7fdac712343d75
Gilded: 188, 231, 267, 329, 466, 472, 562, 1363
The Gilded set is derived the same way. Anyone can compute it from the seed and check each one against isGilded(tokenId) on chain. We check this ourselves before publishing, because we have already shipped a mismatch once in development: a hard-coded list of eight, written before any seed existed, disagreed with the chain the moment a real seed was revealed.
09 — Where the metadata comes from, and why that is not the weak point
The metadata is served from an endpoint we control, which means we could change what it serves. We are not claiming otherwise. tokenURI points at https://feedmoro.fun/api/metadata/, that domain is ours, and the string is immutable in the contract — so it will always point there and we will always be the ones answering.
We considered IPFS and chose not to pretend. A content hash cannot be baked in at deploy, because the art depends on a seed that is only revealed after the mint closes — which is after the contract exists. IPNS would let the pointer move, but the pointer still has to be repointed by whoever holds the key, so it is not less mutable than a domain, only less legible. An endpoint we control is the honest version of the same trust assumption, and it is faster and easier to debug.
What is not a matter of trust is the art. Every image is a pure function of the revealed seed, and the checksum of the whole collection is published. If this endpoint ever served an image that did not match, it would be provable in minutes by anyone:
git clone <repo> && cd moro && pnpm install
# the seed comes off the chain, not from us
MORO_SEED=$(cast call <MORO> 'seed()(bytes32)' --rpc-url <rpc>) \
node art/engine/cli.ts manifest
# compare the printed root against the published oneThat regenerates all 999 birds from scratch and hashes every image. A matching root means the collection you can see is the collection the seed produces. A differing root means it is not, and you should say so loudly.
After the reveal the rendered collection is also pinned to IPFS and its CID published, so anyone can mirror it or serve it themselves. That is the real answer to “what if their endpoint goes down” — not a promise that it will not, but a copy you can host without us.
Published root (Robinhood Chain (4663)): 6f552fff1c926a08ed6af67f6ee00b8a01261fa5fe55eea20b7fdac712343d75
10 — What things cost
Measured on Robinhood Chain testnet from transaction receipts, not estimated. Gas prices move, so the gas figure is the durable one; the cost column is what that gas came to at 0.01 gwei.
| Action | Gas | Cost @ 0.01 gwei |
|---|---|---|
| Mint 4 birds (first mint of the collection) | 175,644 | 0.0000018 ETH |
| Mint 4 birds (thereafter) | 141,444 | 0.0000014 ETH |
| Approve $MORO to MORO (once per wallet) | 55,587 | 0.0000006 ETH |
| Wake a bird | 143,747 | 0.0000014 ETH |
| Wake a bird already woken once (after a sale) | 84,231 | 0.0000008 ETH |
| Transfer a bird | 150,012 | 0.0000015 ETH |
| Withdraw a Nest | 102,294 | 0.0000010 ETH |
| Poke one elapsed hour | 158,170 | 0.0000016 ETH |
| Reveal the seed | 80,461 | 0.0000008 ETH |
| Sweep mint proceeds to the treasury | 33,949 | 0.0000003 ETH |
Waking a bird costs more when it also has to settle a backlog of unsettled hours — the measured 223,894 is a wake that closed one elapsed hour on its way through. Minting several birds in one transaction is much cheaper per bird than minting them one at a time.
11 — The asset in the Nest is not ours, and it can be paused
Our three contracts have no owner, no pause and no upgrade path. The asset they hold does.
A Nest holds NVDA, the tokenized NVIDIA stock issued by Robinhood at 0xd0601ce157db5bdc3162bbac2a2c8af5320d9eec. That address is a beacon proxy. It holds no logic of its own — it reads an implementation address from a beacon at 0xe10b6f6b275de231345c20d14ab812db62151b00 and forwards every call to it. Today that implementation is 0xb35490d6f9163DE4F80d88dc75c3516eb64C5aE2. Whoever controls the beacon can replace it, for every holder at once, without asking anyone.
The token also has a pause switch. paused() returns false right now, so it is not paused. If it were ever paused, withdrawals from every Nest would revert until it was unpaused, because withdrawing is a transfer of that token and a paused token refuses transfers. Your balance would not be lost and nothing would be taken — the withdrawal simply would not go through until the issuer allowed transfers again.
We cannot prevent this, work around it, or fix it for you, and neither can anyone else holding MORO. It is not a flaw in what we built; it is what it means to hold an asset somebody else issues. Every address above is on chain and you can check all of it yourself — paused() on the token, and implementation() on the beacon.
The same is true of the stock exposure itself. What the token is worth, whether it keeps tracking NVIDIA, and under what terms it can be redeemed are all decided by its issuer under agreements we are not party to.
12 — What is not audited
The contracts have not been audited. If you are reading this before that changes, nothing below has been reviewed by anyone outside the people who wrote it.
What that does and does not mean. The contracts are covered by 82 tests, including property tests that compare the accumulator against an independent reference implementation, and the full lifecycle has been run on a real chain. That is evidence, and it is not the same thing as an audit. Tests demonstrate the behaviour we thought to check for. An audit is someone whose job is to think of what we did not.
Our own testing has already found one real bug of exactly this kind — a bird woken during a long backlog of unsettled hours was credited for hours it had slept through, at one point receiving half the entire holder pool. It was found by writing a test specifically to attack that path, which is precisely the sort of thing that is easy to not think of. We do not assume it was the last one.
What reduces the damage if something is wrong: there is no owner, no pause, no upgrade path and no rescue function, so a bug cannot be exploited by us and cannot be patched by us either. Nobody can drain the contracts through a privileged function, because there is no privileged function. That is a deliberate trade — it removes the insider risk and accepts that a mistake is permanent.
Other things not covered by any review: the front end you are reading, the indexer behind its lists, the relay, and the art pipeline. And the asset inside every Nest is a proxy its issuer can upgrade and pause — see section 11, which is a separate risk from this one and does not go away if an audit comes back clean.
Buying an NFT here can lose you everything you spend. "border-t-[3px] border-ink">