Sumário
- Como criar seu NFT na Blockchain Ethereum
- Distinguindo entre tokens Fungíveis e Não Fungíveis
- Tokens Fungíveis: Fungibilidade e Quantidade
- Tokens não fungíveis: Não-fungibilidade e Quantidade
- Padrão ERC-721
- As Funções são:
- Criação de um Token ERC-721 - NFT - com OpenZeppelin e Truffle
- Conclusão
Como criar seu NFT na Blockchain Ethereum
NFT é um termo acrônimo para "Non-fungible tokens" (tokens não fungíveis). Um NFT é um ativo digital único e especial que não é fungível - inigualável e incomparável. Os NFTs são únicos e não fungíveis porque cada NFT tem uma propriedade ou característica especial ou rara que não está presente em outros NFTs. Esta característica de raridade se aplica a todos os NFTs. Ele é bloqueado em um contrato inteligente; é por isso que ele é normalmente criado ou cunhado em blockchains que têm um contrato inteligente. Uma dessas blockchains é a Ethereum.
A blockchain Ethereum é descentralizada, sem permissão, com a função adicional de um contrato inteligente. Os contratos inteligentes são condições ou termos de acordo pré-definidos incorporados em códigos de programação que se auto-executam uma vez que as condições pré-definidas tenham sido cumpridas. Um dos vários casos de uso de um contrato inteligente em uma determinada blockchain se estende a permitir que outros tokens sejam construídos ou criados na blockchain. É por isso que a Ethereum pode abrigar outros tokens que estão sendo lançados em seu ecossistema. Tais tokens podem ser fungíveis ERC-20 ou não fungíveis ERC-721.
Distinguindo entre tokens Fungíveis e Não Fungíveis
Os tokens fungíveis e não fungíveis podem ser diferenciados por duas características distintas: permutabilidade - fungibilidade - e valor - quantidade.
Tokens Fungíveis: Fungibilidade e Quantidade
Fungibilidade ou permutabilidade é a capacidade de trocar ou substituir ativos por outros. Por exemplo, Kelly e George receberam notas separadas de 100 dólares de seu tio. Como ambas as notas representam o mesmo valor, elas podem ser trocadas enquanto ainda mantêm seu respectivo valor. Isso é fungibilidade!
Agora imagine se Kelly e George concordassem em juntar seu dinheiro para comprar um ingresso de cinema para dois.
O dinheiro total deles agora é de 200 dólares, certo?
Quantidade ou quantidade de tokens fungíveis podem ser adicionadas para ter uma quantia maior enquanto ainda têm o dinheiro.
Os tokens ERC-20 são os tokens fungíveis que podem ser trocados por sua espécie ou por outro token equivalente. O padrão de tokens ERC-20 é explorado para a criação de tokens fungíveis. Exemplos de tokens ERC-20 incluem ETH, BNB, DAI, USDT, e USDC, entre outros.
Tokens não fungíveis: Não-fungibilidade e Quantidade
Um token não-fungível - NFT - é um token único que não pode ser trocado por outro token. Da mesma forma, você não pode somar NFTs para obter uma quantidade superior ou maior. Como não se pode trocar um sofá por um caixote do lixo, também não se pode substituir um NFT por outro porque cada um tem suas propriedades incomparáveis.
O padrão de token Ethereum que permite a criação de NFTs na blockchain Ethereum é o padrão de token ERC-721. Os tokens ERC-721 são tokens não fungíveis que não podem ser trocados por outro, ou seja, um determinado NFT não pode ser trocado por outro NFT mesmo que ambos os NFTs fossem de uma coleção de um único criador. Exemplos de tokens não-fungíveis são Cryptopunks, Bored Ape, e Cryptokitties.
Padrão ERC-721
O padrão ERC-721 aplica um conjunto de mecanismos para reconhecimento e envolvimento com os Tokens Não Fungíveis. O mecanismo envolve três camadas: Núcleo, Extensões e Conveniência.
As EIPs - Propostas de Melhoria Ethereum - têm três interfaces; IERC721, IERC721Metadata, e IERCEnumerable. Para que um contrato seja compatível com o ERC721, apenas o IERC721 é necessário. Entretanto, todas elas são implementadas no ERC721.
O IERC é a interface do contrato do token, enquanto o ERC é a implementação do contrato do token. A interface IERC tem dois subconjuntos que são:
- Eventos
- Funções
A categoria eventos inclui Transfer, Approval, and ApprovalForAll.
As Funções são:
balanceOf
: Fornece o saldo dos NFTs na conta do proprietário
ownerOf
: Fornece o endereço do proprietário - da identificação do token fornecido
safeTransferFrom
: Transfere um determinado NFT de um endereço para outro tendo verificado e se certificado de que o endereço do destinatário pode aceitar o NFT para que não seja perdido ou queimado, enviando-o para o endereço.
transferFrom
: Transfere o NFT de um endereço para outro - não é recomendado utilizar esta função. Se o endereço do destinatário não for do endereço aprovado, ele deverá ser aprovado por meio da função aprove ou da função SetApprovalForAll.
approve
: Aprova qualquer outro endereço para enviar NFT do endereço do proprietário para qualquer outro endereço aprovado.
setApprovalForAll
: Permite ou impede um operador - qualquer endereço, principalmente carteiras e exchanges - de enviar NFTs do endereço do proprietário para qualquer outro endereço.
getApproved
: Devolve para os proprietários um endereço para o qual os NFTs podem ser transferidos. Se nenhum endereço for definido, devolve 0.
isApprovedForAl
l: Retorna verdadeiro se o endereço for aprovado por um proprietário específico.
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);
}
Criação de um Token ERC-721 - NFT - com OpenZeppelin e Truffle
Antes de podermos criar ou desenvolver um NFT com a biblioteca OpenZeppelin e o Truffle, precisamos primeiro configurar o Truffle:
mkdir simple
truffle init
npm install openzeppelin-solidity
Agora, vamos criar um novo contrato para nosso token:
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));
}
}
Do exposto acima, herdamos dois contratos simultaneamente; o ERC721FULL e o Ownable.
Ownable
: Com este contrato, seremos capazes de administrar a propriedade do nosso contrato e também de cunhar NFTs somente do endereço do proprietário do contrato.
ERC721FULL
: Esta é uma implementação padrão da interface ERC-721 mencionada anteriormente. Vamos dar uma olhada no interior deste contrato:
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
{
}
}
Internamente, o ERC721FULL herda 3 contratos - o ERC721, o ERC721Enumerable, e o ERC721Metadata. Vamos nos concentrar no ERC721 para entender melhor como ele funciona.
Antes de passar pela função principal uma após a outra, vamos entender como os tokens são armazenadas primeiro:
// Mapeamento do ID do token para o proprietário
mapping (uint256 => address) private _tokenOwner;
// Mapeamento do ID do token para o endereço aprovado
mapping (uint256 => address) private _tokenApprovals;
//Mapeamento do proprietário para o número de tokens possuídos
mapping (address => uint256) private _ownedTokensCount;
// Mapeamento do proprietário para as aprovações do operador
mapping (address => mapping (address => bool)) private _operatorApprovals;
_tokenOwner
: Este mapeamento é necessário para o armazenamento do token contra seu proprietário. Podemos descobrir quem possui um determinado ID de token usando isso.
_tokenApprovals
: Este mapeamento é necessário para o armazenamento do ID do token contra um endereço que tenha sido aprovado pelo proprietário do token para transferir um token em nome do proprietário.
_ownedTokenCount
: Este mapeamento é necessário para determinar o número de tokens que um endereço possui. Se este mapeamento não for criado, teremos que fazer um loop para obter esta contagem de tokens, que consome muito gas na EVM.
_operatorApprovals
: Mapeamento de um proprietário e de um operador - qualquer endereço, principalmente carteiras e trocas - para determinar se o proprietário aprovou ou não.
Agora, podemos examinar as funções
balanceOf
: Isso devolverá o saldo de um endereço. Ele verifica primeiro um endereço válido, e depois usa _ownedTokensCount
para retornar a conta do token.
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0));
return _ownedTokensCount[owner];
}
OwnerOf
: Usando o mapeamento _tokenOwner
, retornará o endereço do proprietário para um token específico
function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _tokenOwner[tokenId];
require(owner != address(0));
return owner;
}
approve: Isto autoriza um endereço para transferir um token em nome do proprietário. A função verifica inicialmente se a função foi chamada pelo proprietário ou se a chamada foi aprovada pelo proprietário para enviar todos os tokens. Se tudo estiver correto, ela atualizará o _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
: Há duas funções similares com argumentos variados. Estas funções chamam internamente a função transferFrom
que tem outra tarefa principal que elas desempenham. Elas verificam se o endereço do destinatário está ou não autorizado a receber o token. Isto contribui para a segurança do token.
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes _data
)
public
{
transferFrom(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data));
}
transferFrom
: Esta é a principal função para transferir um token de um determinado endereço para outro. Ela faz o seguinte:
- Determina se o token é de propriedade da chamada, ou aprovada pelo chamador. Ela também verifica se um endereço é válido.
- Limpa a aprovação, remove a propriedade existente e diminui a contagem de tokens do proprietário atual.
- Adiciona um token à conta do destinatário e aumenta a contagem do token do destinatário.
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
: Esta função autoriza o endereço para enviar todos os tokens em nome do proprietário. Ela verifica se os endereços called
e to
são diferentes antes de atualizar o mapeamento _operatorApprovals
.
function setApprovalForAll(address to, bool approved) public {
require(to != msg.sender);
_operatorApprovals[msg.sender][to] = approved;
emit ApprovalForAll(msg.sender, to, approved);
}
isApprovedForAll
: Essa função verifica se o owner
permitiu ou não ao operator
transferir tokens.
function isApprovedForAll(
address owner,
address operator
)
public
view
returns (bool)
{
return _operatorApprovals[owner][operator];
}
getApproved
: Retorna o endereço aprovado para um certo ID de token.
function getApproved(uint256 tokenId) public view returns (address) {
require(_exists(tokenId));
return _tokenApprovals[tokenId];
}
Conclusão
Nós apenas usamos a Solidity na Ethereum para criar um Token Não Fungível. Os NFTs servem principalmente como colecionáveis, mas também podem ser usados para representar imóveis, obras de arte, certificações e empréstimos, entre outras coisas. Os NFTs são usados como itens e coleções em jogos, metaverso, e outras plataformas.
Não é divertido?
Esse artigo foi escrito por Abubakar Maruf O. e traduzido por Fátima Lima. Seu original pode ser lido aqui.
Abrace a oportunidade de elevar sua jornada de desenvolvimento para um nível superior. A criação de NFTs é apenas o começo; os builds incríveis da WEB3DEV representam a chave de entrada para o emocionante cenário web3. 🚀🧑💻
Não perca tempo, 👉inscreva-se👈 agora mesmo e comece a desbravar o universo Blockchain!
Seja também WEB3DEV!
Oldest comments (0)