Marko Bera
ENSR
Let’s talk

← All work · 02 / 06

Prediction market for Serbia

Protectum

An app where people predict how real events in Serbia will turn out, like elections and the economy, using play money. It runs on iOS, Android and the web. The AI writes the questions, and a separate check catches its mistakes.

Role
Founder and sole builder, working with AI agents
Status
iOS TestFlight · web live
Period
September 2026
Stack
Expo, React Native, Supabase, Deno, Gemini
774
questions checked against real news
319
had a mistake, 117 cancelled and refunded
43
database migrations in one month
$12.61
cost of the day I switched the automation off

Video and screens

Motion graphic made entirely from the code: the native screens rendered frame by frame, one real 1 € demo purchase, iOS chrome drawn around it.
Feed: open markets, Top bet
Feed: open markets, Top bet
An event with five outcomes
An event with five outcomes
Price history per outcome
Price history per outcome
Buy: payout and price impact up front
Buy: payout and price impact up front
Slide to confirm
Slide to confirm
The slip with a QR proof
The slip with a QR proof
Portfolio and history
Portfolio and history

The idea

Polls in Serbia are rare, late and often doubted. A prediction market answers the same question differently: people put something at stake, so the price of a “yes” is the crowd’s real estimate. The app says it plainly on every board: the number is the price of a YES card, the sum of what people staked, not our estimate.

Two rules shaped everything else. Resolution is fixed when a market opens: the rule and the official source (for elections, the electoral commission) are written in advance and never change, and a correction only happens after a public objection within 24 hours. And there is no real money: everyone gets the same monthly demo salary, so the ranking measures judgement, not wealth.

Timeline

  1. Expo + Supabase foundation: market maker with tests, feed, portfolio, sign-in with Google, Apple or e-mail and password (codes, no SMS).

  2. Slide-to-confirm for every trade, IBKR-style, with haptics along the way.

  3. Events with many outcomes, Polymarket-style, plus “Top bet” and “Premium” placements.

  4. An admin chat with Claude that turns a conversation into a finished market form.

  5. Web version on Vercel, sharing the same code and database.

  6. Automation: football markets from free live data, settled every 2 minutes; AI writer and judge for everything else.

  7. First audit: 154 of 287 AI markets had a problem.

  8. Cut sports entirely (1,276 markets voided, 18,688.80 demo € refunded) to focus on the elections.

  9. Second audit of all 774 open markets. Design direction: it must not look AI-made.

  10. Crash fixed, controller before publishing, cost per call logged, automation switched off. iOS build in TestFlight.

Every feature

01

Feed and categories

Open, closing soon and settled, filtered by category (politics, society, economy, culture, world and more). “Top bet” and “Premium” placements sit on top. The feed draws 24 cards at a time and adds more near the bottom, because 700+ cards with photos at once crashed iOS.

Feed and categories

02

Events with many outcomes

One question like “Next prime minister of Serbia?” holds several outcomes, and each outcome is its own YES/NO market. A price chart per outcome (1D, 7D, 30D, all), volume, number of traders and the full resolution rule sit on the same page.

Events with many outcomes

03

Automated market maker

Prices come from a market maker in the database, not from a bookmaker. Every buy moves the price, and the app shows exactly how much before you confirm: “Chance after: 74% → 75%”. The pricing maths is covered by unit tests and shared test vectors between the app and the database.

04

Buying

Pick a side, type an amount or tap +1/+5/+25 €, and the quote shows what you win if you are right, your profit, the number of cards and the average price. A card that wins pays out 1 €.

Buying

05

Slide to confirm

No trade happens from an accidental tap. The button has to be dragged to the end: right and green for YES, left and red for NO. The phone ticks at each third of the way and gives a firm bump when the trade unlocks at 88%. Let go early and it springs back.

Slide to confirm

06

The slip

Every trade produces a shareable slip: the market photo, the side, the stake, the card price and the payout, with a QR code. The code opens a public proof of that one trade: who, when to the second, what and at which price. Sharing a slip never exposes the rest of your portfolio. “Save image” exports it in full resolution.

The slip

07

Portfolio and demo salary

