استاندارد توکن ERC-721 چیست و چگونه یک توکن ساده بسازیم؟

ما در این مقاله به بررسی استاندارد توکن ERC-721 ، عدم قابلیت جایگزینی و ساخت یک توکن ERC-721 ساده می پردازیم.

توکن ERC-721 چیست؟

استاندارد توکن ERC-721 استاندارد توکن اتریوم است که توکن های غیر قابل جایگزین (NFTs) را بر روی بلاک چین اتریوم مقدور می کند. درست مانند استاندارد توکن ERC-20 که به ایجاد توکن های قابل جایگزین کمک می کند، ERC-721 متمرکز بر طراحی دارایی غیر قابل جایگزینی می باشد. آیا CryptoKitties را به یاد دارید؟ این بازی یک توکن غیر قابل جایگزینی است یعنی هر دارایی Kitty یا همان گربه شما منحصر به فرد است.

قابلیت جایگزینی (Fungibility)

قبل از درک عدم قابلیت جایگزینی، لازم است قابلیت جایگزینی را درک کنیم. دو ویژگی اصلی برای قابلیت جایگزینی وجود دارد:

۱- قابلیت معاوضه: شما می توانید به معاوضه یا جابجایی واحد های یک دارایی قابل جایگزینی بپردازید. اسکناس ۲۰ دلاری شما و اسکناس ۲۰ دلاری من یک چیز را ارائه می دهند و می توان آنها را با هم معاوضه کرد. به عنوان یک مثال دیگر می توانیم بگوییم که یک کیلوگرم شمش طلا برابر با یک کیلوگرم دیگر شمش طلا می باشد. آنها ارزش مشابهی را ارائه می دهند و می توانند با همدیگر معاوضه شوند.

۲- مقدار: شما می توانید به ادغام واحد های یک دارایی قابل جایگزینی بپردازید تا به ارزش بالاتری در کمیت و مقدار دست یابید. به عنوان مثال شما می توانید تعداد زیادی غلات را با هم جمع کنید و حالا شما همان چیز را دارید اما با تعداد و کمیت بالاتری.

عدم قابلیت جایگزینی (nonfungibility

ERC-721

یک توکن غیر قابل جایگزینی ارائه دهنده توکن منحصر به فردی است که نمی توان آن را با توکن دیگری معاوضه کرد. در اینجا شما نمی توانید برای رسیدن به کمیت بالاتر به تقسیم و یا جمع کردن بپردازید زیرا هر واحد منحصر به فرد است و نمی توان آن را با دارایی های دیگر جابجا یا معاوضه کرد. به عنوان مثال دو قطعه زمین را در نظر بگیرید، آنها هر دو با توجه به موقعیتی که دارند غیر قابل جایگزین می باشند.

مثالی از توکن های غیر قابل جایگزین

توکن های غیر قابل جایگزین زیادی وجود دارند. تعدادی از مشهورترین آنها CryptoKitties، Etheremons، Crypto Bots و Blockchain Cuties می باشند. می توانید لیست کاملی از توکن های ERC-721 را از طریق این لینک بررسی کنید.

استاندارد ERC-721

حال اجازه دهید به بررسی عمیق استاندارد ERC-721 بپردازیم. این استاندارد مجموعه ای از روش ها را تعریف می کند که به شناسایی و تعامل با یک توکن غیر قابل جایگزین کمک می کنند.

رویداد ها (Events)

رویداد هایی هستند که در انتقال و تایید ها صادر می شوند.

عملکرد های ERC-721

balanceOf: موجودی یک آدرس را برخواهد گرداند.

ownerOf: آدرس مالک یک توکن را برخواهد گرداند.

safeTransferFrom: انتقال توکن از یک آدرس به آدرس دیگر با بررسی های انجام شده به منظور اطمینان حاصل کردن از این که گیرنده می تواند توکن را بپذیرد، پس توکن منهدم و یا گم نمی شود.

transferFrom: انتقال توکن از یک آدرس به آدرس دیگر (استفاده از این عملکرد توصیه نمی شود). دعوت کننده این روش مسئول گذاشتن آدرس گیرنده صحیح می باشد.

Approve: به تصویب هر آدرس دیگری برای ارسال یک تراکنش از اکانت مالک توکن به اکانت دیگر می پردازد.

setApprovalForAll: به یک اپراتور (هر آدرسی، اکثرا کیف پول ها و صرافی ها) اجازه می دهد و یا گاها اجازه نمی دهد که به ارسال همه توکن ها از آدرس مالک به یک آدرس دیگر بپردازد.

getApproved: آدرسی را برمی گرداند که مجاز به انتقال توکن برای مالکان می باشد. اگر آدرسی تنظیم نشده باشد ۰ را برمی گرداند.

isApprovedForAll: اگر اپراتور مورد نظر (هر آدرسی) توسط مالک مورد نظر تایید شود، True (درست) را برمی گرداند.

pragma solidity ^0.4.20;interface ERC721 /* is ERC165 */ {event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);function balanceOf(address _owner) external view returns (uint256);function ownerOf(uint256 _tokenId) external view returns (address);function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;function transferFrom(address _from, address _to, uint256 _tokenId) external payable;function approve(address _approved, uint256 _tokenId) external payable;function setApprovalForAll(address _operator, bool _approved) external;function getApproved(uint256 _tokenId) external view returns (address);function isApprovedForAll(address _owner, address _operator) external view returns (bool);}

