Skip to content
Back to skills

Sui Move Object

ASecurity

Sui object model — struct declarations, abilities (key/store/copy/drop), object ownership, naming conventions, and dynamic fields.

  • 7 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 26, 2026
developmentgotesting

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add widnyana/eyay-toolkits --skill sui-move-object --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sui Move Object?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sui Move Object
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/widnyana-sui-move-object/badge)](https://www.skillsdirectory.com/skills/widnyana-sui-move-object)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sui-move-object
description: Sui object model — struct declarations, abilities (key/store/copy/drop), object ownership, naming conventions, and dynamic fields.
---

## 1. Structs

All structs must be declared `public`. Ability declarations go **after** the fields:

```move
// ✅
public struct Pool has key {
    id: UID,
    balance_x: Balance<SUI>,
    balance_y: Balance<USDC>,
}

public struct PoolCap has key, store {
    id: UID,
    pool_id: ID,
}

// ❌ Legacy — no public keyword
struct Pool has key {
    id: UID,
}
```

**Object rule**: Any struct with the `key` ability **must** have `id: UID` as its first field. Use `object::new(ctx)` to create UIDs — never reuse or fabricate them.

### Naming conventions

**Capabilities** must be suffixed with `Cap`:

```move
// ✅
public struct AdminCap has key, store { id: UID }

// ❌ Unclear it's a capability
public struct Admin has key, store { id: UID }
```

**No `Potato` suffix** — a struct's lack of abilities already communicates it's a hot potato:

```move
// ✅
public struct Promise {}

// ❌
public struct PromisePotato {}
```

**Events named in past tense** — they describe something that already happened:

```move
// ✅
public struct LiquidityAdded has copy, drop { ... }
public struct FeesCollected has copy, drop { ... }

// ❌
public struct AddLiquidity has copy, drop { ... }
public struct CollectFees has copy, drop { ... }
```

**Dynamic field keys** — use positional structs (no named fields):

```move
// ✅
public struct BalanceKey() has copy, drop, store;

// ⚠️ Acceptable but not canonical
public struct BalanceKey has copy, drop, store {}
```

### Constants naming

Error constants use `EPascalCase`. All other constants use `ALL_CAPS`:

```move
// ✅
const ENotAuthorized: u64 = 0;
const MAX_FEE_BPS: u64 = 10_000;

// ❌
const NOT_AUTHORIZED: u64 = 0;   // error should be EPascalCase
const MaxFeeBps: u64 = 10_000;   // non-error should be ALL_CAPS
```

---

## 2. Object Abilities Cheat Sheet


| Ability | Meaning in Sui                                                                                                 |
| ------- | -------------------------------------------------------------------------------------------------------------- |
| `key`   | Struct is an on-chain object; requires `id: UID` as first field                                                |
| `store` | Can be embedded inside other objects; enables `public_transfer`, `public_share_object`, `public_freeze_object` |
| `copy`  | Value can be duplicated (not valid on objects with `key`)                                                      |
| `drop`  | Value can be silently discarded                                                                                |


**Object ownership model:**

```move
// Transfer to an address (owned object)
transfer::transfer(obj, recipient);             // key only — module-restricted
transfer::public_transfer(obj, recipient);      // key + store — usable anywhere

// Share (accessible by anyone, goes through consensus)
transfer::share_object(obj);                    // key only — module-restricted
transfer::public_share_object(obj);             // key + store

// Freeze (immutable forever)
transfer::freeze_object(obj);                   // key only — module-restricted
transfer::public_freeze_object(obj);            // key + store
```

Only call `transfer`, `share_object`, and `freeze_object` (the non-`public_` variants) inside the module that **defines** that object's type.

**Never** construct an object struct literal outside of its defining module.

---

## 3. Dynamic Fields

Use dynamic fields for extensible storage or when the key set is not known at compile time:

```move
use sui::dynamic_field as df;
use sui::dynamic_object_field as dof;

// Add a dynamic field (value stored inline with parent)
df::add(&mut parent.id, key, value);

// Add a dynamic object field (value is an independent object)
dof::add(&mut parent.id, key, child_obj);

// Access
let val: &MyType = df::borrow(&parent.id, key);
let val: &mut MyType = df::borrow_mut(&mut parent.id, key);

// Remove
let val: MyType = df::remove(&mut parent.id, key);
```

---

## Routing

| Task                                             | Load                    |
| ------------------------------------------------ | ----------------------- |
| Capability pattern, OTW, events                  | `sui-move-patterns`     |
| Coin / Balance types and their abilities         | `sui-move-stdlib`       |
| Function parameter ordering with objects         | `sui-move-syntax`       |
| Package config, building, testing                | `sui-move-setup`        |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.