پرش به محتوای اصلی
Change page

ERC-721 استاندارد توکن تعویض ناپذیر

آخرین ویرایش: @nader.sedigh(opens in a new tab), ۲۸ آبان ۱۴۰۲

معرفی

توکن تعویض ناپذیر چیست؟

از یک توکن تعویض ناپذیر (NFT) برای شناسایی چیزی یا شخصی به روشی منحصر به فرد استفاده می شود. این نوع توکن برای استفاده در پلتفرم هایی که آیتم های کلکسیونی، کلیدهای دسترسی، بلیط های بخت آزمایی، صندلی های شماره دار دارند و همچنین برای کنسرت ها و مسابقات ورزشی و غیره مناسب می باشد. این نوع خاص از توکن دارای امکانات شگفت انگیزی است، بنابراین سزاوار استانداردی مناسب است، بنابراین ERC-721 برای حل آن آمده است!

ERC-721 چیست؟

ERC-721 استانداردی را برای NFT معرفی می کند، به عبارت دیگر، شاید به دلیل قدمت، کمیاب بودن یا حتی چیز دیگری همچون ظاهر آن، این نوع توکن منحصر به فرد است و می تواند ارزش متفاوتی نسبت به توکن دیگری از همان قرارداد هوشمند را داشته باشد. صبر کنید، ظاهر؟

بله! همه NFT ها دارای یک متغیر uint256 به نام tokenId هستند، بنابراین برای هر قرارداد ERC-721، جفت contract address، uint256 tokenId باید در سطح جهانی یکتا باشد. گفته می شود، یک dapp می تواند یک "مبدل" داشته باشد که از tokenId به عنوان ورودی استفاده می کند و تصویری از چیز جالبی مانند زامبی ها، سلاح ها، مهارت ها یا بچه گربه های شگفت انگیز را خروجی می دهد!

پیش نیاز ها

  • حساب ها
  • ↳ قرارداد‌های هوشمند
  • استانداردهای توکن

Body

ERC-721 (درخواست اتریوم برای نظرات 721)، که توسط ویلیام انتریکن، دیتر شرلی، جیکوب ایوانز، ناستاسیا ساکس در ژانویه 2018 پیشنهاد شد، یک استاندارد توکن تعویض ناپذیر است که یک API برای توکن‌ها در قراردادهای هوشمند پیاده‌سازی می‌کند.

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

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

از EIP-721(opens in a new tab):

روشها

1 function balanceOf(address _owner) external view returns (uint256);
2 function ownerOf(uint256 _tokenId) external view returns (address);
3 function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
4 function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
5 function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
6 function approve(address _approved, uint256 _tokenId) external payable;
7 function setApprovalForAll(address _operator, bool _approved) external;
8 function getApproved(uint256 _tokenId) external view returns (address);
9 function isApprovedForAll(address _owner, address _operator) external view returns (bool);
نمایش همه
کپی

رویدادها

1 event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
2 event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
3 event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
کپی

مثال‌ها

بیایید ببینیم یک استاندارد چقدر مهم است که کار ما را برای بررسی قراردادهای هوشمند ERC-721 آسان می‌کند. ما فقط به رابط دوتایی برنامه قرارداد (ABI) برای ایجاد یک رابط برای هر توکن ERC-721 نیاز داریم. همانطور که در زیر می بینید ما از یک ABI ساده شده استفاده می کنیم تا آن را به عنوان مثالی با اصطکاک کم تبدیل کنیم.

مثال Web3.py

ابتدا مطمئن شوید که کتابخانه پایتون Web3.py(opens in a new tab) را نصب کرده اید:

