🎮 Game Design & Interactive Media · game translation services

Metered Negotiator

The endpoint answers unpaid POSTs with a 402 and an MPP challenge; game designers sends AlphaUSD on chain 42431 and the server checks the receipt before delivering anything.

Tempo MPP· verifiable AlphaUSD receipt
Section · Agentic

The kernel.

full primer →

An agent runs the protocol server-side and game designers get a signed, auditable result they can act on without leaving the app.

Why this primitiveTempo MPP on Tempo Moderato fits game translation services in Game Design & Interactive Media because game designers can settle 0.05 AlphaUSD via a TIP-20 transfer with an on-chain Transfer receipt before the negotiator endpoint returns anything.

Kernel
pay → receipt → side effect on Tempo Moderato (chainId 42431) — the server 402s with a `WWW-Authenticate: MPP` challenge, the client pays AlphaUSD via TIP-20 `transfer` on `0x20c0…0001`, the server verifies the `Transfer` log against the payer and amount, and only then runs the unlock
Drives the UI as
a Pay & Unlock button that streams Challenge · Sign Transfer · Verify · Unlock into the flow log, with a `/receipt/{hash}` link on the Tempo explorer
Appendix · Secrets

Required key.

LOVABLE_API_KEY
Auto-provisioned by Lovable when you enable the Lovable AI add-on. Powers the buyer, seller and merchant agents through an OpenAI-compatible gateway in front of every frontier LLM. Zero copy-paste.
open ↗

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

Appendix · Mega-prompt

The build prompt.

Paste into a fresh Lovable project. Make sure the key above is set first. read the build strategy →

Build "Metered Negotiator · mpp" as a ONE-SHOT Lovable build. The participant has only
5 credits — this single message must produce a working demo with no follow-ups.
Single-page TanStack Start app. Cut scope ruthlessly.

CONCEPT
Lovable AI runs an agent negotiating translation rates via A2A so creators auto-checkout localized UI strings.
Reframed as a paid, agent-callable HTTP endpoint on Tempo Moderato MPP (0.05 AlphaUSD via TIP-20 transfer + pay-receipt-effect verification).
Discipline: Game Design & Interactive Media (game translation services).

LOVABLE BUDGET (HARD CAP: ONE-SHOT, ~5 CREDITS TOTAL):
The participant has FIVE Lovable credits for the whole build. This prompt MUST
ship a working demo on the FIRST message with zero follow-ups. Engineer for that.
- ONE TanStack Start app, ONE route (`src/routes/index.tsx`). No extra pages, no auth, no nav.
- ONE TanStack server route under `src/routes/api/public/` that runs the protocol.
- ONE client surface (a button + flow log) that triggers the payment and renders the result.
- NO database, NO Lovable Cloud, NO extra integrations beyond what's listed below.
- NO tests, NO docs pages, NO settings screens.
- Demo-fallback contract: every code path must boot with NO secrets and return
  realistic simulated envelopes flagged `simulated: true`. Real signing activates
  only when the user signs in and the wallet is funded.

PROTOCOL SURFACE — MPP on Tempo Moderato (self-contained; participant has no skills)

CONFIG (src/lib/mpp/config.ts) — copy exactly:
```ts
export const MPP_RECIPIENT      = process.env.MPP_RECIPIENT ?? "0x0000000000000000000000000000000000000000";
export const TEMPO_CHAIN_ID     = 42431;
export const TEMPO_RPC_URL      = "https://rpc.moderato.tempo.xyz";
export const TEMPO_EXPLORER     = "https://explore.testnet.tempo.xyz";
export const TEMPO_FAUCET_URL   = "https://faucet.moderato.tempo.xyz";
export const ALPHAUSD_ADDRESS   = "0x20c0000000000000000000000000000000000001" as const;
export const CHARGE_AMOUNT_USD  = "0.05";
export const CHARGE_AMOUNT_UNITS = 50_000n;  // 0.05 * 10^6 (AlphaUSD is 6 decimals)
```

