Waldrop SDK · Getting Started

Concepts

Four ideas you need before things make sense — what Walrus stores, what Waldrop tracks on Sui, what SEAL adds, and how epochs differ between the two chains.

Walrus blobs vs Waldrop BlobRefs

Walrus is a content-addressed storage network. You upload bytes, you get a blob_id — a hash. Anyone with the id can download the bytes. The id is all the network knows about you: there's no user, no account, no folder.

That's a problem for apps. "Show me my files" doesn't work when the storage layer doesn't know what "my" means.

Waldrop closes the gap with a Sui Move package. Every time you upload, the SDK signs one extra transaction (register_blob) that creates a BlobRef on Sui:

Walrus            Sui (Waldrop Move package)
──────            ──────────────────────────
blob_id           BlobRef {
"vEYTwxx..."       blobId: "vEYTwxx...",
                   sizeBytes, fileName, contentType,
                   contentHash,SHA-256 of original
                   storedEpoch, expiryEpoch,
                   encrypted, sealMarker,if SEAL
                 }

Now you can ask Sui "give me all BlobRefs owned by address X" and get a typed list back. That's client.blob.list({ owner }).

BlobStore — the per-user index

A user's BlobRefs live inside a single Sui object called a BlobStore:

BlobStore

One per user (shared object on Sui). Holds a Table of BlobRefs keyed by blob_id, total bytes, total count, viewer allowlist, per-blob share table.

BlobRef

One per uploaded blob. Lives inside the BlobStore's Table — not a standalone object. Drops via Move's drop ability when released.

The first time you call client.blob.upload(...) without a blobStoreId, the SDK creates a BlobStore + registers your first BlobRef in one PTB. The result returns blobStoreId: 0x…save it, you'll need it for encrypted uploads.

Subscription — gates on plan tier

register_blob requires a Subscription object id. The contract reads the subscription's planTier to enforce:

  • SEAL access — Free tier can't upload encrypted blobs.
  • File-count cap — Free tier limited to N blobs per BlobStore.
  • Lifetime cap — Plans cap max expiryEpoch based on tier.
interface SubscriptionSummary {
  subscriptionId: string;
  planTier: number;     // 0 FREE, 1 STARTER, 2 PRO, 3 ENTERPRISE
  startedEpoch: number;
  expiresEpoch: number;
  status: number;       // 0 ACTIVE, 1 CANCELLED, 2 EXPIRED
}

Subscribe via the Waldrop dapp once — the SDK reads the resulting object via client.subscription.get({ owner }).

SEAL — threshold encryption

When you set encrypted: true on upload, the SDK runs the plaintext through SEAL before the publisher PUT. SEAL is identity-based threshold encryption:

ciphertextSEAL.encrypt(threshold=1, packageId, identity, plaintext)

The identity is a 53-byte string the SDK constructs:

identity = store_id (32 bytes)
         || marker  (16 bytes)recorded on BlobRef
         || nonce   (5 bytes)random, uniqueness only

The 16-byte marker is what the BlobRef records on-chain. Per-blob shares key off this marker — granting access to one blob doesn't grant access to the whole store.

What SEAL protects · what it doesn't

ProtectedNot protected
The blob contentsFilename + MIME type (plaintext on-chain)
Who can decrypt (gated by seal_approve)Upload metadata (size, hash, sender address)
Network observers (publisher knows the source IP)

To hide filenames too, you'd need encrypted metadata — out of scope for this SDK version.

Walrus epochs vs Sui epochs

Two separate epoch clocks, both used by Waldrop:

01
Sui epoch

~24 hours. Recorded on every BlobRef as storedEpoch / expiryEpoch — used for "is this blob still active" checks.

02
Walrus epoch

1 day on testnet, 14 days on mainnet. The unit you pay storage in — client.blob.upload({ epochs }) is Walrus epochs, not Sui epochs.

The contract just stores expiryEpoch as a number — it's intentionally ambiguous about which clock. The dapp uses Sui epoch since that's what's trivially readable on-chain.

The complete upload pipeline

Putting it all together:

1. SHA-256(data)contentHash recorded on BlobRef
2. SEAL.encrypt(data,)if encrypted=true
3. PUT to publisherciphertext (or plaintext) lands on Walrus
4. publisher returns blob_idcontent-addressed hash
5. Build PTB:
   - new_blob_ref(blobId, hash,)
   - register_blob(BlobStore, Config, PlanRegistry, Subscription, BlobRef)
   - [optional] add_blob_share(...)bundle initial viewers
6. Wallet signs + executes the PTBONE signature, the only one
7. Wait for tx finalization

Each step is independent — if step 4 succeeds but step 6 fails, you have a checkpoint. See the Resume guide.

Edit this page on GitHub ↗
Waldrop · 2026cryptokarigar