How Uploads Work
A step-by-step walkthrough of the upload process, from file selection to permanent storage on Arweave.
~3 min read
Uploading to Helix takes seconds, but behind that simple interface is a carefully orchestrated process ensuring your data is encrypted, paid for, and permanently stored. Let's trace a file's journey from your device to the permaweb.
The Upload Journey
File Selection
You select a file through drag-and-drop or the file picker. The file is read into memory using the browser's FileReader API. At this point, your file has not left your device.
// Read file into memory
const reader = new FileReader();
reader.onload = (e) => {
const arrayBuffer = e.target.result;
// File now in memory, ready for processing
};
reader.readAsArrayBuffer(file);Encryption (Optional)
If encryption is enabled (default), a random 256-bit AES key is generated. The file is encrypted using AES-GCM with a random IV. The key is stored locally—it never leaves your browser.
// Generate random key
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
// Generate random IV
const iv = crypto.getRandomValues(new Uint8Array(12));
// Encrypt file data
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
fileData
);
// Combine IV + encrypted data for storage
const combined = new Uint8Array(iv.length + encrypted.byteLength);
combined.set(iv);
combined.set(new Uint8Array(encrypted), iv.length);Cost Calculation
We query Irys for the exact cost to store your file permanently. The cost is based on file size and current network conditions. You see the price in SOL before approving anything.
// Get exact cost from Irys
const price = await irys.getPrice(fileBytes);
const priceInSol = irys.utils.fromAtomic(price);
// Display to user
console.log(`Storage cost: ${priceInSol} SOL`);
// Typical: 0.000005 SOL for 1KB (~$0.001)Wallet Approval
Your wallet (Phantom, Solflare, etc.) prompts you to approve the transaction. You see exactly how much SOL will be spent. This is a real Solana transaction transferring funds to Irys.
WALLET PROMPT
Approve transaction
0.000218 SOL to Irys
Irys Upload
Once payment confirms on Solana (~400ms), the encrypted data is uploaded to Irys. You receive a transaction ID immediately—this is your file's permanent address.
// Upload to Irys
const receipt = await irys.upload(encryptedData, {
tags: [
{ name: "Content-Type", value: "application/octet-stream" },
{ name: "App-Name", value: "Helix" },
{ name: "Wallet", value: walletAddress },
]
});
// Permanent URL available immediately
const url = `https://arweave.net/${receipt.id}`;
// e.g., https://arweave.net/abc123...xyzArweave Anchoring
In the background, Irys bundles your data with others and anchors it to the Arweave blockchain. This happens automatically—your file is already accessible via the transaction ID.
Metadata Storage
We save the transaction ID and metadata to our database, linked to your wallet address. This enables your dashboard and sharing features. The actual file content stays on Arweave.
// Save to database
await prisma.file.create({
data: {
walletAddress: wallet.publicKey.toString(),
transactionId: receipt.id,
encryptedName: encryptedFileName, // Client-encrypted
mimeType: file.type,
size: file.size,
isEncrypted: true,
}
});Timeline
File Selected
User selects file through UI
Encryption Complete
Client-side AES-256 encryption
Cost Calculated
Irys returns exact storage price
Wallet Approved
User signs transaction
Solana Confirmed
Payment confirmed on-chain
Upload Complete
File accessible at arweave.net/{id}
Arweave Anchored
Permanent block confirmation
Forever Stored
Data persists permanently
Instant Availability
What Gets Stored Where
Error Handling
Uploads can fail at various stages. Here's how we handle each:
Wallet Rejection
If you reject the wallet transaction, nothing happens. No data has been uploaded, no payment made. Simply try again when ready.
Insufficient Balance
If your wallet doesn't have enough SOL, we'll show the required amount before you attempt the transaction. No failed partial uploads.
Network Error During Upload
If the upload fails after payment, the funds are held in your Irys balance. You can retry the upload without paying again—the balance persists.
Browser Closed Mid-Upload
If payment succeeded but upload didn't complete, your Irys balance still has the funds. Reconnect your wallet and upload again.
Atomic Operations
Download Flow
Downloading reverses the upload process:
- Fetch encrypted data from arweave.net/{transactionId}
- Retrieve encryption key from localStorage
- Extract IV from first 12 bytes of data
- Decrypt remaining data using AES-GCM
- Create blob and trigger browser download
async function downloadFile(transactionId: string, key: CryptoKey) {
// Fetch encrypted data from Arweave
const response = await fetch(`https://arweave.net/${transactionId}`);
const encrypted = await response.arrayBuffer();
// Extract IV (first 12 bytes)
const iv = new Uint8Array(encrypted.slice(0, 12));
const ciphertext = encrypted.slice(12);
// Decrypt
const decrypted = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
ciphertext
);
// Create download
const blob = new Blob([decrypted]);
const url = URL.createObjectURL(blob);
// Trigger download...
}Last updated: February 2025