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 a TRC-721 token on Tron Shasta pointing at an IPFS CID, so authorship and timestamp are provable from a single Tronscan link.
Why this primitiveTRC-721 on Shasta guarantees verified news photo provenance and ownership.
Kernel
a TRC-721 contract on Shasta that mints a creator-owned token pointing at an IPFS CID, verified on Tronscan
Drives the UI as
a 'mint to claim authorship' button that returns the tokenId, base58 owner address, and Shasta Tronscan link
Required keys.
TRONGRID_API_KEY
TronGrid full-node key. Used as TRON-PRO-API-KEY on every Shasta build + broadcast.
open ↗TRONSCAN_API_KEY
Optional — automates Tronscan source verification. Manual upload works without it.
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 the 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: TRC-721 on Shasta 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 Shasta, verified on Tronscan.
- Privy is always the auth + signing layer (Google login, embedded Tron wallet, raw-hash sign). It does NOT sponsor gas.
- Transactions are built and broadcast via TronGrid Shasta (`/api/public/tron-build` + `/api/public/tron-sponsor`). Shasta’s free daily bandwidth covers gas for small tx like `log(string)` — no TRX is paid, no relayer sponsors it.
- 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).
- 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.
- Privy Tron support is TIER-2 raw-sign (docs: https://docs.privy.io/recipes/tron/transatron).
PrivyProvider config:
<PrivyProvider appId={import.meta.env.VITE_PRIVY_APP_ID}
config={{ loginMethods:['google','email'],
appearance:{ theme:'dark' } }}>
- Read (or auto-create) the embedded Tron wallet via
`useCreateWallet({ chainType:'tron' })` and read the base58 address off
the resulting wallet. Addresses are base58 (T-prefixed), NOT hex.
- SHASTA RPC RULE (critical): use TronGrid Shasta
`https://api.shasta.trongrid.io` for BOTH transaction build AND
broadcast, with header `TRON-PRO-API-KEY: process.env.TRONGRID_API_KEY`
on every request. Do NOT hit `api.transatron.io` on Shasta — that
endpoint is mainnet-only and returns `Smart contract is not exist.` for
a live Shasta contract, which surfaces in the UI as `build failed
(500)`. Transatron sponsorship is a mainnet swap; on Shasta a fresh
account’s free daily bandwidth (~600) covers a small `log(string)`
event without any sponsor.
- Two server routes, both under `src/routes/api/public/` (auth-bypass
prefix), both constructing TronWeb the same way:
import { TronWeb, providers } from 'tronweb';
const SHASTA_RPC = 'https://api.shasta.trongrid.io';
const headers = { 'TRON-PRO-API-KEY': process.env.TRONGRID_API_KEY };
const tronWeb = new TronWeb({
fullNode: new providers.HttpProvider(SHASTA_RPC, 60_000, '', '', headers),
solidityNode: new providers.HttpProvider(SHASTA_RPC, 60_000, '', '', headers),
eventServer: new providers.HttpProvider(SHASTA_RPC, 60_000, '', '', headers),
});
1. POST /api/public/tron-build → builds the unsigned tx with
`triggerSmartContract(contractHex, 'log(string)', { feeLimit }, [...], ownerHex)`
and returns `{ transaction, txId: transaction.txID }`.
2. POST /api/public/tron-sponsor → attaches the recovery byte to
the user’s signature (try `1b`, fall back to `1c` by checking
`tronWeb.trx.ecRecover(signed) === walletAddress`) and broadcasts
via `tronWeb.fullNode.request('wallet/broadcasttransaction',
signed, 'post')`. Same TronGrid host — no Transatron on Shasta.
- Client signs the `txID` with Privy’s raw signer (not sendTransaction):
import { useSignRawHash } from '@privy-io/react-auth/extended-chains';
const { signature } = await signRawHash({
address: tronAddress, chainType: 'tron',
hash: (txId.startsWith('0x') ? txId : '0x' + txId) as `0x${string}`,
});
// POST { walletAddress, signature, transaction } to /api/public/tron-sponsor
- Do NOT set `chainId` (Tron has no numeric EVM chainId). Do NOT reuse
viem’s `sepolia`/`mainnet` chain objects. Do NOT add ZeroDev /
SmartWalletsProvider / a paymaster URL — EVM-only concepts.
- TronBox in /contracts (kept outside the Vite bundle). Install
`tronbox` (>=4.x). Solidity 0.8.x only (TVM caps at ~0.8.23 — do NOT
bump above 0.8.20 for safety).
- tronbox-config.js:
module.exports = {
networks: {
shasta: {
privateKey: process.env.TRON_PRIVATE_KEY,
userFeePercentage: 100,
feeLimit: 1000_000_000,
fullHost: 'https://api.shasta.trongrid.io',
network_id: '2',
headers: { 'TRON-PRO-API-KEY': process.env.TRONGRID_API_KEY },
},
},
compilers: { solc: { version: '0.8.20' } },
};
- Deploy: `tronbox migrate --network shasta`.
- Verify: upload source at `https://shasta.tronscan.org/#/contracts/verify`
(needs a reCAPTCHA — cannot be scripted). If TRONSCAN_API_KEY is set
you may POST multipart to `https://apilist.tronscanapi.com/api/solidity/verify`.
- Write the deployed base58 address to `src/data/contract.json` so the UI
links to `https://shasta.tronscan.org/#/contract/<address>`.
CONTRACT (contracts/NewsFrameProvenance.sol):
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/TRC721/TRC721.sol";
/// @title NewsFrameProvenance
/// @notice TRC-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 TRC721 {
uint256 public nextId;
mapping(uint256 => string) public cidOf;
constructor() TRC721("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.
2. After the user creates a photojournalism artefact, pin the file to IPFS via Pinata, then call `mint(cid)` on the deployed contract through Privy's sponsored transaction. Show tokenId, IPFS preview (`https://gateway.pinata.cloud/ipfs/<cid>`), and Tronscan 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):
- TRON_PRIVATE_KEY Shasta deployer key (64 hex, no 0x prefix). Fund it: https://shasta.tronex.io/join/getJoinPage
- TRONGRID_API_KEY TronGrid full-node key. Free: https://www.trongrid.io/dashboard/apikeys. Sent as `TRON-PRO-API-KEY` header on EVERY Shasta call — both build and broadcast.
- TRONSCAN_API_KEY Optional — only for automated Tronscan source verification. Manual upload works without it: https://tronscan.org/#/myProfile/apiKeys
- PRIVY_APP_ID Google sign-in + embedded Tron wallet via Privy. Docs: https://docs.privy.io/recipes/tron/transatron
- TRANSATRON_SPENDER_KEY MAINNET ONLY — unused on Shasta. Reserve for a future mainnet swap; keep server-side. Docs: https://docs.transatron.io/
- 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.