TESTNET. Chain ···· · Robinhood Chain testnetEvery token here is worthless and will never be migratedContracts are unaudited and not deployed to mainnet

Documentation · Robinhood Chain testnet

Order/Flow

Retail produces it. Makers take a rebate on it. This page explains, without decoration, exactly what happens when you sign each transaction.


The setting

On a trading floor somewhere in the metaverse, a crowd of Retail traders park their capital side by side and produce a steady supply of $FLOW. They sit together on The Exchange, and their owners settle them from time to time to collect what has accrued. With more $FLOW, a trader can open more positions, and the floor grows louder.

On the other side of every one of those orders sits something Retail would rather not think about. The Makers are not raiders; they are counterparties, and the rulebook is on their side. They can internalize an order before it ever reaches the book. They can catch a trader on the way out and take the whole position in slippage. Nothing they do is against the rules, because they helped write them.

So the brokerage struck a deal. The Makers are paid a rebate on all $FLOW production, and in exchange they leave Retail alone while it sits quietly on The Exchange. Both sides signed. Both sides meant it.

But when Retail withdraws, or when a new order is routed to the floor, the deal does not apply. And there, the Makers do not hold back.

What this is

Order Flow is a risk protocol for NFTs. It is a fork of Wolf Game, ported to Robinhood Chain and rebuilt around a source of randomness that nobody involved can steer.

The honest statement of what is new is narrow, and it is worth stating narrowly. Your NFT can take another player's NFT, and the token that NFT produces, on the chain itself — and no operator, no sequencer and no player is able to choose who wins. Two things happen without your consent and without anybody's discretion:

  • A newly minted token past the paid tranche has a 10% chance of being internalized — delivered to a randomly chosen staked Maker rather than the wallet that paid for it. The weighting across Makers is by Alpha.
  • A Retail position leaving The Exchange has a 50% chance of having every $FLOW it accrued routed to the Makers instead of to its owner.

Everything downstream of those two rolls is deterministic and public. What makes the claim defensible is not the game design, which is inherited — it is that the entropy driving both rolls does not exist at the moment you pay for them, and is fixed in advance by a party that never learns it in time to matter. Section 9 is the whole argument.

Everything else lives on-chain: the traits, the pixel art, the accounting, the rolls. There is no metadata server, no roadmap, and no discretionary switch that redirects an outcome after it has been requested.

The terms

  • There will only ever be ···· Gen 0, minted for ···· each. The ···· Gen 1 are minted by burning $FLOW. ···· in total, ever.
  • Retail can be staked on The Exchange to earn $FLOW, and pays a ···· rebate to the staked Makers every time it settles.
  • When Retail leaves The Exchange, the Makers roll to take everything it has accrued. Leaving requires ···· since the position was opened or last settled.
  • When a token past the paid tranche is minted, the Makers roll to internalize it. If they succeed it is routed to a staked Maker, not to the buyer who paid.
  • Makers carry an Alpha from · to ·. Higher Alpha means a larger slice of the rebate and a better chance of catching a mint. Only staked Makers earn or take anything.
  • Every roll resolves in a later block than the one that paid for it. Minting and exiting are therefore two transactions each, not one.
  • Up to 10 tokens per mint transaction. No per-wallet cap is enforced on chain.

Contracts

Live on Robinhood Chain testnet. Everything on this page is read from these addresses when the page loads — nothing below is transcribed by hand unless it is marked as a compile-time constant.

Game status

Minted
····of ····
Retail staked
····on The Exchange
Maker alpha staked
····sum of Alpha in the pack
$FLOW in circulation
····faucet paid ····
Beacon requests
····rolls served since deploy
Operator bond
····slashable on a stall

reading chain…

value read from the chain when this page loaded — hover for the exact call. value a constant compiled into the deployed bytecode: real, but not stored in a slot any eth_call can return, so it is transcribed from the source and labelled as such.

Minting

Token IDCostPaid inNotes
···· ···· native ETH The paid tranche. These are never internalized — the buyer always receives what they paid for.
···· ···· $FLOW, burned Free in ETH. The $FLOW is burned from your wallet at commit time, before the roll.
···· ···· $FLOW, burned Same. A 10% internalization roll applies to every token in this band and the ones after it.
···· ···· $FLOW, burned The last tranche.

