# Stockimus for agents Stockimus splits a tokenized stock on Robinhood Chain into two ERC-20s: the price of the share (**pToken**, e.g. pSPY-DEC27) and every dividend it earns until maturity (**yToken**, e.g. ySPY-DEC27). One stock token in, one pToken and one yToken out, less a 10 bps fee; one of each merged back gives the stock token back, free, at any time. The pToken trades below one share and redeems for the share at maturity, so its discount is a fixed rate. The yToken's price is the market's forecast of the dividends. Everything below is public, needs no key, and can be read or executed by a program. Site: https://stockimus.com · X: https://x.com/PayStockimus · Docs for humans: https://stockimus.com/docs · Tests and safeguards: https://stockimus.com/security ## Chain - Robinhood Chain, chain id **4663** (hex 0x1237), EVM (Arbitrum Orbit). Gas token ETH. - Public RPC: `https://rpc.mainnet.chain.robinhood.com`, or `POST https://stockimus.com/api/rpc/4663` (the same JSON-RPC, read only: writes are refused; batches up to 100 calls). - Explorer: https://robinhoodchain.blockscout.com. `contracts/deploy.sh` submits the source of every contract it creates to Sourcify (chain 4663). - Dollars on this chain: USDG `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168` (6 decimals). ## Stockimus contracts Contracts publish here at launch. Nothing is deployed yet, so there is no Stockimus contract to call. Series: one stock and one maturity, tag `TICKER-MONYY`. The first four mature at unix **1830283200** (31 Dec 2027 20:00 UTC); read `vault.maturity()` rather than hardcoding. Token names `Stockimus Principal SPY Dec 2027` / `Stockimus Yield SPY Dec 2027`, symbols `pSPY-DEC27` / `ySPY-DEC27`, 18 decimals, ERC-20 with permit. The series list on chain is `factory.allSeries()`. Stock tokens that get an accountant at launch (issued by Robinhood Assets (Jersey) Ltd., 18 decimals): | Symbol | Stock token | Series | |---|---|---| | SPY | `0x117cc2133c37B721F49dE2A7a74833232B3B4C0C` | SPY-DEC27, cap 330 | | QQQ | `0xD5f3879160bc7c32ebb4dC785F8a4F505888de68` | QQQ-DEC27, cap 350 | | AAPL | `0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9` | AAPL-DEC27, cap 770 | | PFE | `0x7066A64c24e4206CD62E83bf198c1E7EB361F51e` | PFE-DEC27, cap 9,100 | | SCHD | `0xd63ABB2C13d7a8421a8017a712802053568e3C1D` | accountant only | | NVDA | `0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC` | accountant only | | MSFT | `0xe93237C50D904957Cf27E7B1133b510C669c2e74` | accountant only | | SGOV | `0x92FD66527192E3e61d4DDd13322Aa222DE86F9B5` | accountant only | | JNJ | `0x03DfbBE0AC4E7bCDaFd08eD41A400326B77D8c80` | accountant only | | GOOGL | `0x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE3` | accountant only | | META | `0xc0D6457C16Cc70d6790Dd43521C899C87ce02f35` | accountant only | | COST | `0x4EA005168D7F09a7A0Ba9D1DEf21a479950E44C2` | accountant only | | XOM | `0xf9B46d3D1B22199D4D1025a9cEDB540A33F1a2d5` | accountant only | | AVGO | `0x156E175DD063a8cE274C50654eF40e0032b3fbcF` | accountant only | Caps are in whole shares of raw stock a series may hold (`vault.depositCap()`, 18 decimals; 0 means closed to new splits). ## Read (JSON, no key, cached 30 to 60 s; `/api/rh-tokens` about an hour, `/api/flags` and `POST` routes not at all) | Endpoint | What you get | |---|---| | `GET /api/rates` | Per series: `key` (spy, qqq, aapl, pfe), `symbol`, `tag`, `px` (stock per pToken), `discount`, `fixed` (annualised return to maturity), `py` (stock per yToken), `dividendsToMaturity`, `impliedDividendYield` (the market's dividend forecast, simple annual), `impliedSource`, `maturity`, `years`, `synced`, `drip`, `settled`, `splitsPaused`, plus the series addresses. Before deployment `series` is empty and `planned` lists the four launch series, with `prelaunch: true`. | | `GET /api/oracle` · `?token=spy` | The dividend oracle: per stock token, the live and scheduled multiplier (`uiMultiplier`, `newUIMultiplier`, `effectiveAt`, `scheduled`), cumulative `dividendIndex` and `splitFactor`, `isSynced`, `pending`, `pendingCount`, `lastEvent` (the last checkpoint). Accountant fields are `null` before deployment. `?token=` takes a symbol or the stock token address. **If `isSynced` is false, treat every price for that stock as stale.** | | `GET /api/markets` | Every Uniswap v3 pool the app trades through: address, fee tier, `sqrtPriceX96`, tick, liquidity, token0 and token balances, and `checked`, every pair looked up. | | `GET /api/market` · `?id=pspy` | The Morpho Blue lending market for a pToken against USDG: lent, borrowed, utilisation, borrow and lend APY, LLTV, oracle read. `id` is the key or the Morpho market id. Before a market exists the entry has `stage: "planned"`. | | `GET /api/pool?series=spy&pair=stock` | One pool's price history (from its Initialize and Swap logs) and its state now. `pair`: `stock` (pToken/stock, 0.05%), `yt` (yToken/stock, 1%), `lp` (pToken/USDG, 0.3%), `usd` (the stock itself in USDG, from its deepest stock/USDG pool, or through WETH when it has none). Without `pair`, pfe reads its pPFE/USDG 0.3% pool (`lp`) and every other series reads `stock`. | | `GET /api/numbers` | Protocol totals: value locked, volume, splits and swaps since deployment, per market and per pool. Before deployment it answers zeros with `prelaunch: true`. | | `GET /api/rh-tokens` · `?format=text` | A dated snapshot of every Robinhood stock token on the chain, with whether it pays a dividend (`null` where no flag is on file) and whether Stockimus covers it. | | `GET /api/read?to=0x...&data=0x...` · `&block=` | One `eth_call`, result as JSON (`{result}` or `{error}`); `block` is latest, a number or 0x hex. | | `GET /api/flags` | Client feature flags (`source`, `direct`, `wc`). | | `POST /api/request` | Ask for oracle coverage of a stock token: JSON `{token, project, contact, note}`. Answers `{id, token: {known, symbol}, noted: true, stored: false}`: the request is written to the site log, not to a database. | The OpenAPI description is at https://stockimus.com/openapi.json. Machine-readable addresses: https://stockimus.com/contracts.json. ## Act (on chain, from any wallet) All contracts are plain Solidity with no allow lists and no proxies. Amounts are in the token's own decimals (18 for stocks, pTokens and yTokens, 6 for USDG). **Split.** `stock.approve(vault, amount)`, then `vault.split(uint256 amount) returns (uint256 minted)`, or `vault.splitTo(address to, uint256 amount)`. Mints `amount - amount * 10 / 10000` of each half to the caller. Only while `vault.state() == 0` (ACTIVE), splits not paused, and the deposit cap has room (`vault.totalStock()` plus the minted amount at most `vault.depositCap()`). `vault.previewSplit(amount) returns (uint256 minted, uint256 fee)` shows the result. **Merge.** `vault.merge(uint256 amount)` or `vault.mergeTo(address to, uint256 amount)` burns `amount` of each half and returns `amount` stock (cut pro rata only if the stock token ever leaves the vault holding less than it booked). No fee, in every state, never paused. **After maturity.** `vault.settle()` (anyone, once `block.timestamp >= maturity` and the accountant has booked every move dated at or before it; if the stock token stops answering `uiMultiplier()`, 30 days after maturity on the booked index), then `vault.redeemPT(amount)` pays `amount * d0 / dT` stock and `vault.redeemYT(amount)` pays `amount * (dT - d0) / dT` stock less 5% of that. `vault.previewRedeemPT(uint256) returns (uint256)` and `vault.previewRedeemYT(uint256) returns (uint256 out, uint256 fee)` are estimates before settlement. A holder of both halves should merge instead of redeeming the yToken: merge is free. **Accrued dividends.** `vault.accruedDripFactor()` returns `(d - d0) * 1e18 / d`: 0 means no dividend yet, and it never reverts. The drip so far, as a growth ratio, is `x / (1 - x)` with `x = accruedDripFactor / 1e18`. **Trade.** Ordinary Uniswap v3 on Robinhood Chain. SwapRouter02 `0xCaf681a66D020601342297493863E78C959E5cb2` (its `exactInputSingle` / `exactInput` structs have no deadline field), QuoterV2 `0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7`, NonfungiblePositionManager `0x73991a25C818Bf1f1128dEAaB1492D45638DE0D3`, factory `0x1f7d7550B1b028f7571E69A784071F0205FD2EfA`, WETH `0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73`. Each series has a pToken/stock pool on the 0.05% tier and a yToken/stock pool on the 1% tier; pPFE also has a pPFE/USDG pool on the 0.3% tier. Pool addresses come from `/api/markets` or `factory.getPool`. Pools start thin: quote first and set slippage. **Pool (pPFE/USDG through StockimusLP).** Approve PFE and USDG to StockimusLP, then `deposit((address vault, address quote, uint24 fee, int24 tickLower, int24 tickUpper, uint256 stockAmount, uint256 quoteAmount, uint256 ptMin, uint256 quoteMin, uint256 deadline)) returns (uint256 tokenId, uint128 liquidity, uint256 ptPlaced, uint256 quotePlaced, uint256 ytOut)`. It splits the PFE, mints a Uniswap position of pPFE and USDG to you (quote must be USDG, fee 3000, ticks on multiples of 60), sends you the yPFE, merges unplaced pPFE back into PFE and returns unused USDG. To exit, approve the position NFT and the yPFE to StockimusLP, then `withdraw((address vault, address quote, uint256 tokenId, uint128 liquidity, uint256 ptMin, uint256 quoteMin, uint256 ytToMerge, uint256 deadline)) returns (uint256 ptOut, uint256 quoteOut, uint256 stockOut)`. `liquidity: 0` means the whole position; only the position's owner can withdraw; the NFT is never burned. The helper has no owner, no fee and holds nothing between calls. **Borrow.** Morpho Blue `0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010`: collateral a pToken (pSPY-DEC27 is the planned market), loan USDG, LLTV 62.5%, Adaptive Curve IRM `0x2BD3d5965B26B51814AC95127B2b80dD6CcC0fa1`. The market id and oracle come from `/api/market` and contracts.json once the market is created. `supplyCollateral`, `borrow`, `repay`, `withdrawCollateral`, `supply`, `withdraw` as on any Morpho market. The oracle prices a pToken as the stock feed times its redemption value (d0 / d discounted for the time left, at most one share; no pool price goes in); it reverts on a feed that is not positive, older than 5 days or older than the latest booked split, and while an unbooked split-sized move waits. **Fees, complete list.** Split: 10 bps of the deposit (cap 50 bps). Redeem yToken: 5% of the dividend growth (cap 10%). Merge, redeem pToken, transfers: nothing. Fees are fixed per series at creation. Pool swaps pay the pool's Uniswap fee to its LPs. ## How to price things - `pToken + yToken = 1 stock token`, held there by free merge. If the two pools sum above par, split and sell both; below par, buy both and merge. - Fixed rate on the share: `(1 / px) ^ (1 / years) - 1`, with `years = (maturity - now) / 31557600`. - Market dividend forecast: `py / years` (simple annual), or `(1 - px) / years` when the yToken pool has no price. - Fair value from the accountant: with G = dT / d0 - 1, pToken about `1 / (1 + G)` and yToken about `G / (1 + G)`. - A stock token's dividends arrive as a rise in its on-chain multiplier, not as a transfer. The accountant tells dividends (0 < r - 1 <= 3%) from stock splits (a clean num:den ratio, terms up to 50, at least 20% from 1); anything else waits for a guardian resolution behind a 2 day timelock, or the default after 14 days. Use `dividendIndex` for accrued dividends and `splitFactor` for share counts. ## Rules of the road - Nothing here is custodial and nothing needs an API key. Reads are cached 30 to 60 seconds; do not poll faster. - Check `isSynced` (per stock, in `/api/oracle`) before you price, split or borrow. While it is false, prices are stale by design. - Merge is never paused. The owner can pause new splits and change a deposit cap; nobody can move a vault's stock. - $STOCKIMUS, the community coin, has not launched. Its contract address will be published on https://stockimus.com (Copy CA) and https://x.com/PayStockimus only. No Stockimus contract reads it. - Not investment advice. Stock tokens are issued by Robinhood Assets (Jersey) Ltd. and are not available everywhere. Stockimus is independent software and is not affiliated with Robinhood. Questions, coverage requests and bug reports: https://x.com/PayStockimus, or the form at https://stockimus.com/oracle#request.