Artigo original: https://www.freecodecamp.org/news/how-to-make-an-nft-and-render-on-opensea-marketplace/

Neste artigo, eu vou mostrar para você como fazer um NFT sem nenhuma habilidade em engenharia de software. Depois, vamos aprender como fazer NFTs customizáveis ilimitados com o Brownie, Python e o Chainlink (todos os links em inglês). Então, veremos como renderizar e vender nossa criação no Marketplace de NFTs da OpenSea.

Se estiver procurando por um tutorial que use o Truffle, JavaScript e alguns personagens medievais legais, dê uma olhada em como Construir, Implantar e Vender seu NFT aqui (em inglês).

O que é um NFT?

NFTs (do inglês non-fungible tokens, ou  "tokens não fungíveis") podem ser resumidos em uma palavra: "únicos".  Eles são contratos inteligentes implantados em uma blockchain que representam algo único.

ERC20 x ERC721

NFTs são tokens padrão de blockchain, similares ao ERC20 (em inglês), como AAVE, SNC e LINK (tecnicamente, um ERC677). ERC20s são tokens "fungíveis" o que significa que são "substituíveis" ou "intercambiáveis".

Por exemplo, a nota de dez reais vai valer R$ 10,00, não importando qual nota você use, desde que ela seja uma nota de dez reais. O código na nota pode até ser diferente, mas as notas são intercambiáveis e elas vão valer dez reais independentemente de outras coisas.

NFTs, por outro lado, são "não fungíveis". Eles seguem seu próprio padrão de token, o ERC721. Por exemplo, a Mona Lisa é "não fungível". Mesmo que alguém faça uma cópia dela, sempre vai haver apenas uma Mona Lisa. Se a Mona Lisa tivesse sido criada em uma blockchain, ela seria um NFT.

image-145-1
Imagem original retirada da Wikipédia

Para que serve um NFT?

NFTs agregam valor para os criadores, artistas, designers de jogos e outros por terem um histórico permanente de implantação armazenado on-chain.

Você sempre saberá quem criou o NFT, quem o comprou, de onde ele veio e mais, o que dá a eles muito valor, mais do que arte tradicional. Na arte tradicional, pode ser bem difícil discernir o que é falso, enquanto um histórico on-chain é facilmente rastreável.

Como os contratos inteligentes e os NFTs são 100% programáveis, NFTs podem também ter royalties e qualquer outra funcionalidade embutida. Recompensar os artistas sempre foi um problema, dado que um trabalho artístico geralmente é apresentado sem nenhuma atribuição, como ouvir uma música no parque.

Mais e mais artistas e engenheiros estão aproveitando desse valor agregado, porque finalmente é uma boa maneira de recompensar os artistas por seu trabalho. Mais que isso, os NFTs são maneiras divertidas de botar para quebrar com sua criatividade e se tornar um colecionador em um mundo digital.

O valor dos NFTs


Os NFTs percorreram um longo caminho e continuamos vendo recordes de vendas de NFTs, como "Everydays: The First 5.000 Days" sendo vendido por US$ 69,3 milhões.

Screen-Shot-2021-03-31-at-9.48.19-AM
Imagem retirada do Twitter

Então, existe um grande valor aqui, além de ser divertido, dinâmico e uma forma engajadora de criar arte em um mundo digital e aprender sobre criação de um contrato inteligente. Agora, eu vou ensinar a você tudo o que precisa saber sobre criar NFTs.

Como criar um NFT

O que não vamos ensinar

A maneira mais fácil de fazer um NFT é ir a uma plataforma, como a Opensea, a Rarible ou a Mintible, e seguir o seu passo a passo para a implantação na plataforma escolhida.

Você pode seguir por esse caminho. No entanto, você pode acabar ligado à plataforma de alguma forma e ficará preso na funcionalidade que a plataforma tiver. Desse modo, você não poderá alcançar a personalização ilimitada nem utilizar realmente qualquer uma das vantagens que os NFTs têm. Mas se você for um engenheiro de software principiante, ou se não for muito técnico, esse caminho servirá para você.

Se você procura se tornar um engenheiro de software melhor, aprender um pouco sobre Solidity e ter o poder de criar algo com criatividade ilimitada, siga com a leitura!

Se você é novo com Solidity, não se preocupe. Também passaremos pelo básico.

Como criar um NFT com customização Ilimitada

