Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Uploading Assets

This guide explains how to upload your NFT assets to the blockchain using the storage contract.

Asset Pipeline

magical-nft provides a complete pipeline for preparing and uploading assets:

Source Files → Convert → Encode → Upload → Verify

Preparing Assets

1. Convert Images to AVIF

AVIF provides excellent compression for onchain storage:

bun run convert-to-avif

This converts images in assets/ to AVIF format.

2. Base64 Encode

Encode assets to base64 for embedding in metadata:

bun run base64-encode

3. Extract HTML

If using HTML-based NFTs, extract and minify:

bun run extract-html

Configure Upload List

Edit config/filesToUpload.json to specify files to upload:

{
  "files": [
    {
      "key": "image",
      "path": "assets/image.avif"
    },
    {
      "key": "animation",
      "path": "html/output.html"
    }
  ]
}

Upload Files

Upload All Files

bun run upload-all-files

This uploads all files listed in the config.

Upload Single File

bun run upload-file <key> <path>

Verify & Extract

After uploading, verify the data was stored correctly and extract the final output.

Verify Uploads

Download files from the storage contract to the tmp/ directory and verify their integrity:

source .env && forge script script/VerifyUploads.s.sol --rpc-url $RPC_URL

Extract HTML

Fetch the tokenURI for token #1, decode the metadata and HTML, and save it to tmp/final_check.html:

bun run extract-html

Open tmp/final_check.html in your browser to verify the NFT renders correctly.

Extract Metadata

Extract just the JSON metadata from the tokenURI:

bun run extract-metadata

Gas Considerations

Uploading large files can be expensive. Consider:

  • Chunking - Split large files across multiple transactions
  • Compression - Use AVIF for images, minify HTML/JS
  • Timing - Upload during low gas periods
  • L2s - Consider deploying on Layer 2 for lower costs

Storage Limits

SSTORE2 can store up to ~24KB per pointer. For larger files:

  1. Split into chunks
  2. Store each chunk separately
  3. Concatenate in the renderer

Troubleshooting

Transaction Reverts

  • Check gas limit is sufficient
  • Verify file size is under 24KB
  • Ensure storage contract is deployed

Wrong Data Stored

  • Verify file encoding (UTF-8 vs binary)
  • Check base64 encoding is correct
  • Re-upload with correct data