Berinteraksi dengan kontrak lain dari Solidity
Pada tutorial sebelumnya kita telah banyak belajar cara menerapkan kontrak pintar pertama Anda dan menambahkan beberapa fitur ke dalamnya seperti mengontrol akses dengan pengubah (modifier) (opens in a new tab) atau penanganan kesalahan di Solidity (opens in a new tab). Pada tutorial ini kita akan belajar cara menerapkan kontrak pintar dari kontrak yang sudah ada dan berinteraksi dengannya.
Kita akan membuat kontrak yang memungkinkan siapa saja untuk memiliki kontrak pintar Counter mereka sendiri dengan membuat pabrik (factory) untuknya, namanya adalah CounterFactory. Pertama, berikut adalah kode dari kontrak pintar Counter awal kita:
1pragma solidity 0.5.17;23contract Counter {45 uint256 private _count;6 address private _owner;7 address private _factory;8910 modifier onlyOwner(address caller) {11 require(caller == _owner, "You're not the owner of the contract");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "You need to use the factory");17 _;18 }1920 constructor(address owner) public {21 _owner = owner;22 _factory = msg.sender;23 }2425 function getCount() public view returns (uint256) {26 return _count;27 }2829 function increment(address caller) public onlyFactory onlyOwner(caller) {30 _count++;31 }3233}Tampilkan semuaPerhatikan bahwa kita sedikit memodifikasi kode kontrak untuk melacak alamat pabrik dan alamat pemilik kontrak. Saat Anda memanggil kode kontrak dari kontrak lain, msg.sender akan merujuk ke alamat pabrik kontrak kita. Ini adalah poin yang sangat penting untuk dipahami karena menggunakan kontrak untuk berinteraksi dengan kontrak lain adalah praktik yang umum. Oleh karena itu, Anda harus memperhatikan siapa pengirimnya dalam kasus-kasus yang kompleks.
Untuk ini kita juga menambahkan pengubah onlyFactory yang memastikan bahwa fungsi pengubah status hanya dapat dipanggil oleh pabrik yang akan meneruskan pemanggil asli sebagai parameter.
Di dalam CounterFactory baru kita yang akan mengelola semua Counter lainnya, kita akan menambahkan pemetaan (mapping) yang akan mengaitkan pemilik dengan alamat kontrak counter-nya:
1mapping(address => Counter) _counters;Di Ethereum, pemetaan setara dengan objek dalam javascript, mereka memungkinkan untuk memetakan kunci tipe A ke nilai tipe B. Dalam hal ini kita memetakan alamat pemilik dengan instansiasi Counter-nya.
Menginstansiasi Counter baru untuk seseorang akan terlihat seperti ini:
1 function createCounter() public {2 require (_counters[msg.sender] == Counter(0));3 _counters[msg.sender] = new Counter(msg.sender);4 }Kita pertama-tama memeriksa apakah orang tersebut sudah memiliki counter. Jika dia belum memiliki counter, kita menginstansiasi counter baru dengan meneruskan alamatnya ke konstruktor Counter dan menetapkan instansiasi yang baru dibuat ke pemetaan.
Untuk mendapatkan hitungan dari Counter tertentu, akan terlihat seperti ini:
1function getCount(address account) public view returns (uint256) {2 require (_counters[account] != Counter(0));3 return (_counters[account].getCount());4}56function getMyCount() public view returns (uint256) {7 return (getCount(msg.sender));8}Fungsi pertama memeriksa apakah kontrak Counter ada untuk alamat yang diberikan dan kemudian memanggil metode getCount dari instansiasi tersebut. Fungsi kedua: getMyCount hanyalah jalan pintas untuk meneruskan msg.sender secara langsung ke fungsi getCount.
Fungsi increment cukup mirip tetapi meneruskan pengirim transaksi asli ke kontrak Counter:
1function increment() public {2 require (_counters[msg.sender] != Counter(0));3 Counter(_counters[msg.sender]).increment(msg.sender);4 }Perhatikan bahwa jika dipanggil terlalu sering, counter kita mungkin bisa menjadi korban overflow. Anda harus menggunakan pustaka SafeMath (opens in a new tab) sebanyak mungkin untuk melindungi dari kemungkinan kasus ini.
Untuk menerapkan kontrak kita, Anda perlu menyediakan kode CounterFactory dan Counter. Saat menerapkan misalnya di Remix, Anda harus memilih CounterFactory.
Berikut adalah kode lengkapnya:
1pragma solidity 0.5.17;23contract Counter {45 uint256 private _count;6 address private _owner;7 address private _factory;8910 modifier onlyOwner(address caller) {11 require(caller == _owner, "You're not the owner of the contract");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "You need to use the factory");17 _;18 }1920 constructor(address owner) public {21 _owner = owner;22 _factory = msg.sender;23 }2425 function getCount() public view returns (uint256) {26 return _count;27 }2829 function increment(address caller) public onlyFactory onlyOwner(caller) {30 _count++;31 }3233}3435contract CounterFactory {3637 mapping(address => Counter) _counters;3839 function createCounter() public {40 require (_counters[msg.sender] == Counter(0));41 _counters[msg.sender] = new Counter(msg.sender);42 }4344 function increment() public {45 require (_counters[msg.sender] != Counter(0));46 Counter(_counters[msg.sender]).increment(msg.sender);47 }4849 function getCount(address account) public view returns (uint256) {50 require (_counters[account] != Counter(0));51 return (_counters[account].getCount());52 }5354 function getMyCount() public view returns (uint256) {55 return (getCount(msg.sender));56 }5758}Tampilkan semuaSetelah mengompilasi, di bagian penerapan Remix Anda akan memilih pabrik yang akan diterapkan:
Kemudian Anda dapat bermain dengan pabrik kontrak Anda dan memeriksa perubahan nilainya. Jika Anda ingin memanggil kontrak pintar dari alamat yang berbeda, Anda perlu mengubah alamat di pilihan Akun (Account) pada Remix.
Pembaruan terakhir halaman: 15 Agustus 2023
