build strategy · canton / daml
Real onchain, one secret, 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 Canton/Daml demo in one shot.
Why Canton Seaport and not Ethereum?
Seaport is a hosted Canton 3.x participant on the Canton Devnet global synchronizer. Daml gives you typed contracts, real authorisation by signatories, and a per-user party model — no MetaMask, no gas, no faucet, no chain switching. Every contract id is publicly verifiable through the JSON Ledger API v2. Full validator reference →
The recipe
recipe
# 1. No secrets to add. LOVABLE_API_KEY is auto-provisioned by Lovable. # Optional fallback only if you've exhausted Lovable AI credits: # AISA_API_KEY=... # Settings -> Secrets # 2. The six Canton Devnet values are baked into the prompt. No signup, no validator setup. # 3. Copy a mega-prompt from this repo into Lovable. One paste: # - scaffolds the TanStack Start app # - writes the Daml template (with hackathon credit in a header comment) # - uploads the DAR to the Seaport Devnet validator (idempotent) # - allocates a Canton party + creates a Daml user (userId === JWT sub) # - exposes the contract id, updateId, and party id in the UI # 4. Click 'Run on Canton'. The validator returns an updateId — that's your proof.
1. The Daml template — credit baked in
Every Daml module generated from a Creative Blockchain prompt carries the hackathon credit in a header comment, so provenance is part of the on-ledger source.
daml/Provenance.daml
-- daml/Provenance.daml — every module carries the hackathon credit
-- Built during the Creative AI & Quantum Hackathon
-- organised by StreetKode Fam during Indian Krump Festival 14
module Provenance where
template Provenance
with
author : Party
cid : Text
at : Time
where
signatory author
2. OIDC token, cached server-side
src/lib/canton.functions.ts
// src/lib/canton.functions.ts — server-only OIDC + JSON Ledger API
import { createServerFn } from "@tanstack/react-start";
let cached: { token: string; expiresAt: number } | null = null;
async function mintToken() {
const now = Date.now();
if (cached && cached.expiresAt - 60_000 > now) return cached;
const body = new URLSearchParams({
grant_type: "client_credentials",
client_id: process.env.CANTON_DEVNET_OIDC_RUNTIME_CLIENT_ID!,
client_secret: process.env.CANTON_DEVNET_OIDC_RUNTIME_CLIENT_SECRET!,
audience: process.env.CANTON_DEVNET_OIDC_AUDIENCE!,
scope: process.env.CANTON_DEVNET_OIDC_SCOPE!,
});
const r = await fetch(process.env.CANTON_DEVNET_OIDC_TOKEN_URL!, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body,
});
const j = await r.json();
cached = { token: j.access_token, expiresAt: now + j.expires_in * 1000 };
return cached;
}
3. Exercise a choice, get an updateId
src/lib/canton.functions.ts
// Exercise a Daml choice and get the updateId back
export const publish = createServerFn({ method: "POST" })
.inputValidator((d: { payload: string }) => d)
.handler(async ({ data }) => {
const { token } = await mintToken();
const r = await fetch(
process.env.CANTON_DEVNET_JSON_API_URL + "v2/commands/submit-and-wait-for-transaction",
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
commands: {
userId: USER_ID, // === JWT `sub` claim
commandId: crypto.randomUUID(),
actAs: [PARTY_ID],
readAs: [],
commands: [{
CreateCommand: {
templateId: PROVENANCE_TID,
createArguments: { author: PARTY_ID, cid: data.payload, at: new Date().toISOString() },
},
}],
},
}),
},
);
const j = await r.json();
return { updateId: j.transaction.updateId };
});
Hackathon rules of thumb
- · One mega-prompt = one build message. Don't iterate the architecture, iterate the UI.
- · Always show the contract id and updateId in the UI — that's your proof.
- · Keep the runtime
client_secretserver-only. Never import it in client code. - · On Devnet, set
userIdequal to the JWTsubclaim — the validator rejects mismatches with an opaque 403. - · Add a "Built during the Creative AI & Quantum Hackathon — StreetKode Fam · Indian Krump Festival 14" line to your footer.