DJ Set Provenance
Create certified NFTs of live DJ sets proving originality and performance dates.
NFT provenance mint· onchain authorship
Section · Onchain
full primer →The primitive.
Musicians mint each live set archiving as an ERC-721 token on Flow EVM Testnet pointing at an IPFS CID, so authorship and timestamp are provable from a single Flowscan link.
Why this primitiveERC-721 tokens immutably link to archived set recordings on IPFS.
Kernel
an ERC-721 contract on Flow EVM Testnet that mints a creator-owned token pointing at an IPFS CID, verified on Flowscan
Drives the UI as
a 'mint to claim authorship' button that returns the tokenId, owner address, and Flowscan link
Required keys.
PRIVY_APP_ID
Enables Google sign-in and an embedded wallet (user pays fractional-cent FLOW gas).
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 "DJ Set Provenance" in ONE Lovable message. Single-page demo.
CONCEPT
Create certified NFTs of live DJ sets proving originality and performance dates.
Discipline: Music & Sound Design (live set archiving).
Onchain primitive: NFT provenance mint. Why this primitive: ERC-721 tokens immutably link to archived set recordings on IPFS.
5-CREDIT BUDGET (HARD LIMIT):
- ONE single-page app. No router, no Lovable Cloud, no database, no auth flows beyond Privy drop-in.
- ONE Solidity contract, <=80 lines, deployed to Flow EVM Testnet (chainId 545), verified on Flowscan (Blockscout).
- Privy is the auth layer (Google login, embedded wallet). USER PAYS GAS from the embedded wallet — Flow testnet gas is fractional cents.
- Pinata/IPFS only if the idea genuinely needs to store a file or metadata.
- At most ONE AI call per user action (use Lovable AI Gateway with LOVABLE_API_KEY if AI is part of the idea).
- Skip tests, skip CI, skip docs pages. Ship the demo, nothing else.
STACK
- React + Vite single page (the index route).
- Chain: Flow EVM Testnet — chainId 545, RPC https://testnet.evm.nodes.onflow.org,
explorer https://testnet.flowscan.io/evm. Define it in src/lib/flow-chain.ts via
viem's `defineChain({ id:545, name:'Flow EVM Testnet',
nativeCurrency:{ name:'Flow', symbol:'FLOW', decimals:18 },
rpcUrls:{ default:{ http:['https://testnet.evm.nodes.onflow.org'] } },
blockExplorers:{ default:{ name:'Flowscan', url:'https://testnet.flowscan.io/evm' } } })`.
Never stub the chain as a bare `{ id, name }` object anywhere — Privy requires a full viem chain.
- SSR-safe Privy mount is mandatory. Never import @privy-io/react-auth at
module scope of a route file — it crashes SSR. Use
lazy(() => import('./privy-client-entry')) inside <ClientOnly> + <Suspense>,
and put <PrivyProvider> only inside privy-client-entry.tsx.
- PrivyProvider config (pass the viem `flowEvmTestnet` chain — do NOT stub as {id,name}):
<PrivyProvider appId={import.meta.env.VITE_PRIVY_APP_ID}
config={{ loginMethods:['google','email'],
embeddedWallets:{ ethereum:{ createOnLogin:'users-without-wallets' } },
appearance:{ theme:'dark' },
supportedChains:[flowEvmTestnet],
defaultChain: flowEvmTestnet }}>
- Read the embedded wallet from useWallets, not user.wallet:
const embedded = wallets.find(w => w.walletClientType === 'privy');
- Every send goes through Privy `useSendTransaction` with `address` ONLY.
DO NOT PASS `sponsor: true` — ZeroDev and native Privy gas sponsorship do
NOT cover Flow EVM. The user's embedded wallet pays the gas directly
(fractional-cent testnet FLOW). Wrap in a 45s Promise.race timeout that
tells the user to fund the wallet from the faucet:
await Promise.race([
sendTransaction(
{ to, data, chainId: 545 },
{ address: embedded.address }
),
new Promise((_, r) => setTimeout(() => r(new Error(
"Transaction timed out after 45s. Fund your embedded wallet with testnet FLOW at https://testnet-faucet.onflow.org."
)), 45_000)),
]);
- Do NOT pass uiOptions:{ showWalletUIs:false } — it aborts with
"signal is aborted without reason". The approval sheet still shows on
the embedded-EOA path; the fee reads a few cents in FLOW.
- Do NOT add ZeroDev / SmartWalletsProvider / a paymaster URL / a bundler
key. There is no Privy dashboard toggle for Flow EVM sponsorship — user
pays gas, period. Show a "Need FLOW? Faucet ↗" link when signed in.
- src/lib/pinata.ts uploads via `fetch('https://api.pinata.cloud/pinning/pinFileToIPFS', { method:'POST', headers:{ Authorization: `Bearer ${import.meta.env.VITE_PINATA_JWT}` }, body: fd })`.
- Hardhat in /contracts (kept outside the Vite bundle). Install
`@nomicfoundation/hardhat-toolbox` AND `@nomicfoundation/hardhat-verify@latest` (>=3.x).
- hardhat.config.cjs — Flowscan is a Blockscout instance; declare it via
`customChains` and pass the `apiKey` field with a placeholder string
("empty" — Blockscout ignores the value, but the field MUST exist):
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.startsWith("0x")
? process.env.FLOW_EVM_PRIVATE_KEY : "0x" + process.env.FLOW_EVM_PRIVATE_KEY],
chainId: 545,
} },
etherscan: {
apiKey: { flowEvmTestnet: "empty" },
customChains: [{
network: "flowEvmTestnet",
chainId: 545,
urls: { apiURL: "https://testnet.flowscan.io/evm/api",
browserURL: "https://testnet.flowscan.io/evm" },
}],
},
sourcify: { enabled: false },
};
- Deploy: `npx hardhat run scripts/deploy.cjs --network flowEvmTestnet`.
- Verify (run RIGHT AFTER deploy, no constructor args for these contracts):
`npx hardhat verify --network flowEvmTestnet <address>`
On success the source becomes readable at
`https://testnet.flowscan.io/evm/address/<address>#code`.
- Frontend reads: `createPublicClient({ chain: flowEvmTestnet, transport: http() })`.
The public Flow EVM RPC handles wide getLogs ranges — `fromBlock = head - 50000n` is fine.
- Write the deployed address to `src/data/contract.json` so the UI links to
`https://testnet.flowscan.io/evm/address/<address>`.
CONTRACT (contracts/DJSetProvenance.sol):
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
/// @title DJSetProvenance
/// @notice ERC-721 provenance for: Create certified NFTs of live DJ sets proving originality and performance dates.
/// @notice Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
contract DJSetProvenance is ERC721 {
uint256 public nextId;
mapping(uint256 => string) public cidOf;
constructor() ERC721("DJSetProvenance", "DJSETP") {}
/// @notice Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
function mint(string calldata cid) external returns (uint256 id) {
id = ++nextId; cidOf[id] = cid; _safeMint(msg.sender, id);
}
function tokenURI(uint256 id) public view override returns (string memory) {
return string(abi.encodePacked("ipfs://", cidOf[id]));
}
}
```
USER FLOW
1. Land on page -> 'Sign in with Google' (Privy) -> embedded wallet auto-provisioned on Flow EVM Testnet.
2. Show a "Need FLOW? Faucet ↗" link to https://testnet-faucet.onflow.org so the user can top up.
3. After the user creates a live set archiving artefact, pin the file to IPFS via Pinata, then call `mint(cid)` on the deployed contract through Privy's embedded wallet. Show tokenId, IPFS preview (`https://gateway.pinata.cloud/ipfs/<cid>`), and Flowscan mint-tx link.
4. Footer renders: "Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14"
REQUIRED SECRETS (Lovable -> Project Settings -> Secrets):
- FLOW_EVM_PRIVATE_KEY Flow EVM Testnet deployer key. Fund it (free): https://testnet-faucet.onflow.org
- PRIVY_APP_ID Google sign-in + embedded wallet. Docs: https://docs.privy.io/llms-full.txt
- PINATA_JWT IPFS uploads (only if app pins media). Docs: https://docs.pinata.cloud/llms-full.txt
- FLOW_EVM_RPC_URL Optional. Defaults to https://testnet.evm.nodes.onflow.org (public RPC works fine).
CREDIT (must appear in UI footer AND as NatSpec on every deployed contract):
Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
Market sizing.
TAM
$1.4B
DJ software market
SAM
$350M
live set sales
SOM
$50M
underground DJ communities
Indicative figures for hackathon pitches — refine with your own research before raising.
Adjacent entries.
sample library curation
Sample Provenance Vault
Securely mint and verify original samples for trusted reuse and licensing.
mix version archivingMix Snapshot Ledger
Mint unique mix versions so producers prove original mixes over time.
synthesizer preset sharingSynth Patch Provenance
Create certified original synth presets with owned provenance for resale or sharing.
remix licensingSample Remix Rights
Mint remixable sample NFTs granting verified usage and royalty rights to remixers.