Menerapkan konsep OOP di Solidity: inheritance dengan keyword is, override dan super, abstract contract, function overloading, serta interface untuk interoperabilitas standar seperti ERC-20 dan ERC-721

Setelah di episode 6 kalian menguasai storage dan optimasi gas, pada episode ini kita masuk ke ranah object-oriented programming: bagaimana Solidity mewarisi, memodifikasi, dan mengekspos logika antar kontrak.
Mengapa episode ini penting? Karena hampir semua kontrak produksi tidak ditulis dari nol — mereka mewarisi dari library standar seperti OpenZeppelin Contracts, mengimplementasikan interface standar token, dan berkomunikasi dengan kontrak lain lewat antarmuka. Episode ini adalah gerbang menuju episode 11 (token standards) dan episode 14 (upgradeable contracts) yang semuanya bergantung pada inheritance dan interface.
is// SPDX-License-Identifier: MIT
pragma solidity ^0.8.36;
contract Base {
uint256 public baseValue;
function get() public view virtual returns (uint256) {
return baseValue;
}
}
contract Derived is Base {
function set(uint256 _v) public {
baseValue = _v;
}
}Derived is Base mewarisi semua state variable dan fungsi non-private dari Base. Sama seperti OOP biasa, ini mendorong reuse: tulis logika sekali di base, pakai di banyak turunan.
Fungsi yang boleh di-override harus ditandai virtual, dan yang meng-override wajib override:
contract Derived is Base {
function get() public view override returns (uint256) {
return baseValue * 2;
}
}Untuk memanggil versi induk, gunakan super:
contract Derived is Base {
function get() public view override returns (uint256) {
uint256 original = super.get();
return original + 1;
}
}Jika terjadi multiple inheritance, urutan resolusi mengikuti urutan deklarasi (kiri-ke-kanan) dan C3-linearization — detail penting saat kontrak mewarisi lebih dari satu base.
Kontrak abstract punya setidaknya satu fungsi yang tidak diimplementasikan (hanya deklarasi, tanpa tubuh):
abstract contract TokenBase {
address public owner;
function transfer(address to, uint256 amount) external virtual;
}Abstract contract tidak bisa di-deploy. Ia menjadi blueprint: turunan wajib mengimplementasikan fungsi yang belum ada tubuhnya sebelum bisa di-deploy.
Note
Ini pola inti OpenZeppelin: ERC20 itu abstract, dan kontrak kalian mengimplementasikan constructor plus memanggil _mint untuk mengeluarkan supply awal. Kita pakai ini langsung di episode 11.
interface adalah kontrak yang hanya berisi deklarasi — tidak ada state variable, tidak ada konstruktor, tidak ada fungsi yang diimplementasikan. Fungsinya adalah kontrak untuk komunikasi: kalian bisa memanggil fungsi kontrak lain tanpa tahu implementasinya.
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}Untuk memanggil kontrak lain, kalian tinggal membuat instance dari alamatnya:
contract TokenRouter {
function sendToken(address token, address to, uint256 amount) external returns (bool) {
IERC20 erc20 = IERC20(token);
return erc20.transfer(to, amount);
}
}Solidity tidak peduli apa yang ada di balik alamat token — ia hanya butuh antarmuka transfer untuk menyusun panggilan. Inilah dasar interoperabilitas di ekosistem EVM: semua token ERC-20 punya fungsi transfer, approve, dan transferFrom dengan signature yang sama, sehingga kontrak apa pun bisa berinteraksi dengan token apa pun.
Solidity mendukung overloading — beberapa fungsi dengan nama sama tapi parameter berbeda:
function deposit(uint256 amount) public payable { ... }
function deposit(address token, uint256 amount) public { ... }Kompiler membedakan keduanya lewat tipe parameter. Overloading harus dipakai dengan hati-hati karena bisa membingungkan pembaca — sering kali nama yang berbeda (depositEth/depositToken) lebih jelas.
Selain inheritance, Solidity juga mendukung composition — menahan instance kontrak lain sebagai state:
contract Vault {
IERC20 public token;
constructor(address _token) {
token = IERC20(_token);
}
function deposit(uint256 amount) external {
token.transferFrom(msg.sender, address(this), amount);
}
}Ini pola dominan di DeFi: vault memegang referensi ke token, lalu memanggil antarmukanya. Composition lebih fleksibel daripada inheritance karena kontrak tidak terikat pada implementasi konkret.
Tip
Aturan praktis: pakai interface untuk interaksi antar kontrak, pakai abstract untuk menyebar logika yang harus diimplementasikan, dan pakai inheritance untuk reuse kode yang sudah nyata. Terlalu dalam inheritance (diamond problem) membuat kode sulit diaudit — kedalaman 1-3 level sudah cukup.
Inti yang harus dibawa pulang:
is mewariskan state dan fungsi; virtual/override/super mengatur modifikasi.Di episode 8 selanjutnya kita akan membahas events & logging — bagaimana kontrak memberitahukan kejadian ke luar, indexed topics, cara membaca event dengan abi.decode, dan bagaimana DApp mengindeksnya dengan The Graph. Sampai jumpa di episode 8!