Vamos começar com o NFT Brownie Mix. Esse é um repositório em desenvolvimento com muito código boilerplate.

Pré-requisitos

Precisaremos de alguns programas instalados antes de começar

Se você não está familiarizado com o Metamask, você pode seguir esse tutorial (em inglês) para configurá-lo.

Estaremos trabalhando também com o Rinkeby Ethereum Testnet para realizar a implantação dos nossos contratos em uma blockchain real, de graça!

Testnets são formas excelentes de testar como os contratos se comportam no mundo real.

Precisaremos do Rinkeby ETH e do Rinkeby LINK, que conseguimos gratuitamente nos links da documentação do Chainlink (em inglês)

Também precisaremos adicionar o token do Rinkeby LINK na nossa metamask, o que podemos fazer seguindo a documentação de como conseguir o LINK (em inglês).

Se você continuar confuso, você pode usar este vídeo como guia (em inglês), apenas certifique-se de usar o Rinkerby ao invés do Ropsten.

Quando trabalhamos com uma plataforma de contratos inteligentes, como a Ethereum, precisamos pagar um pouco de ETH. Quando retiramos dados off-chain precisamos pagar com um pouco de LINK. Por este motivo, nós precisamos dos testnets Link e ETH.

Maravilha, agora vamos mergulhar. Este é o NFT que vamos implantar na OpenSea.

Screen-Shot-2021-03-31-at-10.58.35-AM

Começando

git clone https://github.com/PatrickAlphaC/nft-mix
cd nft-mix

Ótimo! Agora, precisamos instalar o ganache-cli e o eth-brownie.

pip install eth-brownie
npm install -g ganache-cli

Então, podemos configurar nossas variáveis de ambiente (em inglês). Se você não é familiarizado com variáveis de ambiente, pode apenas adicioná-las no seu arquivo .env e executar:

source .env

Deve existir um arquivo .env no repositório que você acabou de clonar com as variáveis de ambiente comentadas. Retire-as dos comentários para usá-las!

Você vai precisar de um WEB3_INFURA_PROJECT_ID e de uma PRIVATE_KEY. O WEB3_INFURA_PROJECT_ID pode ser encontrado ao se cadastrar com uma conta gratuita no Infura. Assim, teremos uma maneira de enviar as transações para a blockchain.

Também vamos precisar de uma private key, que você consegue pegar em sua Metamask. Clique nos 3 pontinhos, vá em Account Details e depois em Export Private Key. NÃO compartilhe essa chave com ninguém se você colocar dinheiro de verdade nela!

export PRIVATE_KEY=YOUR_KEY_HERE
export WEB3_INFURA_PROJECT_ID=YOUR_PROJECT_ID_HERE
.env

Agora, podemos implantar nosso contrato NFT e criar nosso primeiro colecionável com os dois comandos a seguir.

brownie run scripts/simple_collectible/deploy_simple.py --network rinkeby
brownie run scripts/simple_collectible/create_collectible.py --network rinkeby

O primeiro script implanta nosso contrato NFT na blockchain da Rinkerby, e o segundo cria nosso colecionável.

Você acabou de implantar seu primeiro contrato inteligente!

Por enquanto, ele não faz muita coisa, mas não se preocupe – vou mostrar para você como renderizá-lo na OpenSea na parte avançada desse tutorial. Mas, antes, vamos olhar para o padrão de token ERC721.

O padrão de token ERC721

Vamos dar uma olhada no contrato que acabamos de implantar no arquivo SimpleCollectible.sol.

// SPDX-License-Identifier: MIT
pragma solidity 0.6.6;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract SimpleCollectible is ERC721 {
    uint256 public tokenCounter;
    constructor () public ERC721 ("Dogie", "DOG"){
        tokenCounter = 0;
    }

    function createCollectible(string memory tokenURI) public returns (uint256) {
        uint256 newItemId = tokenCounter;
        _safeMint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenURI);
        tokenCounter = tokenCounter + 1;
        return newItemId;
    }

}

Estamos usando o pacote OpenZeppelin (em inglês) para o token ERC721. Esse pacote que importamos nos permite usar todas as funções típicas de um token ERC721. Isso define todas as funcionalidades que nossos tokens vão ter, como transfer, que move tokens para novos usuários, safeMint que cria novos tokens e mais.

Você pode encontrar todas as funções que são fornecidas ao nosso contrato lendo o Contrato de Token ERC721 OpenZeppelin. Nosso contrato herda essas funções nessa linha:

