Ship a Lovable dApp on Circle's Arc Testnet — chain id 5042002 with USDC as 6-decimal native gas, Privy embedded wallets, Circle developer-controlled treasury wallets, Circle SCP contract deploys, Arcscan/Blockscout verification and v2 indexing, ERC-721 + ERC-2981 royalties, ERC-1271 agent authorization, and multi-stablecoin (USDC/EURC/cirBTC) payment UX. Captures Arc-specific traps: the VITE_ secret-prefix ban, Circle entity-secret onboarding, feeLevel vs gasPrice, @circle-fin SDKs breaking the Cloudflare Worker runtime, and Alchemy's 10-block eth_getLogs cap on Arc. Triggers on Arc Testnet, Arcscan, arc.network, USDC gas, Circle SCP, cirBTC, EURC on Arc, Circle treasury wallet.
Instrucciones de origen · Vista previa de solo lectura
name
lovable-arc
description
Ship a Lovable dApp on Circle's Arc Testnet — chain id 5042002 with USDC as 6-decimal native gas, Privy embedded wallets, Circle developer-controlled treasury wallets, Circle SCP contract deploys, Arcscan/Blockscout verification and v2 indexing, ERC-721 + ERC-2981 royalties, ERC-1271 agent authorization, and multi-stablecoin (USDC/EURC/cirBTC) payment UX. Captures Arc-specific traps: the VITE_ secret-prefix ban, Circle entity-secret onboarding, feeLevel vs gasPrice, @circle-fin SDKs breaking the Cloudflare Worker runtime, and Alchemy's 10-block eth_getLogs cap on Arc. Triggers on Arc Testnet, Arcscan, arc.network, USDC gas, Circle SCP, cirBTC, EURC on Arc, Circle treasury wallet.
Lovable · Arc Testnet
Testnet-only. Everything here is what actually broke shipping an Arc app on
Lovable (four contracts, an agent payout engine, an NFT marketplace with
royalties). Skip anything that "should just work" per the generic Circle/Arc
docs — it mostly does; these are the parts that don't.
For CCTP bridging and UCP checkout schemas see dance-ucp-arc-circle. For the
SSR-safe Privy mount see evvm-privy-integration. This skill owns the
Lovable × Arc delta.
Chain constants (copy verbatim)
Thing
Value
chainId
5042002
CAIP-2
eip155:5042002
Native gas token
USDC (6 decimals — not 18)
RPC
https://rpc.testnet.arc.network
Explorer
https://testnet.arcscan.app (Blockscout under the hood)
RPC hostname trap. Circle/Arc docs interleave rpc.testnet.arc.io and
rpc.testnet.arc.network. Only .network resolves reliably. Hardcode it as
the default and allow an env override.
decimals: 6 is non-negotiable — an 18-decimal default renders every balance
as a rounding error.
Hard rules (each one cost hours)
Never install @circle-fin/* SDKs. They assume Node and crash the
Cloudflare Worker runtime the app deploys to ([unenv] … not implemented,
__dirname is not defined, or a blank 500). Hand-roll fetch adapters
against https://api.circle.com/v1/w3s; the whole client is ~150 lines and
uses only Web Crypto. See references/circle-scp.md.
feeLevel: "MEDIUM", never a gasPrice/fee object. Circle rejects
EIP-1559-style fee payloads on Arc with an opaque 400.
Re-encrypt the entity secret on every request. Fetch
/config/entity/publicKey, RSA-OAEP(SHA-256) the 32-byte secret, base64 it.
Reused ciphertext is rejected.
VITE_* is a banned secret prefix in Lovable. Store as PRIVY_APP_ID,
not VITE_PRIVY_APP_ID, and surface it through a route loader reading
process.env. Never ship the Alchemy RPC URL to the browser — proxy it.
Alchemy's Arc endpoint caps eth_getLogs at 10 blocks (free tier) and
rate-limits wide sweeps. Use the public Arc RPC for log reads, chunk the
window, cap the lookback, and cache. Better: read history from the Arcscan
v2 REST API. See references/rpc-and-indexing.md.
Pin solc@0.8.24 in devDependencies and use an exact pragma solidity 0.8.24;. A newer local compiler produces bytecode Blockscout cannot
reproduce, and verification fails with no useful message.
Wrap Privy in <ClientOnly> + React.lazy(). A static import of
@privy-io/react-auth crashes workerd. defaultChain: { id: 5042002, name: "Arc Testnet" } as never — the Privy type is narrow.
No gas sponsorship needed or available. USDC is gas on Arc; fund the
embedded wallet from the faucet and sign normally. No paymaster policy.
Write one JSON file per deployed contract (address, abi, chainId,
explorer, deployTx) under src/data/ and have the UI read it. Deploys
then go live without a code edit.
Demo-fallback over hard failure. Every server module must boot with
zero secrets and return a realistic envelope flagged .
Never throw at module scope for missing config.
Circle SCP as the only deploy path. No EOA, no funded private key in
CI, USDC gas from the treasury wallet. Four contracts shipped this way.
ERC-1271 authorizer contract so agent/treasury actions are authorized by
a contract signature instead of an EOA delegate key.
ERC-2981 royalties enforced inside the marketplace buy(), atomically,
in whichever payment token the buyer selected — a separate royalty leg that
can fail independently is a worse demo and a worse product.
Off-chain session ledger that batches nano-amounts and settles to Arc at
a threshold (~$0.50). A 20 USDC/day faucet then survives a full day of demos;
size each unit at ~$0.001.
Arcscan v2 REST as the indexer for activity/receipt panels — free, full
history, no client-side log scan.
Client-side UnixFS CIDv1 computation before pinning, so the user sees the
content hash and can verify the pin matched.
A human-readable error mapper (mapChainError) between chain/Circle
errors and UI copy. Retrofitting this late was the single biggest time sink.
Run ledger = summary bar + collapsed payloads. State chip, n/total
steps, one big "View receipt on Arcscan" button, payloads behind a
payload · N fields disclosure that auto-opens only on failures.
A single cross-mode settlement list. H2H, H2A, A2A and A2H all write to
one persisted client ledger; judges stop asking whether anything settled.
Mode-independent editorial pages + hidden mode toggle. Content routes
stayed readable even when the user had a persisted GX mode, and the compact
"Recent settlements →" link kept the cart drawer focused on checkout.
Paginated settlement/activity lists. 10-item pages with numbered controls
kept the judge demo compact and the primary action always visible.
What I'd do differently next time
Build the indexer read path and the error mapper on day one. Both were
retrofitted after users hit rate limits and opaque 400s.
Decide the contract JSON artifact shape before the first deploy —
redeploys are cheap, but three UI refactors to chase a changed shape are not.
Treat treasury gas as a first-class UI concern from the start: address,
balance, and a lowGas warning. Payout failures otherwise look like bugs.
Sketch the multi-token decimal matrix (6/6/8) once, in one TOKENS
table, instead of discovering cirBTC's 8 decimals via a wrong balance.
Build the deterministic negotiation fallback before tuning any prompt.
Days went into prompt wording for a two-agent demo that a 15-line
best-in-policy promotion fixed outright.
Ship the shared settlement ledger with the first settlement path, not
after a reviewer asks where the transactions are. Retrofitting it meant
touching every mode's success handler at once.
Decide which routes are mode-driven vs. mode-independent before wiring the
global toggle. Retrofitting content pages to ignore the saved mode meant
touching route wrappers, headers, and mobile drawers at once.
Build pagination into the first settlement/activity panel, not after the
list grows long. A 10-item default with numbered controls keeps demos from
turning into scrolling exercises.
Success checkpoints
bootstrap-circle.mjs prints treasury wallet id + address, and the raw
entity-secret hex is on disk before any network call.
Treasury funded at faucet.circle.com → Arc Testnet.
deploy-arc.mjs polls to status: "COMPLETE" and writes
src/data/<contract>.json with address + abi + chainId: 5042002.
verify-arc.mjs returns 200; a minute later is_verified: true on
https://testnet.arcscan.app/api/v2/smart-contracts/{address}.
Google login via Privy provisions an embedded wallet on 5042002 and a real
tx confirms on Arcscan under that address.
Out of scope
Arc Mainnet. CCTP bridging (dance-ucp-arc-circle). UCP checkout schemas
(same skill). Hardhat + funded-EOA deploys — Arc's pitch is "no EOA, USDC gas
from a Circle wallet"; use SCP.
simulated: true
Agent-demo outcomes come from deterministic code, not prompt wording.
Prompts shape the transcript; a post-loop fallback that promotes the best
in-policy quote guarantees the close. Never let an LLM own your success
rate. See references/agent-negotiation.md.
Any price an LLM emits is untrusted input. Normalise minor-units vs
decimals, clamp to [floor, list], and re-derive the charged total from
the catalog before it reaches a settlement path.
modal={false} on every Radix menu near sticky chrome. Modal mode locks
<body> scroll and breaks a sticky header the moment the menu opens
mid-scroll. See references/demo-ux.md.
Every settlement path writes to one shared client ledger. Add the
record() call in the same edit as the settlement itself. A judge needs one
list — across H2H/H2A/A2A/A2H — proving money moved, with Arcscan links and
confirmed/pending status from the Arcscan v2 API.
Keep the cart drawer focused on checkout. Do not inline transaction
history, settlement lists, or mode-switching chrome inside a cart drawer.
A compact link to the dedicated settlement surface (/judge, /shop, or a
standalone history page) keeps the checkout path short and the receipt
surface authoritative.
Mode-independent editorial/reference pages. Routes that explain the
product (/markets, /moves, /primer, /deck, /judge) must always
render their own content. Never wrap them in a per-mode surface, and hide
the mode toggle on them so a persisted GX mode does not silently swap the
page in the middle of a demo.
Paginate long settlement/activity lists. Judge ledgers, receipt
panels, and marketplace activity lists should paginate at ~10 items with
numbered controls. Long scrollable lists push primary actions below the fold
and break demo pacing.
Round hero stats to 2 decimals. Marketing metrics (e.g., "USDC settled
through the rail") should render with 2-decimal precision, not raw
contract precision, for readable social proof.