Web3 // Product // Architecture

Frontle

Geography Wordle inside MiniPay: connect two countries through their borders and win real stablecoin prizes on Celo. Third place at Celo's Colombia hackathon.

Role
Development & architecture
Year
2026
Status
In production
Stack
Next.js · TypeScript · Solidity · Supabase · Celo
Frontle artwork: the logotype and the line “The world is closer than you think” over a landscape of mountains and a lake, with the Earth and an orbiting location pin

Frontle is a daily geography game: you get two countries and have to connect them through their shared borders using as few countries as possible. Whoever solves it with the shortest path — fastest time breaks ties — takes a share of that day's pot, paid in stablecoins.

It lives inside MiniPay, Opera's wallet with over 16 million users, and runs on Celo. It took third place at Celo's Colombia hackathon and is currently under review for publication inside MiniPay.

3rdCelo Colombia hackathon
16M+Reachable users
4Languages
0CELO the user ever sees

What's unusual about it

Almost every crypto app starts by asking you for three things before letting you do anything: install a wallet, write down twelve words, and acquire the native token to pay for gas. Three walls before the first useful screen.

Frontle asks for none of them. It opens inside MiniPay, where the wallet already exists and already has a balance. And thanks to CIP-64 — Celo's fee abstraction — the user pays gas in the same USDT they already hold. They never see CELO, never learn what CELO is, and don't need to.

The architecture

Three layers, with an explicit boundary between what is money and what isn't:

  1. frontend/ — Next.js 16 and TypeScript. All the game logic: the border graph, path validation, maps via d3-geo and topojson-client. It connects to the wallet through MiniPay's native window.ethereum, with no connection library, falling back to Privy outside MiniPay.
  2. supabase/ — Postgres with RLS for the ranking, and Deno Edge Functions triggered by pg_cron. This is where the things that change often and don't need to be on-chain live.
  3. contracts/ — The FrontleGame contract on Celo Mainnet. It charges, accumulates and distributes. Nothing else.

The split is 80% to the daily pot, 20% to the protocol (protocolBps = 2000). If a level has no winners, its pot cascades into the next harder level that does.

The oracle pattern

This was the part that took the longest to get right.

The ranking lives in Postgres because querying it on-chain would be absurdly expensive. But the prize can't depend on a database I control. The answer was to separate the computation from the truth:

At 00:10 UTC an Edge Function runs close-day: it reads the winners from the ranking per level and calls rollDay(day, winners) on the contract. From there the winner calls claim(day, level) and gets paid. Only the operator can invoke rollDay, and the winners table stays publicly readable for auditing.

The source of truth for the prize is always the contract. Postgres proposes, the chain disposes.

The daily challenge is deterministic: derived from the UTC date, with no server-side randomness. Everyone plays exactly the same problem and anyone can verify it wasn't tampered with.

What I'd do differently

  • Model the pot on-chain from day one. The v1 contract (0x7Ea1...) had no difficulty levels; adding them forced a v2 deploy and a migration. That was foreseeable.
  • Write close-day with retries before needing them. A cron job that moves money and fails silently at 00:10 UTC is a problem you find out about late.
  • Instrument the free-first-attempt funnel much sooner. It's the metric that actually matters and I was slow to measure it.

Where it stands

In production at frontle.earth, with real users and real money, competing in Proof of Ship, Celo's monthly builder program. Under review to enter the MiniPay catalog.

Next project