Net worth, cash, money in positions and profit, open positions with a “sell” button, and a history of every movement. Everyone receives the same demo salary on the first of the month; profit is always counted against the salaries received, so the ranking is fair.

Portfolio and demo salary

08

Society and ranking

A map of people nearby, a monthly and all-time ranking, and public profiles with a photo, an animal sign or a monogram in a colour of your choice. Tap a row and you see that person’s public profile.

09

Judgements and the public archive

Every settled or voided market goes into a public archive with the outcome, the question and the source. Markets waiting for a decision are listed first, so nothing gets quietly forgotten.

10

Admin

A publishing queue with drafts to tick, the AI proposals, the daily AI cost, manual settlement, and a chat with Claude that turns “let’s do a market on the turnout” into a complete form with the rule, deadline and source.

The audit that changed the design

I asked a simple question: do the AI markets even make sense? Six agents checked all 287 open AI markets against current news. 154 had a problem and 66 should not exist. Examples: “Will gold pass $2,700?” when gold was at $4,348. “Will inflation be above 4.5%?” after the statistics office had published 2.2%.

A second pass over all 774 open markets found 319 problems. 117 were voided and 1,890.79 demo € refunded. The root cause was the same every time: the writer does not know the current state of the world, and a single call cannot check itself. The prompt already said “no market if it has already happened”. It did not help.

The fix: a controller before publishing

Every draft now goes through two gates before a human sees it:

  1. Mechanical checks, no AI, 11 unit tests. The deadline must be after the date in the rule, a threshold is compared against the current value, some words are banned, and there are no markets on court cases against private persons.
  2. One small model call per draft with search. Is it already known? Does the deadline hold? Does the price match public polls? The answer is pass, revise or reject, with evidence and a date.

First round: 20 drafts, 3 passed, 6 to revise, 8 rejected (4 of them caught by the mechanical checks alone).

AI architecture

  • Writer → controller → human → judge. The writer reads a sheet of news (RSS plus Bing News) and drafts markets; the controller checks each draft; a human ticks what gets published; the judge settles markets once the answer is public, and hands the uncertain ones back to a human.
  • Edge functions have 150 seconds. Long model calls run in the background and a scheduled collector picks up the results, so nothing waits synchronously on a model.
  • Everything scheduled with pg_cron, everything logged per run with token usage and price.

Cost

The first version logged nothing, so I added token usage and price to every run and put the daily cost on the admin home page. The real Google bill for the first week was $19.47. Then one day hit 97 calls and $12.61, while 736 AI markets had produced two real trades. I switched all six scheduled AI jobs off. Settling is now a manual button in the admin until the numbers justify turning them back on.

A crash with no crash log

The iOS app went back to the home screen with no crash report. With temporary trace logs I found the cause: the feed rendered all 769 markets with images at once, JavaScript froze for about 4 seconds and iOS killed the app for memory. The fix was pages of 24.

The web board

The same code also runs on the web, as a board for the 2026 elections that anyone can cite: percentages, volume and how each market is resolved.

Protectum on the web: the Elections 2026 board

How the video was made

The video at the top was built only from the code. I rendered the native screens through react-native-web in a separate copy of the project, drove the real flow with Playwright (one real 1 € demo purchase), captured every scroll and slider position as its own frame, and assembled it in Remotion. Only the iOS status bar, the glass tab bar and the home indicator are drawn, because on a phone the system draws those too.

What I decided

  • Cut sports entirely to focus on the elections.
  • No real money before a gambling licence. Demo currency, equal monthly salary.
  • Native app first, for the App Store.
  • Design rule: it must not look AI-made. Newspaper density and real photos, with no gradients and no glass.

What the AI did

  • Wrote most of the app, the database migrations and the edge functions.
  • Ran the audits across hundreds of markets in parallel.
  • Wrote and judged the markets through Gemini.

Where I corrected it

  • Trusted its own prompt (“don’t write resolved markets”). The audit proved it didn’t work, so I added a controller.
  • Kept adding rounds to write more markets. I capped the volume and made cost visible.
  • Proposed the web app first. The product needed native.

Next case study

Vision Guard