Build the next
generation of software with the SuiStack
Identity, data, payments, compute, and coordination — unified into a single programmable surface for AI‑native and globally interoperable applications
module hero::example; use sui::balance::{Self, Balance}; use sui::coin::{Self, Coin}; use sui::event; use sui::sui::SUI; public struct Hero has key, store { id: UID, game_id: ID, health: u64, experience: u64, sword: Option<Sword>, } public struct Sword has key, store { id: UID, game_id: ID, magic: u64, strength: u64, } public struct Potion has key, store { id: UID, game_id: ID, potency: u64, } public struct Boar has key, store { id: UID, game_id: ID, health: u64, strength: u64, } public struct Game has key { id: UID, payments: Balance<SUI>, } public struct Admin has key, store { id: UID, game_id: ID, boars_created: u64, potions_created: u64, } public struct BoarSlainEvent has copy, drop { slayer_address: address, boar: ID, hero: ID, game_id: ID, } const MAX_HP: u64 = 1000; const MAX_MAGIC: u64 = 10; const MIN_SWORD_COST: u64 = 100; const EWrongGame: u64 = 0; const EBoarWon: u64 = 1; const EHeroTired: u64 = 2; const ENotAdmin: u64 = 3; const EInsufficientFunds: u64 = 5; const EAlreadyEquipped: u64 = 6; const ENotEquipped: u64 = 7; public fun new_sword(game: &mut Game, payment: Coin<SUI>, ctx: &mut TxContext): Sword { let value = payment.value(); assert!(value >= MIN_SWORD_COST, EInsufficientFunds); coin::put(&mut game.payments, payment); let magic = (value - MIN_SWORD_COST) / MIN_SWORD_COST; Sword { id: object::new(ctx), magic: magic.min(MAX_MAGIC), strength: 1, game_id: object::id(game), } } public fun new_hero(sword: Sword, ctx: &mut TxContext): Hero { Hero { id: object::new(ctx), game_id: sword.game_id, health: 100, experience: 0, sword: option::some(sword), } } public fun new_game(ctx: &mut TxContext): Admin { let game = Game { id: object::new(ctx), payments: balance::zero(), }; let admin = Admin { id: object::new(ctx), game_id: object::id(&game), boars_created: 0, potions_created: 0, }; transfer::share_object(game); admin } public fun new_potion(admin: &mut Admin, potency: u64, ctx: &mut TxContext): Potion { admin.potions_created = admin.potions_created + 1; Potion { id: object::new(ctx), potency, game_id: admin.game_id } } public fun new_boar(admin: &mut Admin, health: u64, strength: u64, ctx: &mut TxContext): Boar { admin.boars_created = admin.boars_created + 1; Boar { id: object::new(ctx), health, strength, game_id: admin.game_id } } public fun slay(hero: &mut Hero, boar: Boar, ctx: &TxContext) { assert!(hero.game_id == boar.game_id, EWrongGame); let Boar { id: boar_id, strength: boar_strength, health: mut boar_health, game_id: _, } = boar; let experience = boar_health; loop { let hero_strength = hero.hero_strength(); if (boar_health < hero_strength) { break } else { boar_health = boar_health - hero_strength; }; assert!(hero.health >= boar_strength, EBoarWon); hero.health = hero.health - boar_strength; }; hero.experience = hero.experience + experience; if (hero.sword.is_some()) { hero.sword.borrow_mut().level_up_sword(1) }; event::emit(BoarSlainEvent { slayer_address: ctx.sender(), hero: object::id(hero), boar: boar_id.uid_to_inner(), game_id: hero.game_id, }); boar_id.delete(); } public fun hero_strength(hero: &Hero): u64 { assert!(hero.health > 0, EHeroTired); let sword_strength = if (hero.sword.is_some()) { hero.sword.borrow().sword_strength() } else { 0 }; (hero.experience * hero.health) + sword_strength } fun level_up_sword(sword: &mut Sword, amount: u64) { sword.strength = sword.strength + amount } public fun sword_strength(sword: &Sword): u64 { sword.magic + sword.strength } public fun heal(hero: &mut Hero, potion: Potion) { let Potion { id, potency, game_id } = potion; id.delete(); assert!(hero.game_id == game_id, EWrongGame); hero.health = (hero.health + potency).min(MAX_HP) } public fun equip(hero: &mut Hero, sword: Sword) { assert!(hero.sword.is_none(), EAlreadyEquipped); hero.sword.fill(sword); } public fun unequip(hero: &mut Hero): Sword { assert!(hero.sword.is_some(), ENotEquipped); option::extract(&mut hero.sword) } public fun take_payment(admin: &Admin, game: &mut Game, ctx: &mut TxContext): Coin<SUI> { assert!(admin.game_id == object::id(game), ENotAdmin); coin::from_balance(game.payments.withdraw_all(), ctx) } #[test_only] use sui::test_scenario as ts; #[test] fun slay_boar_test() { let mut ts = ts::begin(@0x0); let admin = @0xAD; let alice = @0xA; let bob = @0xb; setup_game(admin, &mut ts); acquire_hero(alice, MIN_SWORD_COST, &mut ts); { ts.next_tx(admin); let game: Game = ts.take_shared(); let mut cap: Admin = ts.take_from_sender(); let boar: Boar = cap.new_boar(9, 9, ts.ctx()); transfer::public_transfer(boar, alice); ts.return_to_sender(cap); ts::return_shared(game); }; { ts.next_tx(alice); let mut hero: Hero = ts.take_from_sender(); let boar: Boar = ts.take_from_sender(); hero.slay(boar, ts.ctx()); ts.return_to_sender(hero); }; { ts.next_tx(admin); let mut cap: Admin = ts.take_from_sender(); let potion: Potion = cap.new_potion(1, ts.ctx()); transfer::public_transfer(potion, alice); ts.return_to_sender(cap); }; { ts.next_tx(alice); let mut hero: Hero = ts.take_from_sender(); let potion: Potion = ts.take_from_sender(); let potency = potion.potency; let before = hero.health; hero.heal(potion); assert!(hero.health == before + potency, 0); ts.return_to_sender(hero); }; acquire_hero(bob, MIN_SWORD_COST + 42, &mut ts); { ts.next_tx(admin); let mut game: Game = ts.take_shared(); let cap: Admin = ts.take_from_sender(); let payment = cap.take_payment(&mut game, ts.ctx()); assert!(payment.value() == MIN_SWORD_COST * 2 + 42, 0); transfer::public_transfer(payment, admin); ts.return_to_sender(cap); ts::return_shared(game); }; ts.end(); } #[test] #[expected_failure(abort_code = EWrongGame)] fun test_wrong_game() { let mut ts = ts::begin(@0x0); let admin0 = @0xAD0; let admin1 = @0xAD1; let player = @0xA; setup_game(admin0, &mut ts); let g0 = { ts.next_tx(@0x0); ts::most_recent_id_shared<Game>().destroy_some() }; setup_game(admin1, &mut ts); { ts.next_tx(player); let mut game: Game = ts.take_shared_by_id(g0); let coin = coin::mint_for_testing(MIN_SWORD_COST, ts.ctx()); let sword = game.new_sword(coin, ts.ctx()); let hero = sword.new_hero(ts.ctx()); transfer::public_transfer(hero, player); ts::return_shared(game); }; { ts.next_tx(admin1); let mut cap: Admin = ts.take_from_sender(); let potion: Potion = cap.new_potion(1, ts.ctx()); transfer::public_transfer(potion, player); ts.return_to_sender(cap); }; { ts.next_tx(player); let mut hero: Hero = ts.take_from_sender(); let potion: Potion = ts.take_from_sender(); hero.heal(potion); }; abort 1337 } #[test] #[expected_failure(abort_code = EHeroTired)] fun test_hero_tired() { let mut ts = ts::begin(@0x0); let admin = @0xAD; let player = @0xA; setup_game(admin, &mut ts); acquire_hero(player, MIN_SWORD_COST, &mut ts); { ts.next_tx(admin); let game: Game = ts.take_shared(); let mut cap: Admin = ts.take_from_sender(); let boar: Boar = cap.new_boar(9, 9, ts.ctx()); transfer::public_transfer(boar, player); ts.return_to_sender(cap); ts::return_shared(game); }; { ts.next_tx(player); let mut hero: Hero = ts.take_from_sender(); let boar: Boar = ts.take_from_sender(); hero.health = 0; hero.slay(boar, ts.ctx()); }; abort 1337 } #[test] #[expected_failure(abort_code = EBoarWon)] fun test_boar_win() { let mut ts = ts::begin(@0x0); let admin = @0xAD; let player = @0xA; setup_game(admin, &mut ts); acquire_hero(player, MIN_SWORD_COST, &mut ts); { ts.next_tx(admin); let game: Game = ts.take_shared(); let mut cap: Admin = ts.take_from_sender(); let boar: Boar = cap.new_boar(9, 9, ts.ctx()); transfer::public_transfer(boar, player); ts.return_to_sender(cap); ts::return_shared(game); }; { ts.next_tx(player); let mut hero: Hero = ts.take_from_sender(); let boar: Boar = ts.take_from_sender(); hero.health = 1; hero.slay(boar, ts.ctx()); }; abort 1337 } #[test] #[expected_failure(abort_code = EInsufficientFunds)] fun test_insufficient_funds() { let mut ts = ts::begin(@0x0); let admin = @0xAD; let player = @0xA; setup_game(admin, &mut ts); acquire_hero(player, MIN_SWORD_COST - 1, &mut ts); abort 1337 } #[test] #[expected_failure(abort_code = ENotEquipped)] fun test_unequip_empty() { let admin = @0xAD; let player = @0xA; let mut ts = ts::begin(admin); let _admin = new_game(ts.ctx()); ts.next_tx(player); let mut game: Game = ts.take_shared(); let coin = coin::mint_for_testing(MIN_SWORD_COST, ts.ctx()); let sword = game.new_sword(coin, ts.ctx()); let mut hero = sword.new_hero(ts.ctx()); let _s0 = hero.unequip(); let _s1 = hero.unequip(); abort 1337 } #[test] #[expected_failure(abort_code = EAlreadyEquipped)] fun test_equip_already_equipped() { let admin = @0xAD; let player = @0xA; let mut ts = ts::begin(admin); let _admin = new_game(ts.ctx()); ts.next_tx(player); let mut game: Game = ts.take_shared(); let c0 = coin::mint_for_testing(MIN_SWORD_COST, ts.ctx()); let s0 = game.new_sword(c0, ts.ctx()); let c1 = coin::mint_for_testing(MIN_SWORD_COST, ts.ctx()); let s1 = game.new_sword(c1, ts.ctx()); let mut hero = s0.new_hero(ts.ctx()); hero.equip(s1); abort 1337 } #[test_only] fun setup_game(admin: address, ts: &mut ts::Scenario) { ts.next_tx(admin); let cap = new_game(ts.ctx()); transfer::public_transfer(cap, admin); } #[test_only] fun acquire_hero(player: address, payment: u64, ts: &mut ts::Scenario) { ts.next_tx(player); let mut game: Game = ts.take_shared(); let coin = coin::mint_for_testing(payment, ts.ctx()); let sword = game.new_sword(coin, ts.ctx()); let hero = sword.new_hero(ts.ctx()); transfer::public_transfer(hero, player); ts::return_shared(game); }
module hero::example; use sui::balance::{Self, Balance}; use sui::coin::{Self, Coin}; use sui::event; use sui::sui::SUI; public struct Hero has key, store { id: UID, game_id: ID, health: u64, experience: u64, sword: Option<Sword>, } public struct Sword has key, store { id: UID, game_id: ID, magic: u64, strength: u64, } public struct Potion has key, store { id: UID, game_id: ID, potency: u64, } public struct Boar has key, store { id: UID, game_id: ID, health: u64, strength: u64, } public struct Game has key { id: UID, payments: Balance<SUI>, } public struct Admin has key, store { id: UID, game_id: ID, boars_created: u64, potions_created: u64, } public struct BoarSlainEvent has copy, drop { slayer_address: address, boar: ID, hero: ID, game_id: ID, } const MAX_HP: u64 = 1000; const MAX_MAGIC: u64 = 10; const MIN_SWORD_COST: u64 = 100; const EWrongGame: u64 = 0; const EBoarWon: u64 = 1; const EHeroTired: u64 = 2; const ENotAdmin: u64 = 3; const EInsufficientFunds: u64 = 5; const EAlreadyEquipped: u64 = 6; const ENotEquipped: u64 = 7; public fun new_sword(game: &mut Game, payment: Coin<SUI>, ctx: &mut TxContext): Sword { let value = payment.value(); assert!(value >= MIN_SWORD_COST, EInsufficientFunds); coin::put(&mut game.payments, payment); let magic = (value - MIN_SWORD_COST) / MIN_SWORD_COST; Sword { id: object::new(ctx), magic: magic.min(MAX_MAGIC), strength: 1, game_id: object::id(game), } } public fun new_hero(sword: Sword, ctx: &mut TxContext): Hero { Hero { id: object::new(ctx), game_id: sword.game_id, health: 100, experience: 0, sword: option::some(sword), } } public fun new_game(ctx: &mut TxContext): Admin { let game = Game { id: object::new(ctx), payments: balance::zero(), }; let admin = Admin { id: object::new(ctx), game_id: object::id(&game), boars_created: 0, potions_created: 0, }; transfer::share_object(game); admin } public fun new_potion(admin: &mut Admin, potency: u64, ctx: &mut TxContext): Potion { admin.potions_created = admin.potions_created + 1; Potion { id: object::new(ctx), potency, game_id: admin.game_id } } public fun new_boar(admin: &mut Admin, health: u64, strength: u64, ctx: &mut TxContext): Boar { admin.boars_created = admin.boars_created + 1; Boar { id: object::new(ctx), health, strength, game_id: admin.game_id } } public fun slay(hero: &mut Hero, boar: Boar, ctx: &TxContext) { assert!(hero.game_id == boar.game_id, EWrongGame); let Boar { id: boar_id, strength: boar_strength, health: mut boar_health, game_id: _, } = boar; let experience = boar_health; loop { let hero_strength = hero.hero_strength(); if (boar_health < hero_strength) { break } else { boar_health = boar_health - hero_strength; }; assert!(hero.health >= boar_strength, EBoarWon); hero.health = hero.health - boar_strength; }; hero.experience = hero.experience + experience; if (hero.sword.is_some()) { hero.sword.borrow_mut().level_up_sword(1) }; event::emit(BoarSlainEvent { slayer_address: ctx.sender(), hero: object::id(hero), boar: boar_id.uid_to_inner(), game_id: hero.game_id, }); boar_id.delete(); } public fun hero_strength(hero: &Hero): u64 { assert!(hero.health > 0, EHeroTired); let sword_strength = if (hero.sword.is_some()) { hero.sword.borrow().sword_strength() } else { 0 }; (hero.experience * hero.health) + sword_strength } fun level_up_sword(sword: &mut Sword, amount: u64) { sword.strength = sword.strength + amount } public fun sword_strength(sword: &Sword): u64 { sword.magic + sword.strength } public fun heal(hero: &mut Hero, potion: Potion) { let Potion { id, potency, game_id } = potion; id.delete(); assert!(hero.game_id == game_id, EWrongGame); hero.health = (hero.health + potency).min(MAX_HP) } public fun equip(hero: &mut Hero, sword: Sword) { assert!(hero.sword.is_none(), EAlreadyEquipped); hero.sword.fill(sword); } public fun unequip(hero: &mut Hero): Sword { assert!(hero.sword.is_some(), ENotEquipped); option::extract(&mut hero.sword) } public fun take_payment(admin: &Admin, game: &mut Game, ctx: &mut TxContext): Coin<SUI> { assert!(admin.game_id == object::id(game), ENotAdmin); coin::from_balance(game.payments.withdraw_all(), ctx) } #[test_only] use sui::test_scenario as ts; #[test] fun slay_boar_test() { let mut ts = ts::begin(@0x0); let admin = @0xAD; let alice = @0xA; let bob = @0xb; setup_game(admin, &mut ts); acquire_hero(alice, MIN_SWORD_COST, &mut ts); { ts.next_tx(admin); let game: Game = ts.take_shared(); let mut cap: Admin = ts.take_from_sender(); let boar: Boar = cap.new_boar(9, 9, ts.ctx()); transfer::public_transfer(boar, alice); ts.return_to_sender(cap); ts::return_shared(game); }; { ts.next_tx(alice); let mut hero: Hero = ts.take_from_sender(); let boar: Boar = ts.take_from_sender(); hero.slay(boar, ts.ctx()); ts.return_to_sender(hero); }; { ts.next_tx(admin); let mut cap: Admin = ts.take_from_sender(); let potion: Potion = cap.new_potion(1, ts.ctx()); transfer::public_transfer(potion, alice); ts.return_to_sender(cap); }; { ts.next_tx(alice); let mut hero: Hero = ts.take_from_sender(); let potion: Potion = ts.take_from_sender(); let potency = potion.potency; let before = hero.health; hero.heal(potion); assert!(hero.health == before + potency, 0); ts.return_to_sender(hero); }; acquire_hero(bob, MIN_SWORD_COST + 42, &mut ts); { ts.next_tx(admin); let mut game: Game = ts.take_shared(); let cap: Admin = ts.take_from_sender(); let payment = cap.take_payment(&mut game, ts.ctx()); assert!(payment.value() == MIN_SWORD_COST * 2 + 42, 0); transfer::public_transfer(payment, admin); ts.return_to_sender(cap); ts::return_shared(game); }; ts.end(); } #[test] #[expected_failure(abort_code = EWrongGame)] fun test_wrong_game() { let mut ts = ts::begin(@0x0); let admin0 = @0xAD0; let admin1 = @0xAD1; let player = @0xA; setup_game(admin0, &mut ts); let g0 = { ts.next_tx(@0x0); ts::most_recent_id_shared<Game>().destroy_some() }; setup_game(admin1, &mut ts); { ts.next_tx(player); let mut game: Game = ts.take_shared_by_id(g0); let coin = coin::mint_for_testing(MIN_SWORD_COST, ts.ctx()); let sword = game.new_sword(coin, ts.ctx()); let hero = sword.new_hero(ts.ctx()); transfer::public_transfer(hero, player); ts::return_shared(game); }; { ts.next_tx(admin1); let mut cap: Admin = ts.take_from_sender(); let potion: Potion = cap.new_potion(1, ts.ctx()); transfer::public_transfer(potion, player);
module hero::example; use sui::balance::{Self, Balance}; use sui::coin::{Self, Coin}; use sui::event; use sui::sui::SUI; public struct Hero has key, store { id: UID, game_id: ID, health: u64, experience: u64, sword: Option<Sword>, } public struct Sword has key, store { id: UID, game_id: ID, magic: u64, strength: u64, } public struct Potion has key, store { id: UID, game_id: ID, potency: u64, } public struct Boar has key, store { id: UID, game_id: ID, health: u64, strength: u64, } public struct Game has key { id: UID, payments: Balance<SUI>, } public struct Admin has key, store { id: UID, game_id: ID, boars_created: u64, potions_created: u64, } public struct BoarSlainEvent has copy, drop { slayer_address: address, boar: ID, hero: ID, game_id: ID, } const MAX_HP: u64 = 1000; const MAX_MAGIC: u64 = 10; const MIN_SWORD_COST: u64 = 100; const EWrongGame: u64 = 0; const EBoarWon: u64 = 1; const EHeroTired: u64 = 2; const ENotAdmin: u64 = 3; const EInsufficientFunds: u64 = 5; const EAlreadyEquipped: u64 = 6; const ENotEquipped: u64 = 7; public fun new_sword(game: &mut Game, payment: Coin<SUI>, ctx: &mut TxContext): Sword { let value = payment.value(); assert!(value >= MIN_SWORD_COST, EInsufficientFunds); coin::put(&mut game.payments, payment); let magic = (value - MIN_SWORD_COST) / MIN_SWORD_COST; Sword { id: object::new(ctx), magic: magic.min(MAX_MAGIC), strength: 1, game_id: object::id(game), } } public fun new_hero(sword: Sword, ctx: &mut TxContext): Hero { Hero { id: object::new(ctx), game_id: sword.game_id, health: 100, experience: 0, sword: option::some(sword), } } public fun new_game(ctx: &mut TxContext): Admin { let game = Game { id: object::new(ctx), payments: balance::zero(), }; let admin = Admin { id: object::new(ctx), game_id: object::id(&game), boars_created: 0, potions_created: 0, }; transfer::share_object(game); admin } public fun new_potion(admin: &mut Admin, potency: u64, ctx: &mut TxContext): Potion { admin.potions_created = admin.potions_created + 1; Potion { id: object::new(ctx), potency, game_id: admin.game_id } } public fun new_boar(admin: &mut Admin, health: u64, strength: u64, ctx: &mut TxContext): Boar { admin.boars_created = admin.boars_created + 1; Boar { id: object::new(ctx), health, strength, game_id: admin.game_id } } public fun slay(hero: &mut Hero, boar: boar_id.uid_to_inner(), game_id: hero.game_id, }); boar_id.delete(); } public fun hero_strength(hero: &Hero): u64
Apps for every UseCase
Use
Case
The Sui Stack lets developers build interoperable, AI‑ready applications across content, communication, gaming, commerce, and more — all on a unified, global API surface instead of a patchwork of backend services.
Only
Fins
OnlyFins_Onchain.move
module sui::content_stack {
}
Output
A creator-content pattern where posts live in verifiable storage, access is controlled by cryptographic policy, and payments settle automatically — no centralized platform required.
View demo
↗
Sui
Messenger
Sui_Messenger_Onchain.move
module sui::messenger_stack {
}
Output
Build messaging apps with secure messaging, human-readable usernames, and built-in automation.
View demo
↗
Rogue-like experience
Rogue-like_experience_Onchain.move
module sui::rogue-like_stack {
struct
On-chain randomness
has copy, drop {}
}
Output
A minimal game loop powered by dynamic objects, shared state, and secure randomness — showing how game logic becomes globally composable.
View demo
↗
Only Fins
A creator-content pattern where posts live in verifiable storage, access is controlled by cryptographic policy, and payments settle automatically — no centralized platform required.
View demo
↗
Sui Messenger
Build messaging apps with secure messaging, human-readable usernames, and built-in automation.
View demo
↗
Rogue-like experience
A minimal game loop powered by dynamic objects, shared state, and secure randomness — showing how game logic becomes globally composable.
View demo
↗
Explore theSuiStack
Sui
Stack
A modular ecosystem of composable capabilities for building Al‑native, interoperable applications. Choose the identity, data, compute, and coordination layers you need to build software traditional infrastructure can't support.
Sui
Capability
A globally shared, low-latency execution environment that lets applications and agents coordinate through a universal API surface. Ideal for dynamic workflows that need trusted state across services
Web2 Comparison
Firebase + Postgres + API Gateway, but globally shared, verifiable,
and composable by default.
Walrus
Capability
Verifiable, content-addressed storage for files, datasets, logs, and models — with built-in provenance and integrity. Enables portable, tamper-proof data across apps and trust boundaries.
Web2 Comparison
AWS S3 / GCS, but with built-in provenance, integrity, and portable access policies.
Walrus Sites
Capability
Serverless, content-addressed frontends and applications served directly from storage. Guarantees that clients load exactly the code you deployed, with no servers or intermediaries.
Web2 Comparison
Vercel / Netlify, but trustless, serverless, and tamper-proof
at the hosting layer.
Seal
Capability
Programmable, privacy-preserving access control that attaches policies directly to the data. Allows apps to share and license data securely without custom permission plumbing.
Web2 Comparison
AWS KMS + IAM + custom ACL logic, but portable, programmable,
and enforceable across trust boundaries.
Nautilus
Capability
Confidential, verifiable offchain compute for inference, training,
and business logic. Produces proof-like attestations that apps can trust without relying on a vendor.
Web2 Comparison
AWS Nitro Enclaves, but with verifiable proofs
you can settle onchain.
zkLogin & Passkeys
Capability
Passwordless identity that links users’ existing Web2 accounts
to secure keys — enabling frictionless onboarding and agent-friendly delegation without exposing sensitive data.
Web2 Comparison
OAuth + passkeys, but private, portable,
and agent-friendly.
SuiNS
Capability
Human-readable names for users, agents, and apps
that make discovery and coordination easier across
the ecosystem.
Web2 Comparison
DNS, but native to Sui’s object model.
DeepBook
Capability
A fast, open, programmable liquidity layer that apps and agents
can call directly. Enables atomic payments, multi-party transactions, and machine-speed commerce flows.
Web2 Comparison
Stripe + NASDAQ matching engine,
but composable and trustless.
Sui
Capability
A globally shared, low-latency execution environment that lets applications and agents coordinate through a universal API surface. Ideal for dynamic workflows that need trusted state across services.
Web2 Comparison
Firebase + Postgres + API Gateway, but globally shared, verifiable, and composable by default.
Walrus
Capability
Verifiable, content-addressed storage for files, datasets, logs, and models — with built-in provenance and integrity. Enables portable, tamper-proof data across apps and trust boundaries.
Web2 Comparison
AWS S3 / GCS, but with built-in provenance, integrity, and portable access policies.
Walrus Sites
Capability
Serverless, content-addressed frontends and applications served directly from storage. Guarantees that clients load exactly the code you deployed, with no servers or intermediaries.
Web2 Comparison
Vercel / Netlify, but trustless, serverless, and tamper-proof at the hosting layer.
Seal
Capability
Programmable, privacy-preserving access control that attaches policies directly to the data. Allows apps to share and license data securely without custom permission plumbing.
Web2 Comparison
AWS KMS + IAM + custom ACL logic, but portable, programmable, and enforceable across trust boundaries.
Nautilus
Capability
Confidential, verifiable offchain compute for inference, training, and business logic. Produces proof-like attestations that apps can trust without relying on a vendor.
Web2 Comparison
AWS Nitro Enclaves, but with verifiable proofs you can settle onchain.
zkLogin & Passkeys
Capability
Passwordless identity that links users’ existing Web2 accounts to secure keys — enabling frictionless onboarding and agent-friendly delegation without exposing sensitive data.
Web2 Comparison
OAuth + passkeys, but private, portable, and agent-friendly.
SuiNS
Capability
Human-readable names for users, agents, and apps that make discovery and coordination easier across the ecosystem.
Web2 Comparison
DNS, but native to Sui’s
object model.
DeepBook
Capability
A fast, open, programmable liquidity layer that apps and agents can call directly. Enables atomic payments, multi-party transactions, and machine-speed commerce flows.
Web2 Comparison
Stripe + NASDAQ matching engine,
but composable and trustless.
ConnectWithUs
With
Us
module hero::example; use sui::balance::{Self, Balance}; use sui::coin::{Self, Coin}; use sui::event; use sui::sui::SUI; public struct Hero has key, store { id: UID, game_id: ID, health: u64, experience: u64, sword: Option<Sword>, } public struct Sword has key, store { id: UID, game_id: ID, magic: u64, strength: u64, } public struct Potion has key, store { id: UID, game_id: ID, potency: u64, } public struct Boar has key, store { id: UID, game_id: ID, health: u64, strength: u64, } public struct Game has key { id: UID, payments: Balance<SUI>, } public struct Admin has key, store { id: UID, game_id: ID, boars_created: u64, potions_created: u64, } public struct BoarSlainEvent has copy, drop { slayer_address: address, boar: ID, hero: ID, game_id: ID, } const MAX_HP: u64 = 1000; const MAX_MAGIC: u64 = 10; const MIN_SWORD_COST: u64 = 100; const EWrongGame: u64 = 0; const EBoarWon: u64 = 1; const EHeroTired: u64 = 2; const ENotAdmin: u64 = 3; const EInsufficientFunds: u64 = 5; const EAlreadyEquipped: u64 = 6; const ENotEquipped: u64 = 7; public fun new_sword(game: &mut Game, payment: Coin<SUI>, ctx: &mut TxContext): Sword { let value = payment.value(); assert!(value >= MIN_SWORD_COST, EInsufficientFunds); coin::put(&mut game.payments, payment); let magic = (value - MIN_SWORD_COST) / MIN_SWORD_COST; Sword { id: object::new(ctx), magic: magic.min(MAX_MAGIC), strength: 1, game_id: object::id(game), } } public fun new_hero(sword: Sword, ctx: &mut TxContext): Hero { Hero { id: object::new(ctx), game_id: sword.game_id, health: 100, experience: 0, sword: option::some(sword), } } public fun new_game(ctx: &mut TxContext): Admin { let game = Game { id: object::new(ctx), payments: balance::zero(), }; let admin = Admin { id: object::new(ctx), game_id: object::id(&game), boars_created: 0, potions_created: 0, }; transfer::share_object(game); admin } public fun new_potion(admin: &mut Admin, potency: u64, ctx: &mut TxContext): Potion { admin.potions_created = admin.potions_created + 1; Potion { id: object::new(ctx), potency, game_id: admin.game_id } } public fun new_boar(admin: &mut Admin, health: u64, strength: u64, ctx: &mut TxContext): Boar { admin.boars_created = admin.boars_created + 1; Boar { id: object::new(ctx), health, strength, game_id: admin.game_id } } public fun slay(hero: &mut Hero, boar: Boar, ctx: &TxContext) { assert!(hero.game_id == boar.game_id, EWrongGame); let Boar { id: boar_id, strength: boar_strength, health: mut boar_health, game_id: _, } = boar; let experience =
module hero::example; use sui::balance::{Self, Balance}; use sui::coin::{Self, Coin}; use sui::event; use sui::sui::SUI; public struct Hero has key, store { id: UID, game_id: ID, health: u64, experience: u64, sword: Option<Sword>, } public struct Sword has key, store { id: UID, game_id: ID, magic: u64, strength: u64, } public struct Potion has key, store { id: UID, game_id: ID, potency: u64, } public struct Boar has key, store { id: UID, game_id: ID, health: u64, strength: u64, } public struct Game has key { id: UID, payments: Balance<SUI>, } public struct Admin has key, store { id: UID, game_id: ID, boars_created: u64, potions_created: u64, } public struct BoarSlainEvent has copy, drop { slayer_address: address, boar: ID, hero: ID, game_id: ID, } const MAX_HP: u64 = 1000; const MAX_MAGIC: u64 = 10; const MIN_SWORD_COST: u64 = 100; const EWrongGame: u64 = 0; const EBoarWon: u64 = 1; const EHeroTired: u64 = 2; const ENotAdmin: u64 = 3; const EInsufficientFunds: u64 = 5; const EAlreadyEquipped: u64 = 6; const ENotEquipped: u64 = 7; public fun new_sword(game: &mut Game, payment: Coin<SUI>, ctx: &mut TxContext): Sword { let value = payment.value(); assert!(value >= MIN_SWORD_COST, EInsufficientFunds); coin::put(&mut game.payments, payment); let magic = (value - MIN_SWORD_COST) / MIN_SWORD_COST; Sword { id: object::new(ctx), magic: magic.min(MAX_MAGIC), strength: 1, game_id: object::id(game), } } public fun new_hero(sword: Sword, ctx: &mut TxContext): Hero { Hero { id: object::new(ctx), game_id: sword.game_id, health: 100, experience: 0, sword: option::some(sword), } } public fun new_game(ctx: &mut TxContext): Admin { let game = Game { id: object::new(ctx), payments: balance::zero(), }; let admin = Admin { id: object::new(ctx), game_id: object::id(&game), boars_created: 0, potions_created: 0, }; transfer::share_object(game); admin } public fun new_potion(admin: &mut Admin, potency: u64, ctx: &mut TxContext): Potion { admin.potions_created = admin.potions_created + 1; Potion { id: object::new(ctx), potency, game_id: admin.game_id } } public fun new_boar(admin: &mut Admin, health: u64, strength: u64, ctx: &mut TxContext): Boar { admin.boars_created = admin.boars_created + 1; Boar { id: object::new(ctx), health, strength, game_id: admin.game_id } } public fun slay(hero: &mut Hero, boar: Boar, ctx: &TxContext) { assert!(hero.game_id == boar.game_id, EWrongGame); let Boar { id: boar_id, strength: boar_strength, health: mut boar_health, game_id: _, } = boar; let experience = boar_health; loop { let hero_strength = hero.hero_strength(); if (boar_health < hero_strength) { break } else { boar_health = boar_health - hero_strength; }; assert!(hero.health >= boar_strength, EBoarWon); hero.health = hero.health - boar_strength; }; hero.experience = hero.experience + experience; if (hero.sword.is_some()) { hero.sword.borrow_mut().level_up_sword(1) }; event::emit(BoarSlainEvent { slayer_address: ctx.sender(), hero: object::id(hero), boar: boar_id.uid_to_inner(), game_id: hero.game_id, }); boar_id.delete(); } public fun hero_strength(hero: &Hero): u64 { assert!(hero.health > 0, EHeroTired); let sword_strength = if (hero.sword.is_some()) { hero.sword.borrow().sword_strength() } else { 0 }; (hero.experience * hero.health) + sword_strength } fun level_up_sword(sword: &mut Sword, amount: u64) { sword.strength = sword.strength + amount } public fun sword_strength(sword: &Sword): u64 { sword.magic + sword.strength } public fun heal(hero: &mut Hero, potion: Potion) { let Potion { id, potency, game_id } = potion; id.delete(); assert!(hero.game_id == game_id, EWrongGame); hero.health = (hero.health + potency).min(MAX_HP) } public fun equip(hero: &mut Hero, sword: Sword) { assert!(hero.sword.is_none(), EAlreadyEquipped); hero.sword.fill(sword); } public fun unequip(hero: &mut Hero): Sword { assert!(hero.sword.is_some(), ENotEquipped); option::extract(&mut hero.sword) } public fun take_payment(admin: &Admin, game: &mut Game, ctx: &mut TxContext): Coin<SUI> { assert!(admin.game_id == object::id(game), ENotAdmin); coin::from_balance(game.payments.withdraw_all(), ctx) } #[test_only] use sui::test_scenario as ts; #[test] fun slay_boar_test() { let mut ts = ts::begin(@0x0); let admin = @0xAD; let alice = @0xA; let bob = @0xb; setup_game(admin, &mut ts); acquire_hero(alice, MIN_SWORD_COST, &mut ts); { ts.next_tx(admin); let game: Game = ts.take_shared(); let mut cap: Admin = ts.take_from_sender(); let boar: Boar = cap.new_boar(9, 9, ts.ctx()); transfer::public_transfer(boar, alice); ts.return_to_sender(cap); ts::return_shared(game); }; { ts.next_tx(alice); let mut hero: Hero = ts.take_from_sender(); let boar: Boar = ts.take_from_sender(); hero.slay(boar, ts.ctx()); ts.return_to_sender(hero); }; { ts.next_tx(admin); let mut cap: Admin = ts.take_from_sender(); let potion: Potion = cap.new_potion(1, ts.ctx()); transfer::public_transfer(potion, alice); ts.return_to_sender(cap); }; { ts.next_tx(alice); let mut hero: Hero = ts.take_from_sender(); let potion: Potion = ts.take_from_sender(); let potency = potion.potency; let before = hero.health; hero.heal(potion); assert!(hero.health == before + potency, 0); ts.return_to_sender(hero); }; acquire_hero(bob, MIN_SWORD_COST + 42, &mut ts); { ts.next_tx(admin); let mut game: Game = ts.take_shared(); let cap: Admin = ts.take_from_sender(); let payment = cap.take_payment(&mut game, ts.ctx()); assert!(payment.value() == MIN_SWORD_COST * 2 + 42, 0); transfer::public_transfer(payment, admin); ts.return_to_sender(cap); ts::return_shared(game); }; ts.end(); } #[test] #[expected_failure(abort_code = EWrongGame)] fun test_wrong_game() { let mut ts = ts::begin(@0x0); let admin0 = @0xAD0; let admin1 = @0xAD1; let player = @0xA; setup_game(admin0, &mut ts); let g0 = { ts.next_tx(@0x0); ts::most_recent_id_shared<Game>().destroy_some() }; setup_game(admin1, &mut ts); { ts.next_tx(player); let mut game: Game = ts.take_shared_by_id(g0); let coin = coin::mint_for_testing(MIN_SWORD_COST, ts.ctx()); let sword = game.new_sword(coin, ts.ctx()); let hero = sword.new_hero(ts.ctx()); transfer::public_transfer(hero, player); ts::return_shared(game); }; { ts.next_tx(admin1); let mut cap: Admin = ts.take_from_sender(); let potion: Potion = cap.new_potion(1, ts.ctx()); transfer::public_transfer(potion, player);
module hero::example; use sui::balance::{Self, Balance}; use sui::coin::{Self, Coin}; use sui::event; use sui::sui::SUI; public struct Hero has key, store { id: UID, game_id: ID, health: u64, experience: u64, sword: Option<Sword>, } public struct Sword has key, store { id: UID, game_id: ID, magic: u64, strength: u64, } public struct Potion has key, store { id: UID, game_id: ID, potency: u64, } public struct Boar has key, store { id: UID, game_id: ID, healt




.jpg)