Savings vault · Robinhood Chain

Every payout becomes more of the same coin.

Deposit a coin that pays its holders. Each payout is sold for more of that same coin and released into your share over six hours. When you leave, you redeem the same coin, at the current rate.

Deposit a coin that pays its holders. Each payout is sold for more of that same coin and released into your share over six hours.

the stash goes up only

That is the share rate: coin per share. It never falls, and it rises when a harvest vests. The coin's own price can still fall, all the way to zero.

10%
of each payout, never your principaldefaultcap 30%
6h
to release each harvest, in a straight linedefault10 min–7 days
30min
pool average every swap is checked againstdefault10 min–2 h
72h
longest redemption pause, admin onlythen no newpause for 72 h
Share rate · coin per share test run
USDG
per share

fully vested6 h after the harvest

Share rate in the replay: 1.000000000 at the deposit and at the instant of the harvest, 1.247451118 once the harvest has fully vested six hours later.

Replay of a test run on a local fork · 10,000 USDG in, 1 WETH harvested · test sizes, not a yield forecast

local anvil fork · 22 Sep 2026 · nothing broadcast · 6 h in 24 s

Illustration not to scalethe pawl lets the wheel turn one way only

reading the chain…

Robinhood Chain · read from your browser

L2 block

—

eth_blockNumber blocks/s: measuring
WETH in USDG

—

0.01% pool · slot0() · this visit · 0 reads
Gas price

—gwei

eth_gasPrice · paid in ETH
Chain id

—

eth_chainId
STASH factory

—

reading config…

Why this exists

A coin that pays you also hands you a chore.

Some coins pay their holders: trading fees, ETH, a stablecoin, a stock token. What happens next is up to you, and neither usual answer is a good one.

STASH does one thing with the payout, the same way every time: it turns it into more of the coin you deposited. Your number of shares never changes. Each share just holds more coin.

Option one

Claim and sell it yourself

Claim, approve, swap, buy back. Every round costs gas, a swap fee and your attention, and every round you skip, the pay just sits there.

Per payout
a claim, an approval, a swap and gas, done by you

Option two

Let it pile up

The payouts collect in a token you never chose to hold. Your position in the coin you actually picked stays exactly the same size.

Per payout
nothing to do, and nothing compounds

What STASH does

Put it in the stash

A keeper sells each payout for more of your coin and adds it to the vault. It reaches your share rate over six hours. You don't lift a finger.

Per payout
nothing to do · 10% of the payout (default) goes to the treasury, principal never

How it works

Four calls, and none of them asks you to watch a clock.

You deposit and you redeem. In between, the keeper harvests on its own and the gain arrives in a straight line over six hours. At the instant of a harvest the rate does not move at all, so there is no moment worth being early for.

coinpayoutbecomes rate
redeem · the same coin back deposit mint sCOIN vest into the rate sold for more coin harvest() more of the same coin fee · to the treasury COIN the coin you hold STASH VAULT locked gain forward only sCOIN your share share rate · never falls SWAP Uniswap v3 · TWAP floor PAYOUTS fees · ETH · stables · stock tokens KEEPER the only caller redeem · same coin back deposit mint vest more coin harvest() COIN STASH VAULT locked forward only sCOIN share rate SWAP TWAP floor PAYOUTS KEEPER
coin the vault counts arrived, still locked coin per share: the rate Illustration not to scale
01 deposit
02 harvest
03 vest
04 redeem

Deposits and redemptions change how much coin the vault holds, not how much coin one share holds.

diagram · the arrows are the four calls below; green is the part that becomes share rate

  1. 01anyone

    Deposit

    Send the coin, get sCOIN. Shares are minted on what actually arrived, so a coin with a transfer tax is counted honestly, and the call reverts rather than mint you fewer shares than you asked for.

    deposit(uint256 assets, address receiver, uint256 minSharesOut)selector 0xbc157ac1

    Shares carry 3 more decimals than the coin · coins under 4 decimals are refused · 1,000 virtual shares

  2. 02keeper only

    Harvest

    The keeper sells the payout for more of the coin on Uniswap v3. The fee comes off the payout first. A swap below the price floor reverts the whole harvest, and with no price history there is no harvest at all.

    harvest(uint256 minAssetsOut)selector 0xddc63262

    Fee 10% of the payout by default, capped at 30% · floor = 30-min pool average − pool fee − 1% (defaults; window 10 min – 2 h, tolerance ≤ 10%) · at most one harvest per 2 min by default (floor 60 s, never above the vesting window)

  3. 03automatic

    Vest

    The new coin is locked, then released into the rate in a straight line. At the instant of the harvest the rate does not move at all, so there is no moment worth standing in front of.

    lockedProfitRemaining()selector 0x0dc3f9cd · view

    6 h by default, settable from 10 min to 7 days · a lock already running keeps its own end date

  4. 04anyone

    Redeem

    Burn sCOIN, get the same coin back at the current rate. No exit fee, no queue. Set a minimum and the call reverts instead of paying you less.

    redeem(uint256 shares, address receiver, address owner, uint256 minAssetsOut)selector 0x9f40a7b3

    Redeem pause: admin only, 72 h at most, then no new pause for 72 h · the guardian can never pause it