contract SimpleCollectible is ERC721 {

É assim que a Solidity trabalha com herança. Quando nós implantamos um contrato, o constructor é automaticamente chamado e recebe alguns parâmetros.

constructor () public ERC721 ("Dogie", "DOG"){
        tokenCounter = 0;
    }

Também usamos o construtor do ERC721 no nosso construtor. Temos que dar a ele um nome e um símbolo. No nosso caso, é "Dogie"e "DOG". Isso significa que todos os NFTS criados serão do tipo Dogie/DOG.

É como todos os Pokémons nas cartas de pokémons. Eles no final são pokémons, ou todo jogador de baseball nas cartas colecionáveis (trading cards) continuam jogadores de baseball. Cada jogador é único, mas eles continuam sendo jogadores de baseball. Nós estamos apenas usando o tipo DOG.

Nós temos um tokenCounter no topo que conta quantos NFTs já criamos daquele tipo. Cada novo token ganha um tokenId baseado no tokenCounter atual.

Atualmente, nós podemos criar um NFT com a função createCollectible. É ela que chamamos no nosso script create_collectible.py.

function createCollectible(string memory tokenURI) public returns (uint256) {
        uint256 newItemId = tokenCounter;
        _safeMint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenURI);
        tokenCounter = tokenCounter + 1;
        return newItemId;
    }

A função _safeMint cria o novo NFT e o atribui a quem chamou createdCollectible, também conhecido comomsg.sender, com um newItemId derivado de tokenCounter. É assim que podemos acompanhar quem é proprietário de quê, verificando o proprietário do tokenId.

Você vai perceber que também chamamos a função _setTokenURI. Vamos conversar sobre ela.

O que são metadados de NFT e tokenURI?

Quando os contratos inteligentes estavam sendo criados e os NFTs estavam sendo criados, as pessoas rapidamente perceberam que é beeeeeem caro implantar muitos dados na blockchain. Imagens pequenas de um KB podem facilmente custar mais de 1 milhão de dólares para guardar (em inglês).

Isso é claramente um problema para os NFTs, já que, ao ser o proprietário de arte criativa, você tem que guardar essa informação em algum lugar. Eles também queriam uma maneira mais leve de guardar os atributos sobre NFTs – e é aqui que  os metadados e o tokenURI entram em ação.

TokenURI

O tokenURI em um NFT é um identificador único da "aparência" daquele token. Um URI pode ser uma chamada HTTPS para uma API, um hash IPFS, ou qualquer outra coisa exclusiva.

Eles seguem um padrão de mostrar os metadados que têm essa aparência:

{
    "name": "name",
    "description": "description",
    "image": "https://ipfs.io/ipfs/QmTgqnhFBMkfT9s8PHKcdXBn1f5bG3Q5hmBaR4U6hoTvb1?filename=Chainlink_Elf.png",
    "attributes": [
        {
            "trait_type": "trait",
            "value": 100
        }
    ]
}

Eles mostram como um NFT é e seus atributos. O atributo image aponta para outro URI da aparência do NFT. Isso facilita para as plataformas de NFT como a Opensea, Rarible e Mintable renderizar NFTs nas suas plataformas, já que todos estão esperando receber esses metadados.

Metadados off-chain x metadados on-chain

Agora, você pode estar pensando "Peraí... se os metadados não estão on-chain, significa que o meu NFT pode sumir em algum momento"? E você não poderia estar mais correto.

Você também estaria correto em pensar que metadados off-chain significam que você não pode usá-los para que seus contratos inteligentes interajam um com o outro.

Esse é o motivo pelo qual nós queremos focar nos metadados on-chain, para que assim possamos programar nossos NFTs para interagir uns com os outros.

No entanto, ainda precisamos da parte da imagem (image) dos metadados off-chain, pois não temos uma maneira otimizada de armazenar imagens grandes on-chain. Mas não se preocupe. Podemos fazer isso gratuitamente em uma rede descentralizada ainda usando IPFS.

Aqui está um exemplo de um imageURI do IPFS que mostra o Chainlink Elf criado no tutorial Dungeons and Dragons (em inglês).

Screen-Shot-2021-03-31-at-12.15.22-PM
Chainlink Elf

