01 What Bobber is
A coupon for patience.
Bobber is a barrier coupon line on tokenized stocks. You cast a stock token (SPY, AAPL, NVDA, TSLA, AMZN, GOOGL, META, MSFT, GLD, GME) or USDG as bait into the Reservoir, a single smart contract on Robinhood Chain. The line then waits for four NYSE closing bells. At every bell where the price is still at or above 95% of where you cast, the line earns a small coupon in USDG.
Your bait is never swapped, lent or pledged. It sits in the Reservoir and comes back whole, at any stage, with no fee. Coupons come only from USDG already in the Reservoir, and a line opens only if its worst case is set aside first.
02 A season
Four bells, four stages.




A season is four closing bells: the NYSE close, rung on chain by the observer. When you cast, the Reservoir reads the live Chainlink price of your bait: that is the cast price. The barrier is 95% of it (barrierBps, fixed for your line at the moment you cast).
At every bell the Reservoir reads the same feed again:
- Holds: price ≥ barrier. The stage pays the coupon, 0.25% of your bait value in USDG (
couponBps), or +50% more if you chummed before that bell. - Misses: price < barrier. The stage pays nothing and takes nothing. Your bait is untouched.
A bell counts for your line only once the line has soaked for at least 16 hours (minSoak, fixed for your line at the cast), and only if the Chainlink round it read was published after your cast. With the default 16 hours that means overnight: cast before about midnight ET and that day's 16:00 close counts; cast later and your season starts at the following close. A skipped bell is not a miss, it simply is not one of your four.
USDG bait grows against SPY. USDG is valued at face, so its barrier is set on SPY: a USDG line's stage holds while SPY stays at or above 95% of SPY's price at your cast.
Example · USDG
- Bait
- 1,000 USDG
- Per held bell
- 2.50 USDG
- Chummed bell
- 3.75 USDG
- Max per season
- 15.00 USDG
Four held, chummed bells: 4 × 3.75. Four held bells without chum: 10.00.
Example · AAPL
- Bait
- 3 AAPL at $341.45
- Bait value
- 1,024.36 USDG
- Barrier (95%)
- $324.38
- Per held bell
- 2.56 USDG
The contract uses the full 8-decimal Chainlink price ($341.4532), so the bait value is 1,024.36, not 1,024.35.
03 Chum
Chum the water.
chum(lineId) marks the next bell of your line. If that bell holds, it pays the coupon plus 50% (chumBonusBps, fixed for your line at the cast). If it misses, it pays nothing, like any miss.
Chumming costs only gas. It covers one bell at a time: after that bell rings you can chum the following one. You cannot chum twice for the same bell, and not after the fourth stage. The Reservoir has already reserved the chummed amount for every stage, so a chum never fails for lack of USDG.
04 Reel in & Recast
After the fourth bell.
Once four stages are counted the season is over and you choose:
- Reel in (
reelIn): your bait comes back whole, and everything the line caught is paid in USDG. Works even while casting is paused. - Recast (
recast): a new season starts at today's live price and today's terms. USDG bait compounds: the catch joins the bait instead of being sent. Stock bait pays its catch out in USDG first, then the same tokens go back in at the new price, with a new barrier.
A recast needs the Reservoir to cover the new line's worst case, just like a fresh cast, and the species must still be listed. When the Reservoir is nearly empty a recast can be refused; reel in instead: that always works.
05 Cut line
Leave any time.
cutLine(lineId) ends a line at any stage. Your bait comes back whole, whatever you caught so far is paid in USDG, and there is no fee. The stages left in the season are simply not observed.
Cut line works even while the Reservoir is paused. Nobody, not the owner and not the observer, can stop you from taking your bait back.
If a payment bounces. If a token's issuer has paused transfers or frozen your address at that moment, the Reservoir does not revert: it records the amount as owed to you (owed(token, you), event Owed) and you collect it later with claim(token). The app shows an "Owed to you" card when this happens.
06 The Reservoir
Only what is already there.
The Reservoir holds three kinds of tokens, and keeps them apart:
Every token anglers cast, tracked per token in baitLocked. It only ever leaves to the angler who cast it.
The worst case of every open line: four chummed coupons (1.5% of bait value by default), set aside at the cast in reservedUsdg.
Everything else: freeBalance(USDG), which also excludes payments owed to anglers (owedTotal). New lines, prizes and owner withdrawals can only use this.
The reserve rule. A line opens only if free USDG covers its worst case, which is then reserved until the line closes. So a coupon that is earned is always there to pay. If free USDG is short, the cast is refused (ReservoirCannotPay) instead of opening a line that might not be paid. Right now the Reservoir can take bait worth up to free USDG ÷ 1.5% at default terms.
Who can take what. The owner can withdraw and prize only from the free balance: never bait, never reserved coupons, never owed payments. Prizes carry a public reason on chain in the Prized event. stock(token, amount) is permissionless: anyone can add USDG to the Reservoir; stocked tokens are not bait and leave only as coupons, prizes or a free-balance withdrawal.

