ERC-721 — NFT & aset unik
Sertifikat tanah, tiket bernomor kursi, karya seni digital — semuanya butuh representasi yang beda dari saldo token biasa. ERC-721 menambahkan satu konsep yang tidak ada di ERC-20: identitas per unit.
Intisari
- ERC-721 adalah token non-fungible — tiap
tokenIdunik dan punya pemiliknya sendiri, dilacak lewatownerOf(tokenId), bukanbalanceOfsaja. safeTransferFrommemeriksa penerima (kalau kontrak) mengimplementasikanonERC721Received— mencegah NFT terkirim ke kontrak yang tidak siap menerimanya dan terkunci selamanya.tokenURI(tokenId)menunjuk ke metadata (biasanya JSON di IPFS) — nama, gambar, atribut. Metadata tidak tersimpan on-chain karena terlalu mahal.- Cocok untuk representasi aset yang secara alami satuan: sertifikat kepemilikan tanah, tiket bernomor, sertifikat audit kustodian.
ERC721Enumerablemenambah kemampuan mendaftar semua tokenId milik satu pemilik — tapi menambah biaya gas signifikan tiap mint/transfer; pertimbangkan apakah kamu benar-benar butuh on-chain, atau cukup diindeks di backend (Fase 3).
Beda konsep dari ERC-20
| ERC-20 | ERC-721 | |
|---|---|---|
| Unit dasar | Jumlah (integer, bisa dipecah) | tokenId (integer, tapi tidak bisa dipecah) |
| Kepemilikan dilacak lewat | balanceOf(address) → uint256 | ownerOf(tokenId) → address |
| Dua unit bisa identik? | Ya, seluruhnya identik | Tidak — tiap tokenId berbeda |
| Analog dunia nyata | Saldo rekening | Nomor sertifikat/nomor kursi |
Implementasi dasar
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract SertifikatTanah is ERC721, Ownable {
uint256 private _idBerikutnya;
constructor(address admin) ERC721("Sertifikat Tanah", "STANAH") Ownable(admin) {}
function terbitkan(address pemilik, string memory metadataURI) external onlyOwner returns (uint256) {
uint256 id = _idBerikutnya++;
_safeMint(pemilik, id);
_setTokenURI(id, metadataURI); // perlu extension ERC721URIStorage
return id;
}
}
transferFrom vs safeTransferFrom
Selalu pakai safeTransferFrom, kecuali kamu tahu persis kenapa tidak.
transferFrom polos akan memindahkan NFT ke kontrak apa pun tanpa pengecekan apakah
kontrak itu tahu cara menerima NFT. Kalau kontrak tujuan tidak punya logika untuk memindahkannya lagi,
NFT itu terkunci di sana selamanya — tidak ada mekanisme pemulihan. safeTransferFrom
mewajibkan kontrak penerima mengimplementasikan onERC721Received yang mengonfirmasi ia siap
menerima, sebelum transfer benar-benar terjadi.
Metadata: kenapa tidak disimpan on-chain
{
"name": "Sertifikat Tanah #42",
"description": "Bidang 500m2, Blok C, Desa Sukamaju",
"image": "ipfs://bafybeigdyrzt.../gambar.png",
"attributes": [
{ "trait_type": "Luas (m2)", "value": 500 },
{ "trait_type": "Zona", "value": "Pemukiman" }
]
}
tokenURI(id) mengembalikan tautan ke JSON ini, bukan isinya langsung. Menyimpan gambar
atau deskripsi panjang di storage EVM akan berharga puluhan hingga ratusan juta gas — mustahil secara
ekonomi. Pola standarnya: gambar dan metadata di IPFS (konten diverifikasi lewat hash, tidak bisa diubah
diam-diam), hanya tautan pendeknya yang tersimpan on-chain.
Kapan ERC-721 adalah pilihan yang tepat untuk RWA
| Aset | Standar yang cocok | Alasan |
|---|---|---|
| Emas batangan (bisa dipecah nilainya) | ERC-20 | Fungible — 1 gram emas identik dengan 1 gram emas lain |
| Sertifikat tanah satu bidang spesifik | ERC-721 | Non-fungible — bidang A tidak bisa dipertukarkan dengan bidang B |
| Saham perusahaan (fungible per kelas) | ERC-20 varian (lihat ERC-3643 berikutnya) | Fungible dalam satu kelas saham, tapi butuh kepatuhan KYC |
Latihan: deploy SertifikatTanah, terbitkan dua token ke dua alamat berbeda, lalu
panggil tokenURI() untuk masing-masing dan buka JSON hasilnya (pakai data URI
sederhana untuk latihan, bukan IPFS sungguhan). Verifikasi ownerOf(0) dan
ownerOf(1) mengembalikan dua address yang berbeda.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.