> ## Documentation Index
> Fetch the complete documentation index at: https://docs.robin.markets/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

> How the Robin Staking Vault pairs and merges Polymarket positions into USDC, supplies it to a yield strategy, and tracks yield with ERC-1155 shares.

The Robin Staking Vault takes paired Polymarket outcome tokens, merges them into USDC, supplies that USDC to an ERC-4626 vault, and issues ERC-1155 shares that track each depositor's claim plus accrued yield. This page walks through the contracts, the deposit and withdraw pipelines, and the share accounting that ties them together.

## The moving parts

A deposit flows through three on-chain pieces — the vault, the TWAP oracle, and Polymarket's Conditional Tokens Framework — and external yield sources. `RobinLens` sits alongside as a read-only aggregator for the data you need to build and preview transactions.

## Contracts

| Contract                             | Role                                                                                                                                                                                                                          |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RobinStakingVault`                  | UUPS-upgradeable singleton. Handles deposits and withdrawals, runs the pairing/merging pipeline, and issues ERC-1155 shares — one share token per market per side.                                                            |
| `RobinTwapOracle`                    | Receives signed TWAP price updates from a Robin operator key. A market's TWAP must be fresh before the vault accepts a deposit or withdraw for it, because the TWAP determines how yield splits between the YES and NO sides. |
| `RobinLens`                          | Stateless batch view aggregator. Returns shares, assets, pending yield, deposit/withdraw previews, and market state as arrays aligned to a `conditionIds` input.                                                              |
| `ConditionalTokens` (Polymarket CTF) | External. Holds the YES/NO outcome tokens as ERC-1155, and exposes the merge/split functions the vault uses to convert between paired tokens and USDC.                                                                        |

<Card title="Contract addresses and governance" icon="file-contract" href="/contracts/overview">
  Full address table for Polygon mainnet, including the vault proxy, oracle,
  lens, CTF, and USDC.e.
</Card>

## Deposit pipeline

When you deposit, the vault matches opposing sides within each market and converts the matched pair into yield-bearing USDC.

<Steps>
  <Step title="Pair opposing sides">
    Within a single market, the vault pairs YES against NO. A YES and a NO token
    of the same market together represent a full set worth `1` USDC of
    collateral.
  </Step>

  <Step title="Merge to USDC">
    The vault merges each matched pair on the Polymarket CTF, burning the paired
    outcome tokens and releasing the underlying USDC.
  </Step>

  <Step title="Supply to Yield Strategy">
    The merged USDC is supplied to one or multiple ERC-4626 vaults, where it
    earns organic yield for the life of the deposit.
  </Step>
</Steps>

<Note>
  Unmatched tokens stay idle. If you deposit more of one side than there is of
  the opposite side to pair with, the surplus sits in the vault until a
  counterpart arrives to pair with it. The yield that the vault earns is
  socialized between all depositors (matched or unmatched) of a market.
</Note>

The vault supports two transport paths for getting tokens in — a PULL path (Safe proxy only) and a PUSH path (both wallet kinds). See [Deposits](/developers/deposits) for the call construction and array-encoding rules.

## Withdraw pipeline

A withdrawal reverses the pipeline: it burns your shares, reconstitutes the outcome tokens, and returns them alongside the organic yield those shares earned.

<Steps>
  <Step title="Burn shares">
    The vault burns the ERC-1155 shares you specify for each market and side.
  </Step>

  <Step title="Withdraw USDC and split">
    If outcome tokens are needed, the vault withdraws USDC from the yield
    startegy vault and splits that USDC back into YES and NO tokens on the
    Polymarket CTF.
  </Step>

  <Step title="Return tokens and yield">
    You receive the underlying outcome tokens plus the organic USDC yield those
    shares accrued.
  </Step>
</Steps>

<Tip>
  `batchWithdraw` can wrap the USDC.e yield to PolyUSD via Polymarket's
  `CollateralOnramp` when you pass `wrapYieldToPolyUsd=true`; it falls back to
  USDC.e if the wrap fails. The bonus payout is sent separately by Robin
  afterwards, not by this call. See [Conventions](/developers/conventions) for
  the full signature.
</Tip>

## Shares & accounting

Shares are ERC-1155 — one token per `(market, side)` pair. The vault tracks each side independently because YES and NO can be matched, valued, and withdrawn at different rates.

The vault uses **dual-index accounting** to value those shares:

* **`lossIndex`** — tracks impermanent loss on a side, so shares redeem for the loss-adjusted amount of outcome tokens they are currently worth.
* **`yieldPerShare`** — tracks accrued organic yield per share, so each share claims its proportional cut of the on-chain yield.

Both indices use `INDEX_SCALE=1e18`. Organic yield is split three ways before it reaches a wallet:

1. **Per market, by TVL** — native yield is socialized across the market in proportion to staked value.
2. **Per side, by TWAP price** — the market's TWAP (`PRICE_SCALE=1e6`) determines how that market's yield divides between the YES and NO sides.
3. **Per user, by indices** — the `lossIndex` and `yieldPerShare` snapshots resolve each wallet's individual share of its side.

Read these values directly from `RobinLens` — `batchGetUserYield`, `batchGetMarketIndexes`, and `batchGetUserPortfolio` return them aligned to your `conditionIds`. See [Reading on-chain state](/developers/reading-onchain-state) for the `twapPricesYes` convention used by those calls.

## Organic yield vs. bonuses

<Note>
  The contracts pay **only** the organic yield, distributed through the
  `lossIndex` + `yieldPerShare` accounting above. The 6% guarantee floor, the
  +1% matching bonus, and the +1% points boost are an **off-chain programme
  operated by Robin**. They are computed at withdrawal and paid in a single USDC
  transaction from Robin's operator wallet, separate from the on-chain
  withdrawal — the vault itself never touches them. See
  [Conventions](/developers/conventions) for the APY breakdown, and the [Yield
  Guarantee](/yield-guarantee) overview for the programme details.
</Note>

## Next steps

<CardGroup cols={3}>
  <Card title="Conventions" icon="ruler" href="/developers/conventions">
    Units, ids, the Side enum, and the APY breakdown shape.
  </Card>

  <Card title="Deposits" icon="arrow-down-to-line" href="/developers/deposits">
    Build PULL and PUSH deposits with correctly sorted, aligned arrays.
  </Card>

  <Card title="Reading on-chain state" icon="magnifying-glass" href="/developers/reading-onchain-state">
    Query shares, assets, yield, and previews through `RobinLens`.
  </Card>
</CardGroup>