Não definimos um tokenURI para o NFT simplesmente porque queríamos apenas mostrar um exemplo básico.
Vamos pular para o NFT avançado agora, para que possamos ver alguns dos recursos incríveis que podemos fazer com metadados on-chain, para que o NFT seja renderizado na Opensea, e colocar nosso Dogie no ar!

Se você quiser um vídeo para refrescar sua memória sobre o que acabamos de ver na seção anterior, acompanhe esse vídeo sobre a implantação de um NFT simples.

NFTs dinâmicos e avançados

NFTs dinâmicos são NFTs que podem mudar com o tempo ou ter funcionalidades on-chain que podem ser usadas para interagir umas com as outras. Esses são as NFTs que tem customizações ilimitadas. Assim, podemos criar jogos inteiros, mundos ou algum tipo de arte interativa.
Vamos nos aprofundar na parte avançada desse tutorial.

Início rápido avançado

Certifique-se de ter as testnets ETH e LINK, bem como o suficiente na sua metamask, e então execute o comando a seguir:

brownie run scripts/advanced_collectible/deploy_advanced.py --network rinkeby
brownie run scripts/advanced_collectible/create_collectible.py --network rinkeby

Nosso collectible aqui é uma reprodução de raças de cachorros aleatória retornada do Chainlink VRF (em inglês). Chainlink VRF é uma maneira de obter números aleatórios comprováveis e, portanto, realmente em falta em nossos NFTs. Em seguida, vamos criar seus metadados.

brownie run scripts/advanced_collectible/create_metadata.py --network rinkeby

Podemos, então, como opção, fazer upload desses dados para o IPFS para que possamos ter um tokenURI. Eu vou mostrar para você como fazer isso mais tarde. Por enquanto, vamos usar apenas o tokenURI de exemplo de:

https://ipfs.io/ipfs/Qmd9MCGtdVz2miNumBHDbvj8bigSgTwnr4SbyH6DNnpWdt?filename=1-PUG.json

Se você fizer o download do IPFS Companion no seu navegador, poderá usar aquele URL para ver o que o URI retorna. Ficará parecido com isso:

{
    "name": "PUG",
    "description": "An adorable PUG pup!",
    "image": "https://ipfs.io/ipfs/QmSsYRx3LpDAb1GZQm7zZ1AuHZjfbPkD6J7s9r41xu1mf8?filename=pug.png",
    "attributes": [
        {
            "trait_type": "cuteness",
            "value": 100
        }
    ]
}

Então, podemos executar nosso script set_tokenuri.py:

brownie run scripts/advanced_collectible/set_tokenuri.py --network rinkeby

Teremos, então, uma saída como esta:

Running 'scripts/advanced_collectible/set_tokenuri.py::main'...
Working on rinkeby
Transaction sent: 0x8a83a446c306d6255952880c0ca35fa420248a84ba7484c3798d8bbad421f88e
  Gas price: 1.0 gwei   Gas limit: 44601   Nonce: 354
  AdvancedCollectible.setTokenURI confirmed - Block: 8331653   Gas used: 40547 (90.91%)

Awesome! You can view your NFT at https://testnets.opensea.io/assets/0x679c5f9adC630663a6e63Fa27153B215fe021b34/0
Please give up to 20 minutes, and hit the "refresh metadata" button

E podemos clicar no link que nos foi dado para ver como ficou no Opensea! Talvez você tenha que clicar no botão refresh metadata e esperar alguns minutos.

Screen-Shot-2021-03-31-at-12.33.42-PM
Atualizar os metadados

As raças aleatórias

Vamos falar sobre o que acabamos de fazer. Aqui está nossa AdvancedCollectible.sol:

pragma solidity 0.6.6;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";

