NewsFrame Provenance
Authenticate frontline news photos with immutable creator-owned tokens.
NFT provenance mint· onchain authorship
Section · Onchain
full primer →The primitive.
Photographers mint each photojournalism as an ERC-721 token on Sei Testnet pointing at an IPFS CID, so authorship and timestamp are provable from a single Seiscan link.
Why this primitiveERC-721 on Sepolia guarantees verified news photo provenance and ownership.
Kernel
an ERC-721 contract on Sei Testnet that mints a creator-owned token pointing at an IPFS CID, viewable on Seiscan
Drives the UI as
a 'mint to claim authorship' button that returns the tokenId, owner address, and Seiscan link
Required keys.
SEI_TESTNET_RPC_URL
Public default is https://evm-rpc-testnet.sei-apis.com; override with Ankr/DRPC for heavy reads.
open ↗PRIVY_APP_ID
Google sign-in with a Sei Testnet embedded wallet — user pays their own gas from the Sei faucet.
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 "NewsFrame Provenance" in ONE Lovable message. Single-page demo.
CONCEPT
Authenticate frontline news photos with immutable creator-owned tokens.
Discipline: Photography (photojournalism).
Onchain primitive: NFT provenance mint. Why this primitive: ERC-721 on Sepolia guarantees verified news photo provenance and ownership.
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 Sei Testnet (atlantic-2, chainId 1328).
- Privy is always the auth layer (Google login, embedded wallet). USER PAYS GAS from that wallet.
- 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).
- Privy embedded wallet — USER-PAID gas on Sei Testnet (no ZeroDev, no smart-account
SDK, no bundler, no gas sponsorship). The EOA embedded wallet is the tx sender and
pays sub-cent SEI per action from its own balance.
- `defaultChain` and `supportedChains` MUST be a REAL viem `Chain` object, not a
`{ id, name }` stub (a stub compiles but breaks embedded-wallet transport init).
viem ships Sei Testnet — import it directly:
import { seiTestnet } from "viem/chains";
<PrivyProvider appId={import.meta.env.VITE_PRIVY_APP_ID}
config={{ loginMethods:['google'],
embeddedWallets:{ ethereum:{ createOnLogin:'users-without-wallets' } },
defaultChain: seiTestnet as never,
supportedChains: [seiTestnet] as never }}>
- IMPORTANT — Privy mount must be LAZY + CLIENT-ONLY (`@privy-io/react-auth` crashes
under SSR): load `PrivyProvider` via `lazy(() => import('./privy-client-entry'))`
inside `<ClientOnly><Suspense>` in a `privy-root.tsx`. Never import
`@privy-io/react-auth` at module scope of a route file.
- Every tx call passes `address: embedded.address` so Privy routes through the
embedded wallet (not a connected external wallet):
import { useSendTransaction, useWallets } from "@privy-io/react-auth";
const { sendTransaction } = useSendTransaction();
const embedded = wallets.find(w => w.walletClientType === "privy");
const receipt = await sendTransaction(
{ to: CONTRACT_ADDRESS, data, chainId: 1328 },
{ address: embedded.address },
);
DO NOT pass `{ sponsor: true }` — this app does not run a Privy gas
sponsorship policy; the user pays SEI gas from their embedded wallet.
- If the embedded wallet has 0 SEI, `sendTransaction` fails with "insufficient
funds for gas". Catch that error and show a link to https://sei.io/faucet so the
user can top up their embedded wallet address (copy `embedded.address` for them).
- PRIVY DASHBOARD (required, one-time, in the Privy console for VITE_PRIVY_APP_ID):
1. Chains -> add Sei Testnet (1328) with RPC https://evm-rpc-testnet.sei-apis.com
and explorer https://testnet.seiscan.io, then toggle
"Allow transactions from the client" ON. Without this, `sendTransaction`
hangs forever with no error.
2. DO NOT add a Gas Sponsorship policy — the user pays their own gas.
- 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-ethers` (>=3.x). DO NOT install
`@nomicfoundation/hardhat-toolbox` — it drags Hardhat 3 peers.
- hardhat.config.cjs — Sei Testnet (atlantic-2):
require("@nomicfoundation/hardhat-ethers");
const pk = process.env.METAMASK_PRIVATE_KEY;
module.exports = {
solidity: { version: "0.8.24", settings: { optimizer: { enabled: true, runs: 200 } } },
networks: { seiTestnet: {
url: process.env.SEI_TESTNET_RPC_URL || "https://evm-rpc-testnet.sei-apis.com",
accounts: pk ? [pk.startsWith("0x") ? pk : "0x" + pk] : [],
chainId: 1328,
} },
// Seiscan has no Hardhat-compatible verification API on atlantic-2 — skip verify;
// bytecode + address are inspectable at https://testnet.seiscan.io/address/<addr>
};
- Deploy: `npx hardhat run scripts/deploy.cjs --network seiTestnet`.
- Frontend reads: create a viem public client with the Sei Testnet RPC too —
`createPublicClient({ chain: seiTestnet, transport: http(import.meta.env.VITE_SEI_TESTNET_RPC_URL) })`
(import `seiTestnet` from `viem/chains`).
Expose the RPC to the client by also setting VITE_SEI_TESTNET_RPC_URL to the same value.
- Write the deployed address to `src/data/contract.json` so the UI links to
`https://testnet.seiscan.io/address/<address>`.
CONTRACT (contracts/NewsFrameProvenance.sol):
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
/// @title NewsFrameProvenance
/// @notice ERC-721 provenance for: Authenticate frontline news photos with immutable creator-owned tokens.
/// @notice Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
contract NewsFrameProvenance is ERC721 {
uint256 public nextId;
mapping(uint256 => string) public cidOf;
constructor() ERC721("NewsFrameProvenance", "NEWSFR") {}
/// @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 Sei Testnet.
2. After the user creates a photojournalism artefact, pin the file to IPFS via Pinata, then call `mint(cid)` on the deployed contract from the user's Privy embedded wallet (they pay the ~sub-cent SEI gas). Show tokenId, IPFS preview (`https://gateway.pinata.cloud/ipfs/<cid>`), and Seiscan mint-tx link.
3. Footer renders: "Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14"
REQUIRED SECRETS (Lovable -> Project Settings -> Secrets):
- METAMASK_PRIVATE_KEY Sei Testnet deployer key. Fund it: https://sei.io/faucet
(verify captcha -> Request SEI; 1 request per address per 24h; atlantic-2 only)
- SEI_TESTNET_RPC_URL Public default https://evm-rpc-testnet.sei-apis.com works out of the box.
For heavy reads use Ankr (https://www.ankr.com/rpc/sei/) or DRPC.
- PRIVY_APP_ID Google sign-in + embedded wallet on Sei Testnet. USER PAYS THEIR OWN GAS.
Point new users to the Sei faucet (https://sei.io/faucet) to fund their 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
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
$2.4B
photo software and media tools
SAM
$250M
photojournalism tools
SOM
$25M
newsroom photo verification systems
Indicative figures for hackathon pitches — refine with your own research before raising.
Adjacent entries.
photojournalism
NFT Photo Stories
Create and share onchain photo stories with built-in provenance and no wallet setup hassle.
photo authenticityTrueShot Ledger
Prove original photo ownership to combat unauthorized reuse and forgery.
photo editing historyEditTrace Chain
Track complete edit histories on-chain for transparent creative workflows.
fine art printsProPrint Certify
Certify fine art photo prints with tamper-proof digital provenance.