Getting Started
Warning: Storage Programs are still being developed; this documentation is a preview and might not work correctly.
This guide will walk you through creating your first Storage Program on Demos Network.
Prerequisites
Bun (latest) installed
Demos Network SDK:
@kynesyslabs/demosdkA Demos wallet with some balance for transaction fees
Connection to a Demos Network RPC node
Installation
bun add --latest @kynesyslabs/demosdkYour First Storage Program
Step 1: Initialize the SDK
import { DemosClient } from '@kynesyslabs/demosdk'
import { deriveStorageAddress } from '@kynesyslabs/demosdk/storage'
// Connect to Demos Network
const demos = new DemosClient({
rpcUrl: 'https://rpc.demos.network',
privateKey: 'your-private-key-here' // Use environment variables in production
})
// Get your wallet address
const myAddress = await demos.getAddress()
console.log('My address:', myAddress)Step 2: Generate Storage Address
Before creating a Storage Program, you can calculate its address client-side:
// Generate deterministic address
const programName = "myFirstProgram"
const salt = "" // Optional: use different salt for multiple programs with same name
const storageAddress = deriveStorageAddress(
myAddress,
programName,
salt
)
console.log('Storage address:', storageAddress)
// Output: stor-a1b2c3d4e5f6789012345678901234567890abcd...Address Format: stor- + 40 hex characters (SHA256 hash)
Step 3: Create Your Storage Program
Let's create a simple user profile storage:
import { StorageProgram } from '@kynesyslabs/demosdk/storage'
// Create storage program with initial data
const result = await demos.storageProgram.create(
programName,
"private", // Access control: private, public, restricted, deployer-only
{
initialData: {
username: "alice",
email: "[email protected]",
preferences: {
theme: "dark",
notifications: true
},
createdAt: Date.now()
}
}
)
console.log('Transaction hash:', result.txHash)
console.log('Storage address:', result.storageAddress)Access Control Modes:
private: Only you can read and writepublic: Anyone can read, only you can writerestricted: Only you and whitelisted addresses can accessdeployer-only: Explicit deployer-only mode (same as private)
Step 4: Write Data to Storage
Add or update data in your Storage Program:
// Write/update data (merges with existing data)
const writeResult = await demos.storageProgram.write(
storageAddress,
{
bio: "Web3 developer and blockchain enthusiast",
socialLinks: {
twitter: "@alice_demos",
github: "alice"
},
lastUpdated: Date.now()
}
)
console.log('Data written:', writeResult.txHash)Important: Write operations merge with existing data. They don't replace the entire storage.
Step 5: Read Data via RPC
Reading data is free and doesn't require a transaction:
// Read all data
const allData = await demos.storageProgram.read(storageAddress)
console.log('All data:', allData.data.variables)
// Read specific key
const username = await demos.storageProgram.read(storageAddress, 'username')
console.log('Username:', username)Need more detail on pagination, caching, or response formats? The RPC Queries guide covers the full schema and performance advice.
Complete Example
Here's a complete working example:
import { DemosClient } from '@kynesyslabs/demosdk'
import { deriveStorageAddress } from '@kynesyslabs/demosdk/storage'
async function main() {
// 1. Initialize SDK
const demos = new DemosClient({
rpcUrl: 'https://rpc.demos.network',
privateKey: process.env.PRIVATE_KEY
})
const myAddress = await demos.getAddress()
console.log('Connected as:', myAddress)
// 2. Generate storage address
const programName = "userProfile"
const storageAddress = deriveStorageAddress(myAddress, programName)
console.log('Storage address:', storageAddress)
// 3. Create storage program
console.log('Creating storage program...')
const createResult = await demos.storageProgram.create(
programName,
"private",
{
initialData: {
displayName: "Alice",
joinedAt: Date.now(),
stats: {
posts: 0,
followers: 0
}
}
}
)
console.log('Created! TX:', createResult.txHash)
// 4. Wait for transaction confirmation (optional but recommended)
await demos.waitForTransaction(createResult.txHash)
console.log('Transaction confirmed')
// 5. Read the data back
const data = await demos.storageProgram.read(storageAddress)
console.log('Data retrieved:', data.data.variables)
console.log('Metadata:', data.data.metadata)
// 6. Update some data
console.log('Updating stats...')
const updateResult = await demos.storageProgram.write(
storageAddress,
{
stats: {
posts: 5,
followers: 42
},
lastActive: Date.now()
}
)
console.log('Updated! TX:', updateResult.txHash)
// 7. Read specific field
const stats = await demos.storageProgram.read(storageAddress, 'stats')
console.log('Stats:', stats)
}
main().catch(console.error)Where to Go Next
Master permissions in the Access Control guide.
Dive deeper into each operation in the Operations guide.
Explore practical recipes in the Storage Program Cookbook.
Troubleshooting
Error: "Data size exceeds limit"
Problem: Your data exceeds the 128KB limit.
Solution:
// Check data size before storing
import { getDataSize } from '@kynesyslabs/demosdk/storage'
const data = { /* your data */ }
const size = getDataSize(data)
console.log(`Data size: ${size} bytes (limit: ${128 * 1024})`)
if (size > 128 * 1024) {
console.error('Data too large! Consider splitting or compressing.')
}Error: "Access denied"
Problem: Trying to write to storage you don't have access to.
Solution: Check the access control mode and your permissions:
const data = await demos.storageProgram.read(storageAddress)
const metadata = data.data.metadata
console.log('Access control:', metadata.accessControl)
console.log('Deployer:', metadata.deployer)
console.log('Allowed addresses:', metadata.allowedAddresses)Error: "Storage program not found"
Problem: Trying to read a Storage Program that doesn't exist yet.
Solution: Verify the address and ensure the creation transaction was confirmed:
// Check if storage program exists
try {
const data = await demos.storageProgram.read(storageAddress)
console.log('Storage program exists')
} catch (error) {
console.log('Storage program not found or not yet confirmed')
}Error: "Nesting depth exceeds limit"
Problem: Your object structure is too deeply nested (>64 levels).
Solution: Flatten your data structure:
// ❌ BAD: Too deeply nested
const badData = { level1: { level2: { level3: { /* ... 64+ levels */ } } } }
// ✅ GOOD: Flattened structure
const goodData = {
"user.profile.name": "Alice",
"user.profile.email": "[email protected]",
"user.settings.theme": "dark"
}Best Practices
1. Use Environment Variables
// ✅ GOOD
const demos = new DemosClient({
rpcUrl: process.env.DEMOS_RPC_URL,
privateKey: process.env.PRIVATE_KEY
})
// ❌ BAD
const demos = new DemosClient({
privateKey: 'hardcoded-private-key' // NEVER DO THIS
})2. Wait for Transaction Confirmation
// ✅ GOOD
const result = await demos.storageProgram.create(...)
await demos.waitForTransaction(result.txHash)
const data = await demos.storageProgram.read(storageAddress)
// ❌ BAD
const result = await demos.storageProgram.create(...)
const data = await demos.storageProgram.read(storageAddress) // Might fail, tx not confirmed yet3. Check Data Size Before Writing
// ✅ GOOD
import { getDataSize } from '@kynesyslabs/demosdk/storage'
const size = getDataSize(myData)
if (size > 128 * 1024) {
throw new Error('Data too large')
}
await demos.storageProgram.write(storageAddress, myData)4. Use Descriptive Program Names
// ✅ GOOD
const storageAddress = deriveStorageAddress(myAddress, "userProfile", "v1")
// ❌ BAD
const storageAddress = deriveStorageAddress(myAddress, "data", "")5. Structure Data Logically
// ✅ GOOD: Organized structure
const userData = {
profile: { name: "Alice", bio: "..." },
settings: { theme: "dark", notifications: true },
stats: { posts: 5, followers: 42 }
}
// ❌ BAD: Flat and unorganized
const userData = {
name: "Alice",
bio: "...",
theme: "dark",
notifications: true,
posts: 5,
followers: 42
}Next Steps
Now that you've created your first Storage Program, explore:
Operations Guide - Learn all CRUD operations in detail
Access Control - Master permission systems
RPC Queries - Efficient data reading patterns
Examples - Practical real-world examples
API Reference - Complete API documentation
Quick Reference
SDK Methods
// Create storage program
await demos.storageProgram.create(programName, accessControl, options)
// Write data
await demos.storageProgram.write(storageAddress, data)
// Read data
await demos.storageProgram.read(storageAddress, key?)
// Update access control
await demos.storageProgram.updateAccessControl(storageAddress, updates)
// Delete storage program
await demos.storageProgram.delete(storageAddress)
// Generate address
deriveStorageAddress(deployerAddress, programName, salt?)Storage Limits
Max size: 128KB per program
Max nesting: 64 levels
Max key length: 256 characters
Access Control Modes
private- Deployer only (read & write)public- Anyone reads, deployer writesrestricted- Deployer + whitelistdeployer-only- Same as private
Last updated