1pip install web3
1from web3 import Web3
2from web3._utils.events import get_event_data
3
4
5w3 = Web3(Web3.HTTPProvider("https://cloudflare-eth.com"))
6
7ck_token_addr = "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d" # CryptoKitties Contract
8
9acc_address = "0xb1690C08E213a35Ed9bAb7B318DE14420FB57d8C" # CryptoKitties Sales Auction
10
11# This is a simplified Contract Application Binary Interface (ABI) of an ERC-721 NFT Contract.
12# It will expose only the methods: balanceOf(address), name(), ownerOf(tokenId), symbol(), totalSupply()
13simplified_abi = [
14 {
15 'inputs': [{'internalType': 'address', 'name': 'owner', 'type': 'address'}],
16 'name': 'balanceOf',
17 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}],
18 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True
19 },
20 {
21 'inputs': [],
22 'name': 'name',
23 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}],
24 'stateMutability': 'view', 'type': 'function', 'constant': True
25 },
26 {
27 'inputs': [{'internalType': 'uint256', 'name': 'tokenId', 'type': 'uint256'}],
28 'name': 'ownerOf',
29 'outputs': [{'internalType': 'address', 'name': '', 'type': 'address'}],
30 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True
31 },
32 {
33 'inputs': [],
34 'name': 'symbol',
35 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}],
36 'stateMutability': 'view', 'type': 'function', 'constant': True
37 },
38 {
39 'inputs': [],
40 'name': 'totalSupply',
41 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}],
42 'stateMutability': 'view', 'type': 'function', 'constant': True
43 },
44]
45
46ck_extra_abi = [
47 {
48 'inputs': [],
49 'name': 'pregnantKitties',
50 'outputs': [{'name': '', 'type': 'uint256'}],
51 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True
52 },
53 {
54 'inputs': [{'name': '_kittyId', 'type': 'uint256'}],
55 'name': 'isPregnant',
56 'outputs': [{'name': '', 'type': 'bool'}],
57 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True
58 }
59]
60
61ck_contract = w3.eth.contract(address=w3.to_checksum_address(ck_token_addr), abi=simplified_abi+ck_extra_abi)
62name = ck_contract.functions.name().call()
63symbol = ck_contract.functions.symbol().call()
64kitties_auctions = ck_contract.functions.balanceOf(acc_address).call()
65print(f"{name} [{symbol}] NFTs in Auctions: {kitties_auctions}")
66
67pregnant_kitties = ck_contract.functions.pregnantKitties().call()
68print(f"{name} [{symbol}] NFTs Pregnants: {pregnant_kitties}")
69
70# Using the Transfer Event ABI to get info about transferred Kitties.
71tx_event_abi = {
72 'anonymous': False,
73 'inputs': [
74 {'indexed': False, 'name': 'from', 'type': 'address'},
75 {'indexed': False, 'name': 'to', 'type': 'address'},
76 {'indexed': False, 'name': 'tokenId', 'type': 'uint256'}],
77 'name': 'Transfer',
78 'type': 'event'
79}
80
81# We need the event's signature to filter the logs
82event_signature = w3.keccak(text="Transfer(address,address,uint256)").hex()
83
84logs = w3.eth.get_logs({
85 "fromBlock": w3.eth.block_number - 120,
86 "address": w3.to_checksum_address(ck_token_addr),
87 "topics": [event_signature]
88})
89
90# Notes:
91# - Increase the number of blocks up from 120 if no Transfer event is returned.
92# - If you didn't find any Transfer event you can also try to get a tokenId at:
93# https://etherscan.io/address/0x06012c8cf97BEaD5deAe237070F9587f8E7A266d#events
94# Click to expand the event's logs and copy its "tokenId" argument
95recent_tx = [get_event_data(w3.codec, tx_event_abi, log)["args"] for log in logs]
96
97if recent_tx:
98 kitty_id = recent_tx[0]['tokenId'] # Paste the "tokenId" here from the link above
99 is_pregnant = ck_contract.functions.isPregnant(kitty_id).call()
100 print(f"{name} [{symbol}] NFTs {kitty_id} is pregnant: {is_pregnant}")
نمایش همه
کپی

قرارداد CryptoKitties دارای رویدادهای جالبی به غیر از موارد استاندارد است.

بیایید دو مورد از آنها، حامله و تولد را بررسی کنیم.

1# Using the Pregnant and Birth Events ABI to get info about new Kitties.
2ck_extra_events_abi = [
3 {
4 'anonymous': False,
5 'inputs': [
6 {'indexed': False, 'name': 'owner', 'type': 'address'},
7 {'indexed': False, 'name': 'matronId', 'type': 'uint256'},
8 {'indexed': False, 'name': 'sireId', 'type': 'uint256'},
9 {'indexed': False, 'name': 'cooldownEndBlock', 'type': 'uint256'}],
10 'name': 'Pregnant',
11 'type': 'event'
12 },
13 {
14 'anonymous': False,
15 'inputs': [
16 {'indexed': False, 'name': 'owner', 'type': 'address'},
17 {'indexed': False, 'name': 'kittyId', 'type': 'uint256'},
18 {'indexed': False, 'name': 'matronId', 'type': 'uint256'},
19 {'indexed': False, 'name': 'sireId', 'type': 'uint256'},
20 {'indexed': False, 'name': 'genes', 'type': 'uint256'}],
21 'name': 'Birth',
22 'type': 'event'
23 }]
24
25# We need the event's signature to filter the logs
26ck_event_signatures = [
27 w3.keccak(text="Pregnant(address,uint256,uint256,uint256)").hex(),
28 w3.keccak(text="Birth(address,uint256,uint256,uint256,uint256)").hex(),
29]
30
31# Here is a Pregnant Event:
32# - https://etherscan.io/tx/0xc97eb514a41004acc447ac9d0d6a27ea6da305ac8b877dff37e49db42e1f8cef#eventlog
33pregnant_logs = w3.eth.get_logs({
34 "fromBlock": w3.eth.block_number - 120,
35 "address": w3.to_checksum_address(ck_token_addr),
36 "topics": [ck_event_signatures[0]]
37})
38
39recent_pregnants = [get_event_data(w3.codec, ck_extra_events_abi[0], log)["args"] for log in pregnant_logs]
40
41# Here is a Birth Event:
42# - https://etherscan.io/tx/0x3978028e08a25bb4c44f7877eb3573b9644309c044bf087e335397f16356340a
43birth_logs = w3.eth.get_logs({
44 "fromBlock": w3.eth.block_number - 120,
45 "address": w3.to_checksum_address(ck_token_addr),
46 "topics": [ck_event_signatures[1]]
47})
48
49recent_births = [get_event_data(w3.codec, ck_extra_events_abi[1], log)["args"] for log in birth_logs]
نمایش همه
کپی

بیشتر بخوانید

آیا این مقاله مفید بود؟