Skip to main content

Module 2: Dasar-dasar Bahasa Move

Dalam tutorial ini, kita akan belajar bahasa Move step-by-step dari yang paling dasar. Setiap konsep akan dijelaskan satu per satu dengan contoh sederhana menggunakan data mahasiswa kampus.

Setup Awal

1. Setup Sui CLI

Sui CLI adalah tool untuk membuat dan menjalankan smart contract Move.

Langkah-langkah:

  1. Install Sui CLI dari https://docs.sui.io/build/install
  2. Buat wallet baru:
    sui client new-address ed25519
  3. Dapatkan testnet token:
    sui client faucet
  4. Cek balance:
    sui client balance

2. Setup Project Move

  1. Buat folder project:

    mkdir kampus-move
    cd kampus-move
    sui move new kampus
  2. Struktur project:

    kampus/
    ├── Move.toml
    └── sources/
    └── kampus.move
  3. File Move.toml:

    [package]
    name = "kampus"
    version = "1.0.0"

    [dependencies]
    Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" }

    [addresses]
    kampus = "0x0"
Siap!

Sekarang Anda sudah siap untuk belajar Move dan deploy ke Sui Network!

Move 101: Mengenal Tipe Data

Mari kita mulai dengan memahami tipe data dasar di Move satu per satu.

1. Tipe Data String

String digunakan untuk menyimpan teks.

module kampus::belajar_string {
use std::string::{Self, String};

// Struct untuk menyimpan nama mahasiswa
public struct Mahasiswa has key {
id: UID,
nama: String,
}

// Fungsi untuk membuat mahasiswa baru
public fun buat_mahasiswa(nama: String, ctx: &mut TxContext): Mahasiswa {
Mahasiswa {
id: object::new(ctx),
nama,
}
}

// Fungsi untuk mengubah nama
public fun ubah_nama(mahasiswa: &mut Mahasiswa, nama_baru: String) {
mahasiswa.nama = nama_baru;
}

// Fungsi untuk mendapatkan nama
public fun get_nama(mahasiswa: &Mahasiswa): String {
mahasiswa.nama
}
}

Penjelasan:

  • String = tipe data untuk menyimpan teks
  • public struct Mahasiswa has key = membuat struct yang bisa disimpan di blockchain
  • UID = unique identifier yang diperlukan untuk setiap object
  • &mut = reference yang bisa diubah

2. Tipe Data Number (u64)

u64 digunakan untuk menyimpan angka positif.

module kampus::belajar_number {
// Struct untuk data mahasiswa dengan angka
public struct DataMahasiswa has key {
id: UID,
nim: u32,
umur: u8,
total_sks: u64,
}

// Fungsi untuk membuat data mahasiswa
public fun buat_data_mahasiswa(
nim: u32,
umur: u8,
ctx: &mut TxContext
): DataMahasiswa {
DataMahasiswa {
id: object::new(ctx),
nim,
umur,
total_sks: 0,
}
}

// Fungsi untuk menambah SKS
public fun tambah_sks(data: &mut DataMahasiswa, sks: u64) {
data.total_sks = data.total_sks + sks;
}

// Fungsi untuk menambah umur
public fun tambah_umur(data: &mut DataMahasiswa) {
data.umur = data.umur + 1;
}
}

Penjelasan:

  • u8 = angka dari 0 sampai 255
  • u32 = angka dari 0 sampai ~4 miliar
  • u64 = angka dari 0 sampai ~18 quintillion
  • data.total_sks + sks = operasi penjumlahan

3. Tipe Data Boolean

Boolean hanya punya 2 nilai: true atau false.