exchangeRateRay() = 1000 × 1e27 × (totalAssets() + 1) ÷ (totalSupply() + 1000) starts at exactly 1e27 · totalAssets() excludes the part still vesting

The share rate

One number, read from the chain.

The share rate is how much coin one share is worth. It starts at exactly 1.000000000 when a vault opens, never falls, and rises when a harvest vests. The number below is read from vault #1 by your browser; until a vault exists, it says so.

exchangeRateRay() ÷ 1e27 · vault #1 reading the chain…
1.000000000

coin per share · 9 decimals · never lower than the last reading

What moves the share rate
What happensCoin in the vaultShare rate
You deposit↑more=unchanged
A harvest lands↑more, locked=unchanged at that instant
The harvest vests↑counted as it vests↑rises in a straight line
You redeem↓less=unchanged
The coin's price falls=same amount=unchanged

Rounding always goes in the vault's favour, so a deposit or a redemption can never lower the rate. The rate counts coin, not dollars: a falling price is yours to carry.

Vesting explorer · one harvest, second by second

The coin arrives at once. The rate takes six hours.

At the harvest the vault's balance and its lock rise by the same amount, so the rate does not move. Then the lock runs down in a straight line and every second of it reaches the rate. Drag the time.

10,000 11,000 12,000 in the vault · rawAssets() counted · totalAssets()
6 h 00 min · fully vested
counted by the rateheld by the vaultreleased so farstill lockedUSDG · time since the harvest
Share rateexchangeRateRay() ÷ 1e27
1.247451118
CountedtotalAssets()
12,474.511185
Still lockedlockedProfitRemaining()
0.000000
In the vaultrawAssets()
12,474.511185
SharestotalSupply() · sUSDG
10,000.000000000

Replay of a test run on a local fork · 10,000 USDG in, 1 WETH harvested · test sizes, not a yield forecast

local anvil fork · 22 Sep 2026 · nothing broadcast · each value is the contract's own maths at that second

Why it vests

One instant used to be worth 99% of a harvest.

When a whole harvest lands in one instant, whoever holds the most shares at that instant collects most of it, and the keeper chooses the instant. So nothing lands at once: the gain is locked and released in a straight line over six hours, and a share earns only for the time it is actually held.

The keeper's twelve seconds after its own harvest now earn twelve seconds' worth of a six-hour release.

The test scenario A holder has 1,000,000 USDG in the vault. The keeper deposits 99,000,000 twelve seconds before its own harvest and redeems twelve seconds after it.

Before: the harvest landed in one instant

pre-fix

20,493of 20,700 to the keeper · 99%

keeper took 20,493holder kept 207

measured on the pre-fix contract (one-instant harvest), unit-test replay

After: the gain vests over six hours

today

11.38of 20,700 to the keeper · 0.055%

keeper's take: 11.38the rest vests into the rate

unit test, test/unit/Vesting.t.sol

Where the keeper's 24 seconds fallIllustration not to scale

One instant pre-fix

keeper in · out the whole step lands inside the window

Six-hour line today

keeper in · out 12 s of a 6 h line lands inside it

12 s before the harvestharvest12 s after6 h later

Safeguards

What the contract enforces, with the numbers it enforces.

Every figure here is a constant or a default in the contract source. Where the admin can change a setting, the limit it cannot pass is printed next to it.

10%

A fee on the payout only

10% of each payout goes to the treasury by default. The code caps it at 30%. It is never taken from principal.

DEFAULT_FEE_BPS 1_000 · MAX_FEE_BPS 3_000

6h

Every gain vests

Each harvest is released in a straight line over 6 hours by default, settable from 10 minutes to 7 days. A lock already running keeps its own end date.

DEFAULT_VESTING_PERIOD 6 hours · MIN 10 minutes · MAX 7 days

30min

Every swap is price-checked

The swap must clear the pool's 30-minute average price, minus the pool fee, minus 1% (defaults; window 10 minutes to 2 hours, tolerance at most 10%). The keeper can only make the floor stricter. No price history, no harvest.

DEFAULT_TWAP_WINDOW 30 minutes · DEFAULT_MAX_SLIPPAGE_BPS 100 · SLIPPAGE_CAP_BPS 1_000

2min

Harvests are throttled

At most one harvest per 2 minutes by default. The floor is 60 seconds, and the interval can never be longer than the vesting window.

DEFAULT_HARVEST_INTERVAL 120 · MIN_HARVEST_INTERVAL 60

72h

A redemption pause is capped

Only the admin can pause redemption, for at most 72 hours, and then cannot pause it again for 72 hours. The guardian can pause deposits and harvests, never redemption.

MAX_REDEEM_PAUSE 72 hours · REDEEM_PAUSE_COOLDOWN 72 hours

4roles

Four addresses at creation

The factory refuses to create a vault unless admin, guardian, treasury and keeper are four different non-zero addresses. After that the admin can reassign the guardian, treasury and keeper; only non-zero is checked.

createVault → DuplicateRole · setGuardian / setTreasury / setKeeper

1,000

Virtual shares against inflation

