Sui Move
Move is a resource-oriented programming language created at Meta for the Diem (Libra) project. When that project wound down, the language survived its sponsor: it now underpins several chains, of which Sui is the most prominent. Sui Move is Mysten Labs’ dialect, adapted to fit Sui’s object model rather than the account storage of the original (“core”) Move and its other major descendant, Aptos Move. IOTA runs the same Mysten dialect, so the material here applies there too.
The language’s central idea is that on-chain assets should be ordinary typed values that the type system refuses to copy, drop, or otherwise mishandle. This is the opposite of Solidity, where a token balance is just a number in a mapping and nothing in the language stops you from forgetting to update it. The tooling rhymes with Ethereum’s, and the safety guarantees that smart contract authors there maintain by convention are enforced here by the compiler.
Resources and Linear Types#
A struct in Move is a value with linear (or “affine”) semantics. By default the type system will not implicitly copy it and will not let it silently go out of scope. A value in hand has to be disposed of deliberately — returned, stored, or passed on. Duplicating a coin by assigning it to two variables and losing one by letting it fall out of scope are both compile errors. Whole bug classes — accidental token loss, double-spends from a stray copy — are simply not expressible.
That is what “resource-oriented” means in practice: an asset is not a number someone remembers to decrement, it is a value the compiler tracks from creation to destruction.
Abilities#
Move controls what can be done with a type through four abilities, declared with has:
copy— the value may be duplicated.drop— the value may be discarded without being used.store— the value may be stored inside another struct and persisted, and (as an owned object) transferred between addresses.key— the struct is a top-level Sui object. Akeystruct must have aUIDas its first field, namedid.
A real asset deliberately omits copy and drop — that omission is what makes it scarce and conserved. A typical Sui object carries key and store:
module my_pkg::sword {
use sui::object::UID;
public struct Sword has key, store {
id: UID,
strength: u64,
}
}key lets Sword exist as a standalone object the protocol can own and address; store lets it be embedded in another object (say, a chest) or transferred via the generic transfer functions below.
No Global Storage#
In core Move, contracts read and write a per-account global store with move_to, borrow_global, and move_from. Sui Move has none of that. State lives entirely in objects, and a function can only touch the objects explicitly passed into it.
Functions marked public or entry therefore take objects as parameters. There is no ambient “the caller’s storage” to reach into — if a function needs an object, that object must appear in its signature, which is exactly what lets Sui schedule non-overlapping transactions in parallel. To get an object back out to a user, you call one of:
transfer::transfer— give an object to an address (the object’s module must define this for its own type).transfer::public_transfer— the same, for any type withstore, callable from outside the defining module.transfer::share_object— make an object shared, so anyone may reference it (this is how AMM pools and order books are built).
module my_pkg::sword {
use sui::object::{Self, UID};
use sui::tx_context::TxContext;
use sui::transfer;
public struct Sword has key, store {
id: UID,
strength: u64,
}
/// Mint a new Sword and hand it to `recipient`.
public entry fun mint(strength: u64, recipient: address, ctx: &mut TxContext) {
let sword = Sword { id: object::new(ctx), strength };
transfer::transfer(sword, recipient);
}
}object::new(ctx) draws a fresh UID from the transaction context; transfer consumes the sword value, satisfying the linear-type rule that it must be disposed of deliberately.
Modules and Packages#
Code is organized into modules (module pkg::name { ... }), and modules are grouped into packages that you publish as a unit. A published package is itself an immutable on-chain object — its bytecode cannot be mutated in place. Upgrades work through a versioned upgrade policy: you publish a new version of the package and migrate, rather than patching the deployed code. This makes “the code at this address can change under you” a non-default, opt-in property, unlike a Solidity proxy.
The Move 2024 Edition#
Sui Move’s syntax was substantially revised in the Move 2024 edition, which is now the default for new packages. Highlights:
- Method syntax — call
x.foo(y)instead ofmodule::foo(x, y)whenfootakes the receiver as its first argument. - Enums — sum types with named or positional variants, enabling exhaustive
match. - Macro functions —
macro funbodies inline at the call site and accept lambdas, giving higher-order patterns (vector::for_each!) without runtime closures. - Positional fields — tuple-style structs like
public struct Wrapper(Coin<SUI>). public(package)— replaces the oldfriendmechanism for intra-package visibility; the compiler infers the rest.
Note that public struct (rather than bare struct) and ability annotations are required in this edition.
Contrast with Solidity#
| Sui Move | Solidity | |
|---|---|---|
| Assets | linear typed values, conserved by the compiler | numbers in mappings, conserved by hand |
| Reentrancy | impossible for owned objects (no shared mutable global state to re-enter) | a perennial vuln class requiring guards |
| Ownership | explicit and protocol-tracked | implicit in storage layout |
| Verification | designed for formal verification (Move Prover) | bolted on after the fact |
The tradeoff is real. Move has a steeper learning curve — linear types and the no-global-storage model force a different mental model — and a smaller, younger tooling and library ecosystem than the EVM’s. The trade is a large ecosystem with well-catalogued footguns for a smaller one with fewer of them available.
External Links#
- The Move Book — the canonical Sui Move language reference
- Sui Move Concepts — official docs on packages, modules, and abilities
- Move Adds Enums and Macros in 2024 Edition — the Move 2024 feature announcement