Users & integrators
Tokens, bonds, staking, backing, oracles, user journeys and integration rules.
Protocol guide
STONK is a treasury-backed reserve protocol for Robinhood Chain. Users exchange approved reserve assets for vested STONK through bond markets, stake STONK into the rebasing sSTONK representation, and may wrap sSTONK into the non-rebasing gSTONK governance token. New supply is constrained by conservative onchain backing.
This guide explains the protocol from a user and integrator perspective. Architecture describes contract boundaries, security documents assumptions and invariants, and the production runbook covers operation.
Protocol at a glance
Approved reserve assets
│
▼
BondDepository ───────► TRSRY custody
│ │
│ vested STONK │ Chainlink-valued backing
▼ ▼
STONK ◄──────────── backing-constrained MINTR
│
▼ stake
sSTONK ─── wrap ───► gSTONK ─── delegate ───► Governor
▲ │
│ bounded rebase ▼
Distributor ◄── permissionless keeper ─── Timelock ─── protocol controls
The frontend and keeper are clients of the protocol. Neither is trusted with custody, prices, minting, administration, or emergency authority.
Tokens
| Token | Decimals | Behavior | Primary use |
|---|---|---|---|
| STONK | 9 | fixed-balance ERC-20 | liquid protocol token and staking input |
| sSTONK | 9 | rebasing balance derived from gons | staked position that receives distributions |
| gSTONK | 18 | non-rebasing ERC20Votes wrapper | governance voting and delegation |
STONK
Only the MINTR module is the STONK vault and may call mint. Policies cannot mint freely: the Kernel must activate the policy, grant its exact module selector, and the policy must have enough per-policy mint allowance. Burning remains available to token holders through burn and approved spenders through burnFrom.
sSTONK
sSTONK represents a proportional claim on the STONK held by the staking contract. Account balances are derived from a fixed gon balance and the current gon-to-fragment conversion. A rebase changes visible balances without iterating over holders.
The index reports how much sSTONK corresponds to the indexed initial unit. Integrations must read live balances or the current index; they must not assume an sSTONK balance is static.
gSTONK
gSTONK wraps sSTONK at the current index:
gSTONK18 = sSTONK9 × 1e18 / index9
sSTONK9 = gSTONK18 × index9 / 1e18
Its balance does not rebase, but each unit unwraps into more sSTONK as the index grows. gSTONK implements ERC-20 Permit, ERC20Votes checkpoints, delegation, and an ERC-6372 timestamp clock.
Bond markets
Bond markets let the protocol acquire reserve assets without borrowing. A market defines its quote token, STONK capacity, per-deposit maximum payout, start and floor price, daily decay, purchase bump, vesting duration, and conclusion time.
Price behavior
The market price decays linearly with time toward its configured floor. Each purchase bumps the price by a configured basis-point amount proportional to payout. This creates a feedback loop: waiting can improve the offered price, while demand moves it upward.
The application presents the current bond price and discount relative to risk-adjusted backing. Users set both a maximum acceptable price and a minimum acceptable payout. A deposit reverts if either bound is violated.
Deposit flow
- The user approves the quote token to BondDepository. A third-party depositor also needs explicit approval from the note recipient.
- BondDepository checks that the market is live and the current price is within the user's maximum.
- The quote token transfers directly to TRSRY.
- The contract measures the treasury balance delta, so fee-on-transfer tokens cannot overstate the deposit.
- PRICE performs strict quote-token valuation. Invalid or stale prices fail closed.
- The payout is calculated in 9-decimal STONK units.
- The user's minimum payout, per-deposit payout, remaining capacity, and conservative backing checks are enforced against the final calculated payout.
- STONK is minted into BondDepository and a linearly vesting note is recorded for the recipient.
The deposit receives no immediate liquid STONK. The resulting note becomes claimable continuously between creation and maturity.
Redeeming notes
Anyone may call redeem(user, indexes) or redeemAll(user) for a beneficiary. Claimable STONK always transfers to the recorded user, so a third party can help execute redemption without redirecting funds. Repeated redemption pays only newly vested value.
Markets stop accepting deposits when closed, concluded, or fully sold. Closing a market freezes its current price and returns unused mint allowance.
Staking and rebases
Staking exchanges STONK for the same nominal amount of sSTONK. Unstaking returns STONK by transferring sSTONK back to the staking contract. There is no lockup in the staking contract.
Epochs are time-based. Mainnet configuration uses an 8-hour epoch. When an epoch is due, anyone may call rebase(); the keeper merely automates this public action.
For each processed epoch, Staking:
- applies the reward prepared during the preceding epoch to sSTONK;
- advances the epoch number and end time;
- asks Distributor for the next reward;
- records the actual STONK balance increase for the following epoch.
Distributor chooses the smaller of:
configured reward = total STONK supply × rate / 1,000,000
available excess = max(risk-adjusted reserves - STONK supply, 0)
Therefore a configured rate is a ceiling, not a promise. If conservative excess backing is zero, the next distribution is zero.
Each rebase() processes at most 16 epochs to keep gas bounded. Repeated calls catch up a larger backlog. Stake and triggered unstake reject a backlog larger than one call can process; untriggered unstake remains available as an exit path.
Treasury and backing
TRSRY holds the protocol reserve assets. It exposes custody and per-policy withdrawal allowances but does not decide policy. TreasuryCustodian is the withdrawal policy and enforces the backing floor after every withdrawal.
Backing is calculated from actual configured treasury balances:
grossUsd18 = tokenAmount × oraclePrice18 / 10^tokenDecimals
riskAdjustedUsd18 = grossUsd18 × (10,000 - haircutBps) / 10,000
reservesValue9 = sum(riskAdjustedUsd18) / 1e9
USDG is capped at $1. Volatile tokenized equities use a governance-configured absolute cap and haircut. If an aggregate reserve price is invalid, that asset contributes zero instead of preventing all protocol reads. Operations that require the quote asset's value, such as a bond deposit, use strict pricing and revert.
The protocol does not promise that market price equals backing per STONK. Backing is an accounting constraint, not a redemption guarantee or price peg.
Oracle validation
PRICE reads Chainlink AggregatorV3 proxies directly. It does not accept keeper-submitted or signed offchain prices.
PRICE has explicit strict and unprotected implementations. Strict StonkPrice requires the configured L2 sequencer uptime feed to report healthy operation and the recovery grace period to elapse before every successful asset read. Initial Robinhood mainnet deployment uses StonkPriceUnprotected under the documented STK-001 High-risk acceptance because no canonical feed was found. It retains every asset/feed check below but cannot detect downtime or protect the early recovery window, and reports sequencerProtectionEnabled=false.
For every read, the module verifies:
- the asset is registered and enabled;
- the feed answer is positive;
- the round is complete and belongs to the requested round;
- the timestamp is not in the future and is within the heartbeat;
- feed decimals and description still match governance-bound configuration;
- the move from the preceding completed round is within the configured maximum;
- the optional absolute cap is applied; and
- for Robinhood equity tokens,
oraclePaused()is false.
Mainnet equity configuration uses a six-hour heartbeat and pause awareness. Deposits may therefore be intentionally unavailable outside a valid source-price window. USDG uses a 24-hour heartbeat and a $1 cap.
The deployment itself creates no bond markets and uses a zero Distributor rate. Governance separately authorizes market capacity. Once a canonical sequencer feed exists, governance can install strict StonkPrice after its constructor validates and copies the current asset registry. See the accepted-risk record for the failure scenario, exposure model, and upgrade plan.
Governance
Governance power begins with staked STONK:
STONK → sSTONK → gSTONK → delegate → propose / vote
gSTONK voting power must be delegated, including self-delegation, before checkpoints count it. Governor proposals use timestamp-based delays and voting periods. Successful proposals are queued in StonkTimelock and cannot execute until the Timelock delay has elapsed.
Mainnet defaults are a one-day voting delay, five-day voting period, 4% quorum, 100 gSTONK proposal threshold, and two-day Timelock delay. Treat the deployed contracts as authoritative; governance may update supported parameters.
The guardian Safe can immediately stop minting and/or withdrawals and veto queued Timelock operations. It cannot propose, execute, administer oracles, create bond markets, withdraw treasury assets, or restart the protocol. Restart requires governance through the Timelock.
See governance for the full lifecycle and authority matrix.
User journeys
Acquire and stake
- Choose a live bond market and inspect price, discount, oracle freshness, capacity, and vesting.
- Approve and deposit the quote asset with a maximum price and minimum payout.
- Redeem vested STONK as it becomes claimable.
- Stake STONK to receive sSTONK.
- Keep sSTONK for rebasing exposure or wrap it into gSTONK for governance.
Participate in governance
- Stake STONK and wrap sSTONK into gSTONK.
- Delegate gSTONK voting power to yourself or another address.
- Review proposal targets, calldata, value transfers, description, and discussion.
- Vote during the active period.
- After a successful vote, queue the proposal in the Timelock.
- Execute only after the delay, provided the proposal has not been canceled.
Exit
- Redeem any vested bond notes.
- Unwrap gSTONK into sSTONK.
- Unstake sSTONK into STONK. Use untriggered unstake if an unusually large rebase backlog prevents the triggered path.
There is no protocol-level treasury redemption endpoint that exchanges STONK for a pro-rata basket of assets.
Integration rules
- Discover addresses from the deployment manifest for the connected chain; never hardcode a testnet or mainnet address from documentation.
- Read token decimals onchain and preserve full integer precision through transaction construction.
- Treat sSTONK balances as rebasing and gSTONK conversion output as index-dependent.
- Quote bond deposits immediately before submission and set
maxPriceUsd18explicitly. - Surface oracle freshness, pause state, market liveness, capacity, vesting, emergency state, and pending rebase epochs.
- Decode custom errors and retain transaction hashes through confirmation.
- Expect public RPC disagreement and temporary data-source unavailability; do not silently substitute an offchain price.
- Do not infer authority from a frontend button. Verify Kernel executor, Timelock roles, ROLES membership, and module activation onchain.
Contract directory
| Contract | Responsibility |
|---|---|
| Kernel | module installation/upgrades, policy lifecycle, selector permissions, executor |
| StonkAuthority | governor, guardian, policy and vault authority pointers |
| STONK | liquid token, mint restricted to MINTR vault |
| sSTONK | rebasing staked representation |
| gSTONK | non-rebasing voting wrapper |
| Staking | stake/unstake and bounded epoch processing |
| StonkMinter / MINTR | active-gated mint/burn and per-policy allowances |
| StonkTreasury / TRSRY | reserve custody and per-policy withdrawal allowances |
| StonkPrice / PRICE | asset registry and validated Chainlink valuation |
| StonkRoles / ROLES | exact bytes32 role membership |
| BondDepository | market pricing, deposits, vesting notes and redemption |
| Distributor | backing-bounded staking rewards |
| TreasuryCustodian | governed withdrawals with post-withdrawal backing floor |
| OracleAdmin | governed asset and feed registry changes |
| RolesAdmin | governed role grants and revocations |
| Emergency | guardian shutdown and governance restart |
| StonkGovernor | proposal and voting lifecycle |
| StonkTimelock | delayed execution and queued-operation cancellation |
What the protocol does not do
- It does not custody user wallets or private keys.
- It does not rely on a proprietary backend to publish prices.
- It does not guarantee a fixed APY, market price, or treasury redemption price.
- It does not let the guardian execute arbitrary protocol actions.
- It does not make the keeper privileged.
- It does not make stale tokenized-equity prices available by carrying them forward.
Sources of truth
The deployed bytecode and current onchain state are authoritative for a live deployment. In this repository, src/ defines contract behavior, config/ defines deployment inputs, script/Deploy.s.sol defines bootstrap wiring, test/ encodes invariants, and deployments/<chainId>.json identifies deployed instances. Documentation explains those sources but cannot supersede them.