Sui.

Post

Share your knowledge.

Klaus.move.
Sep 04, 2025
Expert Q&A

Access control patterns in Move – what’s recommended

What’s the best way to enforce role-based permissions in Move? Should I store roles as capabilities, or use object ownership?

  • Sui
  • Architecture
  • Security Protocols
1
5
Share
Comments
.

Answers

5
GSui.
GSui789
Sep 4 2025, 12:38

1. Capabilities for roles Think of a capability as a “key” that proves you’re allowed to do something. In Move, these are resources that can’t be copied, only moved. That makes them perfect for roles like Admin, Moderator, Treasurer. You can:

  • Mint the capability once, controlled by some authority.
  • Hand it to the account that should hold that role.
  • Gate privileged functions by requiring the capability as a parameter.

This is flexible because you can revoke roles (burn the capability), delegate them, or even design temporary roles (capabilities that expire).

2. Object ownership for resource-bound access Ownership shines when the permission depends on “who owns what.” Example: if Alice owns an NFT, Move’s type system enforces that only Alice can move or modify it. No need for explicit role checks.

So you’d use ownership for “local rights” (I can only mess with my own vault, coin, or NFT), not global roles.

3. Combining both Real systems usually mix them. Example:

  • A DAO treasury might only let the TreasurerCapability holder spend funds.
  • But within that, each vault entry is still owned by whoever deposited it.

4. Why this pattern is recommended

  • Capabilities encode roles in a type-safe way, enforced at compile time and runtime.
  • Ownership encodes resource safety, automatically preventing double-spend or unauthorized transfers.
  • Together they avoid “manual role tables” (like a map<address, role>) which are brittle and less auditable.

In short: use capabilities for who you are, and ownership for what you own. That’s the idiomatic Move way.

8
Comments
.
epidote.
Sep 7 2025, 15:14

The recommended way to enforce role-based permissions in Move (on Sui) is to use the capability design pattern. This is a best practice for fine-grained, object-centric access control and is more flexible and secure than simply relying on object ownership.


Capability Design Pattern

Capabilities are special objects (structs) that represent the right to perform privileged actions. Only users who possess a specific capability object can call certain functions.

How it works:

  1. Define a Capability Struct

    public struct TeacherCap has key {
        id: UID
    }
    

    This struct acts as a "permission token" for privileged actions.

  2. Require Capability as a Function Parameter

    public fun create_wrappable_transcript_object(
        _: &TeacherCap,
        history: u8,
        math: u8,
        literature: u8,
        ctx: &mut TxContext,
    ) {
        // ... privileged logic ...
    }
    

    Only callers who can provide a reference to a TeacherCap can execute this function.

  3. Distribute Capabilities

    • On module initialization, mint and transfer the initial capability to the deployer:
      fun init(ctx: &mut TxContext) {
          transfer::transfer(TeacherCap {
              id: object::new(ctx)
          }, ctx.sender())
      }
      
    • To add more admins/roles, create and transfer additional capability objects as needed.
  4. Non-Transferrable Capabilities (Soulbound)

    • Omit the store ability from the struct to make it non-transferrable.

Object Ownership

  • Object ownership is a lower-level access control mechanism.
  • Only the owner of an object can mutate or transfer it.
  • This is useful for basic access control (e.g., only the owner can update their profile), but it is less flexible for role-based or multi-role systems.

Best Practice

  • Use capabilities for role-based permissions.
    • This allows you to define multiple roles, delegate, revoke, and even create hierarchical permissions.
    • Capabilities can be transferred, burned, or made non-transferrable as needed.
  • Use object ownership for simple, single-owner access control.
    • Good for user-owned assets, but not for complex admin/role systems.

Source & Example

See the Capability Design Pattern for a full example and explanation.

2
Comments
.
WAGMI.
Sep 5 2025, 20:39

In Move, capabilities act as unforgeable keys for global roles (e.g. Admin, Treasurer), while ownership enforces local rights over resources (e.g. your own NFT or vault). Real systems often combine both: roles are gated by capabilities, while assets remain tied to their owners. This approach is safer and cleaner than using manual role tables—capabilities define who you are, ownership defines what you control.

1
Comments
.
NakaMoto. SUI.
Sep 4 2025, 12:56

you’d use ownership for “local rights” (I can only mess with my own vault, coin, or NFT), not global roles.

Combining both Real systems usually mix them. Example:

A DAO treasury might only let the TreasurerCapability holder spend funds. But within that, each vault entry is still owned by whoever deposited it.

Why this pattern is recommended

Capabilities encode roles in a type-safe way, enforced at compile time and runtime. Ownership encodes resource safety, automatically preventing double-spend or unauthorized transfers. Together they avoid “manual role tables” (like a map<address, role>) which are brittle and less auditable. In short: use capabilities for who you are, and ownership for what you own. That’s the idiomatic Move way.

0
Comments
.
Meaning.Sui.
Sep 7 2025, 15:21

You do not need to create your own pool to build a DEX on Sui using DeepBook. DeepBook is designed as a shared, permissionless central limit order book (CLOB) and acts as a public liquidity layer for the entire Sui ecosystem.

Key Points from the Documentation

  • Shared Liquidity:
    DeepBook pools are globally shared objects. Each pool represents a unique trading pair (e.g., SUI/USDC), and there is only one pool per pair on DeepBook.

    "The Pool shared object represents a market, such as a SUI/USDC market. That Pool is the only one representing that unique pairing (SUI/USDC) and the pairing is the only member of that particular Pool."
    Source

  • Permissionless Access:
    Any DEX, wallet, or app can interact with existing DeepBook pools. You can place orders, query the order book, and settle trades using the shared pools—no need to create your own unless the pair does not exist yet.

  • When to Create a Pool:
    You only need to create a new pool if the trading pair you want does not already exist on DeepBook.

    "Pools can only be created if the asset pair has not already been created before."
    Source

  • Ecosystem Collaboration:
    DeepBook is designed to be a public good, so all DEXs and DeFi apps on Sui can share liquidity and benefit from a unified order book.

    "DeepBook provides a stable liquidity layer enabling a new generation of DeFi apps... Designed as permissionless and released as open source, DeepBook exists as a Move package that lets anyone publish a liquidity pool to enable trading between a pair of assets."
    Source


Summary

  • If the pool for your desired trading pair exists:
    Use the existing DeepBook pool—no need to create your own.
  • If the pool does not exist:
    You can create it permissionlessly using DeepBook’s API.
0
Comments
.

Do you know the answer?

Please log in and share it.