walrus 0.1.0
walrus: ^0.1.0 copied to clipboard
Flutter SDK for Walrus decentralized storage protocol built on Sui blockchain.
Walrus Flutter SDK #
A Flutter SDK for Walrus, the decentralized storage protocol built on Sui blockchain.
Note: This is a community-maintained SDK. For official SDKs, see Walrus Documentation.
Features #
- ✅ Store - Upload blobs to the Walrus network
- ✅ Read - Retrieve blobs by their ID
- ❌ Encryption - Client-side AES-GCM encryption support
- ❌ Streaming - Handle large files with streaming upload/download
- ✅ Async/Await - Modern Dart async patterns
- ✅ Flutter Ready - Works seamlessly with Flutter mobile apps
Installation #
Add walrus to your pubspec.yaml:
dependencies:
walrus: ^0.0.1
Then run:
flutter pub get
🚀 Quick Start #
Initialization #
Initialize once in your app's main.dart:
import 'package:flutter/material.dart';
import 'package:walrus/walrus.dart';
Future<void> main() async {
await WalrusClient.initialize(
publisherUrl: 'https://publisher.walrus-testnet.walrus.space',
aggregatorUrl: 'https://aggregator.walrus-testnet.walrus.space',
);
runApp(MyApp());
}
Basic Usage #
After initialization, use the singleton instance anywhere:
import 'dart:convert';
import 'dart:typed_data';
import 'package:walrus/walrus.dart';
// Get singleton instance
final walrus = WalrusClient.instance;
// Upload data
final data = Uint8List.fromList(utf8.encode('Hello, Walrus!'));
final result = await walrus.store(data);
print('Blob ID: ${result.blobId}');
print('Object ID: ${result.objectId}');
print('Is New: ${result.isNew}');
print('URL: ${walrus.getBlobUrl(result.blobId)}');
// Download data
final retrieved = await walrus.read(result.blobId);
print('Content: ${utf8.decode(retrieved)}');
Upload with Options #
import 'dart:io';
import 'package:walrus/walrus.dart';
final walrus = WalrusClient.instance;
// Read image file
final imageBytes = await File('photo.jpg').readAsBytes();
// Upload with options
final result = await walrus.store(
imageBytes,
epochs: 5, // Storage duration (5 epochs)
permanent: true, // Cannot be deleted
// deletable: true, // Can be deleted by owner
);
print('Image URL: ${walrus.getBlobUrl(result.blobId)}');
Important: Up to (including) Walrus version 1.32, blobs are stored as permanent by default. Starting with version 1.33, newly stored blobs are deletable by default. If you care about blob persistence, make sure to use the appropriate flag.
Mainnet Configuration #
Future<void> main() async {
await WalrusClient.initialize(
publisherUrl: 'https://your-mainnet-publisher.com', // Auth required
aggregatorUrl: 'https://aggregator.walrus-mainnet.walrus.space',
);
runApp(MyApp());
}
📖 API Reference #
WalrusClient #
Static Methods
| Method | Description |
|---|---|
initialize({required String publisherUrl, required String aggregatorUrl, Dio? dio}) |
Initialize singleton instance |
instance |
Get singleton instance (throws if not initialized) |
isInitialized |
Check if initialized |
reset() |
Reset singleton (for testing) |
Instance Methods
| Method | Description | Returns |
|---|---|---|
store(Uint8List data, {int? epochs, bool? deletable, bool? permanent}) |
Upload blob to network | Future<StoreResponse> |
storeFile(String path, {int? epochs, bool? deletable, bool? permanent}) |
Upload file by path | Future<StoreResponse> |
read(String blobId) |
Download blob by ID | Future<Uint8List> |
getBlobUrl(String blobId) |
Get HTTP URL for blob | String |
exists(String blobId) |
Check if blob exists | Future<bool> |
StoreResponse #
class StoreResponse {
final String blobId; // Unique blob identifier
final String? objectId; // Sui Object ID
final int? endEpoch; // Storage expiration epoch
final bool isNew; // True if newly created, false if already existed
final String? mediaType; // Media type of the blob
}
Exceptions #
// Base exception
class WalrusException implements Exception {
final String message;
final int? statusCode;
final Object? cause;
}
// Blob not found
class BlobNotFoundException extends WalrusException { }
// Store operation failed
class StoreException extends WalrusException { }
// Network request failed
class NetworkException extends WalrusException { }
🔧 Flutter Integration #
Display Walrus Images #
import 'package:cached_network_image/cached_network_image.dart';
import 'package:walrus/walrus.dart';
class WalrusImage extends StatelessWidget {
final String blobId;
const WalrusImage({required this.blobId});
@override
Widget build(BuildContext context) {
final walrus = WalrusClient.instance;
return CachedNetworkImage(
imageUrl: walrus.getBlobUrl(blobId),
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
);
}
}
Upload from Camera/Gallery #
import 'package:image_picker/image_picker.dart';
import 'package:walrus/walrus.dart';
Future<String?> uploadImage() async {
final picker = ImagePicker();
final image = await picker.pickImage(source: ImageSource.gallery);
if (image == null) return null;
final bytes = await image.readAsBytes();
final walrus = WalrusClient.instance;
final result = await walrus.store(bytes, permanent: true);
return result.blobId;
}
🌐 Network Endpoints #
| Network | Publisher | Aggregator |
|---|---|---|
| Testnet | https://publisher.walrus-testnet.walrus.space |
https://aggregator.walrus-testnet.walrus.space |
| Mainnet | (Auth required - No public publisher) | https://aggregator.walrus-mainnet.walrus.space |
Note: On Mainnet, there are no public publishers without authentication, as they consume both SUI and WAL tokens. You need to run your own publisher node or use an authenticated service.
🛡️ Error Handling #
import 'package:walrus/walrus.dart';
try {
final walrus = WalrusClient.instance;
final result = await walrus.store(data);
print('Stored: ${result.blobId}');
} on StateError catch (e) {
print('Not initialized: ${e.message}');
} on BlobNotFoundException catch (e) {
print('Blob not found: ${e.message}');
} on StoreException catch (e) {
print('Store failed: ${e.message}');
} on NetworkException catch (e) {
print('Network error: ${e.message}');
} on WalrusException catch (e) {
print('Walrus error: ${e.message}');
}
🗺️ Roadmap #
- ✅ Basic store/read operations
- ✅ Deletable/Permanent blob support
- ❌ AES-GCM encryption
- ❌ Streaming upload/download for large files
- ❌ Sui blockchain integration (Object management)
- ❌ Multi-publisher support
- ❌ Retry with exponential backoff
🤝 Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create an issue (main)
- Create your feature branch (
git checkout -b feature/feature-name) - Commit your changes (
git commit -m 'Add some feature') - Push to the branch (
git push origin feature/feature-name) - Open a Pull Request
Development Setup #
# Clone the repository
git clone https://github.com/keem-hyun/walrus_dart.git
cd walrus
# Get dependencies
flutter pub get
# Run tests
flutter test
# Check formatting
dart format --set-exit-if-changed .
# Analyze code
dart analyze
📄 License #
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Links #
💬 Support #
- 📫 Open an issue for bug reports
- 💡 Start a discussion for feature requests
- ⭐ Star this repo if you find it useful!