Sui

← Target Reference | VM: MOVEVM

Sui is the object-centric blockchain powered by MOVEVM. Trident compiles to Move bytecode (.mv) and links against sui.ext.* for Sui-specific runtime bindings. Sui's unique contribution is the object model -- state is organized as objects with explicit ownership, enabling parallel execution without global locks.


Runtime Parameters

Parameter Value
VM MOVEVM
Runtime binding sui.ext.*
Account model Object-centric (ownership graph)
Storage model Object store
Transaction model Signed (Ed25519, Secp256k1, zkLogin)
Cost model Gas
Cross-chain --

Programming Model

Entry Points

Sui programs expose entry functions that receive objects as arguments. The runtime passes objects based on the transaction's specified inputs.

  • init -- called once when the module is published
  • entry functions -- callable by transactions
  • public functions -- callable by other modules
program my_token

use sui.ext.object
use sui.ext.transfer
use sui.ext.tx
use sui.ext.coin

// Called once at module publication
fn init() {
    let treasury: Field = sui.ext.object.new()
    sui.ext.transfer.send(treasury, sui.ext.tx.sender())
}

// Entry function: mint tokens
pub fn mint(treasury: Field, amount: Field, recipient: Field) {
    // Verify caller owns the treasury capability
    let coin: Field = sui.ext.coin.mint(treasury, amount)
    sui.ext.transfer.public_send(coin, recipient)
}

// Entry function: transfer tokens
pub fn send(coin: Field, recipient: Field) {
    sui.ext.transfer.public_send(coin, recipient)
}

State Access

Sui state is organized as objects -- uniquely identified entities with an owner. Objects come in three flavors:

Object type Access Consensus Use for
Owned Single writer (owner) No consensus needed Tokens, capabilities, user data
Shared Multiple writers Consensus-ordered AMM pools, auctions, registries
Immutable Read-only, everyone No consensus needed Package code, frozen configs
use sui.ext.object
use sui.ext.dynamic_field

// Create a new object
let id: Field = sui.ext.object.new()

// Read object fields (by UID)
let value: Field = sui.ext.object.borrow(id, field_offset)

// Mutate object fields
sui.ext.object.borrow_mut(id, field_offset, new_value)

// Delete an object
sui.ext.object.delete(id)

// Dynamic fields -- attach/read/remove key-value pairs on objects
sui.ext.dynamic_field.add(parent_id, key, value)
let val: Field = sui.ext.dynamic_field.borrow(parent_id, key)
sui.ext.dynamic_field.remove(parent_id, key)
let exists: Bool = sui.ext.dynamic_field.exists(parent_id, key)

The object model eliminates Ethereum's global state contention. Transactions touching different owned objects execute in parallel without ordering. Only shared objects require consensus.

Identity and Authorization

Transaction sender identity comes from the signing key:

use sui.ext.tx

let sender: Field = sui.ext.tx.sender()
let epoch: Field = sui.ext.tx.epoch()
let epoch_timestamp: Field = sui.ext.tx.epoch_timestamp_ms()

Authorization is enforced by object ownership: only the owner of an object can pass it to a transaction as a mutable reference. Capabilities are objects that grant specific permissions:

// Capability pattern: whoever owns the TreasuryCap can mint
pub fn mint(treasury_cap: Field, amount: Field, recipient: Field) {
    // treasury_cap is an owned object -- only the owner can call this
    let coin: Field = sui.ext.coin.mint(treasury_cap, amount)
    sui.ext.transfer.public_send(coin, recipient)
}

No access control lists, no role mappings. If you own the capability object, you have the permission.

Value Transfer

Sui has native Coin<T> objects. Value moves by transferring object ownership:

use sui.ext.coin
use sui.ext.transfer

// Split a coin (take amount out of existing coin)
let split_coin: Field = sui.ext.coin.split(coin, amount)

// Merge coins (combine into one)
sui.ext.coin.merge(target_coin, source_coin)

// Get coin value
let balance: Field = sui.ext.coin.value(coin)

// Transfer coin to recipient
sui.ext.transfer.public_send(coin, recipient)

// Create a zero-value coin
let empty: Field = sui.ext.coin.zero()

Cross-Contract Interaction

Sui modules can call each other's public functions directly -- there is no message-passing layer. Shared objects enable multi-module transactions:

// Direct function call to another module
// (if the module is imported and the function is public)
use other_package.amm

fn swap(pool: Field, coin_in: Field) -> Field {
    other_package.amm.swap(pool, coin_in)
}

Shared objects are the mechanism for composability. An AMM pool is a shared object that multiple users can interact with concurrently (consensus-ordered).

