Real onchain, four 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 DATA-Foundation-registered demo in one shot.
Why Aeneid and not mainnet?
Aeneid is the DATA Foundation's public testnet (chainId 1315). It runs the same IP Asset, License Terms, Royalty and CDR contracts as mainnet, has its own block explorer (aeneid.explorer.datafdn.org), and is funded by a free faucet. Every IP Asset you register is publicly inspectable, but you never spend real IP and your demo can't accidentally lock up real royalties. Move to mainnet (chainId 1514) after the hackathon by flipping the SDK's chain flag.
The recipe
# 1. In your Lovable project, hardcode two publishable IDs into src/config.ts. # Both values ship in the browser bundle; they are NOT secrets. export const PRIVY_APP_ID = "cm..."; // https://dashboard.privy.io export const AENEID_RPC_URL = "https://aeneid.storyrpc.io"; // DATA Foundation public RPC # 2. In the Privy dashboard: Gas sponsorship -> App pays -> add Story Aeneid # (chainId 1315) -> toggle "Allow transactions from the client" ON. # Fallback if Aeneid sponsorship is unavailable: prefund the embedded wallet # from https://aeneid.faucet.datafdn.org and drop `sponsor: true`. # 3. Copy a mega-prompt from this repo into Lovable. One paste: # - scaffolds the React app # - installs @story-protocol/core-sdk + @piplabs/cdr-sdk + @privy-io/react-auth # - registers the artefact as an IP Asset on Aeneid # - attaches PIL License Terms + (optional) licensing hook # - mints a License Token for the consumer path # - seals private artefacts in a CDR encrypted vault gated by the License Token # - exposes the ipId + aeneid.explorer.datafdn.org link in the UI # 4. Open the DATA Foundation explorer link. Your creative work is a registered IP Asset.
1. Register the IP Asset
For the four core primitives you don't write Solidity — the DATA Foundation already deployed the registry. Every artefact goes through @story-protocol/core-sdk. Credit lives in the IP Asset's description or tags, on-chain forever. If your idea genuinely needs a bespoke event / registry / counter the SDKs don't cover, see "Bespoke contracts" below for the credit-safe path.
// src/lib/story.ts — register an artefact as an IP Asset on Aeneid
import { StoryClient } from "@story-protocol/core-sdk";
import { http } from "viem";
import { AENEID_RPC_URL } from "@/config";
export async function registerIp(walletClient: any, title: string, cid: string, mediaHash: `0x${string}`) {
const story = StoryClient.newClient({
wallet: walletClient,
transport: http(AENEID_RPC_URL),
chainId: "aeneid",
});
const ipMetadata = story.ipAsset.generateIpMetadata({
title,
description: "Built during the Creative AI & Quantum Hackathon — StreetKode Fam · Indian Krump Festival 14",
createdAt: Math.floor(Date.now() / 1000).toString(),
mediaUrl: `ipfs://${cid}`,
mediaHash,
mediaType: "image/png",
creators: [{ name: "you", address: walletClient.account.address, contributionPercent: 100 }],
});
const { ipId, txHash } = await story.ipAsset.registerIpAsset({
nft: { type: "mint", spgNftContract: "0xc32A8a0FF3beDDDa58393d022aF433e78739FAbc" },
ipMetadata,
});
// https://aeneid.explorer.datafdn.org/ipa/${ipId}
return { ipId, txHash };
}
2. Attach License Terms + Hook
// attach PIL License Terms + optional Hook at registration time
await story.ipAsset.registerIpAsset({
nft: { type: "mint", spgNftContract: "0xc32A8a0FF3beDDDa58393d022aF433e78739FAbc" },
ipMetadata,
licenseTermsData: [{
terms: {
transferable: true,
commercialUse: true,
commercialRevShare: 5, // 5% royalty back to the licensor
derivativesAllowed: true,
defaultMintingFee: 0n,
},
licensingConfig: {
isSet: true,
mintingFee: 0n,
// Optional: cap total license mints via a whitelisted hook.
licensingHook: "0xaBAD364Bfa41230272b08f171E0Ca939bD600478", // TotalLicenseTokenLimitHook
hookData: "0x",
commercialRevShare: 5,
disabled: false,
expectMinimumGroupRewardShare: 0,
expectGroupRewardPool: "0x0000000000000000000000000000000000000000",
},
}],
});
3. Mint a License Token
// mint a License Token so the consumer can legally use / remix
const { licenseTokenIds, txHash } = await story.license.mintLicenseTokens({
licensorIpId,
licenseTermsId,
amount: 1,
maxMintingFee: 0n,
maxRevenueShare: 100,
receiver: user.address as `0x${string}`,
});
4. Seal privately in a CDR vault
// src/lib/cdr.ts — seal an artefact in a CDR vault; License Token holders decrypt
// Lazy-load the SDK inside the handler (top-level import breaks SSR).
export async function sealInVault(walletClient: any, ipId: `0x${string}`, licenseTermsId: bigint, file: Blob) {
const cdr = await import("@piplabs/cdr-sdk");
const cdrClient = cdr.CDRClient.forChain("aeneid", { walletClient });
const vault = await cdrClient.uploader.allocate({
readCondition: cdr.conditions.holdsLicenseToken({ ipId, licenseTermsId }),
});
const ciphertext = await cdrClient.uploader.encrypt({
uuid: vault.uuid,
plaintext: new Uint8Array(await file.arrayBuffer()),
});
const { txHash } = await cdrClient.uploader.write({ vault, ciphertext });
return { vaultUuid: vault.uuid, txHash };
}
5. Sign in with Google via Privy
// src/main.tsx — Privy social login for Aeneid
import { PrivyProvider } from "@privy-io/react-auth";
import { PRIVY_APP_ID } from "@/config";
<PrivyProvider
appId={PRIVY_APP_ID}
config={{
loginMethods: ["google", "email"],
embeddedWallets: { ethereum: { createOnLogin: "users-without-wallets" } },
appearance: { theme: "dark" },
}}
>
<App />
</PrivyProvider>
// chainId 1315 is passed per-call in useSendTransaction — NEVER via defaultChain.
Bespoke contracts — credit-safe path
The 5-credit budget now permits one tiny custom Solidity contract per demo — deployed from the Lovable sandbox, never from the browser and never as part of the app runtime. Reach for it only when the idea needs a bespoke event, registry, or counter that @story-protocol/core-sdk and @piplabs/cdr-sdkdon't already cover.
- · Hard limits: ≤ 1 contract file, ~120 LOC, OpenZeppelin OK, no proxies, no upgradeability.
- · Deploy inside the sandbox with Foundry:
cd contracts && forge script script/Deploy.s.sol --rpc-url https://aeneid.storyrpc.io --broadcast --private-key $DEPLOYER_PK - · Fund the deployer once at aeneid.faucet.datafdn.org. Store
DEPLOYER_PKas a Lovable Project Secret — never commit it. - · After deploy, commit
{ address, chainId: 1315, abi }tosrc/data/<name>.jsonand read from there via viem. - · Reference implementation in this repo:
contracts/ChoreoLedger.sol+contracts/script/Deploy.s.sol→src/data/choreo-ledger.json(live at0x5f48…0e4fon Aeneid).
Hackathon rules of thumb
- · One mega-prompt = one build message. Don't iterate the architecture, iterate the UI.
- · Always show the live
aeneid.explorer.datafdn.org/ipa/<ipId>link in the UI — that's your proof. - · Use Privy sponsored tx so judges don't need a wallet to try the demo.
- · If the artefact is sensitive (unreleased track, private choreo video, screenplay draft), seal it in a CDR vault gated by the License Token — never expose it via a naked URL.
- · Add a "Built during the Creative AI & Quantum Hackathon — StreetKode Fam · Indian Krump Festival 14" line to your footer.