Minting out the whole collection burns ···· $FLOW. That figure is the sum of the three bands above, each one read from mintCost() and multiplied by the width of its band — it is not a target, it is what the schedule adds up to.

A mint is two transactions

This is the one place the chain forces a change on the original design, and it cannot be avoided. Read section 9 for why. Mechanically:

  1. commitMint(amount, stake) — payable You pay, the token IDs are reserved, and a randomness request is registered. No token exists yet. Nothing about the outcome is decided or decidable at this point; the entropy it will use has not been produced. If you passed stake = true, anything that survives the roll goes straight onto The Exchange without a second approval.
  2. the roll matures The beacon fixed a seed block two L1 blocks ahead of your commit. That is roughly 24 seconds of real time. Until that block is mined and the operator reveals its next hash-chain link, the answer does not exist anywhere.
  3. revealMint(requestId) Traits, faction and the internalization roll all resolve, and the tokens are minted. This call is permissionless: anybody can push it, including a keeper. That is deliberate — the outcome takes no private input, so allowing only you to submit it would let you sit on a result you disliked.

If a commit is abandoned

The seed block's hash is only retained for 250 L1 blocks, about fifty minutes. Past that the entropy is gone and the roll can never be resolved. The only remaining path is settleExpired(requestId), which anyone may call. It mints the floor outcome — Retail, with the null trait set, no Maker, no rarity — and it refunds nothing.

This is not a penalty for bad luck; it is what stops a re-roll being free. A refundable commit would mean a player who dislikes a pending result simply walks away and pays again, which would undo the entire point of splitting the transaction. Reveal your commits, or let a keeper do it.

Retail

You have a 90% chance of minting Retail, each with its own traits drawn from the rarity tables held in the NFT contract. Retail is the only thing in this game that produces $FLOW, and the only thing that carries risk.

ActionNotesRisk
Join The Exchange setApprovalForAll(exchange, true), then addManyToExchangeAndPack(you, ids). Accrues ···· $FLOW per day, prorated to the second, from the moment the stake lands. None. One transaction, no roll.
Settle claimManyFromExchangeAndPack(ids, false). You receive ···· of what has accrued and the position stays open, with its timer reset to now. The Makers take a fixed ···· rebate, split across every staked Maker in proportion to Alpha. Deterministic — one transaction, no roll, no chance of losing the rest.
Withdraw · commit commitExit(ids). Registers the roll and locks the listed positions. Requires ···· of accrued time on every token in the batch — the settlement cycle the equity market ran on for a decade. Once this is signed the roll cannot be cancelled, avoided, or re-requested. Committing is the decision.
Withdraw · settle settleExit(requestId), once the beacon has fulfilled. Permissionless. The NFTs return to their owner either way, and the timer stops. 50% chance every $FLOW accrued on that token goes to the Maker pool instead of to you. Rolled per token, not per batch — a batch of five is five independent coin flips.

Read this before signing an exit

Settling and withdrawing are not the same transaction and not the same risk. claimManyFromExchangeAndPack(ids, false) costs you a fixed ···· and cannot take more. commitExit puts the entire accrued balance on one bit of a beacon word. If your goal is to realise $FLOW and keep playing, settle; the exit roll exists to price leaving, not claiming.

Attempting to unstake Retail through claimManyFromExchangeAndPack(ids, true) reverts with USE commitExit. There is no single-transaction Retail exit, by construction.

Makers

You have a 10% chance of minting a Maker. Every Maker carries an Alpha score from · to ·, stored as alphaIndex and read back as MAX_ALPHA − alphaIndex. A higher Alpha buys exactly two things:

  • A larger share of the rebate paid by every settling Retail position.
  • A better chance of being the Maker that catches an internalized mint.

Both are strictly proportional to Alpha, and both are zero unless the Maker is staked. An unstaked Maker is a picture.

The Alpha curve

