Roadmap¶
What has already been verified, what comes next, and what we have decided not to do. Only items with evidence behind them — not "we might." Each entry states what exists today and what does not, so the size of the remaining work is visible.
Phases¶
| Phase | Duration | Goal | Status |
|---|---|---|---|
| MVP · testnet | 2 months | Ship the P0 features on testnet | Done |
| Productize · launch | 2 months | Private mainnet deployment, first users | Upcoming |
| Growth | Ongoing | Scale against transaction metrics | Later |
"Next" below maps to the productize phase; "After that" maps to growth.
So far — verified in P0¶
These are not plans. Each was confirmed working on the live networks. The evidence is in the P0 verification record and the MVP final review.
| Feature | How it was verified |
|---|---|
| Wallet sign-in | Browser E2E → confirmed PostgreSQL session row |
| XMTP 1:1 messaging | Real A↔B and B↔C round trips |
| Group conversations of three or more | A/B/C group send and receive. Details below |
| Dojang badges and three-way inbox routing | Live GIWA Sepolia lookups |
| On-chain evidence | A real GIWA Sepolia transaction |
| Encrypted evidence archive | Restorable only by signing wallets |
Group conversations of three or more¶
A 1:1 is internally a two-member MLS group, so there is a single code path,
and adding people takes that same path. CreateGroup requires at least two
peers besides yourself, so a group is three people at minimum.
CreateGroup.execute(peerAddresses)
drop self, deduplicate, sort
reject if peers.length < 2 -> a group is at least three people
check reachability with canMessage()
create the XMTP MLS group
If any address cannot receive XMTP messages, UnreachableParticipantsError
names the offending addresses and no group is created. This avoids leaving a
half-formed group behind.
| Test | What it covers |
|---|---|
messaging-three-users.spec.ts |
A/B/C group send and receive over the live XMTP dev network |
app-three-users.spec.ts |
Three sign-ins, 1:1 round trips, request-inbox routing and evidence blocking for unverified peers (3 scenarios, 57.4s) |
app-group-evidence.spec.ts |
Group conversation from evidence proposal through on-chain submission |
late-group-stream.spec.ts |
Stream delivery for a participant who joins late |
Evidence holds in groups exactly as it does in 1:1 — groups are arguably the point.
| Layer | Participant constraint |
|---|---|
CreateGroup |
Two peers besides yourself (three minimum) |
| Evidence API | participants between 2 and 32 |
| Evidence contract | Reverts with TooFewParticipants below two |
Inbox routing treats groups explicitly. A group lands in the main inbox only
when every participant other than yourself is verified; if even one is
not, it goes to the request inbox. Likewise, evidence can only be proposed in
a group where everyone is verified.
Next — where the groundwork already exists¶
Every item here was recorded as a limit during P0, and most are in the state of having a working backend with one screen or path missing. That makes them the first bundle of the productize phase.
Refreshing logs you out¶
The session cookie is valid for 7 days, but app state lives only in memory, so a refresh returns you to onboarding. To the user it reads as "I got logged out." This friction has to go before launch.
There is no evidence rejection button¶
This is unfinished work, not dead code. The backend API
(POST /:id/rejection), the domain state transition, and the tests all exist,
and Flow 5 in the user flows already includes
[reject]. Only the UI wiring is missing. Today, instead of rejecting,
you wait out the one-hour expiry.
Peer signatures are detected by 5-second polling¶
A peer's signature shows up on the evidence screen up to 5 seconds late. Announcing the signature over an XMTP control message would remove the polling entirely. The control-message path is already used for evidence proposals, so this adds one more kind.
Signature collection as groups grow¶
Evidence requires every participant to sign, so the larger the group, the more a single straggler holds up everyone. We need a flow that shows who is outstanding and nudges them. Three-person groups are verified, but this problem grows with headcount.
Switching devices shows an empty history¶
MLS keys differ per installation, so a new installation cannot decrypt messages sent before it joined. This is a consequence of end-to-end encryption rather than a bug, but to the user it looks like "my conversation disappeared."
XMTP offers a path for transferring history between devices
(historySyncUrl, syncAll). However, an existing installation has to
still be alive to hand it over, so once storage has been cleared there is no
recovery. The first decision is how much to guarantee. Details are in
Message History.
Explaining the 10-installation limit¶
Every clear-storage-and-sign-in-again burns a slot, and at the limit sign-in hangs. Today the symptom is "pressing sign in never advances," with no way to tell why. At minimum we should surface the remaining slots and how to revoke.
After that — decisions needed first¶
For these, deciding what to give up matters more than the engineering difficulty.
Migrating to the XMTP production network¶
We are on dev today, so there is no interop with production XMTP apps and
XMTP does not guarantee data retention on dev. Migrating opens cross-app
interoperability, but neither identity nor messages carry across
environments, so existing conversations do not continue. When to cut over is
the decision. XMTP is itself migrating to a decentralized network, so the
schedule needs watching (see
where the network stands).
Rendering evidence cards in other apps¶
Today we use text prefixed with gasok:evidence:v1: instead of a custom
codec. Open the conversation in another XMTP app and you see the raw text, not
an evidence card. Defining a proper content type fixes it, but it only means
anything once other apps support that type.
Smart account wallet support¶
P0 supports EOA signatures only. Accepting EIP-1271 smart accounts means extending the contract verification path, and evidence archive restoration has to change with it. The restore key is derived from a wallet signature, which relies on signature determinism (RFC 6979) — and that can break for smart accounts.
The 32-participant ceiling¶
That number comes from the evidence API and is tied to contract gas costs. Supporting larger groups means revisiting where the ceiling comes from.
Past evidence after membership changes¶
When people join or leave, the participant set changes, but evidence is signed against the set as it stood at proposal time. How to present past evidence after membership changes is undecided.
Dojang verification renewal¶
Faucet attestations expire 30 days after issuance. Because the contract re-queries Dojang at submission time, an expired attestation means submission is rejected even with every signature collected. We need a flow that warns before expiry and routes users to reissue.
Cross-platform¶
Today it is a mobile-shaped web app. The boundary for expanding into native
apps is recorded in mobile/README.md. Because the frontend is split into
domain / application / infrastructure / presentation and presentation never
calls an SDK directly, the lower three layers are structured to port as is.
Revenue direction¶
The first priority is a gas fee share. We take a portion of the gas spent on transfers, payments, and signatures that happen inside the app. Nothing is separately charged to the user; it rides on transactions that already occur, which is the lowest initial UX friction.
Early on, though, transaction volume itself is low, which caps revenue. So we look at stacking several layers rather than a single source. The candidates under consideration follow, with on/off-ramp spread as the second priority.
| Candidate | Detail |
|---|---|
| On/off-ramp spread | Currency spread when fiat payments are supported |
| Premium subscription | Advanced spam filtering, bulk evidence storage, group management |
| B2B · API | Dojang-based trust routing and risk filtering offered as an SDK |
| Evidence lookup service | Evidence content lookup, per query or by subscription |
| Gas sponsorship | Partners cover onboarding gas in exchange for exposure |
Decided against¶
Not started at this stage.
| Item | Reason |
|---|---|
| Risk detection integration | A real-time API spec for messenger use has to be agreed first |
| Transfers, payments, on/off ramps | After the revenue model is validated |
| Legal weight of evidence | Concept only. Legal counsel is a later phase |
| Choosing a messaging protocol | XMTP alone is sufficient |
Known risks¶
| Risk | Response |
|---|---|
| Decentralized messaging turns out slow or expensive | Make it a user choice so UX does not degrade. XMTP's mainnet transition is in progress, so we keep watching the schedule |
| Legal weight of evidence is uncertain | Concept only at this stage; legal counsel later |
| Cost of XMTP generational change | v2 went read-only after four years and v2 conversations were not migrated. We accept the operational cost of following such changes |
| Acquiring the first users | Needs a separate channel strategy |
Debt to settle¶
Separate from the roadmap, these sit in the code and need a decision.
006_evidence_content.sqlis unused. No code touches the table and columns it creates, and it overlaps in purpose with 005'sevidence_archives. We need to decide whether it replaces 005 or serves a different purpose (see Database).- PoC mode (
VITE_CHAT_POC=1) is covered by the real app. Dropping it would remove roughly 1,000 lines. - The contract's EIP-712 domain is
GasokConversationEvidence. Renaming requires redeployment, and redeploying invalidates every signature collected so far.