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".

Edit this page on GitHub ↗
Waldrop · 2026cryptokarigar