Alpha is not uniform, and the skew is steep. The distribution below is computed in your browser from the alias tables held in the NFT contract — rarities(17, i) and aliases(17, i), drawn exactly the way selectTrait draws them.

AlphaShare of MakersRoughlyWeight
············reading chain…

How the split works

The Exchange keeps a single accumulator, flowPerAlpha. Every rebate payment adds amount / totalAlphaStaked to it. A Maker's claim is alpha × (flowPerAlpha − snapshotAtStake), so the arithmetic is constant-time regardless of how many Makers are in the pack, and joining late never dilutes what someone else has already accrued.

Two staked Makers, one at Alpha · and one at Alpha ·, split every unit of rebate ···· to ····. An internalized mint lands with them in the same ratio. If no Maker is staked at all when a rebate is paid, it is held in unaccountedRewards and paid to whoever stakes next — it is never burned and never returned to Retail.

ActionNotesRisk
Enter the pack addManyToExchangeAndPack(you, ids). Your Alpha joins totalAlphaStaked and your snapshot is taken at the current flowPerAlpha. You start earning on the next rebate paid, not on the backlog. None.
Collect claimManyFromExchangeAndPack(ids, false). Pays out everything accrued against your Alpha and resets the snapshot. The Maker stays in the pack and stays eligible for internalized mints. None. No rebate is charged to a Maker.
Leave claimManyFromExchangeAndPack(ids, true). Pays out everything accrued and returns the NFT. One transaction — Makers have no exit roll and no settlement period. None. Once out, you stop earning and stop catching mints immediately.

Retail · 90%

····

Carries all the production and all the risk. Pays the rebate, eats the slippage, and is the reason there is anything to take.

Makers · 10%

····

Expected count at full mint-out. Of those, only about ···· reach Alpha ·. The top of the curve is genuinely thin.

Both figures are the expected split of ···· at the coded draw rate, not a supply guarantee. The contract does not reserve a Maker quota; a run of luck moves the real number either way.

$FLOW

Supply and emission

$FLOW is a plain ERC-20 minted by The Exchange as staking rewards and burned by the NFT contract on Gen 1 mints. Two numbers govern the whole economy, and both are constants in the deployed Exchange:

ConstantValueWhat it does
DAILY_FLOW_RATE ···· $FLOW / day Per staked Retail token, prorated to the second. Emission scales with the staked population — this is a per-token faucet, not a fixed global budget divided among stakers.
MAXIMUM_GLOBAL_FLOW ···· The hard stop. Once totalFlowEarned reaches it, the staking faucet closes permanently and accrual after that point is zero for everyone.

Those two together are the emission schedule, and the consequence is worth stating plainly rather than burying: because the rate is per token, the faucet drains faster the more Retail is staked. With N Retail on The Exchange, the remaining budget lasts remaining ÷ (N × ····) days. At the population staked right now:

Faucet budget
····MAXIMUM_GLOBAL_FLOW
Paid out so far
····totalFlowEarned
Runway at current stake
····derived, changes with every staker

Where the rest of it goes

  • Burned on Gen 1. Minting out ids ···· destroys ···· $FLOW — more than the faucet will ever emit. The sink is designed to outrun the source.
  • Rebate. ···· of every Retail settlement is redirected to staked Makers. This is a transfer, not an emission: the total minted is unchanged, only the recipient moves.
  • Slippage. $FLOW taken on a failed exit follows the same path into the Maker pool. Again a transfer, not a burn.

One thing the deployed token does not do

The $FLOW contract carries no hard cap of its own. Its only supply control is which addresses are registered as controllers, and the only controller that mints is The Exchange, which stops at ····. If you have seen a larger maximum-supply figure quoted for this game, treat it as a plan rather than as something the bytecode enforces. This paragraph exists because the difference matters and it would be easy to leave unsaid.

How the randomness works

A game where an NFT takes another player's NFT is only worth playing if nobody can decide who wins. This chain gives you nothing to build that on, so the game brings its own.

