Skip to content

Latest commit

 

History

History
429 lines (321 loc) · 12.1 KB

File metadata and controls

429 lines (321 loc) · 12.1 KB

Walrus Decentralized Storage for Splash

This document covers Walrus storage integration for the Splash event ticketing platform, including blob storage, Sui structures, and Walrus Sites for frontend hosting.

Table of Contents

  1. Overview
  2. Core Concepts
  3. Storing Event Data
  4. Sui Structures
  5. Walrus Sites for Frontend
  6. Integration with Splash
  7. References

Overview

Walrus is a decentralized storage platform built on Sui that provides:

  • Blob storage: Store any file type as immutable blobs
  • Epoch-based duration: Storage paid for specific time periods
  • Sui integration: Blob metadata tracked as Sui objects
  • High availability: Erasure coding across storage nodes
  • Walrus Sites: Decentralized web hosting

Reference: Walrus Documentation | Getting Started


Core Concepts

Blobs

A blob is an immutable array of bytes. Key properties:

Property Description
Blob ID Content-addressed identifier (same content = same ID)
Sui Object ID Corresponding Sui object for metadata management
Epochs Storage duration (Testnet: 1 day, Mainnet: 2 weeks per epoch)
Deletable Whether the blob can be deleted before expiration

Tokens

  • SUI: Pay transaction fees on Sui
  • WAL: Pay for Walrus storage
# Convert SUI to WAL on Testnet
walrus get-wal --context testnet

Networks

Network Epoch Duration Max Epochs Use Case
Testnet 1 day 53 Development and testing
Mainnet 2 weeks 53 Production

Warning: Testnet does not guarantee data persistence and may wipe data.

Reference: Available Networks


Storing Event Data

Installation

Reference: Getting Started

# Install suiup tool
curl -sSfL https://raw.githubusercontent.com/Mystenlabs/suiup/main/install.sh | sh

# Install sui and walrus CLI
suiup install sui
suiup install walrus

# Configure for Testnet
curl --create-dirs https://docs.wal.app/setup/client_config.yaml -o ~/.config/walrus/client_config.yaml

Storing a File

Reference: Client CLI

# Store an event image
walrus store event-banner.png --epochs 52 --context testnet

# Output:
# Blob ID: oehkoh0352bRGNPjuwcy0nye3OLKT649K62imdNAlXg
# Sui object ID: 0x1c086e216c4d35bf4c1ea493aea701260ffa5b0070622b17271e4495a030fe83

Reading a File

# Retrieve blob by ID
walrus read <blob-id> --out downloaded-image.png --context testnet

HTTP API

Walrus also provides HTTP endpoints for programmatic access:

# Store via HTTP (using aggregator/publisher)
curl -X PUT "https://publisher.walrus-testnet.walrus.space/v1/blobs" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @event-banner.png

# Read via HTTP
curl "https://aggregator.walrus-testnet.walrus.space/v1/blobs/<blob-id>" \
  --output downloaded.png

JavaScript/TypeScript SDK

The Walrus SDK is a client extension for the Sui SDK:

import { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';
import { getFullnodeUrl } from '@mysten/sui/client';
import { walrus } from '@mysten/walrus';

// Create client with walrus extension
const client = new SuiJsonRpcClient({
  url: getFullnodeUrl('testnet'),
  network: 'testnet', // Required for walrus
}).$extend(walrus());

// Read a blob
const data = await client.walrus.readBlob({ blobId });

// Write a blob
const { blobId } = await client.walrus.writeBlob({
  blob: eventImageBuffer,
  deletable: false,
  epochs: 3,
  signer: keypair, // Pays for storage
});

Reference: Walrus SDK | Walrus SDKs | Web API


Sui Structures

Walrus uses Sui objects to track blob metadata. These can be queried and used in Move contracts.

Storage Object

/// Reservation for storage for a given period
public struct Storage has key, store {
    id: UID,
    start_epoch: u32,
    end_epoch: u32,
    storage_size: u64,
}

Blob Object

/// Represents a blob registered on Walrus
public struct Blob has key, store {
    id: UID,
    registered_epoch: u32,
    blob_id: u256,
    size: u64,
    encoding_type: u8,
    /// Epoch when certified (None if pending)
    certified_epoch: option::Option<u32>,
    storage: Storage,
    /// Whether this blob can be deleted
    deletable: bool,
}

Querying Blob Status

import { SuiClient } from '@mysten/sui/client';

const client = new SuiClient({ url: 'https://fullnode.testnet.sui.io:443' });

// Get blob object details
const blobObject = await client.getObject({
  id: suiObjectId,
  options: { showContent: true },
});

// Check if certified
const fields = blobObject.data?.content?.fields;
const isCertified = fields?.certified_epoch !== null;
const endEpoch = fields?.storage?.fields?.end_epoch;

Events

Walrus emits Sui events for blob lifecycle:

Event Description
BlobRegistered Blob registered, awaiting certification
BlobCertified Blob successfully stored and available
BlobDeleted Deletable blob was deleted
InvalidBlobID Incorrectly encoded blob detected

Reference: Sui Structures | Walrus Contracts


Walrus Sites for Frontend

Walrus Sites enables hosting complete web applications on Walrus with Sui-based addressing.

Key Features

  • Static hosting: HTML, CSS, JS, images
  • No backend required: Integrate with Sui for dynamic functionality
  • SuiNS integration: Human-readable domain names
  • Portal access: Browse via wal.app or self-hosted portals
  • Per-NFT sites: Create unique sites for each NFT

Installing Site Builder

# Install site builder
suiup install site-builder

# Verify installation
site-builder --help

Publishing a Site

# Build frontend (e.g., Next.js)
npm run build
npm run export  # Generate static files

# Publish to Walrus Sites
site-builder publish ./out --epochs 52

# Output:
# Site published!
# Object ID: 0x1234...
# Browse at: https://<object-id>.walrus.site

Configuring SuiNS Name

# Link SuiNS name to site
site-builder set-name splash.sui --site-object 0x1234...

# Now accessible at: https://splash.wal.app

Site Configuration

Create ws-config.json in your site root:

{
  "routes": {
    "/events/*": "/events/[id].html",
    "/tickets": "/tickets.html",
    "/profile": "/profile.html"
  },
  "fallback": "/index.html"
}

Updating a Site

# Update existing site
site-builder update ./out --site-object 0x1234...

Reference: Walrus Sites Introduction | Tutorial


Integration with Splash

Data Storage Strategy

Data Type Storage Location Notes
Event images Walrus blob Store blob_id in Event object
Event metadata Walrus blob (JSON) Public event details
Encrypted venue details Walrus blob + Seal Encrypted, NFT-gated
Ticket QR codes Walrus blob + Seal Per-ticket encrypted
Attendance badges Walrus blob Image for SBT
Frontend Walrus Sites Entire dApp

Event Creation Flow

async function createEvent(eventData: EventInput, signer: Keypair) {
  // 1. Upload event image to Walrus
  const { blobId: imageBlobId } = await client.walrus.writeBlob({
    blob: eventData.image,
    epochs: 53, // Maximum allowed (~2 years on mainnet)
    deletable: false,
    signer,
  });
  
  // 2. Encrypt venue details with Seal
  const encryptedVenue = await sealClient.encrypt({
    data: eventData.venueDetails,
    packageId: SPLASH_PACKAGE,
    id: eventData.eventId,
    threshold: 2,
  });
  
  // 3. Store encrypted venue on Walrus
  const { blobId: venueBlobId } = await client.walrus.writeBlob({
    blob: encryptedVenue,
    epochs: 53, // Maximum allowed
    deletable: false,
    signer,
  });
  
  // 4. Create event on Sui with blob references
  const tx = new Transaction();
  tx.moveCall({
    target: `${SPLASH_PACKAGE}::event::create_event`,
    arguments: [
      tx.pure.string(eventData.title),
      tx.pure.string(eventData.description),
      tx.pure.u64(eventData.date),
      tx.pure.string(eventData.location),
      tx.pure.u64(eventData.capacity),
      tx.pure.u64(eventData.price),
      tx.pure.u256(imageBlob.blobId),
      tx.pure.u256(venueBlob.blobId),
      tx.pure.bool(eventData.isPrivate),
      tx.pure.string(eventData.requiredBadge || ''),
      tx.pure.vector('string', eventData.tags),
    ],
  });
  
  return await client.signAndExecuteTransaction({ transaction: tx });
}

Reading Event Data

async function getEventDetails(event: EventObject) {
  // 1. Fetch public image from Walrus (via aggregator for simplicity)
  const imageUrl = `https://aggregator.walrus-testnet.walrus.space/v1/blobs/${event.image_blob_id}`;
  
  // Or read directly via SDK:
  // const imageData = await client.walrus.readBlob({ blobId: event.image_blob_id });
  
  // 2. If user has ticket, decrypt venue details
  if (userHasTicket) {
    const encryptedData = await client.walrus.readBlob({ 
      blobId: event.encrypted_details_blob_id 
    });
    
    const decrypted = await sealClient.decrypt({
      data: encryptedData,
      sessionKey,
      txBytes: /* seal_approve PTB */,
    });
    
    return { ...event, venueDetails: decrypted };
  }
  
  return event;
}

Storage Duration Considerations

Important: Walrus blobs expire after the specified epochs.

Note: Maximum epochs per purchase is 53 epochs (~2 years on Mainnet, ~53 days on Testnet). For longer storage, you must extend before expiration.

Event Type Recommended Epochs Duration (Mainnet)
Short-term events 4-8 2-4 months
Annual events 26 ~1 year
Maximum initial 53 ~2 years
Long-term (with renewal) 53 + extensions 2+ years

Renewal Strategy:

// Extend blob storage before expiration
// Use either `epochs` (add N epochs) or `endEpoch` (set specific end)
const tx = await client.walrus.extendBlob({
  blobObjectId: '0x1234...',
  epochs: 26, // Add ~1 year on mainnet
});
await suiClient.signAndExecuteTransaction({ transaction: tx, signer });

Reference: Available Networks - Maximum 53 epochs per purchase


References

Documentation

Code Examples

Tools