module kampus::belajar_boolean {
use std::string::String;

// Struct dengan boolean
public struct StatusMahasiswa has key {
id: UID,
nama: String,
aktif: bool,
lulus: bool,
}

// Fungsi untuk membuat status mahasiswa
public fun buat_status(nama: String, ctx: &mut TxContext): StatusMahasiswa {
StatusMahasiswa {
id: object::new(ctx),
nama,
aktif: true, // Default aktif
lulus: false, // Default belum lulus
}
}

// Fungsi untuk set lulus
public fun set_lulus(status: &mut StatusMahasiswa) {
status.lulus = true;
}

// Fungsi untuk nonaktifkan
public fun nonaktifkan(status: &mut StatusMahasiswa) {
status.aktif = false;
}

// Fungsi untuk cek apakah bisa wisuda
public fun bisa_wisuda(status: &StatusMahasiswa): bool {
status.aktif && status.lulus
}
}

Penjelasan:

  • bool = tipe data yang cuma bisa true atau false
  • status.aktif && status.lulus = operasi AND (dan)
  • && = kedua kondisi harus true

4. Gabungkan Semua Tipe Data

Sekarang kita gabungkan semua tipe data dalam satu module sederhana:

module kampus::data_mahasiswa_lengkap {
use std::string::String;

// Struct lengkap mahasiswa
public struct Mahasiswa has key {
id: UID,
nama: String,
nim: u32,
jurusan: String,
umur: u8,
total_sks: u64,
aktif: bool,
lulus: bool,
}

// Fungsi untuk membuat mahasiswa baru
public fun daftar_mahasiswa(
nama: String,
nim: u32,
jurusan: String,
umur: u8,
ctx: &mut TxContext
): Mahasiswa {
Mahasiswa {
id: object::new(ctx),
nama,
nim,
jurusan,
umur,
total_sks: 0,
aktif: true,
lulus: false,
}
}

// Fungsi untuk ambil mata kuliah (tambah SKS)
public fun ambil_mata_kuliah(mhs: &mut Mahasiswa, sks: u64) {
mhs.total_sks = mhs.total_sks + sks;
}

// Fungsi untuk lulus
public fun set_lulus(mhs: &mut Mahasiswa) {
// Syarat lulus: minimal 144 SKS
if (mhs.total_sks >= 144) {
mhs.lulus = true;
}
}

// Fungsi untuk get info mahasiswa
public fun get_info(mhs: &Mahasiswa): (String, u32, u64, bool) {
(mhs.nama, mhs.nim, mhs.total_sks, mhs.lulus)
}
}

Cara menggunakan:

  1. Save kode di file sources/mahasiswa.move
  2. Compile: sui move build
  3. Publish: sui client publish --gas-budget 100000000

5. Mengenal Vector (Array)

Vector adalah seperti list yang bisa menyimpan banyak data dengan tipe yang sama.

module kampus::belajar_vector {
use std::string::String;
use std::vector;

// Struct untuk menyimpan daftar mahasiswa
public struct DaftarMahasiswa has key {
id: UID,
nama_mahasiswa: vector<String>,
nim_mahasiswa: vector<u32>,
}

// Fungsi untuk membuat daftar kosong
public fun buat_daftar_kosong(ctx: &mut TxContext): DaftarMahasiswa {
DaftarMahasiswa {
id: object::new(ctx),
nama_mahasiswa: vector::empty<String>(),
nim_mahasiswa: vector::empty<u32>(),
}
}

// Fungsi untuk tambah mahasiswa ke daftar
public fun tambah_mahasiswa(
daftar: &mut DaftarMahasiswa,
nama: String,
nim: u32
) {
vector::push_back(&mut daftar.nama_mahasiswa, nama);
vector::push_back(&mut daftar.nim_mahasiswa, nim);
}

// Fungsi untuk menghitung jumlah mahasiswa
public fun jumlah_mahasiswa(daftar: &DaftarMahasiswa): u64 {
vector::length(&daftar.nama_mahasiswa)
}

// Fungsi untuk mendapatkan mahasiswa berdasarkan index
public fun get_mahasiswa_ke(daftar: &DaftarMahasiswa, index: u64): (String, u32) {
let nama = *vector::borrow(&daftar.nama_mahasiswa, index);
let nim = *vector::borrow(&daftar.nim_mahasiswa, index);
(nama, nim)
}

// Fungsi untuk cek apakah daftar kosong
public fun apakah_kosong(daftar: &DaftarMahasiswa): bool {
vector::is_empty(&daftar.nama_mahasiswa)
}
}