Why nothing native works here

  • blockhash(block.number − 1) is byte-identical across roughly 150 consecutive L2 blocks — about fifteen seconds — and identical for every transaction inside that window.
  • block.prevrandao is the literal constant 1.
  • block.timestamp yields about four bits per plateau.
  • All sixteen canonical VRF coordinator addresses are codeless on this chain.
  • eth_call with state overrides is enabled, so anything computable inside your transaction is computable for free before you send it.

Put together, that means any outcome resolved in the paying transaction is knowable in advance and, worse, is knowable for long enough to act on. A player who disliked a mint would simply not send it.

The construction, in plain language

The operator picks one secret value at random and hashes it repeatedly, producing a long chain that runs one way only. It publishes just the far end of that chain — the head — and keeps every link behind it private. Because a hash cannot be run backwards, publishing the head proves the whole chain was fixed before anyone made a request, without revealing any of it.

A roll then mixes two ingredients. One is the next unrevealed link of that chain. The other is the hash of an Ethereum L1 block two blocks in the future — a block that provably did not exist when you paid. Both are needed, and no single party holds both.

Who can cheat, and why they cannot

PartyWhat they would needWhy they fail
You, the player To compute the word before deciding whether to pay. The preimage is secret and the seed block has not been produced. Neither ingredient exists at the moment you sign.
The sequencer To pick a favourable seed block hash. It produces the block, but it does not know the operator's preimage, so it cannot tell a favourable block from an unfavourable one.
The operator To pick a favourable preimage after seeing the request. Its preimage was fixed before the request was written, and it did not know the seed block's hash when it committed. It has one link and no choice about which.

The operator's only remaining power, and how it is removed

Everything above still leaves the operator one lever: it can refuse to reveal. It cannot steer an outcome, but it could sit on one it dislikes. So the beacon removes that too. 64 L1 blocks past the seed block — about thirteen minutes — anyone may call settleStalled(requestId). That derives the word from the seed block hash alone, without the operator's chain, and pays the caller 0.001 ETH out of the operator's bond.

The bond currently standing behind that promise is ····, and it can only be withdrawn after a seven-day notice period, so collateral cannot be pulled in the same block withholding starts. The bond does not secure fairness — the construction already does that — it secures liveness, which is the only thing left to secure.

A detail that breaks naive tooling

Inside the EVM on this chain, block.number returns the Ethereum L1 height, not the L2 height. A seed block of ···· is an L1 number; eth_blockNumber over RPC currently returns ····, which is the L2 height and roughly nine times larger. Comparing a beacon seedBlock against the RPC head will tell you every roll is ready. Read the L1 height from the l1BlockNumber field of a block object instead — which is exactly where the number above came from.

Why this is a fork, not a clone

The 2021 original resolved every roll — faction, traits, theft — inside the transaction that paid for it, from a seed built out of tx.origin, the previous block hash, the timestamp and the mint counter. On Ethereum in 2021 that was weak. On this chain it is not a weakness, it is an open door: the previous block hash is frozen for about fifteen seconds, state-override eth_call is enabled, and the entire batch outcome can be read for free before paying. Anyone who bothered to simulate would take every good roll and skip every bad one.

So the seed had to move. Once it moved into a later block, the transaction had to split, and once the transaction split, the reveal had to be permissionless. Everything else in this fork follows from that one forced change. The rarity and alias tables are transcribed verbatim, so the intended curve is preserved exactly.

Six other defects came with the original code and were fixed rather than inherited. Each has a regression test in the repository whose only job is to fail if it ever comes back.

#Inherited defectEffectFix
1 Uniqueness key omitted a trait structToHash packed nine of the ten fields, leaving nose out. Two tokens differing only in nose collided as duplicates, and the key space was small enough to enumerate. All ten fields packed.
2 Biased alias bucket draw The bucket was uint8(seed) % length. Ten of the eighteen tables have a length that does not divide 256, so low indices were over-selected and the alias tables do not compensate. The published rarity percentages were never the ones the tables encoded. A full 256-bit word per trait. Residual bias near 2⁻²⁴⁸.
3 Off-by-one-bit theft roll (seed >> 245) % 10 consumes eleven bits where the comment claimed ten, giving 205 ⁄ 2048 rather than a clean tenth. The faction draw had the same shape at 6554 ⁄ 65536. Clean modulo on a fresh keccak word.
4 Best Alpha for a token that never existed An unminted id read back as an all-zero trait struct, so MAX_ALPHA − 0 returned the maximum score for something that was never minted. ownerOf is called first and reverts on an unknown id.
5 Ambiguous pack index packIndices stored the raw array index, so a Maker legitimately sitting at slot 0 was indistinguishable from one that had never been staked. Stored as index + 1, with 0 reserved for "not in the pack".
6 Silent truncation of a Maker's claim Stake.value was uint80 but held a flowPerAlpha snapshot in wei, which passes that ceiling once emission accumulates against a small staked alpha total — truncating the entire basis of a Maker's claim without reverting. Widened to a full word. The single-slot packing is lost; gas here is a rounding error.

