Interactive Auction Game
Turn art auctions into engaging games with transparent rules enforced by onchain smart contracts.
TON smart contract· onchain logic
Section · Onchain
full primer →The primitive.
Gamified art auctions gets a tiny FunC contract deployed to the TON testnet; painters see a 'live on TON' badge with the contract address and a one-tap tonscan link.
Why this primitiveTON testnet contracts enable trustless, rule-based game mechanics for auctions.
Kernel
a FunC contract compiled with @ton-community/func-js and deployed to the TON testnet from a 24-word deployer mnemonic, then read back through toncenter
Drives the UI as
a 'live on TON testnet' badge with the contract address and a tonscan link
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 "Interactive Auction Game" in ONE Lovable message. Single-page demo on the TON testnet.
CONCEPT
Turn art auctions into engaging games with transparent rules enforced by onchain smart contracts.
Discipline: Visual Art (gamified art auctions).
Onchain primitive: TON smart contract. Why this primitive: TON testnet contracts enable trustless, rule-based game mechanics for auctions.
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.
CONTRACT (contracts/InteractiveAuctionGame.fc — FunC, compiled with @ton-community/func-js):
```func
;; InteractiveAuctionGame — Turn art auctions into engaging games with transparent rules enforced by onchain smart contracts.
;; 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. Land on the page -> 'Connect Tonkeeper' via TON Connect -> friendly testnet address shown.
2. Painters perform a gamified art auctions action; the app sends a text-comment message to the contract
and the entry appears in the live feed read from toncenter, each row linking to tonscan.
3. 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
$15B
art auction global market
SAM
$500M
gamified auction platforms
SOM
$40M
users engaging in blockchain auctions
Indicative figures for hackathon pitches — refine with your own research before raising.
Adjacent entries.
art ownership tracking
Provenance Palette
Securely track and prove the ownership lineage of paintings with tamper-proof blockchain records.
generative art mintingGenerative Mint Studio
Artists can mint unique generative art pieces directly onto TON testnet with automated smart contracts.
gallery exhibition trackingExhibit Chain Ledger
Record every artwork's exhibition history securely and transparently onchain for galleries and collectors.
color authenticity validationColorCode Certifier
Certify and verify exact color compositions of artworks using blockchain color code hashes.