🎮 Game Design & Interactive Media · casual game incentives

Sovereign Solitaire · Jetton

A hyper-casual puzzle engine where every hint, level skip, and 'Solution Reveal' is a discrete 0.01 USDT-on-TON the Jetton paywall transaction. No ads, no 'gems'—just raw micropayment-gated gameplay. High-score leaderboards are verified by the settlement hash, turning casual play into a high-stakes, pay-to-progress competitive arena optimized for AI-agent solvers and human speedrunners.

TON Jetton paywall· jetton native
Section · Onchain

The primitive.

full primer →

The casual game incentives payload sits behind an HTTP 402 wall priced in Jettons; game designers pay with one Tonkeeper confirmation carrying a one-time memo, and the server unlocks it only after the transfer settles on TON.

Why this primitiveBy removing abstract virtual currencies and replacing them with TEP-74 transfer signed micropayments, the game eliminates friction for global players. The the Jetton paywall model ensures the developer is paid instantly per interaction, making 'free-to-play' economics obsolete in favor of true utility-based gaming.

Kernel
an HTTP 402 paywall metered in Jettons (USDT-on-TON shape) — the client sends a transfer carrying a one-time memo through TON Connect and the server re-reads the TON indexer to match it before releasing the payload
Drives the UI as
a 'pay to unlock' button that shows the memo, the settled transfer, and a tonscan link
Appendix · Secrets

Required keys.

TON_DEPLOYER_MNEMONIC
24-word testnet seed for the deploy script. Fund it free via the Telegram test giver.
open ↗
TONCENTER_API_KEY
Optional. Higher rate limits on the testnet indexer.
open ↗
TON_RECEIVER_ADDRESS
Collects Jetton paywall payments. Can equal the deployer wallet.
open ↗
TON_JETTON_MASTER
Jetton metered by the paywall. Leave empty to meter in Toncoin.
open ↗
PINATA_JWT
Pins images / JSON / manifests to IPFS.
open ↗

Add these in your Lovable project under Settings → Secrets before pasting the prompt below.

Appendix · Mega-prompt

The build prompt.

Target

Paste into a fresh Lovable project. Make sure all five secrets above are set first. read the build strategy →

Build "Sovereign Solitaire · Jetton" in ONE Lovable message. Single-page Jetton-metered paid app on the TON testnet.

CONCEPT
A hyper-casual puzzle engine where every hint, level skip, and 'Solution Reveal' is a discrete 0.01 USDT-on-TON the Jetton paywall transaction. No ads, no 'gems'—just raw micropayment-gated gameplay. High-score leaderboards are verified by the settlement hash, turning casual play into a high-stakes, pay-to-progress competitive arena optimized for AI-agent solvers and human speedrunners.
Discipline: Game Design & Interactive Media (casual game incentives).
Onchain primitive: Jetton micropayments on TON (USDT-on-TON shape, TEP-74 transfers). Why: By removing abstract virtual currencies and replacing them with TEP-74 transfer signed micropayments, the game eliminates friction for global players. The the Jetton paywall model ensures the developer is paid instantly per interaction, making 'free-to-play' economics obsolete in favor of true utility-based gaming.

5-CREDIT BUDGET (HARD LIMIT)
- ONE single-page app. No Lovable Cloud, no database, no auth beyond TON Connect.
- NO custom smart contract. Payments settle as ordinary TEP-74 Jetton transfers to your receiver wallet.
- Self-host the verifier as ONE TanStack server route inside the same app (shape below).
- At most ONE AI call per user action (Lovable AI Gateway with LOVABLE_API_KEY, only if AI is part of the idea).
- Skip tests, skip CI, skip docs. Ship the demo.

STACK
- React + Vite + TanStack Start, single page (the index route).
- SSR-safe wallet mount is MANDATORY. Never import @tonconnect/ui-react at module
  scope of a route file — it touches `window` and crashes SSR. Use
  lazy(() => import('./ton-client-entry')) inside <ClientOnly> + <Suspense>, and
  keep <TonConnectUIProvider> inside ton-client-entry.tsx only.
