ERC-721 Padrão de token não-fungível
Última edição: @junowoz(opens in a new tab), 19 de novembro de 2023
Introdução
O que é um token não fungível (NFT)?
Um token não fungível (NFT) é utilizado para identificar algo ou alguém de uma forma única. Este tipo de token é perfeito para ser usado em plataformas que oferecem itens colecionáveis, acessar chaves, bilhetes de loteria, assentos numerados para concertos, jogos esportivos etc. Este tipo especial de token tem possibilidades incríveis, então merece um padrão adequado, o ERC-721!
O que é ERC-721?
O ERC-721 apresenta um padrão para NFT. Em outras palavras, este tipo de token é único e pode ter um valor diferente do que outro token do mesmo contrato inteligente, talvez devido a sua validade, raridade ou mesmo sua aparência. Um momento, aparência?
Sim! Todos os NFTs têm uma variável uint256
chamada tokenId
, então para qualquer contrato ERC-721, o par contract address, uint256 tokenId
deve ser globalmente único. Dito isso, um dApp pode ter um "conversor" que usa o tokenId
como entrada e retorna uma imagem de algo legal, como zumbis, armas, habilidades ou gatinhos incríveis!
Pré-requisitos
Apresentação
O ERC-721(Ethereum Request for Comments 721), proposto por William Entriken, Dieter Shirley, Jacob Evans e Nastassia Sachs em janeiro de 2018, é um padrão de token não-fungível que implementa uma API para tokens em contratos inteligentes.
Oferece funcionalidades, como transferir tokens de uma conta para outra, para obter o saldo atual do token de uma conta e também a oferta total do token disponível na rede. Além disso, ele também tem algumas outras funcionalidades como aprovar que uma quantidade de token de uma conta pode ser gasta por uma conta de terceiros.
Se um contrato inteligente implementa os métodos e eventos a seguir, ele pode ser chamado de Contrato de token ERC-721 e, uma vez implantado, é responsável por fazer um acompanhamento dos tokens criados no Ethereum.
De EIP-721(opens in a new tab):
Métodos
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);Exibir tudoCopiar
Eventos
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);Copiar
Exemplos
Vejamos por que um padrão é importante e como ele simplifica o controle de qualquer contrato de token ERC-721 no Ethereum. Só precisamos da Interface Binária de Aplicativos (ABI, pela sigla em inglês) do contrato para criar uma interface com qualquer token ERC-721. Como você pode ver abaixo, usaremos uma ABI simplificada, para torná-la um exemplo de fácil compreensão.
Exemplo Web3.py
Primeiro, certifique-se de que você instalou a biblioteca Web3.py(opens in a new tab) do Python:
1pip install web3
1from web3 import Web32from web3._utils.events import get_event_data345w3 = Web3(Web3.HTTPProvider("https://cloudflare-eth.com"))67ck_token_addr = "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d" # CryptoKitties Contract89acc_address = "0xb1690C08E213a35Ed9bAb7B318DE14420FB57d8C" # CryptoKitties Sales Auction1011# This is a simplified Contract Application Binary Interface (ABI) of an ERC-721 NFT Contract.12# Serão expostos apenas os métodos: 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': True19 },20 {21 'inputs': [],22 'name': 'name',23 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}],24 'stateMutability': 'view', 'type': 'function', 'constant': True25 },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': True31 },32 {33 'inputs': [],34 'name': 'symbol',35 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}],36 'stateMutability': 'view', 'type': 'function', 'constant': True37 },38 {39 'inputs': [],40 'name': 'totalSupply',41 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}],42 'stateMutability': 'view', 'type': 'function', 'constant': True43 },44]4546ck_extra_abi = [47 {48 'inputs': [],49 'name': 'pregnantKitties',50 'outputs': [{'name': '', 'type': 'uint256'}],51 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True52 },53 {54 'inputs': [{'name': '_kittyId', 'type': 'uint256'}],55 'name': 'isPregnant',56 'outputs': [{'name': '', 'type': 'bool'}],57 'payable': False, 'stateMutability': 'view', 'type': 'function', 'constant': True58 }59]6061ck_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}")6667pregnant_kitties = ck_contract.functions.pregnantKitties().call()68print(f"{name} [{symbol}] NFTs Pregnants: {pregnant_kitties}")6970# Usando o Evento de Transferência ABI para obter informações sobre os Kitties transferidos.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}8081# We need the event's signature to filter the logs82event_signature = w3.sha3(text="Transfer(address,address,uint256)").hex()8384logs = w3.eth.getLogs({85 "fromBlock": w3.eth.blockNumber - 120,86 "address": w3.toChecksumAddress(ck_token_addr),87 "topics": [event_signature]88})8990# Notes:91# - 120 blocks is the max range for CloudFlare Provider92# - If you didn't find any Transfer event you can also try to get a tokenId at:93# https://etherscan.io/address/0x06012c8cf97BEaD5deAe237070F9587f8E7A266d#events94# Click to expand the event's logs and copy its "tokenId" argument9596recent_tx = [get_event_data(w3.codec, tx_event_abi, log)["args"] for log in logs]9798kitty_id = recent_tx[0]['tokenId'] # Paste the "tokenId" here from the link above99is_pregnant = ck_contract.functions.isPregnant(kitty_id).call()100print(f"{name} [{symbol}] NFTs {kitty_id} is pregnant: {is_pregnant}")Exibir tudoCopiar
Contrato de CriptoKitties tem alguns eventos interessantes além dos padrões.
Vamos ver dois deles, Pregnant
e Birth
.
1# Usando o Evento ABI "Gravidez e Nascimento" para obter informações sobre os novos 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 }]2425# We need the event's signature to filter the logs26ck_event_signatures = [27 w3.sha3(text="Pregnant(address,uint256,uint256,uint256)").hex(),28 w3.sha3(text="Birth(address,uint256,uint256,uint256,uint256)").hex(),29]3031# Here is a Pregnant Event:32# - https://etherscan.io/tx/0xc97eb514a41004acc447ac9d0d6a27ea6da305ac8b877dff37e49db42e1f8cef#eventlog33pregnant_logs = w3.eth.getLogs({34 "fromBlock": w3.eth.blockNumber - 120,35 "address": w3.toChecksumAddress(ck_token_addr),36 "topics": [ck_event_signatures[0]]37})3839recent_pregnants = [get_event_data(w3.codec, ck_extra_events_abi[0], log)["args"] for log in pregnant_logs]4041# Here is a Birth Event:42# - https://etherscan.io/tx/0x3978028e08a25bb4c44f7877eb3573b9644309c044bf087e335397f16356340a43birth_logs = w3.eth.getLogs({44 "fromBlock": w3.eth.blockNumber - 120,45 "address": w3.toChecksumAddress(ck_token_addr),46 "topics": [ck_event_signatures[1]]47})4849recent_births = [get_event_data(w3.codec, ck_extra_events_abi[1], log)["args"] for log in birth_logs]Exibir tudoCopiar
NFTs populares
- Etherscan NFT Tracker(opens in a new tab) lista o maior NFT no Ethereum por volume de transferências.
- CryptoKitties(opens in a new tab) é um jogo centrado em criaturas de coleção adoráveis que chamamos de CryptoKitties.
- Sorare(opens in a new tab) é um jogo global de fantasia em que você pode coletar edições limitadas, gerenciar suas equipes e concorrer para ganhar prêmios.
- Ethereum Name Service (ENS)(opens in a new tab) oferece uma forma segura e descentralizada de endereçar os recursos dentro e fora da blockchain usando nomes legíveis simples.
- POAP(opens in a new tab) oferece NFTs grátis para pessoas que participam de eventos ou realizam ações específicas. Os POAPs são livres para criar e distribuir.
- Unstoppable Domains(opens in a new tab) é uma empresa com sede em São Francisco que cria domínios em blockchains. Os domínios de blockchain substituem endereços de criptomoeda por nomes legíveis e podem ser usados para habilitar sites resistentes à censura.
- Gods Unchained Cards(opens in a new tab) é uma TCG na blockchain Ethereum que usa NFT para representar a propriedade real nos ativos do jogo.
- Bored Ape Yacht Club(opens in a new tab) é uma coleção de 10.000 NFT exclusivos que, além de ser uma peça de arte comprovadamente eclética, atua como um token de adesão ao clube, oferecendo vantagens e benefícios aos membros, que aumentam ao longo do tempo como resultado dos esforços da comunidade.