Events

Sui events are typed and emitted via the event module:

event Transfer { from: Field, to: Field, amount: Field }

// reveal compiles to event::emit
reveal Transfer { from: sender, to: recipient, amount: value }

reveal maps to sui::event::emit. seal emits only the commitment hash as event data.


Portable Alternative (os.*)

Programs that don't need Sui-specific features can use os.* instead of sui.ext.* for cross-chain portability:

sui.ext.* (this OS only) os.* (any OS)
sui.ext.dynamic_field.borrow(id, key) os.state.read(key) → dynamic_field.borrow
sui.ext.tx.sender() os.neuron.id() → tx_context::sender
sui.ext.coin.split() + sui.ext.transfer.public_send() os.signal.send(from, to, amt) → split + public_transfer
sui.ext.tx.epoch_timestamp_ms() os.time.now() → epoch_timestamp_ms

Use sui.ext.* when you need: object ownership (owned/shared/frozen), dynamic fields, capability pattern, or other Sui-specific features. See os.md for the full os.* API.


Ecosystem Mapping

Move/Sui concept Trident equivalent
module my_package::my_token program my_token with use sui.ext.*
fun init(ctx: &mut TxContext) fn init()
public entry fun transfer(...) pub fn transfer(...)
public fun balance(coin): u64 pub fn balance(coin: Field) -> Field
tx_context::sender(ctx) sui.ext.tx.sender()
tx_context::epoch(ctx) sui.ext.tx.epoch()
object::new(ctx) sui.ext.object.new()
object::delete(id) sui.ext.object.delete(id)
transfer::transfer(obj, recipient) sui.ext.transfer.send(obj, recipient)
transfer::public_transfer(obj, recipient) sui.ext.transfer.public_send(obj, recipient)
transfer::share_object(obj) sui.ext.transfer.share(obj)
transfer::freeze_object(obj) sui.ext.transfer.freeze(obj)
dynamic_field::add(parent, key, val) sui.ext.dynamic_field.add(parent, key, val)
dynamic_field::borrow(parent, key) sui.ext.dynamic_field.borrow(parent, key)
dynamic_field::remove(parent, key) sui.ext.dynamic_field.remove(parent, key)
coin::value(coin) sui.ext.coin.value(coin)
coin::split(coin, amount, ctx) sui.ext.coin.split(coin, amount)
coin::join(target, source) sui.ext.coin.merge(target, source)
coin::zero(ctx) sui.ext.coin.zero()
event::emit(MyEvent { ... }) reveal MyEvent { ... }
assert!(condition, ERROR_CODE) assert(condition)

sui.ext.* API Reference

Module Function Signature Description
object new() -> Field Create new object UID
delete(id) Field -> () Delete object
borrow(id, offset) (Field, U32) -> Field Read object field
borrow_mut(id, offset, val) (Field, U32, Field) -> () Write object field
id(obj) Field -> Digest Get object ID
transfer send(obj, recipient) (Field, Field) -> () Transfer owned object
public_send(obj, recipient) (Field, Field) -> () Transfer with store ability
share(obj) Field -> () Make object shared
freeze(obj) Field -> () Make object immutable
dynamic_field add(parent, key, val) (Field, Field, Field) -> () Add dynamic field
borrow(parent, key) (Field, Field) -> Field Read dynamic field
borrow_mut(parent, key, val) (Field, Field, Field) -> () Write dynamic field
remove(parent, key) (Field, Field) -> Field Remove dynamic field
exists(parent, key) (Field, Field) -> Bool Check field existence
tx sender() -> Field Transaction sender
epoch() -> Field Current epoch
epoch_timestamp_ms() -> Field Epoch timestamp (ms)
coin value(coin) Field -> Field Coin balance
split(coin, amount) (Field, Field) -> Field Split coin
merge(target, source) (Field, Field) -> () Merge coins
zero() -> Field Zero-value coin
mint(cap, amount) (Field, Field) -> Field Mint new coins
burn(cap, coin) (Field, Field) -> () Burn coins
event emit(type, data) (Field, [Field]) -> () Emit typed event

Notes

Sui's object model maps naturally to Trident's value semantics -- all values are copied, not referenced. Move's linear type system (resources cannot be copied or dropped) is enforced by the Sui runtime, not by Trident's type checker. The compiler emits the correct Move bytecode with the appropriate abilities (copy, drop, store, key).

Parallel execution: transactions on owned objects bypass consensus entirely. This is why Sui achieves high throughput for transfers and simple operations. Only shared-object transactions require ordering.

For VM details, see movevm.md.

Pages in this namespace

Local Graph