- Publish public/tonconnect-manifest.json ({ url, name, iconUrl }) and pass
  manifestUrl={`${window.location.origin}/tonconnect-manifest.json`}.
- TESTNET IS FORCED: send with `network: CHAIN.TESTNET` and refuse to submit when
  `wallet.account.chain !== CHAIN.TESTNET`, with a 'switch your wallet to testnet' hint.
- Amounts are nanotons as strings ("50000000" = 0.05 TON). A text-comment body is
  beginCell().storeUint(0, 32).storeStringTail(text).endCell().toBoc().toString('base64').
- Read chain state from the public indexer https://testnet.toncenter.com/api/v3
  (/transactions?account=…, /jetton/transfers?address=…). Never poll a wallet for history.
- Contracts live in /contracts, compiled with @ton-community/func-js and deployed with
  @ton/ton + @ton/crypto from a node script — keep them out of the Vite bundle.
- Persistent amber "TON testnet only · no real value moves here" banner at the top of the shell.

PAYWALL PROTOCOL (HTTP 402 + memo verification)
- GET /api/public/ton-paid-content with no PAYMENT-MEMO header returns 402 and a challenge:
    { tonVersion: 1, network: "ton:testnet",
      accepts: [{ scheme: "jetton-transfer", payTo: "<receiver>", asset: "<jetton master>",
                  amount: "<smallest units>", decimals: 6, symbol: "USDT",
                  memoPrefix: "chx-", maxTimeoutSeconds: 900 }] }
- The client mints a one-time memo (`chx-` + 12 hex chars), then sends ONE TON Connect message:
  a TEP-74 `transfer` (op 0x0f8a7ea5) to the payer's jetton wallet with destination = payTo,
  forward_ton_amount > 0 and a forward payload carrying the memo as a text comment.
  Forward TON must be non-zero or the memo never reaches the receiver.
- The client then polls the same endpoint with the `PAYMENT-MEMO` header.
- The SERVER verifies independently — never trust the client's word for a payment:
    GET https://testnet.toncenter.com/api/v3/jetton/transfers?address=<payTo>&direction=in&limit=50
    match jetton_master === asset, amount >= required, decoded_forward_payload comment === memo,
    transaction_aborted === false, and transaction_now within the last 15 minutes.
  Only then return 200 with the payload plus a PAYMENT-RESPONSE header.
- Rate-limit the endpoint per IP and reject memos that do not match /^chx-[a-f0-9]{8,32}$/.
- Toncoin fallback: if no jetton master is configured, verify a plain 0.02 TON transfer with the
  same memo through /transactions?account=<payTo> — identical flow, one config flag.

USER FLOW
1. Connect Tonkeeper (testnet) via TON Connect; free test coins from https://t.me/testgiver_ton_bot.
2. Game designers hit the locked casual game incentives resource -> 402 challenge renders as a step list.
3. One wallet confirmation sends the Jetton transfer with the memo; the app polls until the
   server sees it on-chain, then reveals the payload with a tonscan link.
4. Footer renders: "Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14"

TON SURVIVAL KIT (non-obvious rules — follow all of them)
1. BUFFER: browsers have no `Buffer`, but every TON lib returns one, so
   `cell.toBoc().toString("base64")` throws "Buffer is not defined". Add one helper and
   await it at the top of EVERY function touching @ton/core, @ton/crypto or @ton/ton —
   including the TON Connect path, which is the one people forget:
     export async function ensureBuffer() {
       const g = globalThis as typeof globalThis & { Buffer?: unknown };
       if (g.Buffer) return;
       g.Buffer = (await import("buffer")).Buffer;
     }
