build strategy · onchain

Real onchain, three 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 Flow EVM demo in one shot.

Why Flow EVM Testnet?

Flow EVM Testnet is a real EVM chain (chainId 545) — the same Solidity, the same Hardhat, the same viem, the same wallets — but the faucet is free and gas is fractional cents. Every contract you deploy is publicly inspectable on Flowscan (Blockscout). Move to Flow EVM Mainnet later by swapping the RPC and chainId.

A note on gas

ZeroDev and native Privy sponsorship do not cover Flow EVM, so the user's Privy embedded wallet pays the gas directly. Testnet FLOW is free from the faucet and each tx costs a fraction of a cent. Do not set sponsor: true — that option is silently ignored and only obscures the real payer.

The recipe

recipe
# 1. In your Lovable project, add three secrets (Settings -> Secrets):
FLOW_EVM_PRIVATE_KEY=0x...
PRIVY_APP_ID=...
PINATA_JWT=eyJhbGciOi...
# Optional:
FLOW_EVM_RPC_URL=https://testnet.evm.nodes.onflow.org

# 2. Fund the deployer key on Flow EVM Testnet (free):
open https://testnet-faucet.onflow.org

# 3. Copy a mega-prompt from this repo into Lovable. One paste:
#    - scaffolds the React app
#    - writes the Solidity contract (with hackathon credit in NatSpec)
#    - deploys to Flow EVM Testnet and verifies on Flowscan (Blockscout)
#    - wires Privy social login on Flow EVM (user pays fractional-cent gas)
#    - pins generated assets to IPFS via Pinata
#    - exposes the contract address + Flowscan link in the UI

# 4. Open the live Flowscan link. Your demo is provably onchain.

1. The contract — credit baked in

Every Solidity file deployed from a Creative Flow prompt MUST carry the hackathon credit in NatSpec, so provenance lives onchain alongside the bytecode.

contracts/Provenance.sol
// 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 {
    event Logged(address indexed author, string cid, uint256 at);

    function log(string calldata cid) external {
        emit Logged(msg.sender, cid, block.timestamp);
    }
}

2. Deploy + verify on Flowscan

hardhat.config.cjs
// hardhat.config.cjs — Flow EVM Testnet + Flowscan (Blockscout) verify
require("@nomicfoundation/hardhat-toolbox");
require("@nomicfoundation/hardhat-verify");

module.exports = {
  solidity: { version: "0.8.24", settings: { optimizer: { enabled: true, runs: 200 } } },
  networks: {
    flowEvmTestnet: {
      url: process.env.FLOW_EVM_RPC_URL || "https://testnet.evm.nodes.onflow.org",
      accounts: [process.env.FLOW_EVM_PRIVATE_KEY],
      chainId: 545,
    },
  },
  etherscan: {
    apiKey: { flowEvmTestnet: "empty" },   // Blockscout ignores the value, but the field must exist
    customChains: [{
      network: "flowEvmTestnet",
      chainId: 545,
      urls: {
        apiURL: "https://testnet.flowscan.io/evm/api",
        browserURL: "https://testnet.flowscan.io/evm",
      },
    }],
  },
  sourcify: { enabled: false },
};

// npx hardhat run scripts/deploy.cjs --network flowEvmTestnet
// npx hardhat verify --network flowEvmTestnet <address>

3. Pin assets to IPFS via Pinata

src/lib/pinata.ts
// src/lib/pinata.ts — pin a Blob to IPFS via Pinata JWT
export async function pinToIPFS(file: Blob, name = "artifact") {
  const fd = new FormData();
  fd.append("file", file, name);
  const r = await fetch("https://api.pinata.cloud/pinning/pinFileToIPFS", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.PINATA_JWT}` },
    body: fd,
  });
  const { IpfsHash } = await r.json();
  return IpfsHash as string; // the CID
}

4. Sign in with Google via Privy (Flow EVM)

src/components/privy-client-entry.tsx
// src/components/privy-client-entry.tsx — Privy on Flow EVM Testnet, user-paid gas
import { PrivyProvider } from "@privy-io/react-auth";
import { flowEvmTestnet } from "@/lib/flow-chain";

<PrivyProvider
  appId={import.meta.env.VITE_PRIVY_APP_ID}
  config={{
    loginMethods: ["google", "email"],
    embeddedWallets: { ethereum: { createOnLogin: "users-without-wallets" } },
    supportedChains: [flowEvmTestnet],
    defaultChain: flowEvmTestnet,
  }}
>
  <App />
</PrivyProvider>

// sendTransaction — NO `sponsor: true`. Native Privy sponsorship does not
// cover Flow EVM. The embedded wallet pays fractional-cent testnet FLOW.
await sendTransaction(
  { to, data, chainId: 545 },
  { address: embedded.address }
);

Hackathon rules of thumb

  • · One mega-prompt = one build message. Don't iterate the architecture, iterate the UI.
  • · Always show the live Flowscan link in the UI — that's your proof.
  • · Show a "Need FLOW? Faucet ↗" link in-app so judges can fund their embedded wallet.
  • · Pin every user-generated asset to IPFS the moment it's created.
  • · Add a "Built during the Creative AI & Quantum Hackathon — StreetKode Fam · Indian Krump Festival 14" line to your footer.