Custody & on-chain settlement

Verex does not keep a ledger of who owns what and promise to honour it. Positions are ERC-1155 tokens on Sepolia, and payouts come from collateral locked in a contract. This document explains the mechanism that makes that work.

Conditional tokens

Verex uses Gnosis's Conditional Tokens Framework — the same primitive Polymarket is built on. Its core idea is a split: deposit $1 of collateral and receive one token of every outcome. Since exactly one outcome will eventually be worth $1 and the rest worth $0, the full set is always worth exactly the $1 you put in.

This is what makes the market fundable without anyone taking a directional bet. The operator splits collateral into a complete set, then sells the outcomes it wants to be short of and keeps the rest. It is not betting; it is warehousing inventory.

The operation is reversible in both directions. Holding a complete set, you can merge it back into $1 of collateral at any time, before resolution and without anyone's permission.

How a market is identified

A market's on-chain identity is derived, not assigned. prepareCondition registers a condition, and its id is a hash of three things:

conditionId = keccak256(abi.encodePacked(oracle, questionId, outcomeSlotCount))
  • `oracle` — the address permitted to report the result.
  • `questionId` — the hash of the question key, binding the id to the specific question.
  • `outcomeSlotCount` — how many outcomes exist (2 for a binary market).

Deriving rather than assigning has a useful property: the same inputs always produce the same id, so anyone can verify that a market refers to the question it claims to. It also has the consequence covered in the resolution document — the oracle cannot be changed later, because changing it produces a different market.

What happens when you trade

Matching happens off-chain for speed; settlement happens on-chain for finality. A single trade goes through these stages:

  1. Your order enters the book and matches against resting orders by price-time priority. Large orders walk several levels and receive an average fill price.
  2. The matched pair is written to the database and queued as a settlement job.
  3. A worker submits both signed EIP-712 orders to the CTF exchange's matchOrders, which moves the ERC-1155 outcome tokens and the collateral atomically.
  4. The settlement chip under your fill flips from settling on-chain… to settled with a transaction hash.
The queue is built to survive crashes. Settlement jobs are claimed atomically, retried with exponential backoff, and guarded by an idempotency check that skips any fill whose trade is already confirmed — so a worker dying mid-settlement re-runs safely instead of double-settling. A failed job runs a compensating reversal of the database fill.

Resolution and redemption

Resolution writes a payout vector on-chain via reportPayouts — for a binary market, [1, 0] for Yes or [0, 1] for No. This is a one-time, irreversible write.

After that, holders call redeemPositions to burn their tokens and withdraw the collateral they are owed: $1 per winning token, nothing for losing tokens. The collateral was locked at split time, so redemption is not a promise being honoured — it is a withdrawal of funds that were always there.

In the interface this is the Redeem button that appears on a resolved position in the Portfolio, along with the realised profit and loss against your cost basis.

Multi-outcome markets

A question with five candidates is not one five-slot condition. It is five separate binary markets — one Yes/No pair per candidate — grouped in the application layer.

The group is what keeps the arithmetic honest: whenever one candidate trades, the others are renormalised so the implied probabilities still total 100%. Structuring it this way means every candidate has its own independent order book and can be traded in isolation, which a single multi-slot condition would not allow.