Twenty lessons from minting a hundred quantum NFTs
Quantum Genesis came together over 22 development sessions, from the first quantum circuit to 100 minted pieces on Polygon. Along the way we worked with two quantum platforms (Origin Quantum and IBM Quantum), three Python SDKs, two IPFS services, a hand-rolled Solidity contract, and enough debugging to fill a small novel.
There was no blueprint for this. Every stage — hardware access, SVG rendering, metadata, the contract, getting it in front of people — came with its own set of surprises. These are the twenty lessons we learned the hard way, grouped by where they bit us. A few are technical gotchas; a few are process; a few are about how we thought about the whole thing.

Quantum computing
Lesson 1: pyqpanda3 will break your assumptions. Origin Quantum's Python SDK (pyqpanda3) is a complete rewrite of the older pyqpanda. Different API, different class names, different default URL, and documentation that's almost entirely in Chinese. We lost a full session to discovering that the cloud URL for pyqpanda3 is http://pyqanda-admin.qpanda.cn (note the typo in "pyqanda" — that's the real URL), not the public-facing https://qcloud.originqc.com.cn/api.
What I'd do differently: start with IBM Quantum and add Origin Quantum only after the pipeline works. The provenance value of two platforms is real, but the debugging bill is steep.
Lesson 2: IBM Quantum queue times are unpredictable. IBM's processors are shared by thousands of users. Queues range from 10 seconds to 30+ minutes depending on demand. Generating 82 pieces sequentially, a 30-minute queue per job means 40+ hours of wall time. We ended up with sequential jobs at ~19 seconds per piece on ibm_fez — acceptable, but not optimal. Submit jobs in parallel and collect results asynchronously if you can.
Lesson 3: always have fallbacks. Our service kept three layers: real quantum hardware (Origin WK_C180 or IBM ibm_fez), a cloud quantum simulator (Origin's full_amplitude), and a classical pseudorandom fallback (Python's secrets module). We used all three at different points — hardware goes into maintenance, simulators return unexpected errors, API keys expire. My mistake was building the fallback chain as an afterthought; our v1 script had nothing and crashed whenever the service was down.
Lesson 4: the channel name matters (and it changed). When initializing IBM's QiskitRuntimeService, the channel parameter used to be "ibm_quantum". In newer SDK versions it's "ibm_quantum_platform". This single rename cost us an hour — the error was an unhelpful "authentication failed," not "wrong channel name."
# WRONG (old SDK):
service = QiskitRuntimeService(channel="ibm_quantum")
# CORRECT (new SDK):
service = QiskitRuntimeService(channel="ibm_quantum_platform")
Pin SDK versions in requirements.txt. Quantum SDKs update frequently and breaking changes are common.
Lesson 5: Origin Quantum's docs are in Chinese — deal with it. Origin Quantum is a Chinese company; documentation, forums, error messages, and even source comments are in Mandarin. Google Translate gets you about 80% there; the remaining 20% — technical terms and API jargon — needs patience. Example: pyqpanda3's measure() requires both qubit and classical bit indices explicitly: measure([0,1], [0,1]). That isn't documented clearly in any English source; we figured it out from Chinese forum posts and trial-and-error. Honestly, I wouldn't change this. Only 18 of 100 pieces come from Origin, and the difficulty of access makes them genuinely rare in a way the IBM pieces aren't.
Art generation
Lesson 6: SVG complexity matters more than you think. Our quantum circuits generate seeds that drive an SVG generator. Early versions made simple geometric patterns — fast to render, clean-looking. Later versions added fractals, noise fields, and layered transparency. They looked stunning but produced 500KB+ SVG files that choked some renderers. Set a complexity budget up front: maximum element count, maximum file size, and test rendering across platforms before generating the whole collection.
Lesson 7: cairosvg doesn't work on Windows — use Selenium. We needed SVG-to-PNG conversion for OpenSea. cairosvg works on Linux but on Windows needs a GTK+ runtime (a dependency nightmare), and even then it mangles SVG filters and gradients. Our solution was headless Selenium with Chrome: open the SVG in a real browser and screenshot it. Ugly and slow, but it renders exactly as a browser would — because it is a browser.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless")
options.add_argument("--window-size=1024,1024")
driver = webdriver.Chrome(options=options)
driver.get(f"file:///{svg_path}")
driver.save_screenshot(png_path)
driver.quit()
If I redo it, I'd generate PNGs directly, or render with cairosvg inside a Linux Docker container.
Lesson 8: color harmony from quantum data is possible — if you start from palettes. Early experiments fed raw quantum bits straight into RGB values; the result was ugly, because random colors don't harmonize. We switched to using quantum data to select from curated palettes (Nebula, Plasma, Void, Aurora...), where each palette guarantees visual harmony. Start with curated palettes; don't try to derive aesthetics from pure randomness.
Lesson 9: test the full collection before committing. We generated in batches — #1-18 from Origin, then #19-42, then #43-100 from IBM — and found visual artifacts (overlapping elements, clipped gradients) after the first batch, forcing regeneration. Generate test outputs for all 100 token IDs on a simulator first, verify every image renders, then run the real quantum generation.
IPFS and metadata
Lesson 10: separate CIDs for art and metadata. We initially tried one combined directory. Bad idea — your contract's tokenURI points to metadata, and metadata points to art. They need separate CIDs so you can update metadata without touching art, and because the directory structures differ (art files have extensions; metadata files are just token IDs).
Lesson 11: OpenSea wants PNG, not SVG. OpenSea can display SVGs but inconsistently — features don't render, images differ across browsers, and its thumbnail generator sometimes fails on complex SVGs entirely. PNGs render everywhere, every time. Keep SVGs as source for provenance but upload only PNGs to IPFS.
Lesson 12: metadata versioning is painful. We updated metadata three times. Each update required: regenerating all 100 JSON files, re-uploading to Pinata (new CID), calling setBaseTokenURI, and refreshing metadata on OpenSea for every token — there's no bulk refresh, you hit the button per token and OpenSea caches aggressively for hours. Finalize metadata before minting, or pay the cost later.
Lesson 13: Pinata's free tier is generous but finite. 500 files and 1GB covers most indie projects, but every upload counts against the file quota. Directory uploads count as one file — that's how we kept usage low (two directory pins for 200 actual files). We also hit rate limiting on verification; a small delay between HEAD requests fixed it.
Smart contract
Lesson 14: no-OpenZeppelin has tradeoffs. We wrote our ERC-721 from scratch for smaller bytecode and full control. The reality: days debugging edge cases OpenZeppelin handles for you — enumeration, safe transfers, event emissions. Our contract works and passed verification, but took 3-4x longer. Use OpenZeppelin for the base and customize only what you need; the gas savings are negligible on Polygon anyway.
Lesson 15: batch minting saves significant gas. Minting 100 individually costs ~85,000 gas each = 8.5M total. Batching 20 at a time costs ~1.2M per batch = 6M for 100, a 30% saving — the per-transaction overhead (21,000 base gas) and warm storage slots get amortized.
// Batch mint function in our contract
function batchMint(address to, uint256 count) external onlyOwner {
require(totalSupply + count <= MAX_SUPPLY, "Exceeds max supply");
for (uint256 i = 0; i < count; i++) {
_mint(to, totalSupply + 1);
totalSupply++;
}
}
For even bigger savings, look at ERC-721A, which is specifically optimized for batch minting.
Lesson 16: EIP-2981 royalties are optional — enforce them anyway. EIP-2981 defines the on-chain royalty standard, but compliance is voluntary. OpenSea respects it; some marketplaces don't. We set 5% (500 basis points):
function royaltyInfo(uint256, uint256 salePrice) external view returns (address, uint256) {
return (owner, salePrice * royaltyBps / 10000);
}
There's real debate about creator royalties. Our position: set them on-chain regardless of marketplace support.
Lesson 17: baseURI updates are powerful and dangerous. Our onlyOwner base-URI setter is essential for metadata fixes, but it also means the owner could theoretically swap all artwork. A compromise: a freezeMetadata() function that permanently locks the base URI. We haven't called ours yet in case we need more fixes, but it's there.
Market and strategy
Lesson 18: pricing is art, not science. We built an elaborate data-driven pricing model based on entropy tiers, processor rarity, and complexity scores. It produced defensible prices — and the market didn't care. What sells is the story, not the spreadsheet. Keep the model for internal consistency, but lead with the narrative: this piece was generated by a 156-qubit quantum computer; the patterns emerged from genuine quantum randomness no classical computer can reproduce.
Lesson 19: OpenSea listing is painfully manual. There's no batch listing. For 100 pieces that's 100 individual listings. The OpenSea API has limited listing support and requires approval. We built a Seaport-based lister script (opensea-lister/) but never fully deployed it — if you're doing this at scale, script it from the start.
Lesson 20: niche is better than broad. Quantum Genesis sits at the intersection of quantum computing, generative art, and blockchain — three niche interests. That's a feature. The general NFT market is saturated with PFP projects. But the quantum computing community and the generative art community? Those people light up when they see a CNOT gate in the metadata. The audience here is thousands of people, not millions — but those thousands will care deeply.
The summary
Building Quantum Genesis was a systems-integration exercise. Quantum APIs, IPFS, Solidity, and marketplace dynamics each carry their own complexity, and putting them in one pipeline exposed every assumption and every gap in documentation.
The twenty lessons collapse into a few:
- Build fallbacks for everything. APIs break, services go down, SDKs change. Your pipeline should degrade gracefully.
- Finalize before committing on-chain. Metadata, images, pricing — get them right before minting; post-mint changes are painful.
- Lead with the story. The technical infrastructure is the foundation, but the narrative is what resonates. "Made with a real quantum computer" is a story. "ERC-721 with EIP-2981 royalties" is a spec sheet.
- Niche audiences are gold. Find the people who care about what makes your project genuinely different, and speak directly to them.

If you're building a quantum NFT project — or any technically ambitious one — I hope these save you a fraction of the debugging sessions they cost us. The whole collection, with its provenance data and on-chain metadata, is live on Polygon if you want to poke at the results.
Comments
Post a Comment