> ## 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.

# Refreshing the TWAP oracle

> Each market's TWAP must be fresh before a deposit or withdrawal — fetch a signed update from Robin's API and prepend submitTwap to your batch.

`RobinTwapOracle` holds a time-weighted average YES price for every market. The vault reads it to split organic yield between the YES and NO sides, and refuses a deposit or withdrawal when the market's TWAP is stale. Before you call `batchDeposit`, the push-deposit `safeBatchTransferFrom`, or `batchWithdraw`, fetch a signed update from Robin and prepend `submitTwap` to the same batch when one is needed.

## Why TWAP

A market's outcome tokens (YES and NO) earn yield as one pooled USDC position, but each side accrues at a different rate. The oracle's time-weighted YES price is the split point. It determines how much of the pool's yield belongs to YES holders versus NO holders.

The vault enforces freshness per market. If the stored TWAP is stale, a deposit or withdrawal for that market reverts until a fresh value is submitted. You never compute this price yourself: Robin's backend computes it from Polymarket trade data and returns it signed.

<Info>
  The TWAP payload is signed by a Robin operator key. This signer is migrating to an [Oasis ROFL](https://oasisprotocol.org/rofl) TEE, but the HTTP request and response shapes documented here stay the same — no integration changes are required.
</Info>

## Fetch a signed update

Request the update from the Integration API at `POST /api/v1/twap` — open CORS, no auth, rate-limited per IP like the rest of `/api/v1`. Pass the `conditionId`s (up to 25, unique) for every market in your upcoming batch.

```bash theme={null}
curl -X POST https://app.robin.markets/api/v1/twap \
  -H "Content-Type: application/json" \
  -d '{ "conditionIds": ["0x1234…", "0xabcd…"] }'
```

The response is one of two shapes.

**Mode A — already submitted.** The oracle was refreshed on-chain by someone else. There is nothing for you to do: skip `submitTwap` entirely.

```jsonc theme={null}
{
  "txHash": "0x9f3c…" // oracle already up to date on-chain; do NOT call submitTwap
}
```

**Mode B — you submit it.** You receive `TwapData`-shaped market entries plus a `signature`. Prepend `submitTwap({ markets, signature })` to your batch (see [Submit it](#submit-it)).

```jsonc theme={null}
{
  "markets": [
    {
      "required": true,
      "conditionId": "0x1234…",
      "startTimestamp": "1718000000",
      "endTimestamp": "1718086400",
      "twapPriceYes": "540000", // 6-decimal price; 540000 = 54.00% (PRICE_SCALE = 1e6)
      "marketEndedAt": "0", // 0 = market still live
      "marketEndYesPrice": "0"
    }
  ],
  "signature": "0xc0ffee…"
}
```

<Note>
  All amounts and prices are 6-decimal integer strings. `twapPriceYes` is scaled by `PRICE_SCALE` (1e6), so `1000000` is 100%.
</Note>

## Submit it

When you get Mode B, prepend a single `RobinTwapOracle.submitTwap` call to your deposit or withdrawal batch — the oracle refresh and the vault action then land atomically in the same Safe or relayer transaction.

```solidity theme={null}
struct TwapData {
    bool    required;
    bytes32 conditionId;
    uint256 startTimestamp;
    uint256 endTimestamp;
    uint256 twapPriceYes;
    uint256 marketEndedAt;
    uint256 marketEndYesPrice;
}

struct BatchTwapData {
    TwapData[] markets;
    bytes      signature;
}

function submitTwap(BatchTwapData calldata twapData) external;
```

## Short-circuit

You can skip `submitTwap` even in Mode B when no market actually needs an update.

<Tip>
  If **every** returned market has `required: false` and `marketEndedAt: "0"`, the on-chain TWAP is already fresh and no market has finalised — submitting is a pure no-op. Drop the `submitTwap` call and send your deposit or withdrawal batch on its own.
</Tip>

```ts theme={null}
// `markets` here is the parsed payload, each field already coerced to bigint.
const noop = markets.every((m) => !m.required && m.marketEndedAt === 0n);
// noop === true → omit submitTwap from the batch.
```

The reference `fetchTwap` helper folds all of this into one call: it returns `null` for Mode A and for the short-circuit case, and otherwise returns `{ markets, signature }` with every field already coerced to `bigint`. Your batch builder then conditionally prepends `submitTwap` only when the helper returns non-`null`. See `fetchTwap` in `src/shared.ts` of the `robin-markets-integration` example repo, used by both deposit flows and the withdrawal flow.

## Next steps

<CardGroup cols={2}>
  <Card title="Deposits" icon="arrow-down-to-bracket" href="/developers/deposits">
    Build the pull or push deposit batch that the TWAP update goes in front of.
  </Card>

  <Card title="Withdrawals" icon="arrow-up-from-bracket" href="/developers/withdrawals">
    Burn shares and claim organic yield, with the same fresh-TWAP requirement.
  </Card>
</CardGroup>
