Robinhood Chain connecting

One share. Two tradable halves.
price and yield.

A tokenized stock pays you two different things: the share itself, and the cash it throws off. They trade as a single number. Prism separates them. Deposit one stock token and receive pNVDA, the share, and dNVDA, every distribution it will ever make. Sell either leg. Keep the other.

vault · NVDAt

deposit

NVDAt1 share escrowed
pNVDAthe price leg · real share price
dNVDAthe income leg · multiplier growth
·classifier tests passing
·randomised cases checked
0parties able to touch principal
1 eventcarries every corporate action

Why you'd need this

Four people, one share, incompatible wishes.

A tokenized stock bundles two different assets into one price. That is fine until you want only one of them, and there is no way to ask for it. Prism exists because these four trades are impossible today and obvious tomorrow.

Income buyer

Wants the cash, not the volatility

Buy dNVDA alone and collect every distribution the share pays, without holding a position that can halve on an earnings miss. A bond-like claim on an equity's cash flow, priced by a market rather than by a bank.

Buys the dividend leg

Growth buyer

Wants the upside, unpaid for

Buy pNVDA alone and stop paying for a yield you do not want. Strip the coupon off and the share should get cheaper by exactly the value of what you gave up.

Buys the principal leg

Liquidity provider

Stops being the exit liquidity

Every time the multiplier steps, an LP in a plain stock pool pays the gap to whoever crosses first, because balances never moved and the pool never noticed. A Prism pool charges that gap as a fee, so the event that used to cost you pays you.

Earns the surge fee

Existing holder

Sells one half, keeps the other

Hold the share, want cash now, do not want to sell the position? Split it and sell the dividend strip. You keep full share exposure and forfeit only future distributions. No loan, no liquidation price, no counterparty.

Monetises future yield

None of this needs a new asset class. It needs the existing one to stop being sold as a single indivisible number.

How it works

One deposit, one settlement, one redemption.

A full lifecycle with real arithmetic: a share at $100 paying a $1.00 quarterly distribution, one share deposited.

  1. 1

    Deposit the share

    You send 1 NVDAt to the vault and it stays there. The vault does not lend it, rehypothecate it, or route it to a strategy. You receive 1 pNVDA and 1 dNVDA in the same transaction.

    deposit(1e18) → 1 pNVDA + 1 dNVDA
  2. 2

    Trade the legs apart

    Both tokens are ordinary ERC-20s with their own pools. The market prices them independently: the principal leg tracks the share minus its future income, the dividend leg tracks that income. Their sum should track the share, and where it does not, that gap is the arbitrage.

    pNVDA ≈ $96.20  ·  dNVDA ≈ $3.80  ·  Σ ≈ NVDAt
  3. 3

    The distribution arrives

    No cash moves and your balance does not change. The token's uiMultiplier() rises by 1%, the real share price falls by 1%, and the total-return feed does not move at all. That multiplier step is the distribution, so the vault reads it from the token instead of waiting for money that never arrives.

    uiMultiplier 1.000000 → 1.010000 · feed continuous → INCOME
  4. 4

    The step routes to one leg only

    The 1% accrues to dNVDA holders. pNVDA receives nothing, which is correct: the real share it tracks is worth 1% less than it was. Entitlement follows the token, so it survives a transfer — sell your dNVDA and the buyer inherits the unclaimed accrual.

    incomeIndex ×1.01  ·  price leg unchanged
  5. 5

    Swaps during the gap pay the LPs

    Between the multiplier moving and settlement landing, the pool's books and the token disagree. A hook replaces the 0.30% static fee with a surge fee scaled to the unexplained gap, so the arbitrageur who came to extract that gap funds it instead. Adding liquidity is blocked outright until anyone calls poke().

    currentFee() = BASE_FEE + gapBps × surgeMultiplier / 100
  6. 6

    Redeem whenever you hold both

    Burn 1 pNVDA and 1 dNVDA together and the original share comes back. No maturity, no rollover, no expiry. The two halves are always worth exactly one share, which is what makes the arbitrage between them enforceable rather than hopeful.

    redeem(1e18) → 1 NVDAt

What the vault cannot do. There is no admin key over principal. A steward role can only release quarantined value — accrual the contract has explicitly refused to credit to either leg. It cannot touch deposits, mint, or reverse an accrual already made. A paused oracle freezes settlement rather than guessing at it.

What the bytecode shows

Both legs already exist inside the token.

Every stock token on this chain is a beacon proxy over one implementation exposing uiMultiplier(), effectiveAt() and oraclePaused(), and emitting exactly one corporate-action event. Three properties fall out of reading it.

// UIMultiplierUpdated(old, new, effectiveAt)
old         1.000000000000000000
new         1.002208724969205741
effectiveAt 1788534626

01 · Total return

A distribution is never cash

It is multiplier growth. No stablecoin arrives, no balance moves, and any vault waiting for a transfer waits forever.

02 · Fixed balances

Splits do not move balances either

balanceOf is fixed for life. Every corporate action is one global number moving.

03 · The identity

feed = real price × multiplier

The feed is total return too. On a distribution the multiplier rises by exactly what the real price drops, and the feed does not move.

