Overview
The createDeposit method uploads files to decentralized storage and creates a payment record on the Solana blockchain.
Estimate Cost First
Before uploading, get a cost estimate:
const estimate = await client.estimateStorageCost(files, durationDays);
console.log(`Cost: ${estimate.costInSOL} SOL (~$${estimate.costInUSD})`);
console.log(`Total size: ${estimate.totalSizeInMB} MB`);
Response
{
costInSOL: number; // Cost in SOL
costInUSD: number; // Approximate USD value
totalSizeInMB: number; // Total file size
durationDays: number; // Storage duration
}
Always estimate costs before uploading to avoid transaction failures due to insufficient balance.
Create Deposit
Upload files and create a deposit on-chain:
const result = await client.createDeposit({
file, // File or File[]
durationDays: 30, // Storage duration
payer: publicKey, // Wallet public key
userEmail: '[email protected]', // Optional: for expiration warnings
signTransaction: async (tx) => {
return await signTransaction(tx);
},
});
Parameters
Single file or array of files to upload
Storage duration in days (minimum: 7)
Solana wallet public key for payment
Async function to sign the transactionasync (tx: Transaction) => Promise<Transaction>
Optional email for expiration reminders (sent 7 days before)
Response
Whether the upload succeeded
Content identifier for the uploaded file(s)
Solana transaction signature
IPFS gateway URL to access the file
Human-readable success message
Error message (only if success is false)
Complete Example
import { useDeposit } from 'storacha-sol';
import { useWallet } from '@solana/wallet-adapter-react';
import { useState } from 'react';
import { toast } from 'sonner';
function UploadComponent() {
const client = useDeposit('testnet');
const { publicKey, signTransaction } = useWallet();
const [files, setFiles] = useState<File[]>([]);
const [duration, setDuration] = useState(30);
const [email, setEmail] = useState('');
const handleUpload = async () => {
if (!publicKey || !signTransaction) {
toast.error('Please connect your wallet');
return;
}
// 1. Estimate cost
const estimate = await client.estimateStorageCost(files, duration);
console.log(`Estimated cost: ${estimate.costInSOL} SOL`);
// 2. Check balance
const balance = await connection.getBalance(publicKey);
if (balance < estimate.costInSOL * LAMPORTS_PER_SOL) {
toast.error('Insufficient balance');
return;
}
// 3. Create deposit
const toastId = toast.loading('Uploading to IPFS...');
try {
const result = await client.createDeposit({
file: files.length === 1 ? files[0] : files,
durationDays: duration,
payer: publicKey,
userEmail: email || undefined,
signTransaction: async (tx) => {
toast.loading('Please sign the transaction...', { id: toastId });
return await signTransaction(tx);
},
});
if (result.success) {
toast.success(
`Upload successful! CID: ${result.cid}`,
{ id: toastId, duration: 5000 }
);
console.log('View file:', result.url);
console.log('Transaction:', result.signature);
} else {
toast.error(result.error, { id: toastId });
}
} catch (error) {
toast.error('Upload failed', { id: toastId });
console.error(error);
}
};
return (
<div>
<input
type="file"
multiple
onChange={(e) => setFiles(Array.from(e.target.files || []))}
/>
<input
type="number"
value={duration}
onChange={(e) => setDuration(Number(e.target.value))}
min={7}
/>
<input
type="email"
placeholder="Email (optional)"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<button onClick={handleUpload}>
Upload
</button>
</div>
);
}
Single vs Multiple Files
Single File
const file = new File(['content'], 'document.pdf');
const result = await client.createDeposit({
file, // Single File object
durationDays: 30,
payer: publicKey,
signTransaction,
});
// Access at: result.url (direct file link)
Multiple Files
const files = [
new File(['content1'], 'file1.txt'),
new File(['content2'], 'file2.txt'),
];
const result = await client.createDeposit({
file: files, // File array
durationDays: 30,
payer: publicKey,
signTransaction,
});
// Access at:
// result.url → Directory listing
// result.url/file1.txt → Individual file
Multiple files are packaged as a directory with a single root CID. See CID Computation for details.
Error Handling
Common errors and solutions:
Error: Transaction fails due to insufficient SOLSolution: Check balance before uploading using estimateStorageCostconst estimate = await client.estimateStorageCost(files, duration);
const balance = await connection.getBalance(publicKey);
if (balance / LAMPORTS_PER_SOL < estimate.costInSOL) {
alert('You need more SOL');
}
User Rejected Transaction
Error: User cancels the wallet signature requestSolution: Catch the error and show appropriate messagetry {
const result = await client.createDeposit({...});
} catch (error) {
if (error.message.includes('User rejected')) {
toast.info('Transaction cancelled');
}
}
Error: Failed to upload to IPFS or confirm transactionSolution: Implement retry logic or ask user to try againconst maxRetries = 3;
let attempt = 0;
while (attempt < maxRetries) {
try {
const result = await client.createDeposit({...});
if (result.success) break;
} catch (error) {
attempt++;
if (attempt === maxRetries) throw error;
await new Promise(r => setTimeout(r, 2000)); // Wait 2s
}
}
Error: Browser runs out of memory processing large filesSolution: Limit file size or implement chunked uploadsconst MAX_SIZE = 100 * 1024 * 1024; // 100 MB
if (file.size > MAX_SIZE) {
toast.error('File too large. Max 100 MB');
return;
}
Transaction Flow
What happens when you call createDeposit:
Client-Side CID Computation
Files are processed in the browser to compute the CID
Upload to IPFS
Files are uploaded to Storacha’s IPFS nodes
Create Transaction
A Solana transaction is built with payment details
Sign Transaction
Your signTransaction callback is invoked
Submit to Network
Transaction is submitted to Solana blockchain
Wait for Confirmation
SDK waits for transaction confirmation
Server Processing
Server receives deposit event and records it in the database
Return Result
CID, signature, and URL are returned to your app
Best Practices
Always Estimate First
Check costs before uploading to avoid failed transactions
Show Progress
Use loading states and toasts for better UX
Handle Errors Gracefully
Provide clear error messages to users
Verify Balance
Ensure sufficient SOL before initiating upload