2. ADDRESS FLAVOURS: one key renders as four strings. `EQ…`/`UQ…` are the mainnet
   flavours (bounceable / non-bounceable), `kQ…`/`0Q…` are the test-network flavours.
   Never string-compare addresses across flavours — normalise first with
   `Address.parse(a).equals(Address.parse(b))`. Render with an explicit flavour:
     addr.toString({ testOnly: true, bounceable: false, urlSafe: true })
   Send user transfers NON-bounceable (`bounce: false`); a bounceable send to an
   uninitialised wallet returns the funds and the demo looks broken.
3. WALLET VERSION: the same mnemonic derives DIFFERENT addresses per wallet version.
   A 24-word TON phrase -> `WalletContractV4` (workchain 0); a 12-word BIP39 phrase
   (Gram, MyTonWallet) -> `WalletContractV5R1`. Derive both, query balances, and use
   the funded one — do not guess. A TON wallet is itself a contract: it needs ~0.05 TON
   and its first send carries `init` with `seqno: 0`. "Not deployed" is normal for a
   fresh address, not an error.
4. EXPLORER: link everything to https://testnet.tonscan.org/address/<addr> and
   https://testnet.tonscan.org/tx/<hash>. Derive the base URL from config, never hardcode.
5. WALLET REALITY CHECK: mobile Tonkeeper and Gram ship mainnet-only, so a test-network
   demo opened on a phone dead-ends with "your wallet is on TON mainnet". Ship a fallback:
   generate a throwaway wallet in the browser (`mnemonicNew()` from @ton/crypto, mnemonic
   in localStorage, funded from the faucet) and sign locally with `WalletContractV4`.
   Lock that browser-held key to the test network — never let it touch real funds.
6. TONCENTER: v3 rate-limits hard (HTTP 429). Wrap every read in a retry with backoff and
   send `X-API-Key: TONCENTER_API_KEY` on anything user-facing.
7. PAYMENT VERIFICATION: verify SERVER-side only, never trust a client-reported hash.
   Mint a one-time `chx-<hex>` memo, then match the recipient's recent transactions on
   amount >= price, decoded comment === memo, `transaction_aborted === false`, and a
   15-minute freshness window. Comments must be sent as a base64 BOC, not plain text:
     beginCell().storeUint(0, 32).storeStringTail(memo).endCell().toBoc().toString("base64")
8. SSR: mount TON Connect client-side only — `lazy(() => import("./ton-client-entry"))`
   inside `<ClientOnly>` + `<Suspense>`. Importing @tonconnect/ui-react at route module
   scope crashes the server render. `tonconnect-manifest.json` must sit at a public https URL.
9. INSTALL: npm i @tonconnect/ui-react @ton/ton @ton/core @ton/crypto buffer
   (add @ton-community/func-js only when you compile and deploy a FunC contract).
END TON SURVIVAL KIT

REQUIRED SECRETS (Lovable -> Project Settings -> Secrets):
- TON_DEPLOYER_MNEMONIC  24-word testnet wallet seed used by the deploy script. Fund it free: https://t.me/testgiver_ton_bot
- TONCENTER_API_KEY      Optional but recommended for rate limits. Get one from https://t.me/tonapibot
- TON_RECEIVER_ADDRESS   Testnet wallet that collects the Jetton payments (can equal the deployer).
- TON_JETTON_MASTER      Jetton master address metered by the paywall; leave empty to meter in Toncoin.
- PINATA_JWT            IPFS uploads (only if the app pins media). Docs: https://docs.pinata.cloud/llms-full.txt

CREDIT (must appear in the UI footer):
Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
Appendix · Market

Market sizing.

TAM
$18B
The global casual puzzle game and micro-transaction market transitioning to web3 rails.
SAM
$850M
The casual mobile gaming market shift toward direct-to-developer micro-transactions and ad-free models.
SOM
$12M
On-chain puzzle enthusiasts and autonomous agents on Optimism TON testnet using automated wallet signing.

Indicative figures for hackathon pitches — refine with your own research before raising.

See also

Adjacent entries.