Real onchain, five secrets, one build.
Every mega-prompt in this repo uses the same pattern, because it's the only pattern that lets a Lovable account ship a verifiable Arc Testnet demo in one shot.
Why Arc Testnet?
Arc is Circle's EVM-compatible L1 with sub-second finality where USDC is the native gas token. Contracts deploy with standard Hardhat, are verified on arcscan (Blockscout) with no API key, and settle payments in USDC, EURC or cirBTC via ordinary ERC-20 transfers. Judges can try the demo without holding ETH.
The recipe
# 1. Add the secrets (Settings -> Secrets): CIRCLE_API_KEY=... # console.circle.com (you paste) PRIVY_APP_ID=... # dashboard.privy.io (you paste) # The two below are generated for you by scripts/bootstrap-circle.mjs CIRCLE_ENTITY_SECRET=... # auto — printed by the bootstrap script CIRCLE_TREASURY_WALLET_ID=... # auto — printed by the bootstrap script VITE_CIRCLE_TREASURY_ADDRESS=0x... # auto — the address to fund at faucet.circle.com CIRCLE_KIT_KEY=... # optional, App Kit widgets # 2. Run the bootstrap once in the Lovable sandbox — it generates + registers # CIRCLE_ENTITY_SECRET and mints an ARC-TESTNET treasury wallet: node scripts/bootstrap-circle.mjs # Paste the three values it prints into Project Settings -> Secrets. # 3. Fund the printed treasury ADDRESS with USDC (gas), EURC, cirBTC: open https://faucet.circle.com/ # 4. Copy a mega-prompt from this repo into Lovable. One paste: # - scaffolds the React app on Arc (viem defineChain, decimals: 6) # - writes a Solidity contract (with hackathon credit in NatSpec) # - deploys via Circle SCP (USDC gas straight from the treasury) # - verifies on arcscan / Blockscout via REST (no plugin, no API key) # - wires Privy Google sign-in with Arc as defaultChain + supportedChain # - ships a USDC / EURC / cirBTC token switcher # 5. Open the arcscan link. Your demo is provably onchain on Circle Arc.
1. The contract — credit baked in
Every Solidity file deployed from a Creative Blockchain prompt MUST carry the hackathon credit in NatSpec, so provenance lives onchain alongside the bytecode.
// contracts/Provenance.sol — every contract carries the hackathon credit in NatSpec
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title Provenance
/// @notice Built during the Creative AI & Quantum Hackathon
/// @notice organised by StreetKode Fam during Indian Krump Festival 14
contract Provenance {
// token = USDC / EURC / cirBTC ERC-20 on Arc Testnet
event Logged(address indexed author, address indexed token, uint256 amount, string cid, uint256 at);
function log(address token, uint256 amount, string calldata cid) external {
emit Logged(msg.sender, token, amount, cid, block.timestamp);
}
}
2. Deploy via Circle SCP (USDC gas)
No MetaMask, no Hardhat. Compile with solc, submit to Circle's Smart Contract Platform, and pay gas in USDC straight from the treasury wallet. Entity secret ciphertext is single-use — regenerate every call.
// scripts/deploy-arc.mjs — Circle SCP deploy. USDC gas from the treasury wallet.
// No MetaMask. No Hardhat. Compile with solc, submit to Circle, poll for the address.
import fs from "node:fs"; import crypto from "node:crypto"; import solc from "solc";
const API = "https://api.circle.com/v1/w3s";
const H = { Authorization: `Bearer ${process.env.CIRCLE_API_KEY}`, "Content-Type": "application/json" };
async function encryptEntitySecret() {
const { data } = await fetch(`${API}/config/entity/publicKey`, { headers: H }).then(r => r.json());
return crypto.publicEncrypt(
{ key: crypto.createPublicKey(data.publicKey), oaepHash: "sha256",
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING },
Buffer.from(process.env.CIRCLE_ENTITY_SECRET, "hex")
).toString("base64"); // single-use — regenerate every call
}
const name = process.argv[2];
const src = fs.readFileSync(`contracts/${name}.sol`, "utf8");
const out = JSON.parse(solc.compile(JSON.stringify({
language: "Solidity", sources: { [`${name}.sol`]: { content: src } },
settings: { optimizer: { enabled: true, runs: 200 },
outputSelection: { "*": { "*": ["abi", "evm.bytecode.object"] } } },
})));
const c = out.contracts[`${name}.sol`][name];
const { data: { contractId } } = await fetch(`${API}/contracts/deploy`, {
method: "POST", headers: H, body: JSON.stringify({
walletId: process.env.CIRCLE_TREASURY_WALLET_ID,
blockchain: "ARC-TESTNET", name,
bytecode: "0x" + c.evm.bytecode.object,
abiFunctionSignature: "constructor()",
entitySecretCiphertext: await encryptEntitySecret(),
fee: { type: "level", config: { feeLevel: "MEDIUM" } },
}),
}).then(r => r.json());
let addr;
for (let i = 0; i < 60 && !addr; i++) {
await new Promise(r => setTimeout(r, 2000));
const { data: { contract } } = await fetch(`${API}/contracts/${contractId}`, { headers: H }).then(r => r.json());
if (contract.state === "COMPLETE") addr = contract.contractAddress;
}
fs.writeFileSync("src/data/contract.json", JSON.stringify({ address: addr, abi: c.abi }, null, 2));
console.log(`Deployed ${name} -> ${addr}`);
3. Verify on arcscan / Blockscout (REST)
One POST to /api/v2/smart-contracts/<addr>/verification/via/flattened-code. No API key, no Etherscan, no Hardhat plugin.
// scripts/verify-arc.mjs — Blockscout REST. NO API key. NO plugin. NO Etherscan.
import fs from "node:fs";
const addr = JSON.parse(fs.readFileSync("src/data/contract.json", "utf8")).address;
const source = fs.readFileSync(process.argv[2], "utf8"); // flattened .sol
const form = new FormData();
form.append("compiler_version", "v0.8.24+commit.e11b9ed9");
form.append("license_type", "mit");
form.append("optimization", "true");
form.append("optimization_runs", "200");
form.append("source_code", source);
const res = await fetch(
`https://testnet.arcscan.app/api/v2/smart-contracts/${addr}/verification/via/flattened-code`,
{ method: "POST", body: form },
);
console.log(res.status, await res.text());
// Then poll GET /api/v2/smart-contracts/${addr} until is_verified: true.
4. Multi-stablecoin support (USDC · EURC · cirBTC)
// src/lib/tokens.ts — USDC · EURC · cirBTC on Arc Testnet
export const ARC_CHAIN_ID = 5042002;
export const ARC_RPC_URL = import.meta.env.VITE_ARC_RPC_URL ?? "https://rpc.testnet.arc.network";
export const ARC_EXPLORER = "https://testnet.arcscan.app";
export const TOKENS = {
USDC: { symbol: "USDC", address: "0x3600000000000000000000000000000000000000", decimals: 6, label: "US Dollar (native gas)" },
EURC: { symbol: "EURC", address: "0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a", decimals: 6, label: "Euro Coin" },
cirBTC: { symbol: "cirBTC", address: import.meta.env.VITE_CIRBTC_ADDRESS ?? "0x0000000000000000000000000000000000000000", decimals: 8, label: "Circle Wrapped BTC" },
} as const;
export type TokenKey = keyof typeof TOKENS;
5. Sign in with Google via Privy
// src/lib/arc-chain.ts + src/main.tsx — viem chain + Privy on Arc
import { defineChain } from "viem";
// CRITICAL: decimals: 6 because USDC is the gas token on Arc. Using 18 corrupts every fee by 10^12.
export const arcTestnet = defineChain({
id: 5042002,
name: "Arc Testnet",
network: "arc-testnet",
nativeCurrency: { name: "USD Coin", symbol: "USDC", decimals: 6 },
rpcUrls: { default: { http: [import.meta.env.VITE_ARC_RPC_URL ?? "https://rpc.testnet.arc.network"] } },
blockExplorers: { default: { name: "Arcscan", url: "https://testnet.arcscan.app" } },
});
import { PrivyProvider } from "@privy-io/react-auth";
<PrivyProvider
appId={import.meta.env.VITE_PRIVY_APP_ID}
config={{
loginMethods: ["google", "email"],
embeddedWallets: { createOnLogin: "users-without-wallets" },
defaultChain: arcTestnet,
supportedChains: [arcTestnet], // BOTH required — omitting supportedChains silently drops the chain
}}
>
<App />
</PrivyProvider>
Hackathon rules of thumb
- · One mega-prompt = one build message. Don't iterate the architecture, iterate the UI.
- · Always show the live arcscan link in the UI — that's your proof.
- · Support all three tokens (USDC · EURC · cirBTC) — a token switcher is a five-line component.
- · Use Privy so judges don't need MetaMask to try the demo.
- · Add a "Built during the Creative AI & Quantum Hackathon — StreetKode Fam · Indian Krump Festival 14" line to your footer.