At Solana Breakpoint 2026 and want free Triton RPC credit?

  • Install the Catch the Tritons app on your badge.
  • Find the Triton One crew: King Triton at our booth plus 15 Tritons in the crowd.
  • Catch 10 for $25 of credit, or 14 for $50. When you're next to a Triton team member, open the Catch the Tritons app, and press DOWN. Scan the QR on your badge and submit the form.

The game

We have a ton of Triton engineers at Breakpoint this year, ready to help you optimise your code and slash your RPC bills!

Catch the Tritons turns our team into a card collection of 16 cards: King Triton, who stays at the booth, and 15 roaming Triton sea-gods. Walk up to a Triton, flip to their card in the app and press SELECT to catch them.

At 10 catches you can claim $25 of Triton RPC credit, and at 14 you can claim $50.

You get one reward per badge, so taking $25 means giving up $50. Press UP near a Triton to Talk: a menu of questions about Riptide and Alpenglow, answered by the staff badge.

The hardware and the OS

The Breakpoint badge is an ESP32-C5 (single-core RISC-V, 240 MHz, Wi-Fi 6 on 2.4 and 5 GHz) running Solana OS. Third-party apps are Lua scripts from the badge store. Badges find each other over ESP-NOW, a connectionless Wi-Fi frame protocol, on a shared mesh channel. The receiver measures a signal strength (RSSI) for each frame, and the game is built on that number.

You run a stock Solana OS image and our Lua app. Our team badges run a custom Triton build of Solana OS. It adds a native C module, not a Lua app, that answers catches, Talk and redemptions in the background.

Keys and the signed roster

Each staff badge holds its own Ed25519 signing key, generated offline and imported once at provisioning. A roster ties the event together. It is a compact binary record: a version, the two thresholds (10 and 14), and one entry per slot with the slot number, the badge id, the Ed25519 public key and a validator flag. An offline admin key signs the whole roster.

Staff badges gossip the roster over the mesh in chunks. A badge applies a roster only after it checks the admin signature, and only if the version is higher. USB loading is the fallback. The attendee app ships with the public part of the roster: slots, badge ids and public keys.

A catch is a challenge and a signature

When an attendee presses SELECT, the app sends a challenge with a fresh 16-hex-digit nonce to that Triton's badge over ESP-NOW. The staff badge checks three things: the request came directly over the radio (bridged frames are refused), the RSSI is at or above -68 dBm, and the requester is inside the rate limits. It then signs ctt1|slot|attendee badge id with its Ed25519 key and sends the signature back, with the nonce as metadata. The attendee app matches the nonce to its live challenge, which rejects stale replies, and stores the signature.

The app never verifies signatures. They are evidence for later, and the staff badges check them at redemption.

The signer enforces "be near": the staff badge measures the signal itself and refuses to sign below its floor, so a patched app gains nothing. We calibrated the floor with badges worn at chest height:

  • Side by side: -36 dBm.
  • 1 m, face to face: -59 dBm.
  • 2 m, face to face: -66 dBm.
  • 1 m, one person turned away: -72 dBm.

So -68 dBm means "talking distance, facing each other". It is a proximity threshold, not a distance measurement, because a body between the badges costs more than an extra metre. Talk uses a wider floor of -74 dBm, so you can browse questions from a little further away.

Signing costs time on a microcontroller, so badges rate-limit: one response per attendee per ten seconds, and two per second overall on a roaming badge (four at the booth).

Redemption in one step

At 10 or more catches, the attendee presses DOWN. The app sends its stored evidence to the strongest Triton in range. There is no target picker. The staff badge verifies each catch signature against the roster keys, drops anything invalid and counts valid slots. If the count meets the requested tier, it saves the claim to flash first, then signs a receipt:

cttr1|badge|tier|claim number|validator slot|unix time

If no verdict arrives within 20 seconds, the app retries once with the next strongest Triton still in range. Validators gossip signed claims to each other. A badge that has a receipt at either tier cannot claim again. Gossip only reaches badges in radio range, so the sheet checks duplicates too.

The app packs the receipt into 107 URL-safe characters: a 15-byte base64url header with the claim fields, a dot, and the 64-byte signature. It puts the receipt and badge id into a prefilled Google Form URL and shows it as a QR. The QR renderer takes at most 256 bytes; we budget 248, and the longest real URL is 246. The receipt persists, so DOWN reopens the QR later without a Triton nearby.

Verification without a server

The attendee scans the QR, types an email and submits. A Google Apps Script bound to the response sheet runs on each submission. It holds the 16 published staff public keys and an embedded TweetNaCl verifier. It rebuilds the exact cttr1 message from the header, checks the signature against that validator's key, and checks the badge id field matches. It then flags repeats by badge id or by email. Each row gets one status: Validated, Validated, duplicate, Invalid, or No receipt. A person reviews the rows before the credit goes out.

No server of ours sits in this path. The attendee badge needs no internet for catches or redemption; only the phone talks to the network. The badge never sees the email address.

The whole flow

Step

Where

What happens

Catch

Attendee badge to staff badge, ESP-NOW

Nonce challenge; staff checks RSSI and signs ctt1|slot|badge

Evidence

Attendee app storage

Up to 16 stored catch signatures, unverified

Redeem

Attendee badge to strongest Triton

Staff verifies catches against the signed roster, saves the claim

Receipt

Staff badge

Ed25519 signature over cttr1|badge|tier|claim|slot|time

QR

Attendee badge screen

Receipt packed into a 107-character field in a form URL of at most 248 bytes

Form

Attendee phone

Prefilled badge id and receipt; attendee adds an email

Verify

Apps Script on the sheet

Signature check with public keys, duplicate check, status per row

Constraints that shaped it

  • Heap. On a badge that runs Lua from internal RAM, an app gets 96 KB of heap. We gate the attendee app at 36,864 bytes retained with 30 catches loaded; it measures about 31 KB.
  • One radio, one channel. ESP-NOW peers must share a channel. A staff badge that joins a Wi-Fi network on another channel stops answering. Staff firmware pins Wi-Fi to the mesh channel: it scans and joins only access points on that channel and rejects app requests to move or scan.
  • 5 GHz. The ESP32-C5 supports non-DFS 5 GHz channels, and the mesh channel follows the venue Wi-Fi channel, so the firmware handles both bands.

What we would do differently, and what is next

  • Channel scanning. Today an attendee finds a Triton only on the shared mesh channel. A change in testing lets the app scan the other supported channels for roster Tritons while it is open, then return to the event channel.
  • Hardware measurements earlier. Most of our heap, stack and timing numbers come from the emulator. We would measure RF range, stack margin and signing latency on real badges earlier.
  • A shared claim register. Mesh gossip blocks most double claims, but not between validators that never meet. The sheet covers that today; a small shared register would close the gap at the source.

Come and find us at Breakpoint. Start with King Triton at the booth, and bring your badge.