Anatomi kontrak pintar
Kontrak pintar adalah program yang berjalan pada sebuah alamat di Ethereum. Kontrak pintar terdiri dari data dan fungsi yang dapat dieksekusi setelah menerima sebuah transaksi. Berikut adalah gambaran umum tentang apa yang membentuk sebuah kontrak pintar.
Prasyarat
Pastikan Anda telah membaca tentang kontrak pintar terlebih dahulu. Dokumen ini mengasumsikan Anda sudah familier dengan bahasa pemrograman seperti JavaScript atau Python.
Data
Setiap data kontrak harus ditetapkan ke sebuah lokasi: baik ke storage maupun memory. Memodifikasi penyimpanan dalam kontrak pintar memakan biaya yang mahal, jadi Anda perlu mempertimbangkan di mana data Anda harus disimpan.
Penyimpanan
Data persisten disebut sebagai penyimpanan dan direpresentasikan oleh variabel state. Nilai-nilai ini disimpan secara permanen di rantai blok. Anda perlu mendeklarasikan tipenya agar kontrak dapat melacak berapa banyak penyimpanan di rantai blok yang dibutuhkannya saat dikompilasi.
// Contoh Solidity
contract SimpleStorage {
uint storedData; // Variabel state
// ...
}
# Contoh Vyper
storedData: int128
Jika Anda sudah pernah memprogram dengan bahasa berorientasi objek, Anda mungkin akan familier dengan sebagian besar tipenya. Namun, address mungkin baru bagi Anda jika Anda baru mengenal pengembangan Ethereum.
Tipe address dapat menampung sebuah alamat Ethereum yang setara dengan 20 bita atau 160 bit. Tipe ini mengembalikan nilai dalam notasi heksadesimal yang diawali dengan 0x.
Tipe lainnya meliputi:
- boolean
- bilangan bulat (integer)
- angka titik tetap (fixed point)
- larik bita berukuran tetap
- larik bita berukuran dinamis
- literal rasional dan bilangan bulat
- literal string
- literal heksadesimal
- enum
Untuk penjelasan lebih lanjut, lihat dokumentasinya:
Memori
Nilai yang hanya disimpan selama masa eksekusi fungsi kontrak disebut variabel memori. Karena tidak disimpan secara permanen di rantai blok, variabel ini jauh lebih murah untuk digunakan.
Pelajari lebih lanjut tentang bagaimana EVM menyimpan data (Penyimpanan, Memori, dan Tumpukan) di dokumentasi Solidity (opens in a new tab).
Variabel lingkungan
Selain variabel yang Anda definisikan pada kontrak Anda, ada beberapa variabel global khusus. Variabel ini utamanya digunakan untuk memberikan informasi tentang rantai blok atau transaksi saat ini.
Contoh:
| Properti | Variabel state | Deskripsi |
|---|---|---|
block.timestamp | uint256 | Stempel waktu Epok blok saat ini |
msg.sender | address | Pengirim pesan (panggilan saat ini) |
Fungsi
Dalam istilah yang paling sederhana, fungsi dapat mengambil informasi atau menetapkan informasi sebagai respons terhadap transaksi yang masuk.
Ada dua jenis panggilan fungsi:
internal– ini tidak membuat panggilan EVM- Fungsi internal dan variabel state hanya dapat diakses secara internal (yaitu, dari dalam kontrak saat ini atau kontrak yang diturunkan darinya)
external– ini membuat panggilan EVM- Fungsi eksternal adalah bagian dari antarmuka kontrak, yang berarti fungsi tersebut dapat dipanggil dari kontrak lain dan melalui transaksi. Fungsi eksternal
ftidak dapat dipanggil secara internal (yaitu,f()tidak berfungsi, tetapithis.f()berfungsi).
- Fungsi eksternal adalah bagian dari antarmuka kontrak, yang berarti fungsi tersebut dapat dipanggil dari kontrak lain dan melalui transaksi. Fungsi eksternal
Fungsi juga dapat bersifat public atau private
- Fungsi
publicdapat dipanggil secara internal dari dalam kontrak atau secara eksternal melalui pesan - Fungsi
privatehanya terlihat untuk kontrak tempat fungsi tersebut didefinisikan dan tidak pada kontrak turunannya
Baik fungsi maupun variabel state dapat dibuat publik atau privat
Berikut adalah fungsi untuk memperbarui variabel state pada sebuah kontrak:
// Contoh Solidity
function update_name(string value) public {
dapp_name = value;
}
- Parameter
valuebertipestringditeruskan ke dalam fungsi:update_name - Fungsi ini dideklarasikan sebagai
public, yang berarti siapa pun dapat mengaksesnya - Fungsi ini tidak dideklarasikan sebagai
view, sehingga dapat memodifikasi state kontrak
Fungsi view
Fungsi-fungsi ini menjanjikan untuk tidak memodifikasi state dari data kontrak. Contoh umumnya adalah fungsi "getter" – Anda mungkin menggunakan ini untuk menerima saldo pengguna misalnya.
// Contoh Solidity
function balanceOf(address _owner) public view returns (uint256 _balance) {
return ownerPizzaCount[_owner];
}
dappName: public(string)
@view
@public
def readName() -> string:
return dappName
Apa yang dianggap memodifikasi state:
- Menulis ke variabel state.
- Memancarkan peristiwa (opens in a new tab).
- Membuat kontrak lain (opens in a new tab).
- Menggunakan
selfdestruct. - Mengirim ether melalui panggilan.
- Memanggil fungsi apa pun yang tidak ditandai
viewataupure. - Menggunakan panggilan tingkat rendah.
- Menggunakan rakitan sebaris (inline assembly) yang berisi opcode tertentu.
Fungsi konstruktor
Fungsi constructor hanya dieksekusi sekali saat kontrak pertama kali disebarkan. Seperti constructor dalam banyak bahasa pemrograman berbasis kelas, fungsi ini sering kali menginisialisasi variabel state ke nilai yang ditentukannya.
// Contoh Solidity
// Menginisialisasi data kontrak, mengatur `owner`
// ke alamat pembuat kontrak.
constructor() public {
// Semua kontrak pintar bergantung pada transaksi eksternal untuk memicu fungsinya.
// `msg` adalah variabel global yang mencakup data relevan pada transaksi yang diberikan,
// seperti alamat pengirim dan nilai ETH yang disertakan dalam transaksi.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
owner = msg.sender;
}
# Contoh Vyper
@external
def __init__(_beneficiary: address, _bidding_time: uint256):
self.beneficiary = _beneficiary
self.auctionStart = block.timestamp
self.auctionEnd = self.auctionStart + _bidding_time
Fungsi bawaan
Selain variabel dan fungsi yang Anda definisikan pada kontrak Anda, ada beberapa fungsi bawaan khusus. Contoh yang paling jelas adalah:
address.send()– Soliditysend(address)– Vyper
Fungsi ini memungkinkan kontrak untuk mengirim ETH ke akun lain.
Menulis fungsi
Fungsi Anda membutuhkan:
- variabel dan tipe parameter (jika menerima parameter)
- deklarasi internal/eksternal
- deklarasi pure/view/payable
- tipe kembalian (jika mengembalikan sebuah nilai)
pragma solidity >=0.4.0 <=0.6.0;
contract ExampleDapp {
string dapp_name; // variabel state
// Dipanggil saat kontrak disebarkan dan menginisialisasi nilai
constructor() public {
dapp_name = "My Example dapp";
}
// Fungsi Get
function read_name() public view returns(string) {
return dapp_name;
}
// Fungsi Set
function update_name(string value) public {
dapp_name = value;
}
}
Kontrak yang lengkap mungkin terlihat seperti ini. Di sini fungsi constructor memberikan nilai awal untuk variabel dapp_name.
Peristiwa dan Log
Peristiwa memungkinkan kontrak pintar Anda untuk berkomunikasi dengan frontend Anda atau aplikasi berlangganan lainnya. Setelah sebuah transaksi divalidasi dan ditambahkan ke sebuah blok, kontrak pintar dapat memancarkan peristiwa dan informasi Log, yang kemudian dapat diproses dan dimanfaatkan oleh frontend.
Contoh beranotasi
Berikut adalah beberapa contoh yang ditulis dalam Solidity. Jika Anda ingin bermain dengan kodenya, Anda dapat berinteraksi dengannya di Remix (opens in a new tab).
Hello world
// Menentukan versi Solidity, menggunakan pembuatan versi semantik.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
pragma solidity ^0.5.10;
// Mendefinisikan kontrak bernama `HelloWorld`.
// Sebuah kontrak adalah kumpulan fungsi dan data (state-nya).
// Setelah disebarkan, sebuah kontrak berada di alamat tertentu di rantai blok Ethereum.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
contract HelloWorld {
// Mendeklarasikan variabel state `message` dengan tipe `string`.
// Variabel state adalah variabel yang nilainya disimpan secara permanen di penyimpanan kontrak.
// Kata kunci `public` membuat variabel dapat diakses dari luar kontrak
// dan membuat fungsi yang dapat dipanggil oleh kontrak atau klien lain untuk mengakses nilainya.
string public message;
// Mirip dengan banyak bahasa berorientasi objek berbasis kelas, sebuah konstruktor adalah
// fungsi khusus yang hanya dieksekusi saat pembuatan kontrak.
// Konstruktor digunakan untuk menginisialisasi data kontrak.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
constructor(string memory initMessage) public {
// Menerima argumen string `initMessage` dan mengatur nilainya
// ke dalam variabel penyimpanan `message` kontrak).
message = initMessage;
}
// Fungsi publik yang menerima argumen string
// dan memperbarui variabel penyimpanan `message`.
function update(string memory newMessage) public {
message = newMessage;
}
}
Token
pragma solidity ^0.5.10;
contract Token {
// Sebuah `address` sebanding dengan alamat email - ini digunakan untuk mengidentifikasi akun di Ethereum.
// Alamat dapat mewakili kontrak pintar atau akun (pengguna) eksternal.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
address public owner;
// Sebuah `mapping` pada dasarnya adalah struktur data tabel hash.
// `mapping` ini menetapkan bilangan bulat tak bertanda (saldo token) ke sebuah alamat (pemegang token).
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
mapping (address => uint) public balances;
// Peristiwa memungkinkan pencatatan Log aktivitas di rantai blok.
// Klien Ethereum dapat mendengarkan peristiwa untuk bereaksi terhadap perubahan state kontrak.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
event Transfer(address from, address to, uint amount);
// Menginisialisasi data kontrak, mengatur `owner`
// ke alamat pembuat kontrak.
constructor() public {
// Semua kontrak pintar bergantung pada transaksi eksternal untuk memicu fungsinya.
// `msg` adalah variabel global yang mencakup data relevan pada transaksi yang diberikan,
// seperti alamat pengirim dan nilai ETH yang disertakan dalam transaksi.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
owner = msg.sender;
}
// Membuat sejumlah token baru dan mengirimkannya ke sebuah alamat.
function mint(address receiver, uint amount) public {
// `require` adalah struktur kontrol yang digunakan untuk memaksakan kondisi tertentu.
// Jika pernyataan `require` dievaluasi menjadi `false`, pengecualian akan dipicu,
// yang mengembalikan semua perubahan yang dibuat pada state selama panggilan saat ini.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
// Hanya pemilik kontrak yang dapat memanggil fungsi ini
require(msg.sender == owner, "You are not the owner.");
// Memaksakan jumlah maksimum token
require(amount < 1e60, "Maximum issuance exceeded");
// Meningkatkan saldo `receiver` sebesar `amount`
balances[receiver] += amount;
}
// Mengirim sejumlah token yang ada dari pemanggil mana pun ke sebuah alamat.
function transfer(address receiver, uint amount) public {
// Pengirim harus memiliki cukup token untuk dikirim
require(amount <= balances[msg.sender], "Insufficient balance.");
// Menyesuaikan saldo token dari kedua alamat
balances[msg.sender] -= amount;
balances[receiver] += amount;
// Memancarkan peristiwa yang didefinisikan sebelumnya
emit Transfer(msg.sender, receiver, amount);
}
}
Aset digital unik
pragma solidity ^0.5.10;
// Mengimpor simbol dari file lain ke dalam kontrak saat ini.
// Dalam hal ini, serangkaian kontrak pembantu dari OpenZeppelin.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files
import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";
import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";
// Kata kunci `is` digunakan untuk mewarisi fungsi dan kata kunci dari kontrak eksternal.
// Dalam hal ini, `CryptoPizza` mewarisi dari kontrak `IERC721` dan `ERC165`.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance
contract CryptoPizza is IERC721, ERC165 {
// Menggunakan pustaka SafeMath dari OpenZeppelin untuk melakukan operasi aritmatika dengan aman.
// Pelajari lebih lanjut: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath
using SafeMath for uint256;
// Variabel state konstan di Solidity mirip dengan bahasa lain
// tetapi Anda harus menetapkan dari ekspresi yang konstan pada saat kompilasi.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables
uint256 constant dnaDigits = 10;
uint256 constant dnaModulus = 10 ** dnaDigits;
bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
// Tipe Struct memungkinkan Anda mendefinisikan tipe Anda sendiri
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
struct Pizza {
string name;
uint256 dna;
}
// Membuat array kosong dari struct Pizza
Pizza[] public pizzas;
// Pemetaan dari ID pizza ke alamat pemiliknya
mapping(uint256 => address) public pizzaToOwner;
// Pemetaan dari alamat pemilik ke jumlah token yang dimiliki
mapping(address => uint256) public ownerPizzaCount;
// Pemetaan dari ID token ke alamat yang disetujui
mapping(uint256 => address) pizzaApprovals;
// Anda dapat menyarangkan pemetaan, contoh ini memetakan pemilik ke persetujuan operator
mapping(address => mapping(address => bool)) private operatorApprovals;
// Fungsi internal untuk membuat Pizza acak dari string (nama) dan DNA
function _createPizza(string memory _name, uint256 _dna)
// Kata kunci `internal` berarti fungsi ini hanya terlihat
// di dalam kontrak ini dan kontrak yang diturunkan dari kontrak ini
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters
internal
// `isUnique` adalah pengubah fungsi yang memeriksa apakah pizza sudah ada
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
isUnique(_name, _dna)
{
// Menambahkan Pizza ke array Pizza dan mendapatkan id
uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
// Memeriksa bahwa pemilik Pizza sama dengan pengguna saat ini
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
// perhatikan bahwa address(0) adalah alamat nol,
// menunjukkan bahwa pizza[id] belum dialokasikan ke pengguna tertentu.
assert(pizzaToOwner[id] == address(0));
// Memetakan Pizza ke pemilik
pizzaToOwner[id] = msg.sender;
ownerPizzaCount[msg.sender] = SafeMath.add(
ownerPizzaCount[msg.sender],
1
);
}
// Membuat Pizza acak dari string (nama)
function createRandomPizza(string memory _name) public {
uint256 randDna = generateRandomDna(_name, msg.sender);
_createPizza(_name, randDna);
}
// Menghasilkan DNA acak dari string (nama) dan alamat pemilik (pembuat)
function generateRandomDna(string memory _str, address _owner)
public
// Fungsi yang ditandai sebagai `pure` berjanji untuk tidak membaca dari atau memodifikasi state
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
pure
returns (uint256)
{
// Menghasilkan uint acak dari string (nama) + alamat (pemilik)
uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +
uint256(_owner);
rand = rand % dnaModulus;
return rand;
}
// Mengembalikan array Pizza yang ditemukan oleh pemilik
function getPizzasByOwner(address _owner)
public
// Fungsi yang ditandai sebagai `view` berjanji untuk tidak memodifikasi state
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
view
returns (uint256[] memory)
{
// Menggunakan lokasi penyimpanan `memory` untuk menyimpan nilai hanya untuk
// siklus hidup panggilan fungsi ini.
// Pelajari lebih lanjut: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack
uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);
uint256 counter = 0;
for (uint256 i = 0; i < pizzas.length; i++) {
if (pizzaToOwner[i] == _owner) {
result[counter] = i;
counter++;
}
}
return result;
}
// Mentransfer Pizza dan kepemilikan ke alamat lain
function transferFrom(address _from, address _to, uint256 _pizzaId) public {
require(_from != address(0) && _to != address(0), "Invalid address.");
require(_exists(_pizzaId), "Pizza does not exist.");
require(_from != _to, "Cannot transfer to the same address.");
require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
pizzaToOwner[_pizzaId] = _to;
// Memancarkan peristiwa yang didefinisikan dalam kontrak IERC721 yang diimpor
emit Transfer(_from, _to, _pizzaId);
_clearApproval(_to, _pizzaId);
}
/**
* Mentransfer kepemilikan ID token yang diberikan dengan aman ke alamat lain
* Jika alamat target adalah kontrak, ia harus mengimplementasikan `onERC721Received`,
* yang dipanggil saat transfer aman, dan mengembalikan nilai ajaib
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
* jika tidak, transfer akan dikembalikan.
*/
function safeTransferFrom(address from, address to, uint256 pizzaId)
public
{
// solium-disable-next-line arg-overflow
this.safeTransferFrom(from, to, pizzaId, "");
}
/**
* Mentransfer kepemilikan ID token yang diberikan dengan aman ke alamat lain
* Jika alamat target adalah kontrak, ia harus mengimplementasikan `onERC721Received`,
* yang dipanggil saat transfer aman, dan mengembalikan nilai ajaib
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
* jika tidak, transfer akan dikembalikan.
*/
function safeTransferFrom(
address from,
address to,
uint256 pizzaId,
bytes memory _data
) public {
this.transferFrom(from, to, pizzaId);
require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received.");
}
/**
* Fungsi internal untuk memanggil `onERC721Received` pada alamat target
* Panggilan tidak dieksekusi jika alamat target bukan kontrak
*/
function _checkOnERC721Received(
address from,
address to,
uint256 pizzaId,
bytes memory _data
) internal returns (bool) {
if (!isContract(to)) {
return true;
}
bytes4 retval = IERC721Receiver(to).onERC721Received(
msg.sender,
from,
pizzaId,
_data
);
return (retval == _ERC721_RECEIVED);
}
// Membakar Pizza - menghancurkan token sepenuhnya
// Pengubah fungsi `external` berarti fungsi ini adalah
// bagian dari antarmuka kontrak dan kontrak lain dapat memanggilnya
function burn(uint256 _pizzaId) external {
require(msg.sender != address(0), "Invalid address.");
require(_exists(_pizzaId), "Pizza does not exist.");
require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
ownerPizzaCount[msg.sender] = SafeMath.sub(
ownerPizzaCount[msg.sender],
1
);
pizzaToOwner[_pizzaId] = address(0);
}
// Mengembalikan jumlah Pizza berdasarkan alamat
function balanceOf(address _owner) public view returns (uint256 _balance) {
return ownerPizzaCount[_owner];
}
// Mengembalikan pemilik Pizza yang ditemukan berdasarkan id
function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
address owner = pizzaToOwner[_pizzaId];
require(owner != address(0), "Invalid Pizza ID.");
return owner;
}
// Menyetujui alamat lain untuk mentransfer kepemilikan Pizza
function approve(address _to, uint256 _pizzaId) public {
require(msg.sender == pizzaToOwner[_pizzaId], "Must be the Pizza owner.");
pizzaApprovals[_pizzaId] = _to;
emit Approval(msg.sender, _to, _pizzaId);
}
// Mengembalikan alamat yang disetujui untuk Pizza tertentu
function getApproved(uint256 _pizzaId)
public
view
returns (address operator)
{
require(_exists(_pizzaId), "Pizza does not exist.");
return pizzaApprovals[_pizzaId];
}
/**
* Fungsi privat untuk menghapus persetujuan saat ini dari ID token yang diberikan
* Mengembalikan jika alamat yang diberikan memang bukan pemilik token
*/
function _clearApproval(address owner, uint256 _pizzaId) private {
require(pizzaToOwner[_pizzaId] == owner, "Must be pizza owner.");
require(_exists(_pizzaId), "Pizza does not exist.");
if (pizzaApprovals[_pizzaId] != address(0)) {
pizzaApprovals[_pizzaId] = address(0);
}
}
/*
* Mengatur atau membatalkan persetujuan dari operator yang diberikan
* Seorang operator diizinkan untuk mentransfer semua token pengirim atas nama mereka
*/
function setApprovalForAll(address to, bool approved) public {
require(to != msg.sender, "Cannot approve own address");
operatorApprovals[msg.sender][to] = approved;
emit ApprovalForAll(msg.sender, to, approved);
}
// Memberi tahu apakah seorang operator disetujui oleh pemilik yang diberikan
function isApprovedForAll(address owner, address operator)
public
view
returns (bool)
{
return operatorApprovals[owner][operator];
}
// Mengambil kepemilikan Pizza - hanya untuk pengguna yang disetujui
function takeOwnership(uint256 _pizzaId) public {
require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
address owner = this.ownerOf(_pizzaId);
this.transferFrom(owner, msg.sender, _pizzaId);
}
// Memeriksa apakah Pizza ada
function _exists(uint256 pizzaId) internal view returns (bool) {
address owner = pizzaToOwner[pizzaId];
return owner != address(0);
}
// Memeriksa apakah alamat adalah pemilik atau disetujui untuk mentransfer Pizza
function _isApprovedOrOwner(address spender, uint256 pizzaId)
internal
view
returns (bool)
{
address owner = pizzaToOwner[pizzaId];
// Nonaktifkan pemeriksaan solium karena
// https://github.com/duaraghav8/Solium/issues/175
// solium-disable-next-line operator-whitespace
return (spender == owner ||
this.getApproved(pizzaId) == spender ||
this.isApprovedForAll(owner, spender));
}
// Periksa apakah Pizza unik dan belum ada
modifier isUnique(string memory _name, uint256 _dna) {
bool result = true;
for (uint256 i = 0; i < pizzas.length; i++) {
if (
keccak256(abi.encodePacked(pizzas[i].name)) ==
keccak256(abi.encodePacked(_name)) &&
pizzas[i].dna == _dna
) {
result = false;
}
}
require(result, "Pizza with such name already exists.");
_;
}
// Mengembalikan apakah alamat target adalah kontrak
function isContract(address account) internal view returns (bool) {
uint256 size;
// Saat ini tidak ada cara yang lebih baik untuk memeriksa apakah ada kontrak di sebuah alamat
// daripada memeriksa ukuran kode di alamat tersebut.
// Lihat https://ethereum.stackexchange.com/a/14016/36603
// untuk detail lebih lanjut tentang cara kerjanya.
// TODO Periksa ini lagi sebelum rilis Serenity, karena semua alamat akan menjadi
// kontrak pada saat itu.
// solium-disable-next-line security/no-inline-assembly
assembly {
size := extcodesize(account)
}
return size > 0;
}
}
Bacaan lebih lanjut
Lihat dokumentasi Solidity dan Vyper untuk gambaran umum yang lebih lengkap tentang kontrak pintar:
Topik terkait
Tutorial terkait
- Memperkecil kontrak untuk mengatasi batas ukuran kontrak – Beberapa kiat praktis untuk mengurangi ukuran kontrak pintar Anda.
- Mencatat data Log dari kontrak pintar dengan peristiwa – Pengantar tentang peristiwa kontrak pintar dan bagaimana Anda dapat menggunakannya untuk mencatat data Log.
- Berinteraksi dengan kontrak lain dari Solidity – Cara menyebarkan kontrak pintar dari kontrak yang sudah ada dan berinteraksi dengannya.