Documentation Index
Fetch the complete documentation index at: https://docs.kynesys.xyz/llms.txt
Use this file to discover all available pages before exploring further.
Storage Program Operations
This guide explains when to reach for each Storage Program operation in an end-to-end workflow. The mechanics (build payload → sign → confirm → broadcast) are covered in Getting Started; full method signatures, payload shapes, and response types live in the API Reference. Recipe-style end-to-end examples live in the Storage Program Cookbook. Every write below assumes the same skeleton:demos.storagePrograms.read(address).
Operation overview
| Operation | Transaction? | Who can run it | Typical use |
|---|---|---|---|
CREATE_STORAGE_PROGRAM | Yes | Any funded address (becomes owner) | Provision a new stor- address and seed initial data |
WRITE_STORAGE | Yes | Owner, allowed addresses, group members with write | Replace the entire data field (full snapshots, binary blobs) |
SET_FIELD / SET_ITEM / APPEND_ITEM | Yes | Owner, allowed, group members with write | Surgical JSON updates without rewriting the document |
DELETE_FIELD / DELETE_ITEM | Yes | Owner, allowed, group members with write | Remove a single field or array element from a JSON program |
READ_STORAGE | No (RPC) | Determined by ACL mode + allowed/groups | Fetch program data via demos.storagePrograms.read(address) |
UPDATE_ACCESS_CONTROL | Yes | Owner only | Change ACL mode, allowlist, blacklist, or groups |
DELETE_STORAGE_PROGRAM | Yes | Owner, or group members with delete permission | Permanently remove the program and its data |
StorageProgramOperation enum exported from @kynesyslabs/demosdk/storage. You rarely write them by hand — the StorageProgram.* helpers fill them in.
CREATE — provision a new program
UseStorageProgram.createStorageProgram to mint a new deterministic stor- address and (optionally) seed initial data. The address is derived inside the helper from sha256(deployer:programName:nonce:salt), so you don’t need to call deriveStorageAddress yourself unless you want to know the address before signing.
Pre-flight checks
- Nonce.
options.nonceis required. Fetch the sender’s current nonce withdemos.getAddressNonce(ownerAddress)— without it the helper throws"nonce is required for storage program creation". The nonce is mixed into address derivation so two creates from the same deployer with the sameprogramNameproduce different addresses. - ACL choice. Pick the mode you want now — you can change it later with
UPDATE_ACCESS_CONTROL, but until you do, the default is"owner"(only the owner can read or write). - Encoding.
"json"for structuredRecord<string, any>,"binary"for base64-encoded blobs. Granular operations (setField,appendItem, etc.) are rejected on"binary"programs. - Size. Validate against the 1 MB ceiling before signing:
- Fee budget.
StorageProgram.calculateStorageFee(data, encoding)returns abigintof the fee in OS (1 DEM = 10⁹ OS). Storage is billed at 1 DEM per 10 KB chunk, minimum 1 DEM. - Predict the address up front (optional).
storageLocation defaults to "onchain". The "ipfs" value is reserved for future hybrid storage and currently falls back to "onchain" on the node side — treat it as a forward-looking flag, not a working feature.WRITE — replace the full document
UseStorageProgram.writeStorage when you want to overwrite the entire data field in one shot. This is the right choice for:
- Binary programs. Granular operations don’t apply — every update is a full replacement.
- Full snapshots. You’re computing a new state from scratch (e.g. importing from another source) and don’t need to reason about diffs.
- Atomic multi-field rewrites. When you want every changed field to land in a single transaction even though there are no granular
WRITE_MANYsemantics.
WRITE_STORAGE replaces data wholesale — it does not deep-merge. If you only want to change a couple of keys in a large JSON document, prefer the granular operations below.
Granular operations — surgical JSON updates
For JSON-encoded programs, five granular helpers let you change individual fields and array elements without rewriting (or paying to re-store) the whole document:| Helper | Operation | Use when |
|---|---|---|
StorageProgram.setField(addr, field, value) | SET_FIELD | Setting / replacing a single top-level field |
StorageProgram.setItem(addr, field, index, value) | SET_ITEM | Replacing one element of an array (negative indices supported, -1 = last) |
StorageProgram.appendItem(addr, field, value) | APPEND_ITEM | Pushing onto an array field |
StorageProgram.deleteField(addr, field) | DELETE_FIELD | Removing a top-level field entirely |
StorageProgram.deleteItem(addr, field, index) | DELETE_ITEM | Removing one array element by index |
writeStorage:
- You’re editing a small slice of a large document — fee is computed on the operation payload, not the whole stored document.
- You want concurrent writers each touching different fields without overwriting each other’s changes.
- You want the transaction to fail loudly if the field doesn’t have the shape you expect (e.g.
setItemon a non-array).
writeStorage:
- The program is
"binary"— granular operations are rejected for binary encoding. - You’re rewriting most of the document anyway.
- You need cross-field invariants (multiple fields must change atomically as one logical unit; granular ops are one-op-per-tx).
READ — fetch program data over RPC
Reads do not go through the transaction lifecycle. Use the RPC accessor directly:StorageProgramResponse from @kynesyslabs/demosdk/storage. If the wallet is connected, the SDK automatically attaches an identity/signature header so the node can apply ACL rules to the requester.
StorageProgram.readStorage(address) exists as a payload builder, but it’s intended for transaction-validation flows — for normal reads use demos.storagePrograms.read(address).
For listings, by-owner queries, name search, and field-level lookups (getFields, getValue, getItem, hasField, getFieldType, getAll) see RPC Queries.
UPDATE ACCESS CONTROL — owner-only ACL changes
Only the program owner can change the ACL. Submit a full ACL object — it replaces the existing one rather than merging.Pre-flight checks
- Owner-only. Anyone else gets denied at the ACL check before the transaction lands. There is no “deputy” or co-owner concept.
- Mode is required. Valid values are
"owner"(default — only the owner can read or write),"public"(anyone reads, only the owner / allowed / writers in groups can write), and"restricted"(onlyallowedand matching group members get any access). - Blacklist beats allowlist. An address that appears in both
blacklistedandallowed(or in a group) is denied. Use this to revoke without rebuilding the allow set. - Opening up data. Going from
"owner"or"restricted"to"public"exposes everything currently stored — audit the data first if there’s any chance of secrets.
StorageProgram.publicACL(), privateACL(), restrictedACL(allowed), groupACL(groups), and blacklistACL(mode, blacklisted, allowed?) all return ready-made StorageProgramACL objects. Full coverage in Access Control.
The legacy
accessControl: "private" | "public" | "restricted" | "deployer-only" field on the payload (and the createStorageProgramLegacy / updateAccessControlLegacy helpers) is kept for backward compatibility but is deprecated. Use the acl object with mode for all new code.DELETE — irreversible teardown
Pre-flight checks
- Permission. The owner can always delete. Other addresses can delete only if they are members of an ACL group with the
"delete"permission. - Irreversible. There is no undo, no soft delete, no archival snapshot. The address itself remains derivable from
(deployer, programName, nonce, salt), but the data is gone. - Downstream cleanup. Invalidate caches, notify collaborators, and remove references from indexes before submitting the delete — by the time the transaction lands the data is unrecoverable.
Resource limits at a glance
| Limit | Value | Constant on STORAGE_PROGRAM_CONSTANTS |
|---|---|---|
| Max payload size | 1 MB (1,048,576 bytes) | MAX_SIZE_BYTES |
| Max JSON nesting depth | 64 | MAX_JSON_NESTING_DEPTH |
| Pricing chunk size | 10 KB (10,240 bytes) | PRICING_CHUNK_BYTES |
| Fee per chunk | 1 DEM (= 10⁹ OS) | FEE_PER_CHUNK |
Cross-references
- Getting Started — the four-step build / sign / confirm / broadcast flow with a worked example.
- Access Control —
owner/public/restrictedmodes, allowlists, blacklists, and group permissions. - RPC Queries — listings, by-owner lookups, name search, and granular field-level reads via
StorageProgram.getFields,getValue,getItem,hasField,getFieldType, andgetAll. - API Reference — every
StorageProgramstatic method, the fullStorageProgramPayloadschema, ACL types, and theStorageProgramResponseshape. - Cookbook — Storage Programs — end-to-end recipes for public profiles, team workspaces, and binary attachments.