Single Walrus blob from a Uint8Array — one publisher PUT, one on-chain
register_blob transaction, no encryption. The most common path.
When to use this
Use plaintext upload for public assets — anything you'd serve from a CDN.
If the bytes shouldn't be readable by anyone with the blob_id,
jump to Upload encrypted instead.
Prerequisites
npm install @waldrop/sdk @mysten/sui
You'll need:
A funded testnet Sui address (faucet: curl -X POST https://faucet.testnet.sui.io/v2/gas -H "Content-Type: application/json" -d '{"FixedAmountRequest":{"recipient":"0x…"}}')
An active Subscription object id (subscribe via the Waldrop dapp once; the SDK will read its id)
Recipe
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";import { SuiGrpcClient } from "@mysten/sui/grpc";import type { Transaction } from "@mysten/sui/transactions";import { WaldropClient, type TransactionSigner } from "@waldrop/sdk";// 1. Build a signer adapter the SDK understands.const keypair = Ed25519Keypair.fromSecretKey(process.env.WALDROP_PRIVATE_KEY!);const suiClient = new SuiGrpcClient({ network: "testnet", baseUrl: "https://fullnode.testnet.sui.io:443",});const signer: TransactionSigner = { async signAndExecuteTransaction({ transaction }) { const r = await (suiClient as any).signAndExecuteTransaction({ transaction: transaction as Transaction, signer: keypair, include: { effects: true }, }); const digest = r?.digest ?? r?.effects?.transactionDigest ?? ""; if (digest) await (suiClient as any).waitForTransaction?.({ digest }); return { digest, effects: r?.effects }; },};// 2. Construct the client (shares the suiClient).const client = new WaldropClient({ network: "testnet", suiClient });// 3. Upload.const data = new TextEncoder().encode("hello waldrop");const result = await client.blob.upload({ data, fileName: "hello.txt", contentType: "text/plain", epochs: 2, // ≈ 2 days on testnet senderAddress: keypair.toSuiAddress(), subscriptionId: process.env.WALDROP_SUBSCRIPTION_ID!, signer, onProgress: (e) => console.log(`[${e.stage}] ${e.percent}%`),});console.log(result.blobId); // → "Zb4z_LLozYWPNhTFHO15Zq…"console.log(result.transactionDigest);
What happens
1. SHA-256
Hashes original bytes — recorded on the BlobRef.
2. Publisher PUT
HTTP upload to Walrus (https://publisher.walrus-testnet.walrus.space).
3. register_blob
PTB signed by your keypair. Creates a BlobStore if none exists.
4. waitForTransaction
Block until the fullnode has indexed it so the digest is queryable.