Skip to main content

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

file
File | File[]
required
Single file or array of files to upload
durationDays
number
required
Storage duration in days (minimum: 7)
payer
PublicKey
required
Solana wallet public key for payment
signTransaction
Function
required
Async function to sign the transaction
async (tx: Transaction) => Promise<Transaction>
userEmail
string
Optional email for expiration reminders (sent 7 days before)

Response

success
boolean
Whether the upload succeeded
cid
string
Content identifier for the uploaded file(s)
signature
string
Solana transaction signature
url
string
IPFS gateway URL to access the file
message
string
Human-readable success message
error
string
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 estimateStorageCost
const estimate = await client.estimateStorageCost(files, duration);
const balance = await connection.getBalance(publicKey);

if (balance / LAMPORTS_PER_SOL < estimate.costInSOL) {
  alert('You need more SOL');
}
Error: User cancels the wallet signature requestSolution: Catch the error and show appropriate message
try {
  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 again
const 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 uploads
const 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:
1

Client-Side CID Computation

Files are processed in the browser to compute the CID
2

Upload to IPFS

Files are uploaded to Storacha’s IPFS nodes
3

Create Transaction

A Solana transaction is built with payment details
4

Sign Transaction

Your signTransaction callback is invoked
5

Submit to Network

Transaction is submitted to Solana blockchain
6

Wait for Confirmation

SDK waits for transaction confirmation
7

Server Processing

Server receives deposit event and records it in the database
8

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