Overview
The getUserUploadHistory method retrieves all uploads associated with a Solana wallet address, including file metadata, expiration dates, and deletion status.
Basic Usage
const history = await client . getUserUploadHistory ( publicKey . toString ());
console . log ( 'Total files:' , history . userHistory . length );
console . log ( 'Total spent:' , history . totalSpent , 'SOL' );
Parameters
Solana wallet address (as a string)
Optional server configuration {
url ?: string ; // Custom server URL
}
Response Structure
{
userHistory : UploadedFile [];
totalFiles : number ;
totalStorage : string ; // e.g., "150.5 MB"
totalSpent : number ; // Total SOL spent
activeFiles : number ; // Non-deleted files
}
UploadedFile Type
Each file in the history includes:
{
id : string ; // Database ID
cid : string ; // IPFS content identifier
fileName : string ; // Original filename
fileSize : number ; // Size in bytes
fileType : string ; // MIME type
duration : number ; // Storage duration in days
cost : number ; // Payment in SOL
createdAt : string ; // Upload timestamp
expirationDate : string ; // When file expires
deletionStatus : 'active' | 'warned' | 'deleted' ;
transactionHash : string ; // Solana transaction signature
url : string ; // IPFS gateway URL
daysRemaining : number ; // Days until expiration (negative if expired)
}
Complete Example
import { useDeposit } from '@toju.network/sol' ;
import { useWallet } from '@solana/wallet-adapter-react' ;
import { useEffect , useState } from 'react' ;
function UploadHistoryComponent () {
const client = useDeposit ( 'testnet' );
const { publicKey } = useWallet ();
const [ history , setHistory ] = useState ( null );
const [ loading , setLoading ] = useState ( true );
useEffect (() => {
if ( ! publicKey ) return ;
const fetchHistory = async () => {
setLoading ( true );
try {
const data = await client . getUserUploadHistory (
publicKey . toString ()
);
setHistory ( data );
} catch ( error ) {
console . error ( 'Failed to fetch history:' , error );
} finally {
setLoading ( false );
}
};
fetchHistory ();
}, [ publicKey ]);
if ( loading ) return < div > Loading ...</ div > ;
if ( ! history ) return < div > No uploads found </ div > ;
return (
< div >
< h2 > Your Uploads </ h2 >
< p > Total Files : { history . totalFiles }</ p >
< p > Total Storage : { history . totalStorage }</ p >
< p > Total Spent : { history . totalSpent } SOL </ p >
< p > Active Files : { history . activeFiles }</ p >
< div >
{ history . userHistory . map (( file ) => (
< div key = {file. id } >
< h3 >{file. fileName } </ h3 >
< p > CID : { file . cid }</ p >
< p > Size : {(file.fileSize / 1024 / 1024). toFixed (2)} MB </ p >
< p > Expires : { new Date (file.expirationDate). toLocaleDateString ()}</ p >
< p > Status : { file . deletionStatus }</ p >
< a href = {file. url } target = "_blank" > View File </ a >
</ div >
))}
</ div >
</ div >
);
}
With SWR (Auto-Refresh)
Use SWR for automatic refreshing:
import useSWR from 'swr' ;
function UploadHistoryComponent () {
const client = useDeposit ( 'testnet' );
const { publicKey } = useWallet ();
const { data , error , isLoading , mutate } = useSWR (
publicKey ? [ 'upload-history' , publicKey . toString ()] : null ,
async ([ _ , address ]) => client . getUserUploadHistory ( address ),
{
refreshInterval: 30000 , // Refresh every 30s
revalidateOnFocus: true , // Refresh on window focus
}
);
if ( isLoading ) return < div > Loading ...</ div > ;
if ( error ) return < div > Error loading history </ div > ;
if ( ! data ) return < div > No uploads found </ div > ;
return (
< div >
{ /* Render history */ }
< button onClick = {() => mutate ()} > Refresh </ button >
</ div >
);
}
SWR automatically handles caching, deduplication, and background revalidation.
Filtering & Searching
Filter uploads by status or search by filename:
const { userHistory } = await client . getUserUploadHistory ( address );
// Filter by status
const activeFiles = userHistory . filter (
file => file . deletionStatus === 'active'
);
const expiredFiles = userHistory . filter (
file => file . deletionStatus === 'deleted'
);
// Search by filename
const searchResults = userHistory . filter (
file => file . fileName . toLowerCase (). includes ( query . toLowerCase ())
);
// Sort by expiration date
const sortedByExpiration = [ ... userHistory ]. sort (( a , b ) =>
new Date ( a . expirationDate ). getTime () - new Date ( b . expirationDate ). getTime ()
);
Deletion Status
Files go through three deletion statuses:
active
File is within storage duration and accessible
warned
File will expire in 7 days or less (warning email sent)
deleted
File has expired and been removed from storage
Days Remaining
The daysRemaining field shows time until expiration:
Statistics
The response includes helpful statistics:
const { totalFiles , totalStorage , totalSpent , activeFiles } = history ;
// Calculate average cost per file
const avgCostPerFile = totalSpent / totalFiles ;
// Calculate expired files
const expiredFiles = totalFiles - activeFiles ;
// Parse total storage
const storageMB = parseFloat ( totalStorage ); // "150.5 MB" → 150.5
Viewing Files
Each file has a url property for accessing content:
// IPFS gateway URL
const url = file . url ; // https://w3s.link/ipfs/{cid}
// Open in new tab
window . open ( url , '_blank' );
// Copy CID to clipboard
await navigator . clipboard . writeText ( file . cid );
Transaction History
View blockchain transaction:
// Solana Explorer link
const explorerUrl = `https://explorer.solana.com/tx/ ${ file . transactionHash } ?cluster=testnet` ;
< a href = { explorerUrl } target = "_blank" >
View on Solana Explorer
</ a >
Create Deposit Upload new files
Renew Storage Extend file expiration
Storage Payments Understanding costs
Renewal Concept When to renew