Menyelami Soulbound Token (EIP-4671) Lebih Dalam
Dua tahun terakhir, animo masyarakat web3 terhadap NFT telah tumbuh secara dramatis. Alasan yang mendasarinya cukup beragam, tetapi ini bukan aspek yang ingin saya perdalam dalam artikel ini. Intinya, semakin banyak orang yang familiar dengan konsep NFT.
NFT dapat mewakili kepemilikan atas aset digital atau fisik dan cocok diaplikasikan ke dalam beberapa aspek atau aktivitas seperti pemberian hak akses ekslusif, keanggotaan, meningkatkan engagement, gamifikasi, dan tokenisasi aset riil sebagaimana yang telah disebutkan dalam artikel sebelumnya (Klasifikasi Utilitas NFT).
NFT yang kita kenal sehari-hari dan seperti yang telah disebutkan penggunaannya (meski berbeda utilitasnya) memiliki satu kesamaan yang fundamental. Dalam skenario ini, NFT selalu merepresentasikan barang atau token yang dapat diperdagangkan, yakni bahwa NFT tersebut dapat dijual oleh pemiliknya atau dipindahtangankan ke pemilik lain (bisa ditransfer).
Akan tetapi, pada Januari 2022 lalu muncul konsep yang berbeda dengan NFT yang kita kenal biasanya. Omar Aflak pada proposal Ethereum: EIP-4671 – Non-Tradable Tokens Standard menuturkan:
“…non-tradable tokens … don’t have monetary value, they are personally delivered to you, and they only serve as a proof of possession/achievement”
“… token yang tidak dapat diperdagangkan… tidak memiliki nilai moneter, token tersebut dikirimkan secara pribadi kepada Anda, dan hanya berfungsi sebagai bukti kepemilikan/pencapaian”
Non-Tradable Tokens (NTT) atau yang lebih dikenal dengan branding SoulBound Token (SBT) oleh Vitalik Buterin dalam blognya, seperti namanya, Soul Bound atau terikat jiwa, berarti token ini akan selalu terikat pada pemiliknya dan tidak bisa berpindah kepemilikan ke orang lain. Sebenarnya Non-Tradable Tokens bukan gagasan baru, pada 2018 Nicola Greco, Vitalik Buterin, dkk dengan ERC-1238 telah membuat proposal terkait ide ini, namun tidak berlanjut dan pada akhirnya muncul EIP-4671
Motivasi di balik NTT atau SBT ini adalah untuk mengakomodir implementasi NFT yang seharusnya tidak diperdagangkan/dipindahtangankan. Sebagaimana contohnya, ketika itu mewakili aset pribadi yang intrinsik (materi maupun immateri), seperti ijazah, sertifikat pelatihan, dokumen yang dikeluarkan pemerintah (KTP, SIM, Paspor, buku nikah, dll.), bukti kehadiran, dan sebagainya. NFT, sebagaimana yang beredar pada umumnya, hanya menggambarkan bahwa teknologi blockchain hanya berguna untuk memupuk kekayaan, SBT hadir sebagai upaya yang bertujuan untuk memberikan manfaat yang lebih berarti terhadap teknologi Blockchain. Implementasi SBT dalam aspek kehidupan seperti dunia pendidikan dan sebagainya telah disebutkan dalam artikel ISCHAIN sebelumnya yang berjudul Mengenal Soulbound Token.
Bagaimana Cara Kerja SoulBound Token?
Bagaimanapun, kami (ISCHAIN) penasaran untuk membedah implementasi referensi EIP-4671 ini (yang saat ini masih dalam status draf, dan mungkin akan selalu ada perubahan hingga dinyatakan final). Lantas bagaimana cara kerja SBT jika token ini tidak dapat diperdagangkan? Mari kita bedah smart contract-nya dan silakan coba buat SBT Anda sendiri untuk memahami alur kontrak dari SBT.
Kontrak SBT dianggap mewakili satu jenis sertifikat yang diserahkan oleh satu otoritas ke satu pemilik (satu wallet address). Pilihannya di sini adalah dengan mempersempit standar ERC721 dan mengesampingkan metode transfer agar tidak melakukan fungsi apapun yang berkaitan dengan transer, jadi ini adalah interface IERC4671.
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IERC4671 is IERC165 {
/// Event emitted when a token `tokenId` is minted for `owner`
event Minted(address owner, uint256 tokenId);
/// Event emitted when token `tokenId` of `owner` is revoked
event Revoked(address owner, uint256 tokenId);
/// @notice Count all tokens assigned to an owner
/// @param owner Address for whom to query the balance
/// @return Number of tokens owned by `owner`
function balanceOf(address owner) external view returns (uint256);
/// @notice Get owner of a token
/// @param tokenId Identifier of the token
/// @return Address of the owner of `tokenId`
function ownerOf(uint256 tokenId) external view returns (address);
/// @notice Check if a token hasn't been revoked
/// @param tokenId Identifier of the token
/// @return True if the token is valid, false otherwise
function isValid(uint256 tokenId) external view returns (bool);
/// @notice Check if an address owns a valid token in the contract
/// @param owner Address for whom to check the ownership
/// @return True if `owner` has a valid token, false otherwise
function hasValid(address owner) external view returns (bool);
}
Interface dasarnya cukup sederhana dan tidak terlalu mirip dengan NFT karena hanya menampilkan fungsi paling dasar yang dibutuhkan NTT:
- Minted dan Revoked: token hanya bisa di-minting dan di-revoke oleh pemilik token. Me-revoke atau mencabut token bukan berarti menghapus token, melainkan membuat token tersebut menjadi tidak valid lagi dalam kontrak. Konsepnya sama seperti pencabutan SIM atau buku nikah, token tidak terhapus namun tidak valid lagi dalam kontrak, catatan akan menunjukkan bahwa Anda pernah memiliki token dari kontrak tersebut.
- balanceOf dan ownerOf: mirip dengan interface ERC-721 untuk melihat jumlah saldo token dan pemilik token, tapi fungsinya lebih kepada pengelolaan pencabutan/revoke token pemilik
- isValid: untuk memeriksa apakah token belum dicabut/revoke
- hasValid: untuk memeriksa apakah wallet address tertentu memiliki token yang valid dalam kontrak
Sebagaimana yang telah dijelaskan sebelumnya, kontrak SBT dianggap mewakili satu jenis sertifikat yang diserahkan oleh satu otoritas ke satu pemilik (satu wallet address). Sehingga penggunaan Soul Bound Token ini akan lebih cocok jika digunakan oleh sebuah otoritas tertentu atau pihak ketiga yang memiliki hak untuk menerbitkan dan mencabut dokumen yang bersifat privat. Oleh karenanya, dalam proposal SBT, dibuat juga beberapa ekstensi untuk mendukung implementasi SBT ini seperti yang dijelaskan pada laman EIP-4671:
IERC4671Metadata
: memungkinkan untuk menambahkan metadata yang ditautkan ke setiap token dan persis sama dengan metadata pada IERC721
IERC4671Enumerable
:
memungkinkan penghitungan token pemilik (sangat mirip dengan IERC721Enumerable)
IERC4671Delegate
: memungkinkan hak delegasi pencetakan (minting) token oleh pihak lain
IERC4671Consensus
: memungkinkan pencetakan/pencabutan token berdasarkan konsensus berdasarkan sekumpulan wallet address yang telah ditentukan sebelumnya
IERC4671Pull
: memungkinkan minting dari website pemilik token (pihak pertama) ke wallet pemohon (pihak kedua), di dalam kontrak harus menyediakan tanda tangan yang valid (tokenId, pemilik, penerima).
Official code untuk semua interface ERC4671 untuk SBT, dan cara mengimplementasikan SBT ini, dapat ditemukan di halaman Github Ethereum di sini dan di halaman Github Omar Aflak di sini. Kami belum bisa mengimplementasikan SBT dengan IERC4671 di artikel ini, namun kami telah mencoba membuat “Soul Bound Token” dengan memodifikasi ERC721 yang statusnya sudah final kemudian menyesuaikannya dengan logika Soul Bound Token, yakni tidak transferable dan tidak tradable.
ISCHAIN Soul Bound Token, deploy dan minting di Goerli Testnet
Panduan Membuat dan Mendeploy SBT Smart Contract
Dalam artikel ini, kita akan belajar:
- 1.Membuat smart contract Soul Bound Token (Non-Transferable NFT) di Solidity, menggunakan OpenZeppelin Wizard dan Remix IDE;
- 2.Men-deploy smart contract di Ethereum Goerli Testnet; dan
- 3.Minting dan menampilkan token di Opensea atau marketplace lain (yang mendukung Goerli)
Langkah 1: Menulis Smart Contract NFT (ERC-721)
Sebelum menerapkan logika non-transferable dalam smart contract-nya, tulis dahulu kode dasar ERC-721 untuk NFT. Untuk memulai, silakan menuju ke OpenZeppelin Wizard, pilih “ERC721” sebagai jenis kontrak kita dan memilih beberapa fitur seperti “Mintable”, “Auto-increment IDs” dan “Base URI” dari sidebar seperti yang ditunjukkan.
Base URI
: semacam database (bisa HTTPS/IPFS, biasanya berupa link URL) yang akan di gabung denganuri
untuk menghasilkantokenURI
sebagai tempat menyimpan metadata pada token/NFT Untuk mengisiBase URI
maka perlu membuat dahulu aset NFT nya dan mengunggahnya ke IPFS, dalam hal ini kami menggunakan Pinata. Upload file gambar yang akan ditampilkan sebagai NFT dengan mengklik tombol Upload -> File Untuk melihat gambar yang telah diupload, bisa dengan cara mengklik nama file yang telah diupload. Berikut gambar yang kami gunakan. Kemudian buat folder berisi file teks dengan isi metadata dari NFT nya, seperti berikut:
{
"description" : "Demo minting token soulbound by ISCHAIN",
"image" : "https://gateway.pinata.cloud/ipfs/QmYPcXHEa2ebsTq2x6EsZcTyT8ndWE9MWZmsdegLcJf2yf",
"name" : "Soulbound Token"
}
- –
description
diisi dengan deskripsi tokennya - –
image
diisi dengan link gambar yang telah diupload di Pinata - –
name
diisi dengan nama tokennya
Kemudian simpan file dengan nama berformat string tanpa ekstensi file apapun, misal kita beri nama 1, berikut tampilan kami untuk folder dan file teks di atas: Folder ISBT, berisi file 1 Kembali ke Pinata, kemudian upload folder berisi file teks yang telah dibuat ke Pinata dengan menekan tombol Upload -> Folder. Setelah folder terupload, buka link foldernya dengan mengklik 2 kali folder yang terupload, maka akan terbuka seperti ini: Copy link URL folder yang terupload di Pinata tadi sebagai Base URI
Mintable
: digunakan untuk membuat function safeMint
yang berfungsi agar kita bisa minting melalui kontrak.
Auto Increment Ids:
token baru yang diminting selanjutnya akan otomatis tergenerate tokenId
nya
Ownable
: mekanisme sederhana untuk menggambarkan kepemilikan token
Langkah 2: Modifikasi Kode, Sesuaikan dengan Logika Soul Bound Token
Sekarang kita sudah menyiapkan kode dasarnya, saatnya menuju ke Remix Solidity Compiler dengan mengklik tombol “Open in Remix” (masih pada laman Open Zeppelin Wizard). Ketika sudah masuk ke Remix, maka akan tampil kode berikut:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts@4.7.0/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts@4.7.0/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts@4.7.0/access/Ownable.sol";
import "@openzeppelin/contracts@4.7.0/utils/Counters.sol";
contract ISCHAINSoulboundToken is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("ISCHAIN Soulbound Token", "ISBT") {}
function _baseURI() internal pure override returns (string memory) {
return "https://gateway.pinata.cloud/ipfs/QmYXoBeiRmQkPwFCy2sfwwotVJ1JK86FL1tKoPg3w7H8Pm/";
}
function safeMint(address to, string memory uri) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
}
Sekarang mari kita lanjutkan dengan menambahkan kode baru ke smart contract yang ada agar kita dapat memblokir transfer NFT dan akhirnya menjadikannya “Soul Bound”. Sudah ada API di kontrak ERC721 OpenZeppelin, yang dengannya kita dapat mengontrol transferabilitas token kita. Tambahkan kode berikut di bawah function tokenURI:
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
)internal override virtual {
require(from == address(0), "Err: token transfer is BLOCKED");
super._beforeTokenTransfer(from, to, tokenId);
}
Sekarang mari kita pahami logika di balik kode ini. Setiap kali kode ini dijalankan, pernyataan wajib akan memeriksa: jika parameter from address
dalam fungsi diset ke 0 (nol) -> address from == 0
yang artinya token telah dicetak/minted. Jika ya atau nilainya true
, maka akan memicu tindakan untuk memblokir semua transfer lainnya untuk menjadikannya token yang tidak dapat ditransfer atau dijual.
Langkah 3: Deploy Smart Contract
Untuk mendeploy smart contract langsung dari Remix, buka sidebar dan pilih “Deploy and Run Transaction” dari tab. Atur Environment ke Injected Web3, pilih smart contract Soulbound yang baru saja kita buat dari dropdown contract dan klik Deploy.
- Injected Provider – Provider Name: Untuk menghubungkan Remix ke penyedia web3 yang disuntikkan. Penyedia injeksi yang paling umum adalah Metamask Wallet.
Pastikan MetaMask Anda terhubung ke Ethereum Goerli Testnet dan terisi saldo Goerl iETH yang cukup untuk gas fee transaksi deploy. Untuk mendapatkan faucet Goerli ETH bisa ke laman berikut atau laman penyedia faucet lainnya.
Langkah 4: Minting Soul Bound NFT
Pada langkah ini, akhirnya kita akan membuat NFT dan menampilkannya di Opensea atau marketplace lainnya. Untuk mencetak/minting NFT, kembali ke Remix IDE, cari tombol “Deployed Contract”, dan klik fungsi "safeMint"
.
Pada fungsi safeMint
, input wallet address Anda ke kolom to: dan isikan kolom uri: dengan angka 1. Angka 1 ini merujuk pada nama file teks metadata NFT yang telah dibuat sebelumnya. Sehingga saat NFT di-mint akan menghasilkan tokenURI
yang berupa gabungan dari base URI
dan URI
, yakni seperti berikut:
https://gateway.pinata.cloud/ipfs/QmYXoBeiRmQkPwFCy2sfwwotVJ1JK86FL1tKoPg3w7H8Pm/1
Setelah konfigurasi sudah sesuai tekan Transact, konfirmasi transaksi pada wallet Metamask dan tunggu beberapa detik hingga NFT dicetak. Kemudian buka Opensea Testnet atau Goerli Looksrare untuk melihat apakah NFT berhasil diminting. Berikut tampilan Soul Bound ISCHAIN yang berhasil diminting:
https://testnets.opensea.io/assets/goerli/0x126e2ce1e0a8a83cc9a01510b646bf28f33da761/1
https://goerli.looksrare.org/collections/0x126e2CE1E0A8A83CC9a01510b646BF28f33da761/0
Langkah 5: Uji Transferabilitas NFT
Untuk memastikan apakah NFT yang telah kita buat sebelumnya sudah menjadi Soul Bound, maka kita bsia mengujinya dengan mencoba mentransfer atau menjual NFT tersebut ke orang lain. Jika benar Soul Bound maka ketika kita mencoba mentransfer atau memindahtangankan NFT nya makan akan muncul peringatan bahwa transaksi tertolak seperti berikut:
Uji Transfer
NFT bisa dilisting dan diberi harga di Opensea, namun ketika ada orang lain yang ingin membelinya maka transaksi akan tertolak
Dengan cara ini, dapat dikonfirmasi bahwa NFT yang baru saja dibuat sekarang terikat pada satu wallet address saja dan tidak akan pernah dapat ditransfer atau dijual kepada orang lain.
Penutup
Soul Bound Token terlihat mirip dengan NFT. SBT dapat menyimpan informasi dan metadata, serta berasal dari satu smart contract. Namun, SBT tidak dapat ditransfer atau diperdagangkan. Yang perlu jadi perhatian pada Soul Bound adalah aspek keamanannya. Jika SBT ini benar-benar akan diimplementasikan untuk keperluan yang sifatnya privat, maka perlu ada perhatian khusus pada salah satu aspek keamanan terkait dengan metode tokenURI yang mengembalikan metadata yang ditautkan ke token. Karena standar mewakili kepemilikan pribadi yang bersifat privat dan internal, pengguna mungkin perlu mengenkripsi data yang ditautkan pada SBT, misal jika digunakan sebagai Kartu Identitas, Paspor, dan sejenisnya. Selain itu, pembuat kontrak bertanggung jawab untuk memastikan URI yang dikembalikan dengan metode ini tersedia setiap saat.
Standar pada EIP-4671 tidak menentukan cara untuk mentransfer token dari satu wallet ke wallet lainnya. Oleh karena itu, pengguna harus sangat berhati-hati dengan wallet yang mereka gunakan untuk menerima token ini. Jika wallet hilang/dihack, satu-satunya cara untuk mendapatkan token kembali adalah otoritas penerbit harus membuat token yang hilang menjadi invalid dan mengirimkan tokennya lagi, seperti di kehidupan nyata.
Untuk saat ini, menurut hemat saya pribadi (-penulis), SBT dapat menjadi cara baru untuk memberi penghargaan kepada pengguna di dalam komunitas atas pekerjaan, capaian, atau prestasi yang telah mereka lakukan terhadap komunitas atau sebagai bukti keanggotaan. Mirip dengan airdrop NFT yang saat ini berlangsung di banyak komunitas. Kami pikir sangat bagus jika SBT dapat ditampilkan di profil Anda melalui OpenSea atau website pribadi untuk memperkaya dan mengotentikasi portofolio atau CV Anda.
Sumber/Referensi:
https://github.com/omaraflak/ERC4671 https://vitalik.ca/general/2022/01/26/soulbound.html https://github.com/ethereum/EIPs/issues/1238