DubheSuiSchemasHow It Works

How Dubhe Works

For a new developer, Dubhe can be understood as a three-layer division of responsibility. You are only responsible for the top layer — the framework handles everything else.


Layer 1 — Your config (TypeScript)

Everything starts with dubhe.config.ts. You only need to declare what data your contract has:

export const dubheConfig = defineConfig({
  name: 'my_game',
  resources: {
    level: 'u32', // each player has a level
    stats: {
      // each player has attack / hp
      fields: { attack: 'u32', hp: 'u32' }
    }
  }
});

You do not need to think about how this data is stored on-chain, how it is serialized, or how events are emitted — none of that is your responsibility.


Layer 2 — Auto-generated contract code (codegen)

After running dubhe schemagen, the framework generates Move modules from your config:

sources/codegen/resources/level.move   ← auto-generated, do not edit
sources/codegen/resources/stats.move   ← auto-generated, do not edit

These modules provide a complete, type-safe API:

level::set(dh, player, 10, ctx);  // write
level::get(dh, player);           // read
level::has(dh, player);           // check existence

Key insight: You never need to write or fully understand this layer. It is just a bridge between your config and the Framework.


Layer 3 — Your business logic (systems)

The only code you actually write lives in sources/systems/ — your game rules or application logic:

// sources/systems/combat_system.move  ← you write this
public entry fun level_up(dh: &mut DappHub, ctx: &mut TxContext) {
    let player = address_system::ensure_origin(ctx);
    let lv = level::get(dh, player);
    level::set(dh, player, lv + 1, ctx);  // calls the generated API
}

The foundation — Dubhe Framework (already deployed, nothing to set up)

The generated code ultimately calls Dubhe Framework, a package already deployed on Sui. It handles:

What you triggerWhat the Framework does automatically
level::set(...)Writes to DappHub shared object via dynamic fields
Any write operationEmits a SetRecord event (subscribable by frontends / indexers)
First contract deploymentRegisters your DApp in DappHub, allocates storage credits
Contract upgradeValidates version, blocks old package versions from writing

All DApps share a single DappHub object but are fully isolated through DappKey — a type-level identity — so different DApps’ data never interfere with each other.


The full flow at a glance

dubhe.config.ts  (you write this)

       ▼  dubhe schemagen
codegen/ Move modules  (auto-generated)

       ▼  you call from systems/
Your business logic  (you write this)

       ▼  runtime calls
Dubhe Framework  (on-chain, already deployed)

       ▼  automatically fires
SetRecord events → SDK syncs state to your frontend

Three things every new developer should know

1. You only touch two places. dubhe.config.ts for data declarations and sources/systems/ for business logic. Everything else is either auto-generated or already lives on-chain.

2. schemagen is safe to re-run. Every time you change the config, run dubhe schemagen again. The codegen/ directory is fully regenerated, but your hand-written systems/ files and deploy_hook.move are never touched.

3. Frontend sync is zero-config. Every on-chain state change automatically fires an event. Pair it with @0xobelisk/sui-sdk subscriptions and your frontend stays in sync without polling or any extra sync code.