Skip to main content
A single batchWithdraw call burns your vault shares and returns the underlying Polymarket outcome tokens plus the organic yield those shares accrued. It works identically for both Polymarket wallet kinds.

batchWithdraw

The vault burns the supplied shares and returns the corresponding outcome tokens (loss-adjusted) plus the pending organic USDC.e yield in one transaction.
conditionIds must be sorted strictly ascending with no duplicates, and yesShares / noShares must use the same permutation. This is the same ordering rule as deposits. A wrong order reverts.
A side may be zero (withdraw only YES or only NO), but each row must burn at least one share. The Side enum is YES=0, NO=1.

Getting share balances

Read the shares you can burn — and what they are currently worth in outcome tokens — from RobinLens.batchGetUserSharesAndAssets. The yesAssets / noAssets are loss-adjusted token amounts, so they reflect any impermanent loss already booked against the position.
Prefer HTTP? The Integration API GET /v1/positions?wallet=… returns the same per-market shares (plus live yield and APY) as 6-decimal integer strings, with no on-chain call. Use the resolved staking wallet, not the EOA.
All amounts are 6-decimal fixed-point integers (UNDERLYING_DECIMALS=6). See Reading on-chain state for the full RobinLens surface.

TWAP first

The vault rejects a withdrawal for a market whose TWAP is not fresh, because the TWAP determines how yield is split between the YES and NO sides. Refresh the relevant markets and, when needed, prepend RobinTwapOracle.submitTwap(...) to the same batch as batchWithdraw. See Keeping TWAP fresh.

Bonus payout is separate

The on-chain batchWithdraw returns only the organic yield (paid via the vault’s lossIndex + yieldPerShare accounting). The yield guarantee, matching bonus, and Robin Points are an off-chain programme: Robin computes them at withdrawal and sends them in a separate USDC transaction from its operator wallet shortly after. Your withdraw transaction will not contain that bonus — do not expect it in the Withdrawn event or the returned yield.
The emitted Withdrawn(...) event carries a protocolFee — Robin may take a protocol fee on the organic yield only, never on principal.

Transport

batchWithdraw is identical for both wallet kinds; only how you submit it differs. Resolve the wallet once and submit through its transport.
1

Resolve the wallet

Determine whether the user’s Polymarket account is a DepositWallet or a legacy Gnosis Safe proxy, and key all reads and writes on that resolved address. See Wallets.
2

Build the batch

Sort by conditionId, then assemble the call array — optionally submitTwap first, then batchWithdraw.
3

Submit through the wallet's transport

Safe proxySafe.execTransaction. DepositWallet → the Polymarket relayer. Unlike deposits, there is no pull/push distinction for withdrawals — the vault already holds the shares.
The runnable withdraw.ts in the integration example repo wires all of this together — wallet resolution, TWAP refresh, the multi-market batch, and transport dispatch.

Next steps

Reading on-chain state

Read shares, assets, and pending yield from RobinLens.

Keeping TWAP fresh

Refresh a market’s TWAP before withdrawing.