TEMPO MODERATO GOTCHAS — get these wrong and it silently fails:

1. Explorer path is `/receipt/{hash}`, NOT `/tx/{hash}`. Every UI link and every
   server response uses `${TEMPO_EXPLORER}/receipt/${txHash}`. `/tx/…` renders
   "Page Not Found" with no redirect on Tempo's explorer.

2. Tempo DISALLOWS native value transfers. `sendTransaction({ to, value })` with
   any non-zero `value` reverts. All AlphaUSD payments move as TIP-20
   `transfer(to, amount)` calls on the AlphaUSD contract:
   ```ts
   import { encodeFunctionData, parseAbi } from "viem";
   const data = encodeFunctionData({
     abi: parseAbi(["function transfer(address to, uint256 amount)"]),
     functionName: "transfer",
     args: [MPP_RECIPIENT, CHARGE_AMOUNT_UNITS],
   });
   const txHash = await provider.sendTransaction({
     to: ALPHAUSD_ADDRESS,   // TOKEN address, not recipient
     data,
     value: 0n,              // MUST be zero
   });
   ```

3. Server verification MUST check ALL FIVE in this order — missing any is a
   silent-accept bug:
   (a) `receipt.status === "success"`
   (b) `tx.chainId === 42431`
   (c) `tx.to.toLowerCase() === ALPHAUSD_ADDRESS`
   (d) `tx.from.toLowerCase() === expectedPayer.toLowerCase()`  ← replay guard
   (e) Receipt has a `Transfer(from, to, value)` log emitted by `ALPHAUSD_ADDRESS`
       with `args.to === MPP_RECIPIENT` and `args.value >= CHARGE_AMOUNT_UNITS`.
   Use viem's `parseEventLogs` + `parseAbi(["event Transfer(address indexed from, address indexed to, uint256 value)"])`
   and filter by `log.address === ALPHAUSD_ADDRESS`. Missing (d) lets anyone
   replay someone else's payment tx.

4. Privy dashboard: enable "Allow transactions from the client" for Tempo Testnet
   under Chains. Without it, `sendTransaction` HANGS FOREVER with no error.
   Wrap the call in a 45s `Promise.race` timeout whose rejection message names
   this exact dashboard setting.

5. Privy chain config MUST be a real viem `defineChain`, NOT a `{id, name} as never`
   stub — the stub compiles but breaks embedded-wallet transport init. Define
   once and pass to BOTH `defaultChain` and `supportedChains`:
   ```ts
   import { defineChain } from "viem";
   export const tempoModerato = defineChain({
     id: 42431,
     name: "Tempo Moderato",
     nativeCurrency: { name: "AlphaUSD", symbol: "USD", decimals: 6 },
     rpcUrls: { default: { http: [TEMPO_RPC_URL] } },
     blockExplorers: { default: { name: "Tempo Explorer", url: TEMPO_EXPLORER } },
   });
   ```

6. Privy mount is SSR-forbidden. `@privy-io/react-auth` explodes under SSR —
   load it via `lazy(() => import("./privy-client-entry"))` inside
   `<ClientOnly>` + `<Suspense>` in `src/components/privy-root.tsx`. NEVER
   import the Privy package at the module scope of a route file.

PAY → RECEIPT → EFFECT (the entire trust story):

SERVER ROUTE (src/routes/api/public/mpp-charge.ts) — the side effect ONLY runs
after receipt verification. Preserve HTTP 402 + `WWW-Authenticate` end-to-end.