07 Prices & bells
Chainlink decides what.
Every price Bobber uses comes from the Chainlink feed of that token on Robinhood Chain, normalised to 8 decimals. The cast price is the live Chainlink price at the moment of your cast, not yesterday's close.
- The observer decides only when, never what. It calls
ringBell()once per NYSE close; the contract then reads every feed itself. The observer cannot pass in a price. - Bells are spaced at least 16 hours apart (
minBellGap), so two bells cannot be rung for one close. - Stale or paused feeds are skipped. If a feed has not updated for more than 4 days (
maxStale), or the token's issuer has paused its oracle for a corporate action such as a split (oraclePaused()), that bell records no price for it and is skipped for its lines: not a miss, not a stage. The line waits for the next bell. - Soaking. A bell counts for a line only if it rang at least 16 hours after the cast (
minSoak, snapshotted per line assoak). Earlier bells are skipped for that line the same way. - Fresh rounds only. Each bell stores the price and the time Chainlink published it (
bellObs). A bell counts for a line only if that round was published after the cast, so a line is never judged on the very price it was cast at. - Anyone can settle.
settle(lineId)processes rung bells for any open line, up to 64 per call (MAX_SCAN); call it again for more. It is optional: chum, reel in, recast and cut line settle first on their own.
| Species | Token | Chainlink feed | Price now | Updated |
|---|---|---|---|---|
| Reading feeds… | ||||
08 Contract
One contract, read it.
Live parameters
Reading…
| Parameter | Value | Meaning |
|---|
Functions
Anglers
- cast(bait, amount)
- Open a line. Needs an approve first. Paused → refused.
- chum(lineId)
- +50% on the next bell if it holds. Paused → refused.
- reelIn(lineId)
- After four stages: bait back, catch paid. Works while paused.
- recast(lineId)
- After four stages: a new season. Paused → refused.
- cutLine(lineId)
- Any stage: bait back, catch so far paid, no fee. Works while paused.
- claim(token)
- Collect a payment that bounced earlier and was kept as owed.
Anyone
- settle(lineId)
- Process rung bells for an open line.
- stock(token, amount)
- Add tokens to the Reservoir.
- quote · preview · livePrice
- Views: what a cast would look like, a line as if settled, a live price.
- freeBalance · lines · bells · bellObs · owed
- Views over everything the Reservoir holds, owes and has observed.
Observer
- ringBell()
- Snapshot every feed at a close. Spaced by
minBellGap.
Owner
- listSpecies(token, feed, index, stable)
- Stock a species. Its feed and index are fixed forever; re-listing a delisted species must repeat them exactly. Only USDG can be valued at face.
- delistSpecies(token)
- Stop new casts of a species. Open lines keep fishing and keep being observed.
- setParams(…, soak)
- Terms for new lines, within hard bounds: barrier 50–100%, coupon ≤ 5%, chum ≤ +100%, bell gap ≥ 12 hours, stale 1 hour–7 days, soak 1 hour–3 days. Open lines keep the barrier, coupon, chum and soak they were cast with.
- withdraw(token, to, amount)
- Free balance only.
- prize(to, token, amount, reason)
- Weigh-in prizes from free balance, with a public reason.
- setPaused · setOwner · setObserver
- Pause blocks cast, chum and recast only.
Events
Casta line openedChummednext bell chummedObserveda stage held or missedSkippeda bell did not countReeledreeled in or recast, with the catchLineCutline cutBellRunga close observedStockedtokens addedWithdrawnowner took free balancePrizedprize with reasonSpeciesListedParamsSetOweda payment bounced, kept for claimClaimedowed payment collectedSpeciesDelistedPausedSetOwnerSetObserverSet
Errors, in plain words
| Error | What it means |
|---|
09 Risks
Read this first.
- Your bait moves with the market. A tokenized stock can fall far below the barrier. Bobber returns the same number of tokens you cast, not their value at cast time.
- The issuer can act on the token. If an issuer burns or seizes stock tokens held by the Reservoir, so it holds less than is locked for anglers, each angler of that stock gets back a pro-rata share instead of the whole bait. If transfers are paused or your address is frozen, payments wait as owed until you claim them.
- Coupons exist only while the Reservoir is stocked. There is no promised rate. When free USDG runs low, new lines are refused; open lines keep their reserved coupons.
- Casting can be paused (by the owner key), but nothing can block cut line or reel in. If the observer stops ringing bells, your line simply waits; you can always cut it and take the bait back.
- Owner powers are bounded but real. The owner sets terms for new lines within hard limits, lists and delists species, and can lower the bell spacing to 12 hours. A species' feed can never be changed. Open lines keep the barrier, coupon, chum and soak they were cast with.
- Oracles can fail. A stale or paused Chainlink feed skips bells; a wrong feed price would be read as is.
- Unaudited smart contract. Bugs are possible. Only cast what you can afford to have stuck or lost.
- Non-US persons only. Tokenized stocks on Robinhood Chain are not offered to US persons. Check the rules where you live.
- Not investment advice. Bobber is software. It is not a bank, broker or adviser.
10 Glossary
Words on the dock.
- Angler
- Anyone with a line in the water.
- Bait
- The stock token or USDG you cast. Returned whole.
- Bait value
- Bait × cast price, in USDG. Coupons are a share of it.
- Barrier
- 95% of the cast price. At or above it, a stage holds.
- Bell
- An NYSE close observed on chain.
- Cast
- Opening a line.
- Catch
- USDG a line has earned so far (
accrued). - Chum
- +50% on the next bell if it holds.
- Coupon
- 0.25% of bait value, paid for each stage that holds.
- Cut line
- Leaving early, no fee.
- Observer
- The key that rings bells. Chooses when, never what.
- Recast
- Starting a new season with the same bait.
- Reel in
- Ending a full season: bait back, catch paid.
- Reservoir
- The contract holding bait and USDG.
- Season
- Four counted bells: Ripple, Nibble, Bite, Hooked.
- Owed
- A payment that could not be delivered, kept for you until you
claimit. - Soak
- How long a line must be in the water before a bell can count for it: 16 hours by default, so overnight.
- Weigh-in
- The leaderboard, computed from on-chain lines.