How SHADE works.
Everything about the protocol, in plain terms: what happens to your deposit, how prices are set, who sells to the pools, the limits that protect depositors, the contracts, and the $SHADE token.
Overview
SHADE is a set of pools on Robinhood Chain that buy tokenized stocks a shade under the market price, automatically, on behalf of the people who fund them.
- 1You deposit USDG into a pool for one asset — SPY, QQQ or NVDA.
- 2While it waits, most of your USDG earns yield in an on-chain lending market.
- 3The pool shows a permanent bid below the market price: about 3% during US market hours, 8% when Wall Street is closed.
- 4Anyone who needs to sell that asset fast can sell it to the pool, in one transaction, no signup.
- 5The shares bought are credited to depositors instantly, pro-rata, at that same discounted price.
Sellers pay the discount because it is cheaper than their alternative — slippage on a thin DEX, a liquidation that can't wait, a market that's closed. Depositors collect it. There is nothing to run and nothing to watch: the pool is passive, and every buy is public.
The test version
SHADE is currently live as a test version. Every feature of the app works end to end with your own wallet, but nothing is sent on-chain and no real funds are involved.
How it works
- The test environment runs an exact TypeScript replica of
ShadeVault.sol: same constants, same accounting, same revert messages. What you see here is what the contracts do. - Each action — faucet, deposit, withdraw, cap, mode, sale — asks your wallet for a signature instead of a transaction. Signing is free, costs no gas, works on any network, and can't move funds. The hash of your signature is the action's receipt, shown in your activity and on the Buys page.
- Balances are test USDG and test Stock Tokens from built-in faucets (10,000 USDG and 10 shares per claim). Prices follow a simulated feed around a fixed reference, with small per-minute moves.
- State lives in your browser and is shared across wallets there — connect a second wallet to act as a seller against your own deposits. Clearing site data resets it; so does the reset button.
- A test console lets you move the simulated price and fast-forward the clock, so yield, Auto-sell and the circuit breaker can be seen in minutes rather than days.
- A simulated keeper executes Auto-sell as soon as a position becomes eligible, the way a keeper network will against the live contracts.
Quickstart
From zero to your first discounted buy in about two minutes:
- 1Open the app and connect any wallet.
- 2Pick a pool and claim 10,000 test USDG from the Deposit panel.
- 3Deposit — say 5,000 USDG. 20% stays liquid to fund buys, 80% starts earning yield.
- 4In Sell to the pool, claim 10 test shares, then sell a small amount (use MAX to see what the pool can absorb right now).
- 5Look at Your position: the shares are yours, at an entry price below market. The sale appears on the Buys page and in Analytics.
- 6Use the test console: fast-forward 30 days to see yield accrue; switch to Auto-sell and move the price to watch the keeper take profit; withdraw whenever you want.
Depositing
A deposit sends USDG into one pool and opens (or tops up) your position there. No signup, no lockup, no minimum. Each pool is independent: a position in SPY is separate from one in NVDA.
| On deposit | 20% of the amount stays in the pool as the liquidity reserve; 80% goes to the yield strategy. |
| Your position | Tracks your own USDG balance, the shares bought for you, your average entry price, your cap and your mode. |
| Default settings | Cap 100%, mode Hold. Change both at any time. |
| Position shares | Accounting units for withdrawals (1 USDG deposited = 1e12 units). They are not a token and can't be transferred. |
Positions are tracked per depositor rather than as one pooled token. That is what makes a personal cap and mode possible: two depositors in the same pool can hold different amounts of the stock.
Pricing & discount
market price = min(Chainlink price, DEX TWAP)
buy price = market price × (1 − discount)Two independent sources, and the lower one wins. If one feed is briefly wrong or manipulated upward, the other one caps the price — the pool never pays above either.
| Market state | Discount |
|---|---|
| US market open (Mon–Fri, 13:30–20:00 UTC) | 3% |
| US market closed (nights, weekends) | 8% |
| Hard ceiling in the contract | 10% — no parameter change can exceed it |
The discount is wider when Wall Street is closed: there is no fresh trading to confirm the price, so the pool asks for a larger margin of safety. Market hours are a simplified UTC window; they don't account for daylight saving time or exchange holidays.
How a buy works
A buy is a single call, sellToPool(rwaAmount), open to anyone. In that one transaction the contract:
- 1Reads the market price and rolls the daily window if it's a new UTC day.
- 2Checks the circuit breaker, the pool's liquid USDG and the daily cap.
- 3Computes the buy price and the USDG owed: amount × buy price.
- 4Allocates the shares across depositors, pro-rata to each one's remaining cap headroom.
- 5Pulls the shares from the seller and pays them USDG.
- 6Emits
Bought(seller, rwaAmount, usdgPaid, discountBps, marketPrice)— the public record behind the Buys page.
Allocation
Each depositor's headroom is how much more of their position may become stock under their cap, limited by the USDG they have left. The purchase is split in proportion to headroom, and everyone pays the same clearing price.
If depositors' combined headroom can't cover the sale, it reverts. The pool never buys more than depositors have agreed to hold.
Cap & modes
Cap
Your cap is the maximum share of your position's value that can be held as stock, from 0% to 100%. At 50%, a $10,000 position can hold at most $5,000 of shares; the rest always stays in USDG. At 0%, your deposit only earns yield and never buys.
Modes
| Hold | Shares bought for you stay as shares until you withdraw. You get the stock, at a discount, and decide when to exit. |
| Auto-sell | Once the oracle price is above your average entry price, your shares can be converted back to USDG at that oracle price — locking in the difference. |
Auto-sell is executed by triggerAutoSell(depositor), which anyone can call once the condition holds. The caller supplies the USDG at the oracle price and receives the shares — a fair-value swap, not a dump on a DEX. A non-custodial contract can't schedule itself, so "automatic" means a keeper calls it; in the test version a simulated keeper does this immediately.
Because the pool buys below market, a position is often above its entry price right after a buy. In Auto-sell mode that means the discount can be realised quickly, turning SHADE into a yield-plus-discount strategy rather than a way to accumulate stock.
Yield & reserve
80% of each deposit is placed in a yield strategy — an on-chain lending market such as Morpho in production. The other 20% stays in the pool as the liquidity reserve, never invested, so the pool can always pay a seller on the spot.
Yield is credited to depositors in proportion to their USDG balance, using a per-share accumulator: it settles into your balance automatically the next time your position is touched, and the app shows the unsettled amount in real time. The test version uses a fixed 4% APR strategy.
Shares held don't earn lending yield — only USDG does. Buys spend USDG from the reserve; the reserve refills as new deposits arrive and as Auto-sell converts shares back to USDG.
Withdrawing
withdraw(shares) is open at any time, for any part of your position. You receive your own USDG and your own shares, in proportion to the part withdrawn — exactly what is tracked for you, including settled yield.
Withdrawals are never paused, delayed or gated. If the reserve is short, the contract first pulls the difference out of the yield strategy. No owner switch can stop a withdrawal.
Limits & circuit breaker
| Guardrail | Default |
|---|---|
| Discount ceiling | 10%, hard-coded |
| Daily cap | $50,000 of purchases per pool per UTC day |
| Circuit breaker | Buying stops for the day once the price is 15% or more below the day's opening price |
| Liquidity reserve | 20% of each deposit stays liquid to fund buys |
| Your cap | Per depositor, 0–100% of your position |
| Price source | min(Chainlink, DEX TWAP) — the lower of two independent prices |
The day's opening price is recorded by the first sale of each UTC day. From then on, if the market price falls 15% below it, every further sale that day reverts with circuit breaker active. Deposits and withdrawals are never affected by any of these limits.
Who sells, and why
Selling below market only makes sense when the alternative is worse. On Robinhood Chain, it often is.
| Liquidation bots | They just seized Stock Tokens as collateral and need stablecoins immediately. Certainty and speed beat a better price later. |
| Large sellers | A size too big for a thin DEX pool can cost more in slippage than the pool's discount. SHADE takes the whole size at one price. |
| Off-hours sellers | At 3am on a Sunday there is no fresh price and little liquidity. SHADE still quotes, at a wider discount. |
| Aggregators | A router can include SHADE as one leg of a split order, taking the best price across venues. |
Rather than racing bots for liquidations, SHADE becomes the buyer those bots sell to. That removes the speed race, widens the flow to every seller in a hurry, and keeps the pool passive.
Integrate
Selling to a pool needs three calls and no registration: read the price, approve the Stock Token, call sellToPool.
import { erc20Abi, parseUnits } from "viem";
// publicClient / walletClient: your viem clients on Robinhood Chain.
const vault = "0x…"; // the pool's ShadeVault
const rwa = "0x…"; // the Stock Token it buys
const vaultAbi = [
{ type: "function", name: "buyPrice", stateMutability: "view", inputs: [], outputs: [{ type: "uint256" }] },
{ type: "function", name: "sellToPool", stateMutability: "nonpayable",
inputs: [{ name: "rwaAmount", type: "uint256" }], outputs: [] },
] as const;
const amount = parseUnits("2.5", 18);
// 1. Quote: buyPrice has 8 decimals, USDG has 6, Stock Tokens have 18.
const price = await publicClient.readContract({ address: vault, abi: vaultAbi, functionName: "buyPrice" });
const usdgOut = (amount * price) / 10n ** 20n;
// 2. Approve the vault to pull the Stock Token.
await walletClient.writeContract({ address: rwa, abi: erc20Abi, functionName: "approve", args: [vault, amount] });
// 3. Sell. USDG arrives in the same transaction.
await walletClient.writeContract({ address: vault, abi: vaultAbi, functionName: "sellToPool", args: [amount] });| Revert reason | Meaning |
|---|---|
circuit breaker active | Intraday drop of 15%+ — buying resumes next UTC day. |
daily cap reached | This sale would exceed the pool's daily cap. Sell less. |
insufficient pool liquidity | Not enough liquid USDG in the reserve for this size. |
insufficient buy capacity across depositors | Depositors' caps can't absorb this size. |
amount too small | The USDG owed rounds to zero. |
invalid feed price | A price feed returned zero or a negative value. |
sellToPool has no minimum-output argument. The price is read in the same transaction, from two feeds, and can only move within their bounds — but integrators routing large size should quote with buyPrice() in the same block, or wrap the call in a contract that checks the USDG received.Contracts
| Chain | Robinhood Chain — chain id 4663 (testnet 46630) |
| Explorer | https://robinhoodchain.blockscout.com |
| USDG | Not configured (test version) |
| SPY vault | Not deployed (test version) |
| QQQ vault | Not deployed (test version) |
| NVDA vault | Not deployed (test version) |
| $SHADE | Not launched |
ShadeVault
One vault per asset. Written in Solidity 0.8.26 with OpenZeppelin, tested with Foundry.
| Function | Who |
|---|---|
deposit(usdgAmount) | Anyone |
withdraw(shares) | The position owner |
setCap(bps) | The position owner |
setMode(mode) | The position owner |
sellToPool(rwaAmount) | Anyone |
triggerAutoSell(depositor) | Anyone, once the depositor is eligible |
marketPrice(), buyPrice(), getDiscountBps(), isMarketOpen() | View |
positions(address), pendingYield(address), totalUsdgBacking() | View |
Events: Deposit, Withdraw, Bought, AutoSold, CapUpdated, ModeUpdated, ParamsUpdated. The USDG token, the Stock Token, both price feeds and the yield strategy are immutable — set at deployment, never changeable.
Owner permissions
Each vault has an owner, limited to tuning bounded parameters. The owner has no path to user funds.
| The owner can | Bounds |
|---|---|
setDiscounts(open, closed) | Each at most 10% |
setDailyCap(usdg) | Setting 0 stops new buys; never affects withdrawals |
setReserveBps(bps) | Applies to future deposits only |
setCircuitBreakerBps(bps) | At most 100% |
| The owner cannot | |
|---|---|
| Move, seize or freeze funds | No function transfers user assets except to their owner or a seller |
| Pause deposits or withdrawals | There is no pause |
| Blacklist an address | There is no allowlist or blocklist |
| Upgrade the contract | No proxy, no upgrade path |
| Change the assets, oracles or strategy | All immutable |
Risks
- Buying into declines. The pool typically buys while an asset is falling, and it can keep falling. Depositors carry that price risk; SHADE doesn't hedge it. Index pools, your cap, Auto-sell and the circuit breaker reduce it — they don't remove it.
- Oracle risk. Both price sources can deviate from the true market, briefly or persistently, especially in thin liquidity or after an outage.
- Smart-contract risk. The contracts are experimental and unaudited. A bug could lead to partial or total loss.
- Yield-venue risk. USDG in the strategy is exposed to the lending market it's placed in.
- Stock Token risk. Tokenized stocks carry issuer, custody, redemption and regulatory risks distinct from the underlying shares.
- Keeper dependence. Auto-sell needs someone to call it. Without a keeper, an eligible position simply keeps its shares.
Nothing on this site is investment advice or an offer of securities. Read the disclosures.
$SHADE
$SHADE is the protocol token. It is not launched yet and will launch soon on Robinhood Chain. The launch venue will be announced before launch.
| Launch | Fair launch on Robinhood Chain. No presale, no private round. |
| Trading fees | Directed to the protocol. |
| Use of fees | Buy back $SHADE on the open market, then burn it. Every buyback and burn is shown live. |
| Protocol fee on the discount | Planned, not active. Today 100% of the discount goes to depositors. |
| Utility | None required: the protocol never needs $SHADE to deposit, withdraw or sell. |
| Contract address | Published at launch on this site and on @ShadeLiquidity — nowhere else. |
FAQ
Can my funds be locked?+
No. Withdrawals are always open and no one can pause them.
Where does the yield come from?+
From lending the 80% of deposits that isn't held in reserve on an on-chain lending market.
Why would anyone sell below market?+
Because slippage, urgency or a closed market would cost them more. See “Who sells, and why”.
Can I end up holding only stock?+
Only if your cap is 100%. Set a lower cap to keep a floor of USDG no matter how many buys happen.
What happens if the price keeps falling after a buy?+
Your shares lose value like any stock position. The circuit breaker stops buying after a 15% intraday drop; your cap limits how much you can accumulate.
Does the test version cost anything?+
No. It uses signatures, not transactions: no gas, no funds, any network.
Is SHADE related to Shade Protocol (SHD)?+
No. SHADE on Robinhood Chain is an unrelated project.
Glossary
| Stock Token | A token on Robinhood Chain that tracks a real-world stock or ETF. |
| Pool / vault | One ShadeVault for one Stock Token, holding USDG and that asset. |
| Discount | How far below the market price the pool buys. |
| Buy price | Market price × (1 − discount): what a seller receives per share. |
| TWAP | Time-weighted average price — a DEX price smoothed over time, hard to move in a single block. |
| Headroom | How much more of a position can become stock under its cap. |
| Cap | The max share of a position that can be held as stock. |
| Mode | Hold (keep shares) or Auto-sell (convert back to USDG once above entry). |
| Keeper | Anyone who calls triggerAutoSell for an eligible position. |
| Reserve | The 20% of deposits kept liquid to pay sellers, never invested. |
| Circuit breaker | A pause on buying after a 15% intraday drop. |
| Buyback & burn | Using protocol revenue to buy $SHADE and destroy it, reducing supply. |