1,000 virtual shares, and a minSharesOut on every deposit. A donation attack never paid the attacker in a 256-run fuzz; a deposit that would mint too little reverts instead. Every vault is seeded before it opens.

VIRTUAL_SHARES 1_000 · SlippageShares(got, wanted)

4dp

Coarse coins are refused

A coin with fewer than 4 decimals cannot get a vault, and every share carries 3 more decimals than its coin.

MIN_ASSET_DECIMALS 4 · DECIMALS_OFFSET 3

0

Nothing left open

No mint, no blacklist, no transfer hook, no tax setter, no proxy. The coin, reward, router and fee tier are fixed at creation. The router's allowance is reset to 0 after every harvest, and the rescue function cannot move the coin or the reward.

immutable asset · reward · router · poolFee · CannotRescueCore

Listing rules

A vault opens only when its yield is real.

Source A · the creator signs

The coin's creator points its fee recipient at the vault and signs that change themselves. The transaction goes on Proof.

Source B · twenty real payouts

A vault-shaped test account has to receive 20 payouts from the coin first. Twenty hashes, all on Proof, before any deposit is taken.

Buybacks don't qualify. A buyback pays no holder, so there is no payout for a vault to receive.

No dead coins. A vault needs payouts that keep arriving and a pool to sell them into; the factory refuses a pair with no pool.

Source B · what it asks for Illustration the rule, not a vault

20 / 20 payouts

Each square is one payout the coin sends to the test account, each with its own transaction hash. Twenty in a row show the yield is real and repeating, not a one-off.

Vaults

Vaults, straight from the chain.

Reading config/addresses.json…

Reading the vault list…

launch checklist · derived from config/addresses.json
  1. Factory deployed—
  2. Vault #1 created—
  3. Yield source signed—

Built to be checked

If it's not a hash, it's not a claim.

Every contract claim on this site is either a constant you can read in the source, a test you can run, or a transaction you can open. The chain checks on Proof run in your own browser.

tests · as of 23 Sep 2026all green
$ forge test --no-match-path 'test/fork/*'
Ran 16 test suites in 1.81s (20.34s CPU time): 318 tests passed, 0 failed, 0 skipped (318 total tests)
318
offline tests in 16 suites
4
tests against live chain state
256
fuzz runs per property
tests per suite · 16 suites318 offline + 4 live-state
Price floor under attack

A 1,500 WETH dump could not move the floor.

2,477.780.9 WETH quote before
2,369.67after a same-block dump
2,450.62floor, unchanged · harvest reverted

fork test against live state, 22 Sep 2026

Proof

Chain checks, run in your browser

Chain id, contract code, router wiring. Every row turns into a value read from the chain.

Security

The review, and what it found

The findings, the inflation table and what is still not protected.

Questions

Straight answers.

Including the ones that are not good news.

Does the coin's price go up?

No. The share rate goes up: how much coin one share is worth. The coin itself can fall, all the way to zero, and your share then holds more of a coin that is worth less. STASH does nothing about the price.

Can I lose money?

Yes. In dollars, whenever the coin falls. In coin, your principal can only be lost through a bug in the contracts, and there is no external audit yet.

The keeper can sell a harvest at the edge of the price floor (about 1% plus the pool fee below the 30-minute average, by default). That costs part of that harvest's gain, never principal.

What does it cost?

10% of each payout by default, taken before the swap and sent to the treasury. The code caps it at 30%. There is no deposit fee, no exit fee and no fee on principal. You pay gas in ETH for your own deposit and redeem; the keeper pays the gas for harvests.

Can I always get out?

You can redeem at any time at the current rate: no exit fee, no queue. The one exception is a redemption pause. Only the admin can set one, it lasts 72 hours at most, and after it the admin cannot pause again for 72 hours. The guardian can never pause redemption.

Who can pause what?

The guardian or the admin can pause deposits, and can pause harvests. Only the admin can pause redemption, within the 72-hour limit above. Nobody can pause the share rate: it never moves down, and it rises when a harvest vests.

Why is there no mint() or withdraw()?

With a coin that charges a transfer tax, the amount that actually arrives is only known after the transfer, so a call that promises an exact amount out would be a lie. deposit and redeem, each with a minimum you set, are the honest pair. This is a deliberate departure from ERC-4626, written into the contract.

Is there a STASH token?

No token and no presale. What you receive is a share of one vault, named s plus the coin's ticker (sUSDG for USDG), and it is redeemable for that coin. A token trading under the name STASH is not issued by this project.

Which chain, and which gas token?

Robinhood Chain, chain id 4663. Gas is paid in ETH. The strip at the top of this page reads the chain id straight from the RPC in your browser.

What if the keeper disappears?

Then nothing is harvested: payouts wait in the vault as they are and the rate stays where it is. Your redeem does not depend on the keeper and keeps working. The admin can appoint a new keeper.

Is it audited?

No external audit yet. The contracts went through an internal adversarial review in two passes, and as of 23 Sep 2026 they pass 318 offline tests in 16 suites plus 4 tests against live chain state. Security has the findings; Proof has the checks.

More of the same coin.

One share. A rate that never falls.

Reading config/addresses.json…