-
Notifications
You must be signed in to change notification settings - Fork 184
Closed
Description
I wanted to pin Coin images and metadata JSON files to additional IPFS services for redundancy, but I am finding that the Zora IPFS upload gives a different CID for the same content.
Below is a minimal reproduction script for Filebase as an alternative provider. I have additionally verified with Pinata and bgipfs.com (which return the same CID as Filebase).
/**
* Zora IPFS Upload Bug Report - Proof of Concept
*
* This script demonstrates that Zora's IPFS upload endpoint behaves differently
* from other IPFS services when using the same multipart form data approach.
*
* Issue: Zora produces different CIDs and file sizes compared to other IPFS services
* for the same uploaded content.
*/
import fs from 'node:fs/promises'
import path from 'node:path'
// Test file - replace with your actual file path
const TEST_FILE_PATH = './FILE_TO_UPLOAD'
// API endpoints
const ZORA_UPLOAD_URL = 'https://ipfs-uploader.zora.co/api/v0/add?cid-version=1'
const FILEBASE_UPLOAD_URL = 'https://rpc.filebase.io/api/v0/add?cid-version=1'
// Authentication - replace with your actual keys
const ZORA_JWT = 'JWT_GOES_HERE'
const FILEBASE_API_KEY = 'API_KEY_GOES_HERE'
async function uploadToService(url, authHeader, serviceName) {
try {
// Read the test file
const fileBuffer = await fs.readFile(TEST_FILE_PATH)
const filename = path.basename(TEST_FILE_PATH)
console.log(`\n--- ${serviceName} Upload ---`)
// Create multipart form data
const formData = new FormData()
const file = new File([fileBuffer], filename, {type: 'image/jpeg'})
formData.append('file', file)
// Upload to service
const response = await fetch(url, {
body: formData,
headers: {
Accept: '*/*',
...authHeader,
},
method: 'POST',
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`HTTP ${response.status}: ${errorText}`)
}
const result = await response.json()
console.log(`Upload successful!`)
console.log(`Response CID: ${result.Hash || result.cid}`)
console.log(`Response size: ${result.Size || result.size} bytes`)
return {
cid: result.Hash || result.cid,
responseSize: Number.parseInt(result.Size || result.size, 10),
service: serviceName,
}
} catch (error) {
console.error(`${serviceName} upload failed:`, error.message)
return {
error: error.message,
service: serviceName,
}
}
}
async function main() {
console.log('=== Zora IPFS Upload Bug Report ===')
console.log(`Test file: ${TEST_FILE_PATH}`)
// Check if test file exists
try {
await fs.access(TEST_FILE_PATH)
} catch {
console.error(`\n❌ Test file not found: ${TEST_FILE_PATH}`)
console.log('Please update TEST_FILE_PATH with a valid file path')
return
}
// Upload to both services
const zoraResult = await uploadToService(ZORA_UPLOAD_URL, {Authorization: `Bearer ${ZORA_JWT}`}, 'Zora')
const filebaseResult = await uploadToService(
FILEBASE_UPLOAD_URL,
{Authorization: `Bearer ${FILEBASE_API_KEY}`},
'Filebase',
)
// Compare results
console.log('\n=== COMPARISON RESULTS ===')
if (zoraResult.error || filebaseResult.error) {
console.log('❌ One or more uploads failed')
if (zoraResult.error) console.log(`Zora error: ${zoraResult.error}`)
if (filebaseResult.error) console.log(`Filebase error: ${filebaseResult.error}`)
return
}
console.log(`\nZora:`)
console.log(` Response size: ${zoraResult.responseSize} bytes`)
console.log(` CID: ${zoraResult.cid}`)
console.log(`\nFilebase:`)
console.log(` Response size: ${filebaseResult.responseSize} bytes`)
console.log(` CID: ${filebaseResult.cid}`)
// Analysis
console.log('\n=== ANALYSIS ===')
if (zoraResult.responseSize === filebaseResult.responseSize) {
console.log('✅ Same file sizes returned')
} else {
console.log(
`❌ Different file sizes: Zora (${zoraResult.responseSize}) vs Filebase (${filebaseResult.responseSize})`,
)
}
if (zoraResult.cid === filebaseResult.cid) {
console.log('✅ Same CID generated')
} else {
console.log('❌ Different CIDs generated for the same content')
}
}
main().catch(console.error)Example output:
=== Zora IPFS Upload Bug Report ===
Test file: ./bafybeiazilb4btabwlatsqsnyop4itqfy3f2onqnhw6d7gyb5pjew2a66i.jpeg
--- Zora Upload ---
Upload successful!
Response CID: bafybeiazilb4btabwlatsqsnyop4itqfy3f2onqnhw6d7gyb5pjew2a66i
Response size: 282787 bytes
--- Filebase Upload ---
Upload successful!
Response CID: bafybeibnpauqvbq37bq2hpbq2gjechf4aubbidey6q5ex6zyncgpmkjutm
Response size: 282823 bytes
=== COMPARISON RESULTS ===
Zora:
Response size: 282787 bytes
CID: bafybeiazilb4btabwlatsqsnyop4itqfy3f2onqnhw6d7gyb5pjew2a66i
Filebase:
Response size: 282823 bytes
CID: bafybeibnpauqvbq37bq2hpbq2gjechf4aubbidey6q5ex6zyncgpmkjutm
=== ANALYSIS ===
❌ Different file sizes: Zora (282787) vs Filebase (282823)
❌ Different CIDs generated for the same content
Metadata
Metadata
Assignees
Labels
No labels