Penjelasan:

  • vector<String> = vector yang berisi String
  • vector::empty<String>() = membuat vector kosong
  • vector::push_back() = menambah data ke vector
  • vector::length() = menghitung panjang vector
  • vector::borrow() = mengambil reference ke element vector

Move 102: Object Ownership dan Struct

Sekarang kita belajar cara mengelompokkan data dengan Struct dan memahami ownership pattern di Sui.

1. Mengenal Struct dan Object Model

Struct adalah cara untuk mengelompokkan beberapa data jadi satu. Di Sui, ada 3 jenis object berdasarkan ownership.

Owned Objects - Dimiliki Address Tertentu

module kampus::owned_objects {
use std::string::String;

// Struct mahasiswa yang dimiliki oleh address tertentu
public struct KartuMahasiswa has key, store {
id: UID,
nama: String,
nim: u32,
jurusan: String,
tahun_masuk: u16,
}

// Fungsi untuk membuat kartu mahasiswa (owned object)
public fun daftar_mahasiswa(
nama: String,
nim: u32,
jurusan: String,
tahun_masuk: u16,
ctx: &mut TxContext
) {
let kartu = KartuMahasiswa {
id: object::new(ctx),
nama,
nim,
jurusan,
tahun_masuk,
};

// Transfer ke sender (mahasiswa yang mendaftar)
transfer::transfer(kartu, tx_context::sender(ctx));
}

// Mahasiswa bisa update data sendiri
public fun update_nama(kartu: &mut KartuMahasiswa, nama_baru: String) {
kartu.nama = nama_baru;
}

// Fungsi untuk transfer kartu ke orang lain
public fun transfer_kartu(kartu: KartuMahasiswa, penerima: address) {
transfer::transfer(kartu, penerima);
}
}

Penjelasan:

  • has key, store = object bisa disimpan di blockchain dan di dalam struct lain
  • transfer::transfer() = pindahkan ownership ke address lain
  • Hanya pemilik yang bisa mengakses object owned

Shared Objects - Bisa Diakses Siapa Saja

module kampus::shared_objects {
use std::string::String;
use std::vector;

// Struct untuk registrasi kampus (shared object)
public struct RegistrasiKampus has key {
id: UID,
nama_kampus: String,
total_mahasiswa: u64,
daftar_nim: vector<u32>,
admin: address,
}

// Fungsi untuk membuat registrasi kampus (shared)
public fun buat_registrasi_kampus(
nama_kampus: String,
ctx: &mut TxContext
) {
let registrasi = RegistrasiKampus {
id: object::new(ctx),
nama_kampus,
total_mahasiswa: 0,
daftar_nim: vector::empty<u32>(),
admin: tx_context::sender(ctx),
};

// Share object agar semua orang bisa akses
transfer::share_object(registrasi);
}

// Siapa saja bisa lihat jumlah mahasiswa
public fun get_total_mahasiswa(registrasi: &RegistrasiKampus): u64 {
registrasi.total_mahasiswa
}

// Hanya admin yang bisa tambah mahasiswa
public fun tambah_mahasiswa_ke_registrasi(
registrasi: &mut RegistrasiKampus,
nim: u32,
ctx: &TxContext
) {
// Cek apakah yang memanggil adalah admin
assert!(registrasi.admin == tx_context::sender(ctx), 0);

// Tambah mahasiswa
registrasi.total_mahasiswa = registrasi.total_mahasiswa + 1;
vector::push_back(&mut registrasi.daftar_nim, nim);
}
}

Penjelasan:

  • transfer::share_object() = buat object bisa diakses semua orang
  • Shared object butuh consensus untuk diubah
  • Bisa ada authorization check di dalam fungsi

2. Capabilities Pattern

Capabilities adalah cara memberikan permission dengan object ownership.

