Privy Challenge Leaderboards
Track daily challenges and leaderboards with gasless wallet logins and sponsored updates.
Privy Solana Login· auth
Section · Onchain
full primer →The primitive.
Game designers sign in with Google through Privy — no seed phrase, no wallet extension — and their competitive tracking actions are signed by an embedded Solana wallet in the background.
Why this primitivePrivy social plus sponsored tx supports real-time leaderboard updates without user gas.
Kernel
Privy signs users in with Google and provisions an embedded Solana wallet — no seed phrase, no Phantom extension required.
Drives the UI as
One-tap 'Continue with Google' drops users straight into the workspace with a funded Devnet address ready to sign program calls.
Required keys.
SOLANA_RPC_URL
Alchemy Solana Devnet RPC (https://solana-devnet.g.alchemy.com/v2/<KEY>). The public api.devnet.solana.com is rate-limited and CORS-blocked in the browser.
open ↗PHANTOM_PRIVATE_KEY
Base58 secret key exported from Phantom (Settings → Export Private Key). Used ONCE by scripts/deploy.ts to pay rent + fees for your bespoke program on Devnet. Fund it from https://faucet.solana.com. Never shipped to the browser.
open ↗Add these in your Lovable project under Settings → Secrets before pasting the prompt below.
Appendix · Mega-prompt
The build prompt.
budget · 1 message
Paste into a fresh Lovable project. Make sure all five secrets above are set first. read the build strategy →
Build "Privy Challenge Leaderboards" in ONE Lovable message. Single-page demo on Solana Devnet. This prompt
is self-contained — do NOT rely on any external Solana skill or docs beyond what is inlined here.
CONCEPT
Track daily challenges and leaderboards with gasless wallet logins and sponsored updates.
Discipline: Game Design & Interactive Media (competitive tracking).
Onchain primitive: Privy Solana Login. Why this primitive: Privy social plus sponsored tx supports real-time leaderboard updates without user gas.
5-CREDIT BUDGET (HARD LIMIT — one Lovable message, no follow-ups):
- ONE single-page app (index route only). No router, no Lovable Cloud, no database, no auth flows
beyond the Privy drop-in.
- ONE bespoke Solana program deployed to Devnet FROM THE SANDBOX during this build (see DEPLOY),
then called from the browser via Privy's embedded wallet. No Anchor framework — plain
`solana-program` crate keeps the .so under 100 KB and rent under 0.5 SOL.
- Privy is ALWAYS the browser auth + signing layer (Google login, embedded Solana wallet on Devnet).
- Pinata/IPFS only if the idea genuinely needs to store a file or JSON metadata.
- At most ONE `LOVABLE_API_KEY` call per user action, invoked from a server function (never the browser).
- Skip tests, skip CI, skip docs pages. Ship the demo, nothing else.
REQUIRED SECRETS (Lovable -> Project Settings -> Secrets — add BEFORE sending this prompt):
- LOVABLE_API_KEY Auto-provisioned by Lovable. One AI call per user action, max.
- PRIVY_APP_ID From https://dashboard.privy.io. In the SAME Privy app, whitelist BOTH
`https://*.lovable.app` AND your published `https://<slug>.lovable.app`
under Allowed Origins, or the signing iframe is killed by `frame-ancestors`
CSP and every tx fails with a blank "Something went wrong" modal.
Enable "Solana gas sponsorship" for cluster `solana:devnet` in the same
dashboard so users never see a fund-wallet prompt.
- PINATA_JWT Only required if the app pins media/metadata to IPFS.
Get one at https://app.pinata.cloud (JWT, not the legacy API key pair).
- SOLANA_RPC_URL Alchemy Solana Devnet RPC: https://solana-devnet.g.alchemy.com/v2/<KEY>.
The public https://api.devnet.solana.com is rate-limited and blocks
browser CORS on getLatestBlockhash — do NOT use it.
- PHANTOM_PRIVATE_KEY Base58 secret key exported from YOUR Phantom wallet (Settings -> Security
& Privacy -> Show Secret Recovery Phrase -> Export Private Key). Fund it
with ~2 Devnet SOL from https://faucet.solana.com BEFORE sending this
prompt. Lovable uses this key EXACTLY ONCE inside the sandbox during this
build to `solana program deploy` the bespoke program, then wipes it. The
browser bundle must never import it.
STACK
- React + Vite single page (the index route only).
- `@solana/web3.js` for tx building. `@privy-io/react-auth` v3+ for auth AND signing.
- Cluster: Devnet ONLY. Never mainnet. Use the Alchemy `SOLANA_RPC_URL` everywhere — in the
frontend Connection, in `PrivyProvider.solana.rpcs`, and in the sandbox `solana config`.
- Devnet gas is sponsored by Privy (dashboard setting). Never call `requestAirdrop`, never render
a "fund wallet" UI.
VITE + BUFFER POLYFILL (4 layers — omit any one and it works in dev but blanks the
published mobile build):
1. `bun add buffer vite-plugin-node-polyfills`.
2. `vite.config.ts`:
```ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
plugins: [react(), nodePolyfills({ globals: { Buffer: true, global: true }, protocolImports: true })],
optimizeDeps: { esbuildOptions: { define: { global: "globalThis" } } },
resolve: { alias: { "rpc-websockets/dist/lib/client": "rpc-websockets/dist/lib/client.browser.js" } },
});
```
DO NOT add a top-level `define: { global: "globalThis" }` in vite.config — it conflicts with the
plugin's Rollup inject and leaves Buffer undefined in dependency chunks. DO NOT put `import`
statements inside `build.rollupOptions.output.intro` — top-level import inside a chunk wrapper is
illegal and blanks the page.
3. `index.html` — inline BEFORE any bundle loads:
```html
<script type="module">
import { Buffer } from "https://esm.sh/buffer@6";
globalThis.Buffer = globalThis.Buffer || Buffer;
</script>
```
4. `src/polyfills.ts` (imported FIRST in `src/main.tsx`, before anything else):
```ts
import { Buffer } from "buffer";
(globalThis as any).Buffer = (globalThis as any).Buffer || Buffer;
(window as any).Buffer = (window as any).Buffer || Buffer;
```
Then in every file that touches Solana, add `import { Buffer } from "buffer";` at the top — the
plugin cannot inject into your own TypeScript source.
PRIVY (browser auth + Solana signing) — Privy v3, MUST include `solana.rpcs`:
Install: `bun add @privy-io/react-auth @solana/web3.js @solana/kit @solana-program/memo`
(`@solana-program/memo` is an implicit peer dep of `@privy-io/react-auth/solana`; missing it
crashes the Privy modal at runtime).
`src/components/PrivyRoot.tsx` (single-page app, no SSR concerns here, but keep imports scoped):
```tsx
import { PrivyProvider } from "@privy-io/react-auth";
import { toSolanaWalletConnectors } from "@privy-io/react-auth/solana";
import { createSolanaRpc, createSolanaRpcSubscriptions } from "@solana/kit";
const rpcUrl = import.meta.env.VITE_SOLANA_RPC_URL!; // set from SOLANA_RPC_URL secret
const wsUrl = rpcUrl.replace("https://", "wss://");
export function PrivyRoot({ children }: { children: React.ReactNode }) {
return (
<PrivyProvider
appId={import.meta.env.VITE_PRIVY_APP_ID!}
config={{
loginMethods: ["google", "email"],
embeddedWallets: { solana: { createOnLogin: "users-without-wallets" } },
externalWallets: { solana: { connectors: toSolanaWalletConnectors() } },
solanaClusters: [{ name: "devnet", rpcUrl }],
solana: {
rpcs: {
"solana:devnet": {
rpc: createSolanaRpc(rpcUrl),
rpcSubscriptions: createSolanaRpcSubscriptions(wsUrl),
},
},
},
}}
>{children}</PrivyProvider>
);
}
```
Without the `solana.rpcs` mapping, Privy throws "No RPC configuration found for chain solana:devnet"
the moment the user tries to sign.
Expose the secrets to the browser in `.env.local` (Lovable already mirrors non-VITE secrets, but
Vite only ships `VITE_*` to the client):
```
VITE_PRIVY_APP_ID=<same value as PRIVY_APP_ID secret>
VITE_SOLANA_RPC_URL=<same value as SOLANA_RPC_URL secret>
```
Sign + send with sponsorship:
```tsx
import { useSolanaWallets, useSignAndSendTransaction } from "@privy-io/react-auth/solana";
const { wallets } = useSolanaWallets();
const embedded = wallets.find(w => w.walletClientType === "privy");
const { signAndSendTransaction } = useSignAndSendTransaction();
const { signature } = await signAndSendTransaction(tx, {
address: embedded!.address, // pin to embedded wallet — else Privy routes to an external one
sponsor: true, // opts into the dashboard's gas sponsorship
});
```
Never call `connection.requestAirdrop` and never render a "fund your wallet" UI — sponsorship
covers everything on Devnet.
DEPLOY (Lovable runs this ONCE, inside the sandbox, during THIS build message —
it counts toward the 5-credit budget, so make it the first thing you do):
1. Create `solana/program/src/lib.rs` — a tiny native Rust program (no Anchor) with on-chain
security metadata so Explorer's Security tab shows contact + source URL even before OtterSec
verification lands:
```rust
use solana_program::{account_info::AccountInfo, entrypoint, entrypoint::ProgramResult,
msg, pubkey::Pubkey};
#[cfg(not(feature = "no-entrypoint"))]
use solana_security_txt::security_txt;
#[cfg(not(feature = "no-entrypoint"))]
security_txt! {
name: "<your-program-name>",
project_url: "https://<your-slug>.lovable.app",
contacts: "email:you@example.com",
policy: "https://github.com/<user>/<repo>/blob/main/SECURITY.md",
source_code: "https://github.com/<user>/<repo>",
preferred_languages: "en",
auditors: "None"
}
entrypoint!(process);
pub fn process(_pid: &Pubkey, _accs: &[AccountInfo], data: &[u8]) -> ProgramResult {
msg!("payload: {}", std::str::from_utf8(data).unwrap_or("<binary>"));
Ok(())
}
```
and `solana/program/Cargo.toml` with `[lib] crate-type = ["cdylib", "lib"]`,
`[features] no-entrypoint = []`, and dependencies `solana-program = "1.18"`,
`solana-security-txt = "1.1"`.
Also create `solana/program/rust-toolchain.toml` pinning the channel — this is REQUIRED for
`solana-verify --remote` to produce the same hash as on-chain:
```toml
[toolchain]
channel = "1.89.0"
```
2. In the sandbox shell (run in this exact order):
```bash
# install toolchains if missing
sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"
export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"
bun add bs58
# materialise the deployer keypair from the Phantom secret
node -e '
const bs58 = require("bs58");
const fs = require("fs");
const secret = bs58.decode(process.env.PHANTOM_PRIVATE_KEY);
fs.writeFileSync("/tmp/deployer.json", JSON.stringify(Array.from(secret)));
'
solana config set --url "$SOLANA_RPC_URL" --keypair /tmp/deployer.json
solana balance # sanity check — must be >= 2 SOL
# build + deploy (commit Cargo.lock afterwards — verification needs it)
cargo build-sbf --manifest-path solana/program/Cargo.toml
PROGRAM_ID=$(solana program deploy \
solana/program/target/deploy/*.so --output json | jq -r .programId)
echo "export const PROGRAM_ID = \"$PROGRAM_ID\";" > src/lib/program-id.ts
# wipe the deployer key — the browser bundle must never see it
rm -f /tmp/deployer.json
```
3. Frontend imports `PROGRAM_ID` from `src/lib/program-id.ts`. The Program ID is the only Solana
program identifier that ever reaches the browser bundle.
VERIFY (reproducible build badge on Solana Explorer) — do NOT attempt submission
from the sandbox; instead ship the artifacts so the user can run it themselves once their repo is
public on GitHub:
1. Commit `solana/program/rust-toolchain.toml` AND `solana/program/Cargo.lock` — OtterSec's remote
builder needs both to reproduce the exact on-chain hash. A missing lockfile or unpinned toolchain
returns "hash mismatch" every time.
2. Create `SECURITY.md` at the repo root with a contact email and this "How to verify" section.
3. Create `solana/program/VERIFY.md` with the exact command, program ID substituted in:
```
solana-verify verify-from-repo --remote \
--url https://api.devnet.solana.com \
--program-id <PROGRAM_ID> \
--library-name <snake_case_crate_name> \
--mount-path solana/program \
--keypair ~/.config/solana/id.json \
https://github.com/<user>/<repo>
```
4. Add `src/components/verification-card.tsx` that polls `https://verify.osec.io/status/<PROGRAM_ID>`
every 30s and renders "Reproducible build ✓ verified" (emerald) when `is_verified` is true,
"Verification pending" (amber) otherwise. Render it on the same page as the program demo.
Hard requirements the user must know about (put them in `VERIFY.md`):
- Repo MUST be **public** on GitHub. OtterSec clones anonymously; private repos fail with a clone
error and Explorer will never show the green badge.
- The `~/.config/solana/id.json` on the user's machine MUST be the same upgrade authority that
deployed the program (i.e. the Phantom key they used as `PHANTOM_PRIVATE_KEY`).
- Verification is Docker-free thanks to `--remote` (OtterSec builds server-side). The user does
NOT need Docker installed.
CALL THE DEPLOYED PROGRAM (`src/lib/tx.ts`) — order of `keys` MUST match
your Rust `#[derive(Accounts)]` field-for-field (a swap surfaces as `AccountNotInitialized` or a bare
signature-verification error with no useful message):
```ts
import { Buffer } from "buffer";
import { Connection, PublicKey, Transaction, TransactionInstruction } from "@solana/web3.js";
import { PROGRAM_ID } from "./program-id";
export function connection() {
return new Connection(import.meta.env.VITE_SOLANA_RPC_URL!, "confirmed");
}
export async function buildTx(payer: PublicKey, payload: string) {
const ix = new TransactionInstruction({
keys: [{ pubkey: payer, isSigner: true, isWritable: true }], // order is load-bearing
programId: new PublicKey(PROGRAM_ID),
data: Buffer.from(payload, "utf8"),
});
const { blockhash } = await connection().getLatestBlockhash();
const tx = new Transaction({ recentBlockhash: blockhash, feePayer: payer }).add(ix);
return tx;
}
```
Do NOT install `@coral-xyz/anchor` — it drags in Node-only deps that fight Vite. Build instructions
by hand as above. Explorer link format: `https://explorer.solana.com/tx/<sig>?cluster=devnet`.
USER FLOW
1. Land on page -> "Continue with Google" (Privy) -> embedded Solana wallet auto-provisioned,
Devnet gas sponsored — no airdrop or funding UI.
2. Every competitive tracking action the user performs is turned into a bespoke-program tx signed by their Privy embedded wallet (zero clicks after Google login, gas sponsored) and displayed with a Solana Explorer link.
3. Footer renders the credit line below.
COMMON GOTCHAS (each one has bitten prior participants — read before shipping):
- "Buffer is not defined" on published mobile only: you skipped one of the 4 polyfill layers above.
- Privy modal shows "Something went wrong" and console has a `frame-ancestors` CSP error:
add your `*.lovable.app` origin under Privy Dashboard -> Allowed Origins for the SAME app whose
ID is in `PRIVY_APP_ID`.
- Privy modal shows "No RPC configuration found for chain solana:devnet": you forgot the
`solana.rpcs` mapping in `PrivyProvider` config.
- `signAndSendTransaction` succeeds but user gets a wallet-connect prompt: pass
`{ address: embedded.address, sponsor: true }` — omitting `address` lets Privy route to an
external wallet.
- `429 Too Many Requests` / CORS errors from `api.devnet.solana.com`: switch `SOLANA_RPC_URL` to
Alchemy Devnet.
- `cargo build-sbf: command not found`: install the Anza CLI (see DEPLOY step 2).
- Program deploy fails with "insufficient funds for rent": the wallet backing
`PHANTOM_PRIVATE_KEY` isn't funded — hit https://faucet.solana.com and re-run just the deploy step.
- OtterSec verification returns "hash mismatch": `rust-toolchain.toml` or `Cargo.lock` isn't
committed, or the repo isn't public. Fix all three and re-run the `solana-verify` command.
CREDIT (must appear in UI footer AND, if you mint an NFT, inside the pinned metadata `description` field):
Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
Market sizing.
TAM
$4B
challenge-based gaming market
SAM
$800M
indie competitive platforms
SOM
$160M
gasless leaderboard maintenance
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 spacesPrivy 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.