Cusp
Deposit into a vault, hold a plain ERC-20, redeem at the price the contract computes. Cusp also prints the thing every other vault rounds away: the staircase between what you paid and what you were issued.
| Deposited | 1 USDG |
| Shares minted | 1,000,000,000,000 |
| Redeemed back | 1 USDG |
| Read at | block 55,463,157 |
Not a mock-up. Every byte of that came from js/vault.js — the module this site's app imports — executed against real USDG on Robinhood Chain the last time this page was built.
The problem
A share price is quoted as a number. The contract uses a staircase.
Between the assets you send and the shares you are issued sits one integer division, and it has a floor. A whole interval of deposit sizes mints exactly the same number of shares, and you pay for the top of the step. Every vault in this category has one. None of them will tell you how wide it is.
What the page says
One share is worth totalAssets / totalSupply
- Printed to four decimals, as though the price were a real number.
- Silent about the smallest deposit that mints anything at all.
- Silent about the parameter that sets the width — which is not the one you would guess.
What the contract does
Shares are the floor of that, always
- step() returns the exact interval you are standing on, and a property deposits at both ends to prove it.
- dust() returns the largest deposit that mints nothing. A property sends exactly that and counts zero back.
- The app shows you both before you sign.
Measured on Robinhood Chain
Seed a vault with a thousandth of a token and the grid never recovers
The same vault, the same 1000 USDG in it, one constructor argument apart. The dead zone is the largest deposit that is accepted, transfers your money in, and issues you nothing.
USDG is the most-transferred contract on this chain — 74,029 transfers in the sampled windows — and it has 6 decimals. How that was measured →
Two locks, one door
The attack everyone hardens against is already closed by the accounting
The virtual offset is sold as protection against the ERC-4626 inflation attack. So we ran the attack, four times, on this chain's own EVM: assets tracked in storage or read from the token balance, crossed with the offset off and on. The attacker takes the first share for one wei, donates, and the victim deposits after.
| Accounting | Virtual offset | Victim keeps | Verdict |
|---|---|---|---|
| Tracked in storage | 0 | 100.0000% | defended |
| Tracked in storage | 6 | 100.0000% | defended |
| Read from balanceOf | 0 | 0.0000% | wiped out |
| Read from balanceOf | 6 | 99.9999% | defended |
Either defence alone is enough. Tracking assets in storage closes the attack with the offset switched off entirely — 100.0000% recovered — which is what the fourth property asserts. So the offset is a second lock on a door that is already shut, and its measurable effect is somewhere else entirely: it is what keeps the staircase above from being a cliff. The four runs, and the contract they ran →
What Cusp is
A vault, its token, and the arithmetic underneath both
The vault
An ERC-4626 vault over any ERC-20 on Robinhood Chain. Assets are tracked in storage, so a stray transfer moves nobody's price. The protocol cut applies to harvested income only and is capped by a constant.
- 24 properties executed on this chain, not asserted
- 11 deliberate defects, each one confirmed caught
- The owner has no path to principal
The fold
Three view functions no other vault exposes. dust() is the largest deposit that mints nothing, step() is the exact interval you are standing on, and foldLoss() is what it costs you.
- Exact, not estimated — proved by real deposits at both ends
- Shown in the app before you sign
- 18 rows measured, 8 of them re-executed on chain
Your keys, your deploy
The app deploys the vault from your own address. Every write is an ordinary signed transaction, simulated from your address first. There is no key, no relayer and no backend anywhere in this repository.
- No API key and no proxy — the public node allows the browser directly
- 14 checks of the app's own calldata against real USDG and WETH
- 7,961 bytes of creation code, from the compile that proved it
Markets
Any ERC-20 on this chain, and these are the ones being used
Discovered by counting 293,800 transfers across 4,167 contracts, not from a list. Decimals are read from each token, because decimals is what decides how small a first deposit can be — and therefore how coarse a grid it can leave behind.
How it works
Four calls, and you can read every one
Deploy
Pick an asset and an offset. The app builds the creation code, predicts the address, and your wallet signs. The vault is yours; you are its owner.
Approve and deposit
Before the deposit is signed, the app reads step() from your vault and shows you the interval your amount lands on, and what the top of it costs.
Hold the share
You get an ordinary ERC-20 back. It transfers like any token, and harvested income raises what every share redeems for.
Redeem
Burn shares, take the underlying at the current price. No lockup, no queue, no epoch, and rounding that never favours the vault by more than the wei it is owed.
What the contract guarantees
24 properties, executed rather than claimed
Each one runs on Robinhood Chain's own EVM through an eth_call state override, on every build, at block 55,462,976. Then the contract is broken 11 ways and each defect has to be caught — 10 by a property, and 1 by nothing but a mechanical read of the compiled ABI.
The fold is exact
P18 sends exactly dust() and requires zero shares back, then one wei more and requires exactly one. P19 deposits at both ends of step() and one wei outside each.
Rounding never favours the holder
P2 checks eight sizes from one wei up. A vault that rounds the other way is a slow drain on everybody already in it, and it is invisible per trade.
Nothing reaches the principal
P12 asks collect for one wei more than has accrued and requires a revert. The added-rescue() sabotage breaks no property at all — only the ABI surface check sees it.
A stray transfer moves no price
P3 sends 900 tokens straight to the vault and requires the share price not to move by one wei. Assets are tracked, never read from the balance.
FAQ