module kampus::capabilities_pattern {
use std::string::String;

// Admin capability - hanya admin yang punya
public struct AdminCap has key, store {
id: UID,
}

// Dosen capability - hanya dosen yang punya
public struct DosenCap has key, store {
id: UID,
mata_kuliah: String,
}

// Struct untuk sistem nilai
public struct SistemNilai has key {
id: UID,
total_mahasiswa: u64,
}

// Struct untuk nilai mahasiswa
public struct NilaiMahasiswa has key, store {
id: UID,
nim: u32,
mata_kuliah: String,
nilai: u8,
dosen_pemberi: address,
}

// Init function - jalan sekali saat deploy
fun init(ctx: &mut TxContext) {
// Buat admin capability
let admin_cap = AdminCap {
id: object::new(ctx),
};

// Buat sistem nilai
let sistem = SistemNilai {
id: object::new(ctx),
total_mahasiswa: 0,
};

// Transfer admin cap ke deployer
transfer::transfer(admin_cap, tx_context::sender(ctx));

// Share sistem nilai
transfer::share_object(sistem);
}

// Hanya admin yang bisa buat dosen capability
public fun buat_dosen_cap(
_: &AdminCap, // Admin capability sebagai "kunci"
mata_kuliah: String,
dosen_address: address,
ctx: &mut TxContext
) {
let dosen_cap = DosenCap {
id: object::new(ctx),
mata_kuliah,
};

transfer::transfer(dosen_cap, dosen_address);
}

// Hanya dosen yang bisa kasih nilai
public fun beri_nilai(
dosen_cap: &DosenCap,
sistem: &mut SistemNilai,
nim: u32,
nilai: u8,
mahasiswa_address: address,
ctx: &mut TxContext
) {
// Validasi nilai
assert!(nilai <= 100, 1);

let nilai_obj = NilaiMahasiswa {
id: object::new(ctx),
nim,
mata_kuliah: dosen_cap.mata_kuliah,
nilai,
dosen_pemberi: tx_context::sender(ctx),
};

// Update sistem
sistem.total_mahasiswa = sistem.total_mahasiswa + 1;

// Transfer ke mahasiswa
transfer::transfer(nilai_obj, mahasiswa_address);
}
}

Penjelasan:

  • AdminCap, DosenCap = capabilities untuk different permissions
  • _: &AdminCap = parameter yang harus ada tapi tidak digunakan
  • fun init() = fungsi yang jalan sekali saat deploy contract
  • Capability pattern lebih aman daripada address-based permission

3. Fungsi dan Control Flow

Mari pelajari cara membuat fungsi yang lebih baik dengan error handling:

