Abilities

A struct can only declare an ability if all of its fields have the required abilities:

16.1 The four abilities

Values can be duplicated (copy x, implicit copies) Plain data: numbers, points, config

Values can be discarded / go out of scope Data, events, witnesses

Values can be stored inside other structs in storage Anything placed inside objects/resources; on Sui enables public_transfer Type can be a top-level storage item

Aptos: move_to; Sui: an object (first field must be id: UID)

16.2 Primitive abilities

bool, integers, address copy, drop, store Same as T (minus key) References &T, &mut T

copy, drop (&mut cannot be copied while in use; they can never be stored) store only (no copy, no drop)

16.3 The containment rule

A struct can only declare an ability if all of its fields have the required abilities:

copy requires all fields copy; drop requires all fields drop; store requires all fields store; key requires all fields store.

For generic structs, abilities are conditional: Box<T> has copy, drop, store only has copy when T has copy, and so on.

public struct Wrapper has drop {
    inner: Coin<SUI>,     // ERROR: Coin<SUI> lacks drop
}

16.4 Common ability combinations

copy, drop, store config structs, String Ephemeral data; events (Sui requires copy, drop for events) events, return values Disposable but unique witnesses, one-time witness

Asset that must be explicitly handled but can live inside other things

Sui object with restricted transfer (only its module can transfer) soulbound NFT, shared pool

Freely transferable Sui object; Aptos storable resource Coin<T>, NFTs

Hot potato: must be consumed in the same transaction

16.5 key on Sui vs Aptos

| | Sui | Aptos | |-|-----|-------| | key means | Struct is an object; must have id: UID as first field | Struct can be stored at an address with move_to | | key without store | Only the defining module can transfer/share/freeze it (transfer::transfer) | Cannot be nested inside another resource | | key + store | Anyone can transfer with transfer::public_transfer and wrap it | Can be stored at top level and nested |