Przejdź do głównej zawartości
Change page

ERC-721 – standard tokenów niewymiennych

Ostatnia edycja: @Beas(opens in a new tab), 19 listopada 2023

Wprowadzenie

Czym jest niewymienny token (NFT)?

Niewymienne tokeny (NFT) służą do identyfikacji czegoś lub kogoś w unikalny sposób. Ten typ tokenu jest idealny do użycia na platformach, które oferują przedmioty kolekcjonerskie, klucze dostępu, bilety loteryjne, numerowane miejsca na koncerty i mecze sportowe itp. Ten specjalny rodzaj tokena ma niesamowite możliwości, dlatego zasługuje na odpowiedni standard, ERC-721 pojawił się, aby to rozwiązać!

Co to jest ERC-721?

ERC-721 wprowadza standard dla NFT, innymi słowy ten typ tokena jest unikalny i może mieć różną wartość niż inny token z tego samego inteligentnego kontraktu, być może ze względu na jego wiek, rzadkość, a nawet coś innego, jak jego wygląd. Czekaj, wizualnie?

Tak! Wszystkie NFT mają zmienną uint256 o nazwie tokenId, więc dla każdego kontraktu ERC-721, para contract address, uint256 tokenId musi być unikatowa globalnie. Dzięki temu zdecentralizowana aplikacja może mieć „konwerter”, który używa tokenId jako danych wejściowych i wyświetla obraz czegoś fajnego, takiego jak zombie, broń, umiejętności lub niesamowite kociaki!

Warunki wstępne

  • Konta
  • Inteligentne kontrakty
  • Standardy tokenów

Treść

ERC-721 (Ethereum Request for Comments 721), zaproponowany przez Williama Entrikena, Dietera Shirleya, Jacoba Evansa, Nastassia Sachs w styczniu 2018 r. to standard tokenów niewymiennych, który implementuje interfejs API dla tokenów w ramach inteligentnych kontraktów.

Zapewnia funkcje, takie jak transfer tokenów z jednego konta na drugie, uzyskanie aktualnego salda tokenów na koncie, uzyskanie informacji o właścicielu określonego tokena, a także o całkowitej podaży tokena dostępnej w sieci. Poza tym ma również kilka innych funkcji, takich jak zatwierdzanie, że ilość tokenu z konta może być wydana przez konto osób trzecich.

Jeśli inteligentny kontrakt implementuje następujące metody i zdarzenia, można go nazwać kontraktem tokenów niewymiennych ERC-721 , a po wdrożeniu będzie odpowiedzialny za śledzenie utworzonych tokenów w Ethereum.

Od EIP-721(opens in a new tab):

Metody

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);
Pokaż wszystko
Kopiuj

Wydarzenia

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);
Kopiuj

Przykłady

Zobaczmy, dlaczego standard jest tak ważny, aby ułatwić nam sprawdza kontraktów z tokenami ERC-721 na Ethereum. Potrzebujemy tylko interfejsu binarnego Umowy (ABI), aby utworzyć interfejs dla każdego tokenu ERC-721. Jak możesz zobaczyć poniżej, użyjemy uproszczonego ABI, aby zmniejszyć złożoność przykładu.

Przykład Web3.py

Najpierw upewnij się, że zainstalowałeś Web3.py(opens in a new tab) bibliotekę Pythona:

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# To jest uproszczony interfejs ABI kontraktu ERC-721 NFT.
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.toChecksumAddress(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.sha3(text="Transfer(address,address,uint256)").hex()
83
84logs = w3.eth.getLogs({
85 "fromBlock": w3.eth.blockNumber - 120,
86 "address": w3.toChecksumAddress(ck_token_addr),
87 "topics": [event_signature]
88})
89
90# Notes:
91# - 120 blocks is the max range for CloudFlare Provider
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
95
96recent_tx = [get_event_data(tx_event_abi, log)["args"] for log in logs]
97
98kitty_id = recent_tx[0]['tokenId'] # Paste the "tokenId" here from the link above
99is_pregnant = ck_contract.functions.isPregnant(kitty_id).call()
100print(f"{name} [{symbol}] NFTs {kitty_id} is pregnant: {is_pregnant}")
Pokaż wszystko
Kopiuj

Kontrakt CryptoKitties zawiera kilka ciekawych wydarzeń poza standardowymi.

Sprawdźmy dwa z nich, Pregnant i Birth.

1# Używanie ABI zdarzeń Pregnant i Birth w celu uzyskania informacji o nowych kociakach.
2
3ck_extra_events_abi = [
4 {
5 'anonymous': False,
6 'inputs': [
7 {'indexed': False, 'name': 'owner', 'type': 'address'},
8 {'indexed': False, 'name': 'matronId', 'type': 'uint256'},
9 {'indexed': False, 'name': 'sireId', 'type': 'uint256'},
10 {'indexed': False, 'name': 'cooldownEndBlock', 'type': 'uint256'}],
11 'name': 'Pregnant',
12 'type': 'event'
13 },
14 {
15 'anonymous': False,
16 'inputs': [
17 {'indexed': False, 'name': 'owner', 'type': 'address'},
18 {'indexed': False, 'name': 'kittyId', 'type': 'uint256'},
19 {'indexed': False, 'name': 'matronId', 'type': 'uint256'},
20 {'indexed': False, 'name': 'sireId', 'type': 'uint256'},
21 {'indexed': False, 'name': 'genes', 'type': 'uint256'}],
22 'name': 'Birth',
23 'type': 'event'
24 }]
25
26# We need the event's signature to filter the logs
27ck_event_signatures = [
28 w3.sha3(text="Pregnant(address,uint256,uint256,uint256)").hex(),
29 w3.sha3(text="Birth(address,uint256,uint256,uint256,uint256)").hex(),
30]
31
32# Here is a Pregnant Event:
33# - https://etherscan.io/tx/0xc97eb514a41004acc447ac9d0d6a27ea6da305ac8b877dff37e49db42e1f8cef#eventlog
34pregnant_logs = w3.eth.getLogs({
35 "fromBlock": w3.eth.blockNumber - 120,
36 "address": w3.toChecksumAddress(ck_token_addr),
37 "topics": [ck_extra_events_abi[0]]
38})
39
40recent_pregnants = [get_event_data(ck_extra_events_abi[0], log)["args"] for log in pregnant_logs]
41
42# Here is a Birth Event:
43# - https://etherscan.io/tx/0x3978028e08a25bb4c44f7877eb3573b9644309c044bf087e335397f16356340a
44birth_logs = w3.eth.getLogs({
45 "fromBlock": w3.eth.blockNumber - 120,
46 "address": w3.toChecksumAddress(ck_token_addr),
47 "topics": [ck_extra_events_abi[1]]
48})
49
50recent_births = [get_event_data(ck_extra_events_abi[1], log)["args"] for log in birth_logs]
Pokaż wszystko
Kopiuj

Dalsza lektura

Czy ten artykuł był pomocny?