module kampus::fungsi_lengkap {
use std::string::String;
use std::vector;

// Error constants
const ENIM_INVALID: u64 = 0;
const ENILAI_INVALID: u64 = 1;
const ESKS_INVALID: u64 = 2;
const ENOT_AUTHORIZED: u64 = 3;

public struct MahasiswaProfile has key {
id: UID,
nama: String,
nim: u32,
total_sks: u64,
nilai_list: vector<u8>,
owner: address,
}

// Fungsi dengan validasi lengkap
public fun buat_profile(
nama: String,
nim: u32,
ctx: &mut TxContext
) {
// Validasi NIM (8 digit, dimulai 20)
assert!(nim >= 20000000 && nim <= 29999999, ENIM_INVALID);

// Validasi nama tidak kosong
assert!(string::length(&nama) > 0, 100);

let profile = MahasiswaProfile {
id: object::new(ctx),
nama,
nim,
total_sks: 0,
nilai_list: vector::empty<u8>(),
owner: tx_context::sender(ctx),
};

transfer::transfer(profile, tx_context::sender(ctx));
}

// Fungsi dengan authorization check
public fun tambah_nilai(
profile: &mut MahasiswaProfile,
nilai: u8,
sks: u64,
ctx: &TxContext
) {
// Cek ownership
assert!(profile.owner == tx_context::sender(ctx), ENOT_AUTHORIZED);

// Validasi nilai (0-100)
assert!(nilai <= 100, ENILAI_INVALID);

// Validasi SKS (1-6)
assert!(sks >= 1 && sks <= 6, ESKS_INVALID);

// Update data
vector::push_back(&mut profile.nilai_list, nilai);
profile.total_sks = profile.total_sks + sks;
}

// Fungsi dengan multiple return values dan control flow
public fun analisis_performa(profile: &MahasiswaProfile): (u64, bool, String) {
let jumlah_mk = vector::length(&profile.nilai_list);

// Return early jika belum ada nilai
if (jumlah_mk == 0) {
return (0, false, string::utf8(b"Belum ada nilai"))
};

// Hitung rata-rata nilai
let mut total_nilai = 0u64;
let mut i = 0;

while (i < jumlah_mk) {
let nilai = *vector::borrow(&profile.nilai_list, i);
total_nilai = total_nilai + (nilai as u64);
i = i + 1;
};

let rata_rata = total_nilai / jumlah_mk;

// Tentukan status dan pesan
let (bisa_lulus, pesan) = if (rata_rata >= 60 && profile.total_sks >= 144) {
(true, string::utf8(b"Bisa lulus"))
} else if (rata_rata < 60) {
(false, string::utf8(b"Nilai kurang"))
} else {
(false, string::utf8(b"SKS kurang"))
};

(rata_rata, bisa_lulus, pesan)
}

// Fungsi untuk cari nilai tertinggi
public fun cari_nilai_tertinggi(profile: &MahasiswaProfile): u8 {
let nilai_list = &profile.nilai_list;
let len = vector::length(nilai_list);

assert!(len > 0, 200); // Harus ada nilai

let mut max_nilai = *vector::borrow(nilai_list, 0);
let mut i = 1;

while (i < len) {
let nilai = *vector::borrow(nilai_list, i);
if (nilai > max_nilai) {
max_nilai = nilai;
};
i = i + 1;
};

max_nilai
}
}

Penjelasan Konsep Penting:

  • assert!(condition, error_code) = validasi dengan error code
  • as u64 = type casting untuk konversi tipe data
  • let mut = variabel yang bisa diubah
  • while loop untuk iterasi
  • Multiple return values dengan tuple

Move 103: Hands-On Project

Mari buat project lengkap untuk sistem kampus sederhana.

Project Setup

  1. Buat project baru:

    sui move new sistem_kampus_lengkap
    cd sistem_kampus_lengkap
  2. Edit Move.toml:

    [package]
    name = "sistem_kampus_lengkap"
    version = "1.0.0"

    [dependencies]
    Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" }

    [addresses]
    sistem_kampus = "0x0"

Main Contract: sources/kampus.move

