Upload Files to Arweave
For Feria Nounish Artists: This documentation is inspired by Gabriel Lago from Cali, Colombia, who is building a Feria Nounish MiniApp for the artists participating in this year's fair. The
clientUploadToArweave
function enables artists to upload their artwork and metadata to decentralized storage, creating permanent, onchain records of their contributions to the collective timeline.
Upload files to Arweave decentralized storage for use in your NFT collections and moments. This function is perfect for artists participating in events like Feria Nounish who need to store metadata and assets onchain.
Note: This function uploads files to Arweave and returns a URI that can be used in collection creation or moment creation.
Installation
First, install the required Arweave package:
npm install arweave
Function Implementation
import Arweave from "arweave";
const arweave = Arweave.init({
host: "arweave.net",
port: 443,
protocol: "https",
timeout: 20000,
logging: false,
});
const clientUploadToArweave = async (
file: File,
getProgress: (progress: number) => void = () => {}
): Promise<string> => {
const ARWEAVE_KEY = JSON.parse(
Buffer.from(
process.env.NEXT_PUBLIC_ARWEAVE_KEY as string,
"base64"
).toString()
);
const buffer = await file.arrayBuffer();
const transaction = await arweave.createTransaction(
{
data: buffer,
},
ARWEAVE_KEY
);
transaction.addTag("Content-Type", file.type);
await arweave.transactions.sign(transaction, ARWEAVE_KEY);
const uploader = await arweave.transactions.getUploader(transaction);
while (!uploader.isComplete) {
console.log(
`${uploader.pctComplete}% complete, ${uploader.uploadedChunks}/${uploader.totalChunks}`
);
getProgress(uploader.pctComplete);
await uploader.uploadChunk();
}
return `ar://${transaction.id}`;
};
export default clientUploadToArweave;
Parameters
Parameter | Type | Required | Description |
---|---|---|---|
file | File | Yes | The file to upload to Arweave |
getProgress | (progress: number) => void | No | Optional callback function to track upload progress (0-100) |
Return Value
Returns a Promise that resolves to a string containing the Arweave URI in the format: ar://{transaction_id}
Environment Setup
You'll need to set up your Arweave wallet key as an environment variable:
# Your Arweave wallet key (base64 encoded)
NEXT_PUBLIC_ARWEAVE_KEY=your_base64_encoded_arweave_key_here
Usage Examples
Basic Upload
import clientUploadToArweave from "./clientUploadToArweave";
// Upload a file
const file = document.getElementById("fileInput").files[0];
const arweaveUri = await clientUploadToArweave(file);
console.log("File uploaded to:", arweaveUri);
// Output: ar://abc123...
Upload with Progress Tracking
import clientUploadToArweave from "./clientUploadToArweave";
const file = document.getElementById("fileInput").files[0];
// Track upload progress
const handleProgress = (progress: number) => {
console.log(`Upload progress: ${progress}%`);
// Update your UI progress bar
document.getElementById("progressBar").style.width = `${progress}%`;
};
try {
const arweaveUri = await clientUploadToArweave(file, handleProgress);
console.log("Upload complete:", arweaveUri);
} catch (error) {
console.error("Upload failed:", error);
}
Upload for Collection Metadata
import clientUploadToArweave from "./clientUploadToArweave";
// Upload collection metadata JSON
const metadata = {
name: "Feria Nounish Collection",
description: "Artwork from the Feria Nounish fair",
image: "https://example.com/collection-image.jpg",
external_link: "https://ferianounish.com",
};
// Convert metadata to file
const metadataBlob = new Blob([JSON.stringify(metadata, null, 2)], {
type: "application/json",
});
const metadataFile = new File([metadataBlob], "metadata.json", {
type: "application/json",
});
// Upload to Arweave
const contractUri = await clientUploadToArweave(metadataFile);
console.log("Contract URI:", contractUri);
// Use this URI in your collection creation
Upload for Moment Content
import clientUploadToArweave from "./clientUploadToArweave";
// Upload moment content (text, image, etc.)
const momentContent = {
title: "My Feria Moment",
content: "This is my contribution to the collective timeline",
media: "https://example.com/my-artwork.jpg",
timestamp: new Date().toISOString(),
};
const contentBlob = new Blob([JSON.stringify(momentContent, null, 2)], {
type: "application/json",
});
const contentFile = new File([contentBlob], "moment.json", {
type: "application/json",
});
const momentUri = await clientUploadToArweave(contentFile);
console.log("Moment URI:", momentUri);
// Use this URI when creating your moment
React Hook Example
For React applications, here's a custom hook for file uploads:
import { useState } from "react";
import clientUploadToArweave from "./clientUploadToArweave";
export const useArweaveUpload = () => {
const [isUploading, setIsUploading] = useState(false);
const [progress, setProgress] = useState(0);
const [error, setError] = useState<string | null>(null);
const uploadFile = async (file: File): Promise<string> => {
setIsUploading(true);
setProgress(0);
setError(null);
try {
const uri = await clientUploadToArweave(file, setProgress);
setIsUploading(false);
return uri;
} catch (err) {
setError(err instanceof Error ? err.message : "Upload failed");
setIsUploading(false);
throw err;
}
};
return {
uploadFile,
isUploading,
progress,
error,
};
};
// Usage in component
const MyComponent = () => {
const { uploadFile, isUploading, progress, error } = useArweaveUpload();
const handleFileUpload = async (
event: React.ChangeEvent<HTMLInputElement>
) => {
const file = event.target.files?.[0];
if (file) {
try {
const uri = await uploadFile(file);
console.log("Uploaded to:", uri);
} catch (err) {
console.error("Upload failed:", err);
}
}
};
return (
<div>
<input type="file" onChange={handleFileUpload} />
{isUploading && (
<div>
<p>Uploading... {progress}%</p>
<progress value={progress} max={100} />
</div>
)}
{error && <p style={{ color: "red" }}>Error: {error}</p>}
</div>
);
};
File Types Supported
The function supports any file type that can be stored on Arweave:
- Images: PNG, JPEG, GIF, SVG, WebP
- Documents: PDF, TXT, MD
- Data: JSON, CSV, XML
- Media: MP4, MP3, WebM
- Archives: ZIP, TAR
Best Practices
-
File Size: Arweave has no strict size limits, but larger files take longer to upload and cost more AR tokens.
-
Content-Type Tagging: The function automatically tags files with their MIME type for proper handling.
-
Progress Tracking: Always implement progress tracking for better user experience, especially for larger files.
-
Error Handling: Wrap upload calls in try-catch blocks to handle network issues or insufficient AR tokens.
-
Metadata Structure: When uploading JSON metadata, follow standard NFT metadata schemas for compatibility with marketplaces.
Integration with Collection Creation
After uploading your metadata to Arweave, use the returned URI in your collection creation:
// Upload collection metadata
const contractUri = await clientUploadToArweave(metadataFile);
// Use in collection creation
const createContractData = encodeFunctionData({
abi: tokenAbi,
functionName: "createContract",
args: [
contractUri, // Use the Arweave URI here
collectionName,
royaltyConfig,
smartAccount.address,
[],
],
});
Error Handling
Common errors and solutions:
- Insufficient AR tokens: Ensure your Arweave wallet has enough AR tokens for the upload
- Invalid wallet key: Verify your
NEXT_PUBLIC_ARWEAVE_KEY
is correctly base64 encoded - Network timeout: Increase the timeout value in the Arweave configuration
- File too large: Consider compressing or optimizing your files before upload
Next Steps
After uploading files to Arweave:
- Create a collection using your uploaded metadata URI
- Create moments with your uploaded content
- Browse the timeline to see your contributions