ساخت یک توکن ERC-721 با استفاده از OpenZeppelin و Truffle

حال اجازه دهید با استفاده از کتابخانه OpenZeppelin و Truffle یک توکن ERC-721 بسازیم. ابتدا به سازمان دادن Truffle می پردازیم:

mkdir simple
truffle init
npm install openzeppelin-solidity

اجازه دهید قرارداد جدیدی برای توکن نمونه خود ایجاد کنیم:

pragma solidity ^0.4.24;import “/openzeppelin-solidity/contracts/token/ERC721/ERC721Full.sol”;
import “/openzeppelin-solidity/contracts/ownership/Ownable.sol”;contract SIMPLEToken is ERC721Full, Ownable{

constructor()
ERC721Full(“SIMPLE”, “SMPL”)
public {}function mint(address to, uint256 tokenId) public onlyOwner {
_mint(to, tokenId);
}function _mint(address to) public onlyOwner{
mint(to, totalSupply().add(1));
}}

 

اجازه دهید ببینیم که ما در اینجا داریم چه کار می کنیم. ما در حال دریافت دو قرارداد ERC721FULL و Ownable هستیم.

Ownable

با استفاده از این قرارداد، ما می توانیم به مدیریت مالکیت قراردادمان بپردازیم و تنها قادر به ایجاد توکن ها از اکانت مالک قرارداد خواهیم بود.

ERC721FULL

این پیاده سازی استاندارد سطح کاربری ERC-721 می باشد که در بالا ذکر شد. اجازه دهید ببینیم که در داخل این قرارداد چه چیزی روی می دهد:

pragma solidity ^0.4.24;import “./ERC721.sol”;
import “./ERC721Enumerable.sol”;
import “./ERC721Metadata.sol”;
contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata {
constructor(string name, string symbol) ERC721Metadata(name, symbol)
public
{
}
}

 

ERC721FULL در داخل خود ۳ قرارداد را دریافت می کند. ما اساسا به ERC721 نگاه می کنیم تا این پیاده سازی را درک کنیم.

اجازه دهید مرحله به مرحله از عملکرد اصلی گذر کنیم. قبل از آن باید درک کنیم که توکن ها چگونه ذخیره می شوند:

// Mapping from token ID to owner
mapping (uint256 => address) private _tokenOwner;// Mapping from token ID to approved address
mapping (uint256 => address) private _tokenApprovals;// Mapping from owner to number of owned token
mapping (address => uint256) private _ownedTokensCount;// Mapping from owner to operator approvals
mapping (address => mapping (address => bool)) private _operatorApprovals;

 

_tokenOwner: این طراحی برای ذخیره یک توکن در برابر مالک خود مورد نیاز است. با استفاده از این می دانیم که مالک یک tokenId کیست.

_tokenApprovals: این طراحی برای ذخیره tokenId در برابر آدرسی که توسط مالک توکن تصویب شده مورد نیاز می باشد و با استفاده از آن، توکن برای مالک انتقال داده می شود.

_ownedTokenCount: این طراحی برای دانستن تعداد توکن هایی که یک آدرس مالک آن است مورد نیاز می باشد. اگر این طراحی را ایجاد نکنید، مجبور به تشکیل حلقه برای دسترسی به این اطلاعات هستیم و این تشکیل حلقه نیاز به gas زیادی در EVM دارد.

_operatorApprovals: طراحی یک مالک و اپراتور برای بررسی این است که آیا مالک تایید شده است یا نه.

حال اجازه دهید به بررسی عملکرد ها در این استاندارد بپردازیم:

balanceOf: این موجودی یک آدرس را برخواهد گرداند. ابتدا آن در جستجوی یک آدرس معتبر می باشد و سپس از _ownedTokensCountاستفاده می کند تا شمار توکن را برگرداند.

function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0));
return _ownedTokensCount[owner];
}

OwnerOf: این آدرس مالک را برای یک توکن مورد نظر با استفاده از طراحی _tokenOwner  برمی گرداند.

function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _tokenOwner[tokenId];
require(owner != address(0));
return owner;
}

Approve: این یک آدرس را برای انتقال توکن به خاطر مالک تصویب خواهد کرد. این عملکرد ابتدا بررسی می کند که آیا مالک عملکرد را دعوت کرده و یا آیا این دعوت توسط مالک برای ارسال همه توکن ها تایید شده است. سپس اگر همه چیز صحیح باشد، طراحی _tokenApprovals را به روز رسانی می کند.

function approve(address to, uint256 tokenId) public {
address owner = ownerOf(tokenId);
require(to != owner);
require(msg.sender == owner || isApprovedForAll(owner, msg.sender));_tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}

 

