Digital assets (LSP-4 / LSP-7 / LSP-8)
Mint LSP-7 fungibles and LSP-8 NFTs with collection metadata, per-token metadata, and large media assets stored permanently on Cascade.
LSP-3 lives on a Universal Profile. Digital-asset metadata lives on the token contract itself, and on LSP-8 it can also live per token ID. The Cascade integration is identical to the LSP-3 flow, just pointed at different keys and contracts.
This page assumes you already understand the LSP-3 flow. We'll only cover the diffs.
Where the metadata lives
| Standard | Contract | Key | What it describes |
|---|---|---|---|
| LSP-4 Digital Asset Metadata | LSP-7 or LSP-8 contract | LSP4Metadata (set via setData) | Collection-level info: name, description, attributes, primary art |
| LSP-7 Digital Asset (fungibles) | LSP-7 contract | LSP4Metadata (whole supply shares it) | Token info, brand assets |
| LSP-8 Identifiable Digital Asset (NFTs) | LSP-8 contract | LSP4Metadata via setDataForTokenId(tokenId, ...) | Per-token info: art, attributes, animation_url |
The LSP4Metadata data key is the same in all cases:
The shape it points at is also the same: a VerifiableURI referencing a JSON file.
The LSP-4 JSON shape
Two things to notice that differ from LSP-3:
imagesis an array of arrays: each "image slot" can have multiple resolution variants. Soimages[0][0..n]are variants of the first image,images[1][0..n]are variants of the second image, and so on. This is how galleries are represented.attributes[]is structured key/value/type tuples, designed to be displayed as NFT trait rows in marketplaces.
Setting collection-level metadata (LSP-7 or LSP-8)
For a fungible LSP-7 or for the collection-wide metadata of an LSP-8, the flow is identical to LSP-3:
The diff vs. LSP-3 is exactly two lines: import a different schema (LSP4DigitalAsset.json), call setData on the token contract instead of on the UP. Everything else is the same machinery.
Setting per-token metadata (LSP-8 only)
LSP-8 collections often want different metadata per token: each NFT has its own art, attributes, and rarity. The contract method for that is setDataForTokenId:
Same dataKey (LSP4Metadata), same value shape, but scoped to one tokenId. From the client side:
The tokenId representation depends on your collection's LSP8TokenIdFormat:
| Format | tokenId value | Convert to bytes32 |
|---|---|---|
0 Number | a uint256 counter | padHex(toHex(id), { size: 32 }) |
1 String | a UTF-8 string | padHex(toHex(stringToBytes(id)), { size: 32 }) |
2 Unique bytes | arbitrary 32 bytes | already a bytes32 |
3 Mixed bytes32 | hashed combination | already a bytes32 |
Mint flow with metadata in one go
Putting it together, a clean LSP-8 mint flow looks like this:
For a typical NFT (1 hero @ 3 resolutions + 4 gallery items @ 2 resolutions each + 1 animation + 1 metadata JSON) that's 13 Cascade uploads per mint. Each one is its own permanent on-chain record on Lumera. Each one is hash-bound and verifiable.
Why this is the highest-value Cascade integration on Lukso
LSP-3 profile metadata is small (typically under 500 KB total per profile). LSP-4 collection metadata is larger but still bounded. Per-token LSP-8 metadata is unbounded: every token in a 10000-piece collection has its own art, its own attributes, its own optional animation. That's where IPFS pinning costs really stack up and where Cascade's pay-once model is most asymmetrically better.
If you're building an NFT marketplace or collection-issuance dApp on Lukso, this is the integration that matters.
A note on LSP8TokenMetadataBaseURI
LSP-8 supports an optional collection-wide LSP8TokenMetadataBaseURI key that lets you skip per-token setDataForTokenId calls if every token's metadata lives at <baseURI><tokenId>. You could store the entire metadata directory on Cascade and set LSP8TokenMetadataBaseURI to a single Cascade URL prefix... except cascade-api's /download/<actionId> model is per-file, not per-directory, so LSP8TokenMetadataBaseURI is not a clean fit. Stick with setDataForTokenId per-token, which gives you a verifiable hash per token anyway.