ART_, IMAGE_, AUDIO_*
Three NFT families, one mint flow per media type. Active behind fork gates:
| Family | Fork | Content storage |
|---|---|---|
| ART (SVG) | V3 (mainnet 18554) | Inline svg field (text on-chain) |
| IMAGE (PNG/JPEG/WebP) | V4 (inactive default) | SOCIAL_BLOB chunks via blobId |
| AUDIO (WAV/MPEG/OGG) | V5 (inactive default) | SOCIAL_BLOB chunks via blobId |
All three follow the same shape — only MINT differs in storage. TRANSFER and BURN are identical apart from the type string.
ART_MINT
| Field | Type | Notes |
|---|---|---|
type | "ART_MINT" | — |
from | string | Owner address (initial holder) |
tokenId | string | sha256(taskId + svg) — deterministic |
svg | string | Sanitized SVG markup, ≤ 16384 bytes |
owner | string | Initial owner (often same as from) |
taskId | string | Source TASK_SUBMIT (lineage) |
minerId | string | Miner that generated the SVG |
seedHash | string | sha256(prompt + minerId + blockHash) — deterministic seed |
model? | string | Generator model |
Validation:
tokenId == sha256(taskId + svg)(helper:computeArtTokenId)- SVG passes sanitizer (no
<script>, noonclick, no external URL refs) tokenIdnot minted before
Effect:
state.artNfts[tokenId] = { svg, owner, taskId, minerId, mintedAt }state.artByOwner[owner].push(tokenId)
IMAGE_MINT (Fork V4)
Same as ART_MINT, but svg field replaced with blobId pointing to a finalized SOCIAL_BLOB:
| Field | Type | Notes |
|---|---|---|
type | "IMAGE_MINT" | — |
tokenId | string | sha256(taskId + blobId + format + WxH) |
blobId | string | Pre-uploaded via SOCIAL_BLOB_INIT/CHUNK/FINALIZE |
format | string | "image:png", "image:jpg", "image:webp" |
width, height | number | Pixels |
| Others | — | Same as ART_MINT |
Helper: computeImageTokenId(taskId, blobId, format, width, height).
AUDIO_MINT (Fork V5)
| Field | Type | Notes |
|---|---|---|
type | "AUDIO_MINT" | — |
tokenId | string | sha256(taskId + blobId + format + durationMs) |
blobId | string | Pre-uploaded SOCIAL_BLOB |
format | string | "audio:wav", "audio:mpeg", "audio:ogg" |
durationMs | number | — |
sampleRate? | number | Hz |
| Others | — | Same as ART_MINT |
Helper: computeAudioTokenId(taskId, blobId, format, durationMs).
TRANSFER variants
ART_TRANSFER { type, from, tokenId, to, nonce, timestamp }
IMAGE_TRANSFER { type, from, tokenId, to, nonce, timestamp }
AUDIO_TRANSFER { type, from, tokenId, to, nonce, timestamp }
Effect: ownership changes hands. Token id is preserved.
BURN variants
ART_BURN { type, from, tokenId, nonce, timestamp }
IMAGE_BURN { type, from, tokenId, nonce, timestamp }
AUDIO_BURN { type, from, tokenId, nonce, timestamp }
Effect: NFT record marked burned, removed from owner index. Blob chunks (for IMAGE/AUDIO) remain on-chain as they may be referenced by other tx types.
Builders
buildArtMintTx(from, { tokenId, svg, owner, taskId, minerId, seedHash, model? }, nonce, privKey)
buildArtTransferTx(from, tokenId, to, nonce, privKey)
buildArtBurnTx(from, tokenId, nonce, privKey)
computeArtTokenId(taskId, svg)
computeArtSeedHash(prompt, minerId, blockHash)
buildImageMintTx(from, { tokenId, blobId, owner, taskId, minerId, prompt, seedHash, format, width, height, model? }, nonce, privKey)
buildImageTransferTx(...)
buildImageBurnTx(...)
computeImageTokenId(taskId, blobId, format, width, height)
buildAudioMintTx(from, { tokenId, blobId, owner, taskId, minerId, prompt, seedHash, format, durationMs, sampleRate?, model? }, nonce, privKey)
buildAudioTransferTx(...)
buildAudioBurnTx(...)
computeAudioTokenId(taskId, blobId, format, durationMs)
Large blob upload (IMAGE/AUDIO)
Before minting, upload the binary in chunks:
1. SOCIAL_BLOB_INIT — declare blobId, totalBytes, totalChunks, contentHash
2. SOCIAL_BLOB_CHUNK × N — base64-encoded chunks (≤ 400KB each)
3. SOCIAL_BLOB_FINALIZE — verifies contentHash matches assembled bytes
4. IMAGE_MINT / AUDIO_MINT — reference blobId
See Recipes › Upload large blob for a full example.
Next: Social txs →