← Semua pembelajaran / Blockchain Nol → RWA
Fase 1 · Solidity & Smart Contract

Function, modifier & event

Kamu sudah tahu state variable dan tipe data. Sekarang bagian yang membuat kontrak benar-benar melakukan sesuatu: fungsi dengan aturan aksesnya sendiri, dan cara mengumumkan 'sesuatu terjadi' ke dunia luar kontrak.

Intisari

  • Mutability fungsi (view, pure, payable, atau tanpa keyword) menentukan apakah butuh gas dan transaksi — dibahas tuntas di Fase 3.
  • Modifier adalah kode yang dibungkus di sekitar fungsi lain — persis middleware — ditulis sekali, dipakai berulang lewat nama.
  • Event adalah satu-satunya cara murah menyimpan "log" yang bisa dibaca dari luar rantai; jauh lebih murah dari menyimpan data yang sama di storage.
  • indexed pada parameter event membuatnya bisa difilter saat query log — maksimal 3 parameter per event.
  • Sejak Solidity 0.8.4, custom error (error NamaError(...)) menggantikan require dengan string panjang — jauh lebih hemat gas untuk kasus revert.

Modifier: middleware-nya Solidity

Kalau kamu terbiasa dengan middleware Laravel atau interceptor gRPC, modifier Solidity punya bentuk mental yang sama: kode yang berjalan sebelum (dan opsional sesudah) badan fungsi, ditulis sekali, dipasang ke banyak fungsi lewat nama.

address public owner;

modifier onlyOwner() {
    require(msg.sender == owner, "Bukan pemilik");
    _;   // "_;" menandai: di sinilah badan fungsi asli dijalankan
}

modifier tidakDijeda() {
    require(!dijeda, "Kontrak sedang dijeda");
    _;
}

// Modifier bisa ditumpuk — dieksekusi berurutan dari kiri ke kanan
function tarikDana(uint256 jumlah) external onlyOwner tidakDijeda {
    payable(msg.sender).transfer(jumlah);
}

Posisi _; menentukan urutan eksekusi. Kalau diletakkan di awal modifier, kode setelah _; berjalan setelah badan fungsi selesai — pola ini dipakai untuk modifier yang perlu membersihkan state atau memeriksa invariant pasca-eksekusi, mis. proteksi reentrancy yang dibahas di Fase 4.

Event: log murah yang bisa dibaca backend

Menyimpan riwayat di storage kontrak sangat mahal (~20.000 gas per slot baru). Event menyediakan cara yang jauh lebih murah untuk "mengumumkan sesuatu terjadi" — datanya masuk ke transaction receipt, bukan storage kontrak, dan bisa dibaca backend lewat listener (dibahas tuntas di Fase 3).

event DanaDitarik(address indexed penerima, uint256 jumlah, uint256 timestamp);

function tarikDana(uint256 jumlah) external onlyOwner {
    payable(msg.sender).transfer(jumlah);
    emit DanaDitarik(msg.sender, jumlah, block.timestamp);
}
State variableEvent
Bisa dibaca ulang dari dalam kontrak lain?YaTidak — hanya lewat log, dari luar rantai
Biaya kira-kira~20.000 gas (tulis baru)~375 gas + ~8 gas/byte data + ~375/topic indexed
Dipakai untukState yang harus dibaca ulang on-chainRiwayat/audit trail yang dibaca backend

indexed maksimal 3 parameter per event. Parameter yang di-indexed masuk ke "topics" log dan bisa difilter langsung oleh node (mis. "cari semua event DanaDitarik untuk penerima tertentu") tanpa mengunduh dan memfilter manual di backend. Parameter tanpa indexed masuk ke "data" — tidak bisa difilter node, tapi bisa memuat tipe apa pun termasuk string panjang.

Custom error: revert yang lebih hemat gas

// Gaya lama — string revert disimpan penuh di bytecode DAN di data transaksi gagal
require(msg.sender == owner, "Hanya pemilik yang boleh menarik dana");

// Gaya modern (0.8.4+) — hanya 4 byte selector + argumen yang dikirim saat revert
error BukanPemilik(address pemanggil, address pemilikSah);

function tarikDana() external {
    if (msg.sender != owner) {
        revert BukanPemilik(msg.sender, owner);
    }
}
FungsiButuh transaksi + gas?Bisa emit event?Bisa ubah state?
pureTidak (dipanggil sebagai call)TidakTidak — bahkan tidak boleh membaca state
viewTidak (dipanggil sebagai call)TidakTidak, tapi boleh membaca state
(tanpa keyword)YaYaYa
payableYa, dan boleh menerima native coinYaYa

Latihan: tambahkan modifier tidakDijeda dan event DanaDitarik ke kontrak Sertifikat dari materi sebelumnya, ubah require string di fungsi terbitkan jadi custom error BukanPenerbit(address pemanggil). Deploy ulang di Remix, panggil fungsi yang revert, lalu baca detail error di console Remix — bandingkan ukurannya dengan versi require string yang lama.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.