Back to Hub
Security

Move Security & Gas Tuning

Sui Hub Workshop — 30 Minutes

Secure Contracts • Testing Practices • Cost Optimization

1 / 16

Agenda (30 min)

10mMove Security — Common vulnerabilities & defensive patterns
10mSui Move Testing — Unit tests, scenarios & debugging
7mGas Tuning — Storage, computation & transaction cost optimization
3mQ&A & Resources
2 / 16
ShieldLockAudit

The Security Mindset

Access control vulnerabilities caused 58% of all losses in 2025. On Sui, every shared or immutable object input must be treated as attacker-controlled.

  • Ownership checks must be explicit — never assume
  • Verify the transaction sender owns any object being acted upon
  • Assert conditions in both on-chain and off-chain code
  • Use capability-based access control, not hardcoded addresses
3 / 16

Minimal Abilities Principle

Assign the minimum abilities required. Excessive abilities create attack surface.

// BAD: store is unnecessary for events
struct PoolCreated has copy, store, drop {
  pool_id: ID,
}

// GOOD: only copy + drop needed
struct PoolCreated has copy, drop {
  pool_id: ID,
}

// BAD: Receipt with store + drop breaks flash loan
struct Receipt<T> has store, drop { amount: u64 }

// GOOD: Hot potato — NO abilities
struct Receipt<T> { amount: u64 }
4 / 16

Access Control Patterns

Capability (Soulbound)

key only — cannot be transferred. Bound to owner forever. Best for admin rights.

Capability (Transferable)

key, store — can be sold or traded. Use when rights should be marketable.

// Verify ownership before state changes
assert!(object::owner(&obj) == tx_context::sender(ctx), EUnauthorized);

// Never share AdminCap — transfer to deployer
transfer::public_transfer(admin_cap, tx_context::sender(ctx));
Anti-pattern: Sharing AdminCap via share_object lets anyone call admin functions.
5 / 16

Object Ownership & Transfers

Owned by Address

Requires owner signature. Parallel execution. Best for wallets, personal items.

Shared Object

Anyone can access. Needs consensus. Slower, more expensive. Use sparingly.

// Owned — single writer, fast
transfer::transfer(obj, recipient);

// Shared — multi-writer, consensus needed
transfer::share_object(obj);

// Immutable — no owner, forever
transfer::freeze_object(obj);
Rule: Prefer owned objects. Only share when multiple writers are unavoidable.
6 / 16

Common Security Bugs

VulnerabilityImpactFix
Excessive abilitiesUnexpected transfers, dropsMinimal abilities only
Shared AdminCapAnyone becomes adminTransfer to deployer
Unvalidated genericsWrong coin type acceptedInclude type in signature
Dynamic field collisionData overwriteCheck contains before add
ID leakObject ID reuseOnly fresh IDs from object::new
Coin metadata unfrozenAdmin changes token infopublic_freeze_object
7 / 16

Generics: The Hidden Danger

Public functions with generic <COIN> accept any coin type. Without validation, users can pay with worthless tokens.

// VULNERABLE: Any Coin type accepted
public entry fun buy_pack<COIN>(
  game: &mut Game,
  paid: Coin<COIN>,
  signature: vector<u8>,
  ctx: &mut TxContext
) {
  // Signature doesn't include coin type!
}

// SECURE: Include coin type in signature verification
let message = PackMessage {
  coin_type: type_name::get<COIN>(), // bind type to signature
  // ...
};
8 / 16
TestCheckBug

Sui Move Testing

Unit tests, scenario testing & debugging your contracts

9 / 16

Move Unit Tests

Sui Move has built-in test support. Write tests in the same file or a tests/ directory.

// tests/advance_ptb_tests.move
#[test]
fun test_mint_with_cap() {
  let mut ctx = tx_context::dummy();
  let cap = create_admin_cap(&mut ctx);
  let collection = create_collection(&mut ctx);

  // Admin mints
  let nft = mint(&cap, &mut collection, &mut ctx);
  assert!(nft.id != object::id_from_address(@0x0), 0);

  transfer::public_transfer(nft, @0x1);
  transfer::public_transfer(cap, @0x1);
  transfer::public_share_object(collection);
}

// Run: sui move test
Best practice: Test the happy path, failure paths, and edge cases. Use #[expected_failure] for abort tests.
10 / 16

Test-Only Functions & Scenarios

Use #[test_only] to expose internal state for testing without polluting your public API.

// Only available in test mode
#[test_only]
public fun get_balance_internal(vault: &Vault): u64 {
  vault.balance
}

#[test_only]
public fun set_balance_for_test(vault: &mut Vault, val: u64) {
  vault.balance = val;
}

// Scenario: simulate multiple users
#[test]
fun test_flash_loan_repay() {
  let mut ctx = tx_context::dummy();
  let mut pool = create_pool(1000, &mut ctx);

  // Borrow
  let (coin, receipt) = borrow(&mut pool, 100, &mut ctx);

  // Must repay in same test scope (hot potato)
  repay(&mut pool, coin, receipt);

  assert!(pool.balance == 1000, 0);
}
11 / 16

Debugging & Testing Checklist

Unit Test Checklist

• Happy path works
#[expected_failure] on bad inputs
• Zero/edge amounts
• Unauthorized access blocked
• Object ownership verified

Debugging Tools

sui move test — run all tests
sui move test --gas-limit 1000000
std::debug::print(&value) in tests
sui client publish --dry-run

// Print debugging in tests
use std::debug;

#[test]
fun test_debug() {
  let val = 42;
  debug::print(&val); // outputs in test logs
}
12 / 16
GasBoltCoin

Gas Tuning

Storage, computation & transaction cost optimization on Sui

13 / 16

Sui Gas Model

Sui gas = computation + storage. Unlike Ethereum, storage is a deposit you get back when deleting objects.

Computation Cost

• Bytecode execution
• Native function calls
• Transaction processing

Fixed per tx + variable per op

Storage Cost

• Object creation
• Dynamic field addition
• Event emission

Deposit refunded on deletion

14 / 16

Gas Optimization Techniques

TechniqueSavingsHow
Prefer owned objects~50-80%No consensus overhead vs shared
Batch in PTBs~30-50%One tx fee for 1,024 ops
Avoid dynamic fields~20%Direct wrapping is cheaper
Delete unused objectsRefundGet storage deposit back
Minimize event data~10%Only emit essential fields
Use entry functions~5-10%Simpler call graph = less gas
15 / 16
QuestionHelpChat

Questions?

Move Security & Gas Tuning

DOCS docs.sui.io/build/move/security

COURSE github.com/sui-foundation/sui-move-intro-course

CLI sui move test | sui client publish --dry-run

Thanks for joining — build secure & efficient contracts on Sui!

16 / 16