Two further changes are design decisions rather than bug fixes, and are listed separately for that reason. Trait generation no longer recurses unboundedly against a reseed the caller can also compute — the retry is derived from the committed word and bounded at ten attempts. And the rescue path out of The Exchange is not gated on the beacon, not gated on a pause flag, and not gated on the operator being alive; the original's staking contract was paused two days after launch and thousands of NFTs are still inside it.

Questions

Why does minting take two transactions?

Because on this chain, anything decided inside the transaction you pay for can be read before you pay for it. The randomness a mint needs is produced two Ethereum L1 blocks after your commit, which is roughly twenty-four seconds. Splitting the call is the price of the outcome being genuinely unknown at the moment you sign it. If the roll resolved instantly, it would not be a roll.

What happens if I never call reveal?

Anyone else can, and probably will — revealMint is permissionless and a keeper watches for matured commits. If nobody does it within about fifty minutes, the seed block's hash falls out of the chain's 256-block window and the roll becomes unresolvable. At that point the only path is settleExpired, which mints the floor outcome — plain Retail, null traits — and refunds nothing.

Waiting is strictly worse than revealing. There is no version of abandoning a commit that gets your ETH back, and that is deliberate: a refund would make re-rolling free.

Can someone else reveal my mint, or settle my exit?

Yes, and it costs you nothing. Both settlement calls take no private input, so anybody can submit them and the result is identical regardless of who does. Tokens are minted to the address recorded at commit time and exiting NFTs return to their owner, not to the settler. A keeper pushing your reveal is doing you a favour and paying the gas for it.

Is the exit roll per token or per batch?

Per token. settleExit derives a separate word for each id in the batch, so five positions are five independent 50/50 flips. Batching saves gas; it does not correlate the outcomes in either direction.

Is this audited?

No. Not by anyone, not partially, not informally. There is a test suite in the repository, including regression tests for each of the six inherited defects and an invariant suite over the staking accounting, but a test suite is not an audit and it is not a substitute for one. Treat every contract listed on this page as unreviewed code holding worthless testnet assets — which is exactly what it is.

Is this affiliated with Wolf Game?

No. Order Flow is an unaffiliated fork of publicly available contracts. There is no connection to Wolf Game, to Subzero Labs, or to anyone who worked on the original, and no endorsement from any of them. The debt is acknowledged plainly: the game design, the rarity tables and the alias-method trait selection are theirs. The randomness beacon, the commit–reveal split and the fixes listed above are not.

Is this affiliated with Robinhood?

No. Robinhood Markets, Inc. has no involvement in, knowledge of, or responsibility for this project. It runs on a public testnet that Robinhood operates, in the same way any contract runs on any public chain. The Retail-versus-Makers framing is a comment on how order flow markets work generally, not a claim about any specific firm's conduct.

What are these tokens worth?

Nothing. Chain ···· is a testnet. The ETH is faucet ETH, the $FLOW is a test ERC-20, and none of it will be migrated to a mainnet deployment. Nothing on this page is an offer, an investment, or financial advice. Play it because the mechanism is interesting, not because you expect anything back.

Where does the art live?

In the contracts. tokenURI(id) returns a base64 data URI containing the SVG, assembled on demand by the Traits contract from trait layers stored on chain. There is no metadata server, no IPFS pin, and nothing that can go offline and take the images with it. If the chain is running, the art renders.