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.
indexedpada parameter event membuatnya bisa difilter saat query log — maksimal 3 parameter per event.- Sejak Solidity 0.8.4, custom error (
error NamaError(...)) menggantikanrequiredengan 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 variable | Event | |
|---|---|---|
| Bisa dibaca ulang dari dalam kontrak lain? | Ya | Tidak — hanya lewat log, dari luar rantai |
| Biaya kira-kira | ~20.000 gas (tulis baru) | ~375 gas + ~8 gas/byte data + ~375/topic indexed |
| Dipakai untuk | State yang harus dibaca ulang on-chain | Riwayat/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);
}
}
| Fungsi | Butuh transaksi + gas? | Bisa emit event? | Bisa ubah state? |
|---|---|---|---|
pure | Tidak (dipanggil sebagai call) | Tidak | Tidak — bahkan tidak boleh membaca state |
view | Tidak (dipanggil sebagai call) | Tidak | Tidak, tapi boleh membaca state |
| (tanpa keyword) | Ya | Ya | Ya |
payable | Ya, dan boleh menerima native coin | Ya | Ya |
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.