module sistem_kampus::kampus {
use std::string::{Self, String};
use std::vector;

// === ERROR CONSTANTS ===
const ENIM_INVALID: u64 = 0;
const ENOT_AUTHORIZED: u64 = 1;
const EVALUES_INVALID: u64 = 2;
const ENOT_FOUND: u64 = 3;

// === STRUCTS ===

// Admin capability
public struct AdminCap has key {
id: UID,
}

// Mahasiswa profile (owned object)
public struct MahasiswaProfile has key, store {
id: UID,
nama: String,
nim: u32,
jurusan: String,
semester: u8,
total_sks: u64,
ipk: u64, // IPK x 100 (contoh: 350 = 3.50)
aktif: bool,
owner: address,
}

// Registry kampus (shared object)
public struct KampusRegistry has key {
id: UID,
nama_kampus: String,
total_mahasiswa: u64,
daftar_nim: vector<u32>,
admin: address,
}

// Nilai mata kuliah (owned object)
public struct NilaiMataKuliah has key, store {
id: UID,
nim_mahasiswa: u32,
kode_mk: String,
nama_mk: String,
sks: u8,
nilai: u8,
semester: u8,
tahun: u16,
}

// === EVENTS ===
public struct MahasiswaRegistered has copy, drop {
nim: u32,
nama: String,
jurusan: String,
}

public struct NilaiAdded has copy, drop {
nim: u32,
mata_kuliah: String,
nilai: u8,
sks: u8,
}

// === INIT FUNCTION ===
fun init(ctx: &mut TxContext) {
// Buat admin capability
let admin_cap = AdminCap {
id: object::new(ctx),
};

// Buat kampus registry
let registry = KampusRegistry {
id: object::new(ctx),
nama_kampus: string::utf8(b"Universitas Blockchain Indonesia"),
total_mahasiswa: 0,
daftar_nim: vector::empty<u32>(),
admin: tx_context::sender(ctx),
};

// Transfer admin cap ke deployer
transfer::transfer(admin_cap, tx_context::sender(ctx));

// Share registry untuk akses publik
transfer::share_object(registry);
}

// === ADMIN FUNCTIONS ===

// Register mahasiswa baru (hanya admin)
public fun register_mahasiswa(
_: &AdminCap, // Admin capability sebagai authorization
registry: &mut KampusRegistry,
nama: String,
nim: u32,
jurusan: String,
mahasiswa_address: address,
ctx: &mut TxContext
) {
// Validasi NIM
assert!(nim >= 20000000 && nim <= 29999999, ENIM_INVALID);

// Buat profile mahasiswa
let profile = MahasiswaProfile {
id: object::new(ctx),
nama: nama,
nim,
jurusan: jurusan,
semester: 1,
total_sks: 0,
ipk: 0,
aktif: true,
owner: mahasiswa_address,
};

// Update registry
registry.total_mahasiswa = registry.total_mahasiswa + 1;
vector::push_back(&mut registry.daftar_nim, nim);

// Emit event
sui::event::emit(MahasiswaRegistered {
nim,
nama,
jurusan,
});

// Transfer profile ke mahasiswa
transfer::transfer(profile, mahasiswa_address);
}

// Berikan nilai (hanya admin)
public fun beri_nilai(
_: &AdminCap,
kode_mk: String,
nama_mk: String,
sks: u8,
nilai: u8,
semester: u8,
tahun: u16,
nim_mahasiswa: u32,
mahasiswa_address: address,
ctx: &mut TxContext
) {
// Validasi
assert!(nilai <= 100, EVALUES_INVALID);
assert!(sks >= 1 && sks <= 6, EVALUES_INVALID);

let nilai_mk = NilaiMataKuliah {
id: object::new(ctx),
nim_mahasiswa,
kode_mk: kode_mk,
nama_mk: nama_mk,
sks,
nilai,
semester,
tahun,
};

// Emit event
sui::event::emit(NilaiAdded {
nim: nim_mahasiswa,
mata_kuliah: nama_mk,
nilai,
sks,
});

// Transfer ke mahasiswa
transfer::transfer(nilai_mk, mahasiswa_address);
}

// === MAHASISWA FUNCTIONS ===

// Update profile sendiri
public fun update_semester(
profile: &mut MahasiswaProfile,
semester_baru: u8,
ctx: &TxContext
) {
assert!(profile.owner == tx_context::sender(ctx), ENOT_AUTHORIZED);
assert!(semester_baru >= profile.semester, EVALUES_INVALID);

profile.semester = semester_baru;
}

// Update IPK berdasarkan nilai yang dimiliki
public fun hitung_ipk(
profile: &mut MahasiswaProfile,
daftar_nilai: &vector<NilaiMataKuliah>,
ctx: &TxContext
) {
assert!(profile.owner == tx_context::sender(ctx), ENOT_AUTHORIZED);

let mut total_nilai_tertimbang = 0u64;
let mut total_sks = 0u64;
let mut i = 0;

let len = vector::length(daftar_nilai);
while (i < len) {
let nilai_mk = vector::borrow(daftar_nilai, i);

// Hanya hitung nilai untuk mahasiswa ini
if (nilai_mk.nim_mahasiswa == profile.nim) {
// Konversi nilai ke point (A=4, B=3, C=2, D=1, E=0)
let point = if (nilai_mk.nilai >= 80) 4
else if (nilai_mk.nilai >= 70) 3
else if (nilai_mk.nilai >= 60) 2
else if (nilai_mk.nilai >= 50) 1
else 0;

total_nilai_tertimbang = total_nilai_tertimbang + (point * (nilai_mk.sks as u64));
total_sks = total_sks + (nilai_mk.sks as u64);
};

i = i + 1;
};

// Update profile
profile.total_sks = total_sks;
if (total_sks > 0) {
profile.ipk = (total_nilai_tertimbang * 100) / total_sks; // IPK x 100
};
}

// === VIEW FUNCTIONS ===

// Get info mahasiswa
public fun get_mahasiswa_info(profile: &MahasiswaProfile): (String, u32, String, u8, u64, u64, bool) {
(
profile.nama,
profile.nim,
profile.jurusan,
profile.semester,
profile.total_sks,
profile.ipk,
profile.aktif
)
}

// Get info kampus
public fun get_kampus_info(registry: &KampusRegistry): (String, u64) {
(registry.nama_kampus, registry.total_mahasiswa)
}

// Cek syarat kelulusan
public fun cek_kelulusan(profile: &MahasiswaProfile): bool {
profile.total_sks >= 144 && profile.ipk >= 200 && profile.aktif
}

// Get detail nilai
public fun get_nilai_info(nilai: &NilaiMataKuliah): (u32, String, String, u8, u8) {
(
nilai.nim_mahasiswa,
nilai.kode_mk,
nilai.nama_mk,
nilai.sks,
nilai.nilai
)
}
}