Unpaid POST (no `X-Payment-Tx` header) — return the 402 challenge:
```
HTTP/1.1 402 Payment Required
WWW-Authenticate: MPP intent="charge", chainId=42431, recipient="0x…", amount="0.05", currency="USD", asset="native"
Content-Type: application/json

{ "scheme": "MPP", "intent": "charge", "network": "tempo-moderato",
  "recipient": MPP_RECIPIENT, "chainId": 42431, "asset": "native",
  "amount": "0.05", "amountUnits": "50000", "currency": "USD",
  "description": "Unlock the game translation services pack" }
```
Ship BOTH the `WWW-Authenticate` header AND the JSON body — mppx clients need
the header to retry-with-payment; skipping it makes the endpoint useless.
NEVER map 402 → 500. `amount` is human-readable ("0.05"); `amountUnits` is the
atomic string ("50000"). Servers verify against `amountUnits`; UIs display `amount`.

Paid POST (`X-Payment-Tx: 0x…` + `X-Payer: 0x…`) — verify then execute:
```ts
import { createPublicClient, http, parseAbi, parseEventLogs } from "viem";
import { tempoModerato, ALPHAUSD_ADDRESS, MPP_RECIPIENT, CHARGE_AMOUNT_UNITS, TEMPO_CHAIN_ID } from "@/lib/mpp/config";

const client = createPublicClient({ chain: tempoModerato, transport: http(TEMPO_RPC_URL) });
const [tx, receipt] = await Promise.all([
  client.getTransaction({ hash: txHash }),
  client.getTransactionReceipt({ hash: txHash }),
]);

if (receipt.status !== "success") return json402("tx_not_success");
if (tx.chainId !== TEMPO_CHAIN_ID) return json402("wrong_chain");
if (tx.to?.toLowerCase() !== ALPHAUSD_ADDRESS.toLowerCase()) return json402("wrong_token");
if (tx.from.toLowerCase() !== expectedPayer.toLowerCase()) return json402("payer_mismatch");

const transfers = parseEventLogs({
  abi: parseAbi(["event Transfer(address indexed from, address indexed to, uint256 value)"]),
  logs: receipt.logs,
}).filter((l) => l.address.toLowerCase() === ALPHAUSD_ADDRESS.toLowerCase());

const paid = transfers.some((l) =>
  l.args.to.toLowerCase() === MPP_RECIPIENT.toLowerCase() &&
  l.args.value >= CHARGE_AMOUNT_UNITS,
);
if (!paid) return json402("insufficient_payment");

// side effect happens ONLY past this point
return Response.json({
  ok: true,
  txHash,
  receipt: `${TEMPO_EXPLORER}/receipt/${txHash}`,
  unlocked: { /* the deliverable for game translation services */ },
});
```

USER FLOW (the entire app):
1. Sign In (email/google) — Privy creates an embedded EVM wallet on Tempo Moderato.
2. Show the wallet address + `TEMPO_FAUCET_URL` link.
3. "Pay & unlock" button — POSTs to `/api/public/mpp-charge`, catches the 402,
   parses the challenge, calls the TIP-20 transfer, then re-POSTs with
   `X-Payment-Tx` + `X-Payer` headers. Show a live log: Challenge · Sign
   Transfer · Verify · Unlock.
4. On success, render the unlocked deliverable + a link to
   `${TEMPO_EXPLORER}/receipt/${txHash}`.

SIMULATE MODE (default when signed out): the flow walks the four steps with a
fake `0x…` tx hash flagged `simulated: true`, no real chain call, no signing
prompt. The button label switches from "Pay & unlock (simulate)" to
"Pay & unlock (live · Tempo Moderato)" once the wallet is ready and funded.

STACK
- TanStack Start app, the index route only.
- Tailwind + shadcn. Editorial look: gold accent on a dark or warm-cream background,
  generous type, one strong headline, one primary action.
- Footer renders: "Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14".
- Libraries: template defaults + `@privy-io/react-auth` + `viem` + `zod`. Nothing else.

CREDIT (UI footer + JSDoc on the server handler): Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
Appendix · Market

Market sizing.

TAM
$5B
global localization industry
SAM
$900M
interactive media translation
SOM
$40M
indie game UI localization

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

See also

Adjacent entries.