Skip to main content

When to use

Binary markets cover a single YES/NO question. For a set of mutually exclusive outcomes — e.g. “Who wins the Premier League?” with Arsenal / Chelsea / Draw / Other — PredictStreet uses a neg-risk group backed by the NegRiskAdapter contract. A neg-risk group can have 2 or more outcomes (a 2-outcome group such as “Brazil / Japan” is still neg-risk), so never infer the market type from the outcome count — read negRiskEligible on GET /api/markets or GET /api/markets/{slug}. Neg-risk lets you trade each outcome independently as a separate binary YES/NO, but guarantees collateral efficiency via convertPositions: exactly one outcome of the group resolves YES, so NO tokens on k of the N outcomes (k < N) convert atomically into one YES token on each remaining outcome plus k-1 USDC (see convertPositions below).

Differences from binary

Different verifyingContract. An EIP-712 order signed for the binary exchange will fail signature validation on a neg-risk market. Always match verifyingContract to the market type.

Outcome indexing

Each outcome of a neg-risk group is its own market, with its own symbol and its own YES/NO token pair. The siblings share negRiskMarketId. negRiskQuestionIndex (0..N-1) gives a sibling’s position in the group, and groupItemTitle gives its name. A 4-outcome group (Arsenal / Chelsea / Draw / Other) is four sibling markets with negRiskQuestionIndex 0..3. To trade one outcome, send that sibling’s symbol as marketId, with outcome: "0" for YES or outcome: "1" for NO, and sign under the neg-risk exchange domain. negRiskQuestionIndex is not the order outcome: outcome: "2" is rejected.

convertPositions

The neg-risk invariant: in an N-outcome group, one NO token on each of k outcomes is equivalent to one YES token on each of the other N-k outcomes plus k-1 USDC. convertPositions performs that swap atomically: it burns the NO tokens selected by indexSet and returns the complementary YES tokens plus the USDC. It uses a dual-signature flow (vault owner + backend). First request the backend co-signature:
  • marketId is a sibling market’s symbol; the server resolves it to the group’s on-chain negRiskMarketId. A binary market is rejected.
  • indexSet is a decimal bitmask over negRiskQuestionIndex — bit i burns the NO token of outcome i (0b1110 = "14" burns NO on outcomes 1, 2 and 3). An empty set is rejected, and so is one that covers every outcome (invalid_index_set — burning the full set is a merge, not a convert).
  • amount is in base units (6 decimals), burned per outcome in the set.
  • Any other body field is rejected with 400 invalid_request.
The response carries signedOpId, digest, backendSig, salt, deadline, the bytes32 on-chain marketId, the echoed indexSet and amount, your vaultAddress, and the tokenIds the convert will burn. Then:
  1. Owner signature. With the vault owner’s EOA key, sign the ConvertPositions(bytes32 marketId,uint256 indexSet,uint256 amount,uint256 salt,uint256 deadline) typed data built from the response values, under the vault domain (name: "PredictStreetVault", version: "1", the chain id, verifyingContract: vaultAddress). The returned digest is the EIP-712 hash of exactly that typed data, so you can also sign digest directly (raw, without a personal_sign prefix).
  2. Submit before deadline. Either post { signedOpId, ownerSig, backendSig } to POST /api/me/positions/op-submit — the platform submits it and pays the gas; poll GET /api/me/positions/op-submit/{jobId} — or call vault.convertPositions(marketId, indexSet, amount, salt, deadline, ownerSig, backendSig) on-chain yourself with the values from the response.

Resolution

Each outcome has its own conditionId (outcomes[].conditionId). When the group resolves to a single winner, reportPayouts is called once per outcome: [1, 0] (YES pays) on the winner’s condition and [0, 1] (NO pays) on every other outcome’s condition. The group settles through the neg-risk oracle (negRiskOracle in GET /api/platform/contracts) with the same propose → challenge → finalize lifecycle, bond and challenge window as a binary market, keyed by negRiskMarketId — see Settlement flow.