safeTransferFrom: دو عملکرد وجود دارد که نام های مشابهی دارند اما بحث های آنها متفاوت است. این عملکرد ها به صورت داخلی عملکرد transferfrom نامیده می شوند. آنها همچنین یک وظیفه مهم تر را اجرا می کنند. آنها بررسی می کنند تا ببینند که آیا آدرس گیرنده برای دریافت توکن معتبر است یا نه. این به امنیت توکن کمک می کند.

function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes _data
)
public
{
transferFrom(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data));
}

transferFrom: این عملکرد اصلی برای انتقال یک توکن از یک آدرس به آدرس دیگر است. اجازه دهید ببینیم که این عملکرد چه چیزی انجام می دهد:

۱- بررسی می کند که آیا توکن توسط called به مالکیت درآمده و یا به caller یا دعوت کننده  approved شده است. همچنین به بررسی اعتبار آدرس می پردازد.

۲- تصویب واضح، برداشتن مالکیت حال حاضر و کاهش شمار توکن مالک حال حاضر.

۳- اضافه کردن توکن به یک اکانت گیرنده و افزایش شمار توکن برای گیرنده.

function transferFrom(
address from,
address to,
uint256 tokenId
)
public
{
require(_isApprovedOrOwner(msg.sender, tokenId));
require(to != address(0));_clearApproval(from, tokenId);
_removeTokenFrom(from, tokenId);
_addTokenTo(to, tokenId);emit Transfer(from, to, tokenId);
}

 

setApprovalForAll: این عملکرد آدرس را برای انتقال همه توکن ها به خاطر مالک تایید می کند. آن ابتدا بررسی می کند که آدرس called و to مشابه نباشند و سپس طراحی _operatorApprovalsرا به روز رسانی می کند.

function setApprovalForAll(address to, bool approved) public {
require(to != msg.sender);
_operatorApprovals[msg.sender][to] = approved;
emit ApprovalForAll(msg.sender, to, approved);
}

isApprovedForAll: این عملکرد بررسی می کند که آیا owner، operator را برای انتقال توکن ها تایید کرده است یا نه.

function isApprovedForAll(
address owner,
address operator
)
public
view
returns (bool)
{
return _operatorApprovals[owner][operator];
}

getApproved: آدرس تصویب شده برای tokenId مورد نظر را برمی گرداند.

function getApproved(uint256 tokenId) public view returns (address) {
require(_exists(tokenId));
return _tokenApprovals[tokenId];
}

شما می توانید به بررسی دیگر عملکرد های کمک کننده و قرارداد های دریافت شده بپردازید.

امتحان کردن توکن ERC-721

حال به امتحان و بررسی توکن نمونه خود می پردازیم. ما از یک بلاک چین محلی تعبیه شده در داخل برای نصب و تست قرارداد استفاده می کنیم.

truffle develop

این میز فرمان  Truffle را برای ما فراهم می کند.

حال به نصب قرارداد می پردازیم. به یاد داشته باشید که لازم است یک فایل migration اضافه کنیم. در انتهای مقاله می توانید به بررسی مخزن GitHub پیوست شده بپردازید.

truffle compile
migrate –reset
SIMPLEToken.deployed().then((simple) => {token = simple;})

حال اجازه دهید تعدادی توکن ایجاد کنیم و یک تست انتقال و تایید را انجام دهیم.

oken._mint(web3.eth.accounts[0]) // will mint a new tokentoken.totalSupply() // check token’s total supplytoken.safeTransferFrom(web3.eth.accounts[0] , web3.eth.accounts[1], 1) // transfer token (token id 1) from 0’th account to 1st accounttoken.ownerOf(1) // check owner of token id 1token._mint(web3.eth.accounts[0]) // will mint another tokentoken.approve(web3.eth.accounts[3] , 2) // approve token id 2 to  account[3]token.safeTransferFrom(web3.eth.accounts[0] , web3.eth.accounts[1], 2 , {from:web3.eth.accounts[3]})   // Note that we are adding {from:web3.eth.accounts[3]}, this mean that we are invoking this function using account[3]

 

شما می توانید به تست همه روش ها بپردازید (openZeppelin کتابخانه ای است که به خوبی تست شده است و بنابراین لازم نیست نگران عملکردی باشید که توسط کتابخانه فراهم شده است). شما باید در عوض متمرکز بر تست هر عملکردی باشید که توسط شما اضافه شده است.

نتیجه گیری

امروز ما با استفاده از Solidity بر روی اتریوم یک توکن غیر قابل جایگزین را ایجاد کردیم. این توکن ها اکثرا به عنوان چیز های باارزش برای جمع آوری مورد استفاده قرار می گیرند و گستره ای از کاربرد های دیگر مانند املاک و مستغلات، کار هنری، گواهی نامه ها، وام ها و غیره را دارا می باشند. یک استفاده برجسته دیگر این توکن ها در صنعت بازی می باشد که در این پلتفرم ها می تواند مورد استفاده قرار بگیرد. این واقعا هیجان برانگیز است.


54321
امتیاز 5 از 2 رای

منبع medium
ممکن است شما دوست داشته باشید

ارسال نظر

  اشتراک  
اطلاع از
عضویت در کانال تلگرام میهن بلاکچین