Testing dan Deploy

  1. Build project:

    sui move build
  2. Publish ke testnet:

    sui client publish --gas-budget 100000000
  3. Interaksi dengan contract:

    # Cek objects yang dimiliki
    sui client objects

    # Register mahasiswa (sebagai admin)
    sui client call \
    --package <PACKAGE_ID> \
    --module kampus \
    --function register_mahasiswa \
    --args <ADMIN_CAP_ID> <REGISTRY_ID> "Budi Santoso" 20230001 "Teknik Informatika" <STUDENT_ADDRESS> \
    --gas-budget 10000000

    # Lihat info kampus
    sui client call \
    --package <PACKAGE_ID> \
    --module kampus \
    --function get_kampus_info \
    --args <REGISTRY_ID> \
    --gas-budget 1000000

📝 Rangkuman Module 2

Yang Telah Dipelajari:

  1. Setup Development: Sui CLI dan project Move
  2. Tipe Data Dasar: String, numbers (u8, u32, u64), boolean
  3. Vector: Array dinamis untuk koleksi data
  4. Object Model: Owned, shared objects dan ownership patterns
  5. Struct: Pengelompokan data dengan abilities
  6. Capabilities Pattern: Permission control dengan object ownership
  7. Fungsi: Public functions, parameters, return values
  8. Error Handling: Assert dan error constants
  9. Events: Logging aktivitas di blockchain
  10. Hands-On: Complete campus management system

Konsep Kunci Move:

  • Resource Safety: Object ownership yang jelas dan aman
  • Linear Types: Tidak ada copy, hanya move atau borrow
  • Object-Centric: Semua data adalah object dengan UID
  • Capability-Based Security: Permission melalui object ownership
  • Type Safety: Strong typing untuk mencegah error

Best Practices:

  • Selalu validasi input dengan assert!
  • Gunakan error constants untuk error yang jelas
  • Implement proper authorization checks
  • Emit events untuk monitoring
  • Use descriptive struct dan function names

Next Steps:

Di Module 3, kita akan membangun Counter Contract yang lebih advanced dengan:

  • State management yang kompleks
  • Advanced testing patterns
  • Gas optimization
  • Production deployment strategies

🎯 Selamat! Anda telah menguasai dasar-dasar bahasa Move!

👉 Lanjut ke Module 3: Building a Token System →