sodofi/skincare-or-crypto: The Quiz That Won’t Reveal Anything Until Celo Confirms the Payment

A Farcaster mini app that turns a tiny onchain transfer into the unlock key, using wallet auto-connect and a four-stage state machine to make payment feel native instead of awkward.

12 min read • View on GitHub • More from sodofi

A Farcaster-style quiz card floats above a clean white workspace, with answer chips arranged on one side and a locked results drawer on the other. The image shows the core idea of the app: the result stays hidden until a blockchain receipt arrives and opens the gate.
The unlock is not a checkout page. It is the receipt becoming the key.
Key Takeaways

The quiz is a payment gate

The clever part of this repo is not that it takes payment. It is that it makes the payment feel like the final click of the quiz. You answer, you wait, and the result stays hidden until Celo confirms the transfer.

That is a different product shape from a normal paywall. A usual checkout interrupts the experience and asks for permission to continue. Here, the transaction is the continuation.

Why it feels native inside Farcaster

The front end is doing a lot of quiet work to remove the usual crypto drama. The Farcaster mini app context captures the host environment, calls `sdk.actions.ready()`, and then tries to connect the wallet without making the user hunt for a separate extension. That is why the experience feels less like a dApp and more like a social surface with one unusual rule.

useEffect(() => {
  sdk.actions.ready();
  if (!isConnected) {
    connect();
  }
}, [isConnected, connect]);

The repo also wires in Farcaster-specific auth and manifest support, which tells you this is meant to live inside an existing social identity layer. In other words, it does not ask users to discover the app first and the wallet second. It assumes the social context is already there, then uses it.

The four-stage machine behind the reveal

Under the quiz UI, the real structure is a small state machine: `welcome` to `quiz` to `payment` to `results`. The important jump is the last one, because the app does not treat payment as completion. It treats the receipt as a trigger.

The app is not just a quiz with crypto attached. It is a state machine that waits for a receipt before it unlocks the answer.

if (stage === 'payment') {
  const { isSuccess } = useWaitForTransactionReceipt({ hash });
  if (isSuccess) setStage('results');
}

That tiny loop matters because it changes what the user thinks the app is doing. The quiz is no longer waiting for a backend to flip a flag. It is waiting for the chain to tell the UI that the unlock is real.

Why Celo is the right rail for this trick

Celo is not a branding choice here. It is a timing choice. A curiosity toll only works when fees stay tiny and confirmation stays quick, because the user is paying for immediacy, not for speculation.

AxisNormal quiz or content gateGeneric Web3 appskincare-or-crypto
Entry frictionUser starts immediately and hits a simple submit buttonUser meets a wallet wall before the app feels realMini app context and auto-connect remove most of the ceremony
Unlock conditionA score, email capture, or form submitA wallet signature or token checkA confirmed Celo transfer
What the payment meansUsually nothing beyond accessOften ownership, membership, or identityIt is the content gate itself
User perceptionA quiz with a checkout stepA dApp that asks for patienceA normal Farcaster interaction that happens to settle onchain
A close-up shows a transaction receipt being inserted like a key into a small lock on a results envelope. Behind it, part of a quiz answer card is visible, which makes the mechanism feel tactile and makes the unlock concept easy to read at a glance.
Low fees and fast confirmation matter because the receipt has to feel immediate enough to behave like a key.

That is why the chain choice changes the product feel. If confirmation drags, curiosity cools. If fees spike, the reveal starts to feel like a toll booth instead of a punchline.

What this repo says about the next generation of social apps

The repo structure makes the same point at a different altitude. `apps/web` holds the user-facing flow, `apps/contracts` holds the EVM side, and the surrounding manifest, auth, and webhook code suggest a platform, not a one-off demo. This looks like a template for social apps that want to monetize a moment without breaking the moment.

That is the useful idea here. The repo is not selling a skincare quiz or a crypto quiz. It is showing how a social app can turn a tiny onchain action into a native-seeming product mechanic, then disappear behind the result.