contract AdvancedCollectible is ERC721, VRFConsumerBase {
    uint256 public tokenCounter;
    enum Breed{PUG, SHIBA_INU, BRENARD}
    // add other things
    mapping(bytes32 => address) public requestIdToSender;
    mapping(bytes32 => string) public requestIdToTokenURI;
    mapping(uint256 => Breed) public tokenIdToBreed;
    mapping(bytes32 => uint256) public requestIdToTokenId;
    event requestedCollectible(bytes32 indexed requestId); 


    bytes32 internal keyHash;
    uint256 internal fee;
    uint256 public randomResult;
    constructor(address _VRFCoordinator, address _LinkToken, bytes32 _keyhash)
    public 
    VRFConsumerBase(_VRFCoordinator, _LinkToken)
    ERC721("Dogie", "DOG")
    {
        tokenCounter = 0;
        keyHash = _keyhash;
        fee = 0.1 * 10 ** 18;
    }

    function createCollectible(string memory tokenURI, uint256 userProvidedSeed) 
        public returns (bytes32){
            bytes32 requestId = requestRandomness(keyHash, fee, userProvidedSeed);
            requestIdToSender[requestId] = msg.sender;
            requestIdToTokenURI[requestId] = tokenURI;
            emit requestedCollectible(requestId);
    }

    function fulfillRandomness(bytes32 requestId, uint256 randomNumber) internal override {
        address dogOwner = requestIdToSender[requestId];
        string memory tokenURI = requestIdToTokenURI[requestId];
        uint256 newItemId = tokenCounter;
        _safeMint(dogOwner, newItemId);
        _setTokenURI(newItemId, tokenURI);
        Breed breed = Breed(randomNumber % 3); 
        tokenIdToBreed[newItemId] = breed;
        requestIdToTokenId[requestId] = newItemId;
        tokenCounter = tokenCounter + 1;
    }

    function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );
        _setTokenURI(tokenId, _tokenURI);
    }
}

Usamos o Chainlink VRF para criar uma raça aleatória de uma lista de PUG, SHIBA_INU, BERNARD. Quando chamamos a createCollectible desta vez, na verdade ,iniciamos uma solicitação para o nó Chainlink VRF off-chain e retornamos com um número aleatório para criar o NFT com uma dessas 3 raças.

Usar aleatoriedade verdadeira em seus NFTs é uma ótima maneira de criar escassez verdadeira e usar um número aleatório do oráculo Chainlink significa que seu número é comprovadamente aleatório, não podendo ser influenciado pelos mineradores.

Você pode aprender mais sobre isso na documentação do Chainlink VRF(em inglês).

O nó Chainlink responde chamando a função fulfillRandomness e cria o collectible com base no número aleatório. Ainda temos que chamar _setTokenURI para dar ao nosso NFT a aparência que ele precisa.

Nós não demos nossos atributos do NFT aqui, mas os atributos são uma ótima maneira de fazer com que nossos NFTs batalhem e interajam. Você pode ver um ótimo exemplo de NFTs com atributos neste exemplo de Dungeons and Dragons (em inglês).

Metadados do IPFS

Estamos usando o IPFS para guardar dois arquivos:

  1. A imagem do NFT (a imagem do pug)
  2. O arquivo tokenURI (o arquivo JSON que também inclui o link da imagem)

Nós usamos o IPFS por ser uma plataforma grátis e descentralizada. Também podemos adicionar nossos tokenURIs e imagens no IPFS fazendo download do IPFS desktop (em inglês), clicando no botão import.

Screen-Shot-2021-03-31-at-12.43.13-PM
Adicione um arquivo IFPS

Agora, podemos compartilhar o URI clicando nos três pontos ao lado do arquivo que queremos compartilhar, clicando em share link e copiando o link fornecido. Podemos adicionar esse link no nosso arquivo set_tokenuri.py para mudar o URI do token que queremos usar.

Persistência

No entanto, se o tokenURI estiver apenas em nosso node, isso significa que, quando nosso node estiver inativo, ninguém mais poderá visualizá-lo. Então, queremos que outros façam o pin do nosso NFT. Podemos usar um serviço que realiza o pin como o Pinata para ajudar a manter nossos dados ativos mesmo quando nosso node no IPFS estiver inativo.

Imagino que, no futuro, mais e mais metadados serão armazenados em IPFS e plataformas de armazenamento serão descentralizadas. Servidores centralizados podem ficar inativos, e isso significaria que a arte dos NFTs nesses servidores seria perdida para sempre. Certifique-se de verificar onde está localizado o tokenURI do NFT que você usa!
Também espero que mais pessoas usem plataformas dStorage como Filecoin, pois usar um serviço de pinning também não é tão descentralizado quanto deveria ser.

Indo além

Se você quiser ver um passo a passo em vídeo do NFT avançado que acabamos de fazer, assista ao vídeo sobre NFT avançado.

Agora, você tem as habilidades para criar NFTs lindos, divertidos, personalizados e interativos e renderizá-los em um marketplace.

NFTs são maneiras divertidas e poderosas de compensar os artistas com precisão por todo o trabalho duro que eles fazem. Boa sorte e lembre-se de se divertir!