Skip to main content
RobinSplitVault is a UUPS-upgradeable ERC-4626 vault (rsvUSDC, asset USDC.e) that deploys deposits into equal YES+NO conditional-token pairs on a single manager-selected Polymarket market enrolled in Polymarket’s holder-rewards programme. The market must be a Conditional Tokens Framework (v1) market; the vault cannot hold Protocol V2 positions. A pair always merges back to exactly 1 USDC.e, so withdrawals are instant and at par. The staking vault supplies all merged USDC.e here; anyone else can deposit USDC.e directly. Addresses are on the contracts overview.

Accounting

The vault only ever reads its own books, never live balances, when pricing shares:
  • trackedAssets — net deposits plus every yield tranche recognized so far.
  • totalAssets() — trackedAssets minus the still-vesting remainder (unvestedProfit()). This is what ERC-4626 conversions use.
  • pendingYield() — everything the vault holds above trackedAssets (PolyUSD at par, idle USDC.e, extra pairs). Invisible to the share price until the next compound().
compound() folds pending yield into a linear vesting schedule. A tranche vests over the period it accrued, clamped to [baseVestingDuration, 30 days] (base is 24h on mainnet, floor 8h); it is blended by amount with whatever is still vesting. Net effect: the share price never jumps, yield drips at roughly its earn rate, and neither a daily payout nor a compound backlog can be sniped by a short-lived deposit.
Share decimals are 12 (6 asset decimals + a virtual offset of 6). Yield is only recognized while at least 1e12 shares (1 USDC.e at genesis price) exist; below that it stays pending (YieldPending) rather than accruing to virtual shares.

Functions

Keeper: calling compound

compound() is permissionless and idempotent. Robin runs it daily after Polymarket’s payout; anyone may call it more often. If the offramp is paused the PolyUSD leg is skipped and UnwrapFailed is emitted — USDC.e and pair yield are still recognized, and the accrual clock stays frozen until an unwrap succeeds so the backlog cannot later drip faster than it was earned.

Direct deposits from a DepositWallet

Polymarket DepositWallets cannot call approve, so they cannot use deposit directly. RobinPushDepositRouter is a stateless, unowned periphery for that case. Batch atomically:
  1. USDC.e.transfer(router, assets)
  2. router.depositFor(splitVault, assets, wallet) — mints rsvUSDC to wallet. Pass type(uint256).max to use the router’s whole balance.
Redeeming needs no allowance (redeem with owner == msg.sender).
Never leave funds in the router between transactions. Anything parked there belongs to nobody and can be claimed by anyone via depositFor or rescue.

Events

Roles

Next steps

Capacity

The Split Vault’s headroom is the staking vault’s tier-2 deposit limit.

Architecture

How the staking vault routes merged USDC.e into the Split Vault.