🎵 Music & Sound Design · lyric version control

InkTrace · Jetton

Micropayment-gated version control for lyricists. Pay $0.01 per 'Commit' to cryptographically timestamp a draft. Fans or collaborators pay $0.05 to unlock the 'Process Log', viewing the evolution of a hit song line-by-line. Protects IP via EIP-712 signatures while turning the creative process into a paid ledger.

TON Jetton paywall· jetton native
Section · Onchain

The primitive.

full primer →

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

Why this primitiveTraditional NFTs are too heavy for granular draft tracking. the Jetton paywall allows for high-frequency, low-cost 'save points' that establish a verifiable chain of custody for lyrics. It turns the 'deleted scenes' of songwriting into a new revenue stream for artists.

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 "InkTrace · Jetton" in ONE Lovable message. Single-page Jetton-metered paid app on the TON testnet.

CONCEPT
Micropayment-gated version control for lyricists. Pay $0.01 per 'Commit' to cryptographically timestamp a draft. Fans or collaborators pay $0.05 to unlock the 'Process Log', viewing the evolution of a hit song line-by-line. Protects IP via EIP-712 signatures while turning the creative process into a paid ledger.
Discipline: Music & Sound Design (lyric version control).
Onchain primitive: Jetton micropayments on TON (USDT-on-TON shape, TEP-74 transfers). Why: Traditional NFTs are too heavy for granular draft tracking. the Jetton paywall allows for high-frequency, low-cost 'save points' that establish a verifiable chain of custody for lyrics. It turns the 'deleted scenes' of songwriting into a new revenue stream for artists.

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. Musicians hit the locked lyric version control 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
$1.4B
The global music publishing and IP protection market migrating to automated, on-chain registries.
SAM
$22M
1.5M independent songwriters and topliners using digital workstations and note-taking apps.
SOM
$850K
Early adopters in the web3 music scene and ghostwriters requiring immutable proof of work for royalty disputes.

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

See also

Adjacent entries.