That last line is the whole opportunity. The price leg and the income leg are already separated inside every one of these tokens. They are multiplied together into a single quote, and nobody trades them apart. Prism does not have to invent the decomposition, only expose one that already exists. effectiveAt() is the bonus: corporate actions are announced before they land, so a vault knows what is coming and when.

The problem

A pool prices from a number the action never touches.

An AMM quotes from balanceOf(). A corporate action here does not move balances, it moves a global multiplier. So the pool quotes yesterday for the block after the action lands, and whoever crosses first takes the difference out of LP inventory. Every distribution. Forever.

Prism settles the multiplier before the pool has to answer for it.

01 · Escrow

The vault holds the real share

Deposit the canonical stock token, mint pTOKEN + dTOKEN one-for-one. Burn both together, take the share back. No maturity, no rollover, no synthetic anything.

02 · Classify

One number, read straight from the token

Settlement compares the token's multiplier against the last settled one and checks the feed stayed continuous across the step. A step it cannot explain is never credited.

03 · Route

Value goes where it belongs

Ordinary multiplier growth → income holders, pro rata, surviving every transfer. A step too large to be income → quarantine, pending steward review. Anything else → quarantine, credited to nobody.

ObservedMultiplierFeedVerdict
Distribution+smallcontinuous→ dTOKEN
Market moveflatmoves→ nobody
Large step (split?)+largecontinuous→ steward
Feed desync+anyjumps→ quarantine
Multiplier falls−anyany→ quarantine

The hook

LPs get paid for the gap instead of paying it.

The hook reads the vault's reconciliation state on every swap. While the pool and the token disagree, the static fee is replaced with a surge fee scaled to the unexplained gap, so the value an arbitrageur came to extract is charged to them and paid to the LPs. Liquidity cannot be added to an unreconciled pool at all, and anyone can clear the state with one permissionless poke().

// StripHook.sol
function currentFee() public view returns (uint24) {
    if (!vault.unsettled()) return BASE_FEE;              // 0.30%
    uint256 gapBps = unexplainedGapBps();
    uint256 surge  = BASE_FEE + (gapBps * surgeMultiplier) / 100;
    if (surge > MAX_SURGE_FEE) revert GapTooLarge();      // refuse, don't guess
    return uint24(surge);
}

Live

Run the classifier yourself.

The multiplier model, running live in your browser with integer WAD arithmetic — the same code path the test suite asserts against. Move the inputs and watch the verdict change. Note what a 4-for-1 does: it looks exactly like a distribution, so it stops at a human.

classifier · live

verdict

Dividend

pTOKEN·
dTOKEN·
quarantine·
hook fee 0.30% · pool settled

Network

Connect and read the chain.

The panel reads live chain state over JSON-RPC without a wallet. Point the vault field at any deployed vault and it will read that vault's real settlement state, including whether escrow matches accounting.

wallet

not connected

·

chain

block·
gas·
rpc·
explorerexplorer ↗

vault

statusno vault configured
income index·
accrued / dTOKEN·
quarantined·
escrowed·
price leg out·
income leg out·
solvency·

How to use it

Six calls, start to finish.

This is the full operator flow. Prism ships with no vault address configured, so the write actions below are inert until someone deploys the contracts and fills in config.js. Each step says exactly what it needs.

  1. 1

    Get the chain and the share works now

    Add the network with the button in Network, then hold any amount of the underlying stock token. The vault takes the token as it is — no wrapping, no minimum, no allowlist.

    chainId 4663 · rpc.mainnet.chain.robinhood.com
  2. 2

    Approve the vault needs a vault

    A one-time ERC-20 approval on the stock token, spender set to the vault. Approve only what you plan to deposit if you would rather not leave a standing allowance.

    NVDAt.approve(vault, amount)
  3. 3

    Deposit and receive both legs needs a vault

    One call mints both halves to you in the same transaction, one for one, with no fee and no slippage. The share stays escrowed and is never lent out.

    vault.deposit(amount) → amount pNVDA + amount dNVDA
  4. 4

    Sell the half you do not want no pool

    This is the entire point, and it is the step that depends on somebody seeding liquidity. Both legs are ordinary ERC-20s, but minting them does not conjure a counterparty. Until a pool exists, splitting is a round trip you can make and a trade you cannot.

    pNVDA + dNVDA = NVDAt · the gap is the trade
  5. 5

    Claim, once a distribution lands needs a vault

    Anyone can call poke() to make the vault read the multiplier and route the step. Income holders then withdraw their accrual as the real underlying. Entitlement rides the token, so a buyer inherits whatever is unclaimed.

    vault.poke() · then vault.claim()
  6. 6

    Redeem when you hold both needs a vault

    Burn equal amounts of each leg and the share comes back. No maturity, no expiry, no rollover. Redemption is exact at the wei: the amount burned is the amount returned, with no dust.

    vault.redeem(amount) → amount NVDAt

vault panel

walletnot connected
NVDAt·
pNVDAt·
dNVDAt·
claimable·

connect to read your balances

No vault is configured, so the write actions are disabled. Set one in config.js to enable them.

What this does not do

The uncomfortable half.