Waldrop SDK · Recipe
List, find, and fetch blobs
Read-side recipes — list a user's BlobStore, find a specific blob, fetch
the bytes back from the Walrus aggregator. No wallet, no signing.
Setup
import { WaldropClient } from " @waldrop/sdk " ;
const client = new WaldropClient ({ network : " testnet " });
That's it. The read API works without any keypair — you just need a Sui
address to query.
List a user's blobs
const blobs = await client . blob . list ({
owner : " 0x9d655392521726d0eb26915670f7a37fe78b6fe001d133280ddaf57e4428aae1 " ,
limit : 50 , // optional — defaults to all
});
for ( const blob of blobs ) {
console . log (
blob . blobId ,
blob . sizeDisplay , // human, e.g. "1.23 MB"
blob . originalName ,
blob . encrypted ? " 🔒 " : "" ,
);
}
Returns newest-first. Each entry has:
{
blobId : " Zb4z_LLozYWPNhTFHO15Zq… " ,
sizeBytes : 142 ,
sizeDisplay : " 142 B " ,
storedEpoch : 1098 ,
expiryEpoch : 1100 ,
encrypted : false ,
sealPolicyId : null ,
contentHashHex : " 08ce746f2ce577ed79b35781f6db34a6eec219fa642f0696bcdadbaee5fd5a04 " ,
contentType : " text/plain " ,
originalName : " hello.txt " ,
}
Get the store summary without walking blobs
If you only need totals (e.g. "12 blobs · 1.23 GB"), skip the per-blob walk:
const summary = await client . blob . getStore ({ owner : " 0x… " });
console . log ( ` ${ summary . totalBlobs } blobs, ${ summary . totalSizeBytes } bytes ` );
console . log ( ` viewers: ${ summary . viewers . length } ` );
Throws BlobStoreNotFoundError for users who've never uploaded.
Fetch the bytes
const { bytes , contentType , sizeBytes } = await client . blob . fetch ({
blobId : blobs [ 0 ]. blobId ,
});
// Browser
const blob = new Blob ([ bytes ], { type : contentType });
const url = URL . createObjectURL ( blob );
window . open ( url );
// Node — write to disk
import { writeFileSync } from " node:fs " ;
writeFileSync ( blobs [ 0 ]. originalName , bytes );
The aggregator GET runs with retry + a default 30s timeout. Override either:
const { bytes } = await client . blob . fetch ({
blobId : " … " ,
aggregatorUrl : " https://aggregator.walrus-testnet.walrus.space " ,
timeoutMs : 60_000 ,
});
Find one by filename
The SDK doesn't expose a findByName — just filter the list:
const blobs = await client . blob . list ({ owner });
const match = blobs . find (( b ) => b . originalName === " report.pdf " );
if ( match ) {
const { bytes } = await client . blob . fetch ({ blobId : match . blobId });
// …
}
Verify content integrity
The on-chain content_hash is SHA-256 of the original bytes (before
encryption). For plaintext blobs you can verify directly:
import { sha256 } from " @waldrop/sdk " ;
const blob = blobs . find (( b ) => b . blobId === " … " ) ! ;
const { bytes } = await client . blob . fetch ({ blobId : blob . blobId });
const actual = await sha256 ( bytes );
const actualHex = [... actual ]. map (( b ) => b . toString ( 16 ). padStart ( 2 , " 0 " )). join ( "" );
console . log ( actualHex === blob . contentHashHex ? " ✓ match " : " ✗ mismatch " );
For encrypted blobs, decrypt first, then hash. The hash on chain is always
of the pre-encryption bytes.
Pagination
For wallets with thousands of blobs, page through:
const PAGE = 50 ;
let offset = 0 ;
while ( true ) {
const batch = await client . blob . list ({ owner , limit : PAGE });
// …process batch
if ( batch . length < PAGE ) break ;
offset += PAGE ;
}
Aggregator caching
Walrus aggregators serve via CDN, so cold reads can take a few seconds
while warm reads are instant. The SDK's default 30s timeout covers both
comfortably.
Expired blobs
Walrus garbage-collects blob bytes after expiryEpoch. A blob still
registered on-chain might 404 at the aggregator — catch BlobNotFoundError
and surface "expired" rather than "network error".
← Recipes
Share with another address
Integrations →
Next.js + dapp-kit
Waldrop · 2026 cryptokarigar