Sponsored Multiplayer Drops
Distribute gasless event drops during multiplayer games with embedded wallets and sponsored tx.
TON Connect wallet· wallet UX
Section · Onchain
full primer →The primitive.
Game designers connect Tonkeeper through TON Connect — one QR or deep link, no extension — and every event rewards action becomes a signed testnet transaction they can read back on tonscan.
Why this primitiveTON Connect social and sponsored transactions ensure smooth, gas-free event drop delivery.
Kernel
TON Connect wired to Tonkeeper, MyTonWallet and Tonhub through a public tonconnect-manifest.json — one QR or deep link and the user is on-chain, with every transaction pinned to CHAIN.TESTNET
Drives the UI as
a single 'Connect Tonkeeper' button that swaps into the friendly address and a testnet badge
Required keys.
TON_DEPLOYER_MNEMONIC
24-word testnet seed for the deploy script. Fund it free via the Telegram test giver.
open ↗Add these in your Lovable project under Settings → Secrets before pasting the prompt below.
Appendix · Mega-prompt
The build prompt.
budget · 1 message
Target
Paste into a fresh Lovable project. Make sure all five secrets above are set first. read the build strategy →
Build "Sponsored Multiplayer Drops" in ONE Lovable message. Single-page demo on the TON testnet.
CONCEPT
Distribute gasless event drops during multiplayer games with embedded wallets and sponsored tx.
Discipline: Game Design & Interactive Media (event rewards).
Onchain primitive: TON Connect wallet. Why this primitive: TON Connect social and sponsored transactions ensure smooth, gas-free event drop delivery.
5-CREDIT BUDGET (HARD LIMIT)
- ONE single-page app. No router, no Lovable Cloud, no database, no auth beyond TON Connect.
- ONE FunC contract, <=60 lines, deployed to TON testnet and readable on tonscan.
- TON Connect is always the wallet layer (Tonkeeper, MyTonWallet, Tonhub).
- Pinata/IPFS only if the idea genuinely needs to store a file or metadata.
- At most ONE AI call per user action (Lovable AI Gateway with LOVABLE_API_KEY, if AI is part of the idea).
- Skip tests, skip CI, skip docs pages. Ship the demo, nothing else.
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.
WALLET LAYER (the whole point of this build)
- TON Connect handles identity: no seed phrase typing, no browser extension required —
desktop shows a QR, mobile deep-links straight into Tonkeeper.
- Surface four explicit states: not installed, connected, wrong network (mainnet), and
transaction pending. Never silently retry a rejected transaction.
- Every event rewards action is one `sendTransaction` with a text-comment payload, pinned to CHAIN.TESTNET.
CONTRACT (contracts/SponsoredMultiplayerDrops.fc — FunC, compiled with @ton-community/func-js):
```func
;; SponsoredMultiplayerDrops — Distribute gasless event drops during multiplayer games with embedded wallets and sponsored tx.
;; Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
slice begin_parse(cell c) asm "CTOS";
builder begin_cell() asm "NEWC";
cell end_cell(builder b) asm "ENDC";
cell get_data() asm "c4 PUSH";
() set_data(cell c) impure asm "c4 POP";
int slice_bits(slice s) asm "SBITS";
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
if (in_msg_body.slice_bits() < 32) { return (); }
int op = in_msg_body~load_uint(32);
if (op != 0) { return (); } ;; text-comment messages only
slice ds = get_data().begin_parse();
int total = ds.slice_bits() >= 64 ? ds~load_uint(64) : 0;
set_data(begin_cell().store_uint(total + 1, 64).end_cell());
}
int total_logs() method_id {
slice ds = get_data().begin_parse();
if (ds.slice_bits() < 64) { return 0; }
return ds~load_uint(64);
}
```
The payload itself lives forever in the transaction history; the counter proves the
contract actually processed it. Deploy with a node script that builds
`contractAddress(0, { code, data: beginCell().storeUint(0, 64).endCell() })`, sends 0.05 TON
with `init`, then writes the address into src/data/ton.json.
USER FLOW
1. 'Connect Tonkeeper' -> address chip + testnet badge.
2. Game designers act on their event rewards; the wallet sheet shows the exact nanoton amount and comment.
3. The confirmed transaction appears in the feed 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
- 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 AND as a comment header in every deployed contract):
Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
Market sizing.
TAM
$7B
live multiplayer events market
SAM
$1.3B
indie multiplayer events
SOM
$260M
gasless event reward systems
Indicative figures for hackathon pitches — refine with your own research before raising.
Adjacent entries.
multiplayer coordination
Gasless Guilds
Seamlessly create and join guilds with gas-free onboarding and instant member transactions.
reward distributionSponsored Loot Drops
Distribute in-game rewards directly to players' wallets without any gas fees.
XR social spacesTonkeeper VR Lobby
Enter virtual lobbies with gas-free wallet login and seamless social interactions.
digital fashionOnchain Avatar Store
Buy and customize avatars with zero gas fees using embedded wallets and sponsored transactions.