Yieldback runs only on Robinhood Chain (chain ID 4663). There is no Yieldback token custody contract and no balance database: a user's Yieldback balance is their position in the Steakhouse USDG vault on Morpho, held in their own wallet. The server adds the parts that can't live onchain yet — reward verification, goals and preferences — behind Sign-In With Ethereum.
Data sources
| Data | Source | Freshness |
|---|---|---|
| Your balance, deposits, withdrawals | Steakhouse USDG vault events and balanceOf / previewRedeem on Robinhood Chain | Every request |
| Wallet USDG and ETH | Robinhood Chain RPC, read in your browser | Every 20 s |
| Strategy rate and unlent cash | Morpho public API (the rate is computed from recent interest accrual) | 60 s |
| Strategy fees and total assets | Vault contract on Robinhood Chain | 30 s |
| Stock Token addresses and prices | api.robinhood.com/rhj (Robinhood's Stock Token APIs) | Registry 10 min · prices 15 s |
| Swap routes | LI.FI routing API, restricted to Robinhood Chain → Robinhood Chain | Re-quoted before every signature |
| Token launch state | Pons V2 factory, bonding curve and Uniswap v4 pool manager | 10 s |
| Reward claims, goals, preferences | Yieldback server, tied to a Sign-In With Ethereum session | Live |
Accounting
The position is rebuilt from the vault's Deposit (by onBehalf), Withdraw (by onBehalf) and share Transfer events, scanned in windows the public RPC accepts. Average cost is used, in USDG base units:
money in (s shares, a assets): shares += s; cost += a
money out (s shares, a assets): out = cost × s / shares
realized += a − out; cost −= out
unrealized = previewRedeem(balanceOf(user)) − cost
earnings = realized + unrealized
balance = added by you + rewards credited + other deposits
+ shares received − withdrawn − shares sent + earningsDeposits made by the configured reward treasury are classified as rewards, never as earnings. Share transfers are valued at today's share price because the public RPC doesn't serve historical state; the app flags this whenever it happens. If the event history doesn't reproduce the onchain share balance, the app says so instead of showing a confident number.
Reward verification
A claim is a transaction hash plus a signed-in wallet. The verifier:
- refuses hashes already claimed (by anyone) — checked again inside the write lock;
- loads the receipt; missing means pending or not found, reverted means rejected;
- looks for a USDG Transfer from the claimant to an enrolled merchant's payout address;
- waits until the block is at or below Robinhood Chain's “safe” head (posted to Ethereum);
- calculates reward = amount × rate, rounded down, and marks it calculated;
- later, scans for merchant → customer USDG transfers and applies them as refunds, oldest purchase first, adjusting or reversing the reward;
- marks a reward credited only after a treasury vault deposit for that wallet, of at least that amount, is verified — each deposit backs one reward.
Integration boundaries
Missing pieces are isolated behind interfaces, so connecting them doesn't touch the rest of the app.
- PurchaseVerifier
Today: Onchain USDG payments on Robinhood Chain
Next: A card-linked offers provider implementing verify(): purchase evidence in, verified/pending/rejected out.
- Merchant registry
Today: Empty — configured with YIELDBACK_MERCHANTS
Next: Real merchant agreements: payout address and reward rate per merchant.
- Reward crediting
Today: Not funded — NEXT_PUBLIC_REWARD_TREASURY_ADDRESS unset
Next: A treasury deposits each reward into the vault on the user's behalf; /api/admin/credits confirms it onchain.
- Strategy
Today: Steakhouse USDG (Morpho Vault V2, ERC-4626)
Next: Any other ERC-4626 vault on Robinhood Chain can be added behind the same read/deposit/withdraw calls.
- Swap provider
Today: LI.FI quotes, guarded to chain 4663
Next: Direct Uniswap v4 or RFQ venues on Robinhood Chain, same quote shape.
- Storage
Today: Postgres (Neon) when DATABASE_URL is set, Redis when KV_REST_API_URL is set, otherwise a JSON file
Next: All three share one read/write interface with compare-and-set writes, so instances never overwrite each other.
API
- GET
/api/strategyStrategy snapshot: total assets, share price, fees, variable rate, unlent cash - GET
/api/position?address=Balance and full accounting rebuilt from onchain events - GET
/api/holdings?address=Stock Token balances (raw and share-adjusted) with live value - GET
/api/stocksSupported Stock Tokens from Robinhood's registry, with quotes - GET
/api/swap/quoteSame-chain swap route for USDG → Stock Token (symbol, amount, from, slippage) - GET
/api/tokenYieldback token state on Pons V2, or the pre-launch platform settings - GET
/api/capabilitiesWhat's live, limited, or not available — the source for every status label - GET/POST
/api/purchasesList or submit a payment for verification (session required) - GET/POST/PATCH
/api/goalsCreate, list and update goals; POST /api/goals/:id/contributions tags a verified deposit - GET/PUT
/api/preferencesEarnings destination, stock allocation, eligibility attestation - GET/POST
/api/auth/*nonce, verify (EIP-4361), session, logout - POST
/api/admin/creditsOperator-only: record a treasury deposit that credits a reward (verified onchain)
Run npm run verify:chain to re-check every contract address, the vault, Pons V2, the Stock Token registry and swap routing against the live network.
Configuration
RH_RPC_URL- Server RPC (e.g. a dedicated Alchemy endpoint). Defaults to the public endpoint, which is rate-limited; ordinary reads fail over to PublicNode and Pocket Network.
DATABASE_URL- Postgres connection string (set automatically by the Neon integration). Makes account data durable.
NEXT_PUBLIC_RH_RPC_URL- Browser RPC. Same default.
SESSION_SECRET- 32+ characters. Required in production for sign-in.
YIELDBACK_MERCHANTS- JSON list of enrolled merchants. Empty means no purchase earns.
NEXT_PUBLIC_REWARD_TREASURY_ADDRESS- Treasury whose vault deposits count as credited rewards.
ADMIN_TOKEN- Bearer token for the credit-recording endpoint.
NEXT_PUBLIC_YIELDBACK_TOKEN_ADDRESS- The token's address once launched on Pons V2.
NEXT_PUBLIC_SUPPORTED_STOCKS- Comma-separated Stock Token symbols (default NVDA,AAPL,AMZN).
LIFI_API_KEY- Optional, raises LI.FI rate limits.