DubheSuiSchemas

Schemas

What is Schemas?

In Dubhe, Schemas are a typed on-chain storage layer. When building with Dubhe, developers declare all contract state in a dubhe.config.ts file. The schemagen CLI then generates a complete set of Move modules that handle storage reads, writes, and events automatically.

This replaces the traditional Move approach of defining data structures and table access manually:

Traditional Move storage

// Declare manually
struct Player has store {
    level: u32,
    hp: u64,
}
 
// Store and retrieve manually
let player = Player { level: 1, hp: 100 };
table::add(&mut storage, addr, player);
let p = table::borrow(&storage, addr);

Dubhe Schemas

// dubhe.config.ts — declare once
resources: {
  level: 'u32',
  hp:    'u64',
}
// Generated Move — type-safe, no boilerplate
level::set(dh, player, 1, ctx);
let lv = level::get(dh, player);

All storage operations emit standardized events that enable zero-code indexing and off-chain data synchronization.


Core storage model

Schemas use a three-level key-value store backed by Dubhe’s shared DappHub object:

DappHub → dapp_key → resource_account → key_tuple → value
  • DappHub — a single shared object that holds all dapp state on chain.
  • dapp_key — a unique identifier per published package derived from its type_name.
  • resource_account — a String that identifies the entity (typically an address). Omitted for global resources.
  • key_tuple — zero or more additional key fields defined in the config.

Resource patterns

There are six patterns depending on the combination of global, keys, and fields:

PatternConfig shapePrimary use case
Global singletonglobal: truePackage-level counters, config flags
Entity single value'MoveType' shorthandSimple per-player properties
Entity multi-field recordfields onlyStructs keyed by entity
Keyed single valuefields + keys (1 value field)Maps like (player, item_id) → quantity
Keyed multi-value recordfields + keys (multiple value fields)Rich indexed data
Offchainoffchain: trueEvents only, no on-chain storage

See Config Reference for the full API generated by each pattern.


Enum and error support

Custom enum types can be declared alongside resources and used as field or key types. Each enum compiles to a Move module with constructors, matchers, and BCS helpers.

Custom error codes compile to assertion helpers that abort with a message string, making contract revert reasons immediately readable.


Why Schemas?

Schemas address several hard problems in on-chain application development:

  • Separation of state from logic — business logic lives in system contracts; all state lives in DappHub. Upgrading logic never migrates data.
  • Granular access control — different system contracts can access different slices of the same data store.
  • Automatic sync to frontends — all writes emit standardised events that a Dubhe indexer can consume without any extra code.
  • Cross-contract queries — any contract that receives DappHub can read data from any registered dapp.
  • Gas efficiency — values are tightly packed in the underlying storage, often cheaper than hand-written table access.