WEB3DEV

Cover image for Construindo um Serviço de Cunhagem de NFTs
Paulo Gio
Paulo Gio

Posted on

Construindo um Serviço de Cunhagem de NFTs

Neste tutorial, você aprenderá como criar um novo token NFT do zero e armazená-lo no IPFS e Filecoin usando o nft.storage, tudo em um aplicativo web descentralizado construído usando o JavaScript, a biblioteca ethers.js e o React.

Para os propósitos deste guia, vamos cunhar NFTs na blockchain Ethereum. No entanto, os conceitos descritos aqui podem ser facilmente aplicados a outras blockchains.

Se você nunca trabalhou com Ethereum ou outra plataforma de contratos inteligentes antes, nosso guia de primeiros passos o orientará através de um exemplo rápido de "olá, mundo" usando uma rede de testes (testnet) da Ethereum.

Por que IPFS e nft.storage?

Nosso exemplo usa um serviço gratuito chamado nft.storage para adicionar um arquivo de imagem e os metadados do nosso NFT ao IPFS (InterPlanetary File System). Vamos nos aprofundar no motivo pelo qual o IPFS é uma boa escolha para NFTs em nossa discussão sobre endereçamento de conteúdo, mas, por enquanto, vamos apenas dar uma visão geral.

Quando um NFT é criado e vinculado a um arquivo digital que vive em algum outro sistema, a forma como os dados são vinculados é crítica. Há algumas razões pelas quais os links HTTP tradicionais não são uma ótima escolha para as demandas dos NFTs.

Com um endereço HTTP como https://cloud-bucket.provider.com/my-nft.jpg, qualquer pessoa pode buscar pelo conteúdo de my-nft.jpg, contanto que o proprietário do servidor pague suas contas. No entanto, não há como garantir que o conteúdo de my-nft.jpg seja o mesmo de quando o NFT foi criado. O proprietário do servidor pode facilmente substituir my-nft.jpg por algo diferente a qualquer momento, fazendo com que o NFT mude seu significado.

Esse problema foi demonstrado por um artista que “puxou o tapete” (rug pull) dos NFTs que ele criou, mudando suas imagens depois que eles foram cunhados e vendidos para outras pessoas.

O IPFS resolve esse problema potencialmente catastrófico graças ao seu uso de endereçamento de conteúdo. Adicionar dados ao IPFS produz um identificador de conteúdo (CID), que é diretamente derivado dos próprios dados e que se vincula para os dados na rede IPFS. Porque um CID só pode se referir a um pedaço de conteúdo, sabemos que ninguém pode substituir ou alterar o conteúdo sem quebrar o link.

Usando esse CID, qualquer pessoa pode buscar por uma cópia de seus dados da rede IPFS, desde que pelo menos uma cópia exista na rede - mesmo que o provedor original tenha desaparecido. Isso torna os CIDs perfeitos para armazenamento de NFTs. Tudo que precisamos fazer é colocar o CID em um URI ipfs://, como ipfs://bafybeidlkqhddsjrdue7y3dy27pu5d7ydyemcls4z24szlyik3we7vqvam/nft-image.png, e temos um link imutável da blockchain para os dados do nosso token.

É claro, pode haver alguns casos em que você realmente queira mudar os metadados de um NFT depois que ele foi publicado. Sem problemas! Você só precisa adicionar suporte ao seu contrato inteligente para atualizar o URI de um token depois que ele foi emitido. Isso permitirá que você mude o URI original para um novo URI do IPFS, mantendo um registro da versão inicial no histórico de transações da blockchain. Isso oferece responsabilidade, deixando claro para todos o que foi mudado, quando e por quem.

Ao usar o nft.storage, podemos disponibilizar os dados do nosso NFT no IPFS de graça, com a persistência de conteúdo resolvida automaticamente! Notavelmente, o nft.storage inclui tanto o “armazenamento a frio" a longo prazo na rede descentralizada Filecoin, quanto o “armazenamento a quente" usando o IPFS Cluster. Como bônus, você também ganha uma biblioteca de cliente JavaScript que ajuda a carregar dados no IPFS e gerar metadados de NFT em apenas uma linha de código.

Configurando

Para ajudar a explicar como os NFTs e o IPFS trabalham juntos, criamos um exemplo de aplicativo web descentralizado, ou dApp, baseado no excelente framework inicial scaffold-eth.

O framework scaffold-eth é um boilerplate "tudo incluso" com todos os tipos de componentes e integrações úteis, alguns dos quais não vamos abordar neste guia. No entanto, uma vez que você tenha seguido este tutorial, você pode se aprofundar na funcionalidade do scaffold-eth explorando o restante do código de exemplo ou conferindo os projetos apresentados no Buidl Guidl, um grupo de desenvolvedores Ethereum focados em educar e aumentar a comunidade de desenvolvedores Ethereum.

Pré-requisitos

Você precisará ter o git, o node.js e o yarn instalados para seguir este tutorial.

O aplicativo de exemplo usa o React para a interface do usuário (IU), aproveitando os componentes integrados ao scaffold-eth. Se você já é um desenvolvedor React, deve se sentir em casa. Se você é novo no React ou prefere um framework diferente, isso não é um problema. Vamos manter este guia focado no gerenciamento de ativos NFT e interações de contratos inteligentes, que se aplicarão a qualquer estrutura de IU ou padrão de design.

Obtenha o Código

Vamos verificar o repositório de exemplos para que possamos começar a brincar com NFTs!

1 - Clone o repositório de exemplos da nft-school e vá para o diretório nft-school-examples/end-to-end.

git clone https://github.com/ipfs-shipyard/nft-school-examples

cd nft-school-examples/end-to-end
Enter fullscreen mode Exit fullscreen mode

2 - Instale as dependências do JavaScript com o yarn.

yarn install
Enter fullscreen mode Exit fullscreen mode

3 - Inicie um simulador de blockchain local (também chamado de devnet, ou rede de desenvolvimento).

yarn chain
Enter fullscreen mode Exit fullscreen mode

Isso mostrará algumas informações sobre as contas na rede de desenvolvimento local. Mantenha este terminal aberto e abra um novo terminal para os próximos comandos.

4 - Em um novo terminal, implante o contrato inteligente NFTMinter.

yarn deploy
Enter fullscreen mode Exit fullscreen mode

Você deve ver algo como:

https://nftschool.dev/assets/img/e2e-yarn-deploy.687890c1.png

5 - Inicie o servidor de desenvolvimento para o aplicativo web do React.

yarn start
Enter fullscreen mode Exit fullscreen mode

Este comando continuará a ser executado, então mantenha o terminal aberto enquanto você brinca com o aplicativo.

Uma vez que o servidor tenha iniciado, ele imprimirá o URL do frontend. Por padrão, o URL é http://localhost:3000, mas você pode ver um URL diferente se já tiver algo escutando na porta 3000.

6 - Se o seu navegador não abrir automaticamente, navegue até o URL mostrado na saída do último comando.

Você deve ver uma página como essa:

https://nftschool.dev/assets/img/e2e-first-launch.56e9537d.png

7 - Consiga alguns ETH (Ether) falsos para brincar

Para cunhar um NFT, precisamos pagar uma pequena quantidade de ETH em gás, que é uma taxa cobrada pelos mineradores por operações que alteram o estado da blockchain.

Graças ao scaffold-eth, conseguir um pouco de ETH falso para brincar em nossa rede de desenvolvimento local é simples. Por padrão, o scaffold-eth cria uma nova "conta descartável" com saldo zero, para que você não precise se conectar a uma carteira, como a MetaMask, apenas para carregar o aplicativo.

Clique no botão que diz “Grab funds from the faucet” (pegar fundos da torneira) para conseguir um pouco de dinheiro de brincadeira. Você deve ver um pop-up mostrando o ID da transação, rapidamente seguido por uma atualização no saldo da conta no topo da tela. Agora você está pronto para cunhar!

✅ Dica

O botão da torneira só aparecerá ao usar uma rede de desenvolvimento local. Se você implantar o contrato em uma rede de testes ou rede principal (Mainnet), seus usuários precisarão usar o botão “Conectar” para entrar com uma carteira como a MetaMask.

8 - Obtenha uma chave de API para o nft.storage

Para fazer solicitações ao nft.storage, você precisa de uma chave de API.

Faça login ou inscreva-se para uma conta gratuita, depois crie uma chave de API.

Copie a chave para a área de transferência e edite o arquivo end-to-end/packages/react-app/src/constants.js.

Perto do topo do arquivo, substitua o valor da constante NFT_STORAGE_KEY pelo token que você copiou anteriormente.

Cunhe um NFT

Para cunhar um NFT em nosso exemplo, tudo o que você precisa fazer é selecionar um arquivo (usaremos uma imagem), dar-lhe um nome e uma descrição opcional, e clicar no botão de cunhagem “Mint”! Isso fará o upload de sua imagem e metadados para o nft.storage, que nos dará um URI do IPFS que podemos armazenar na blockchain. Em seguida, chamamos uma função no contrato inteligente para cunhar o token. Uma vez que a transação seja confirmada, estamos prontos!

Abaixo está um exemplo em GIF animado de todo o processo:

https://nftschool.dev/assets/img/e2e-minting-animated.0033f91b.gif

Como Funciona a Cunhagem

Até agora, cunhamos um NFT, adicionamos à blockchain Ethereum e hospedamos no IPFS. Agora vamos nos aprofundar exatamente no que o contrato faz e por quê. Também vamos explorar as coisas no lado do IPFS e como o próprio NFT é armazenado.

O Contrato Inteligente NFTMinter

Nosso exemplo usa um contrato inteligente escrito em Solidity, a linguagem mais popular para o desenvolvimento na Ethereum. O contrato implementa o padrão Ethereum de NFTs ERC-721 ao herdar o conveniente e totalmente equipado contrato base ERC721 do OpenZeppelin.

Como o contrato base do OpenZeppelin fornece grande parte da funcionalidade central, o contrato NFTMinter é simples:

//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;

import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract NFTMinter is ERC721 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor(string memory tokenName, string memory symbol) ERC721(tokenName, symbol) {
        _setBaseURI("ipfs://");
    }

    function mintToken(address owner, string memory metadataURI)
    public
    returns (uint256)
    {
        _tokenIds.increment();

        uint256 id = _tokenIds.current();
        _safeMint(owner, id);
        _setTokenURI(id, metadataURI);

        return id;
    }
}
Enter fullscreen mode Exit fullscreen mode

Se você ler o guia do OpenZeppelin ERC721, verá que nosso contrato é extremamente semelhante. A função mintToken simplesmente incrementa um contador para emitir IDs de token, e usa a função _setTokenURI fornecida pelo contrato base para associar o URI de metadados com o novo ID de token.

Uma coisa a observar é que definimos o prefixo do URI base no construtor como ipfs://. Quando definimos um URI de metadados para cada token na função mintToken, não precisamos armazenar o prefixo, uma vez que a função assessora tokenURI do contrato base o aplicará a cada URI de token.

⚠️ AVISO

É importante notar que este contrato não está pronto para produção. Ele não inclui quaisquer controles de acesso para limitar quais contas têm permissão para chamar a função mintToken. Se você decidir desenvolver uma plataforma de produção com base neste exemplo, deve explorar os padrões de controle de acesso disponíveis e considerar qual deles deve ser aplicado ao modelo de acesso de sua plataforma.

JavaScript com Sabor Ethereum

O projeto scaffold-eth que usamos para criar o aplicativo de exemplo tem muito código, mas podemos ignorar a maior parte dele para este tutorial. Vamos nos concentrar apenas nas coisas relacionadas a NFTs e deixamos você explorar o resto dos componentes de boilerplate incluídos com o scaffold-eth.

Todo o código abaixo pode ser encontrado no arquivo end-to-end/packages/react-app/src/components/Minter.jsx, no repositório de exemplos da nft-school.

Não vamos entrar em detalhes sobre o código da UI, mas fique à vontade para brincar com ele se quiser melhorar a aparência das coisas!

Para este guia, vamos apenas olhar o cerne do processo de cunhagem. Primeiro, colocamos nossa imagem e metadados no IPFS usando o nft.storage. Em seguida, usamos o URI de nossos metadados para chamar a função mintToken do contrato inteligente.

Fazendo Upload para o IPFS com o nft.storage

Colocar nossos dados no IPFS é simples, graças à biblioteca do cliente do nft.storage. Tudo que precisamos fazer é criar um novo cliente e chamar o método store:

const client = new NFTStorage({ token: NFT_STORAGE_KEY });
  const metadata = await client.store({
    name,
    description,
    image,
  });
Enter fullscreen mode Exit fullscreen mode

O objeto metadata retornado pelo método store tem uma propriedade url com o URI do IPFS para nossos metadados. A seguir, veremos como colocar esse URI na blockchain.

Chamando a função mintToken do Contrato Inteligente

Vamos ver como nosso código interage com a função mintToken do contrato inteligente.

// Nosso contrato inteligente já adiciona o prefixo "ipfs://" aos URIs, então removemos antes de chamar a função `mintToken`.
const metadataURI = metadata.url.href.replace(/^ipfs:\/\//, "");

// O auxiliar Transactor do scaffold-eth nos fornece uma bela janela pop-up quando uma transação é enviada.
const transactor = Transactor(provider, gasPrice);
const tx = await transactor(contract.mintToken(ownerAddress, metadataURI));

setStatus("Transação blockchain enviada, aguardando confirmação...");

// Aguarda a confirmação da transação e, em seguida, obtém o ID do token a partir do evento Transfer emitido.
const receipt = await tx.wait();
let tokenId = null;
for (const event of receipt.events) {
  if (event.event !== 'Transfer') {
    continue;
  }
  tokenId = event.args.tokenId.toString();
  break;
}
Enter fullscreen mode Exit fullscreen mode

A ação real acontece na chamada contract.mintToken. Aqui, o objeto contract é fornecido pela biblioteca ethers.js, que está conectada ao nosso contrato inteligente.

Envolvemos a chamada com um Transactor, que é um auxiliar fornecido pelo scaffold-eth para criar um belo pop-up de UI com os detalhes da transação.

Queremos obter o ID do novo token, mas como a função mintToken modifica o estado da blockchain, ela não pode retornar um valor imediatamente. Isso ocorre porque a chamada da função cria uma nova transação na Ethereum e não há como saber com certeza se o bloco contendo a transação será realmente minerado e incorporado à blockchain - por exemplo, pode não haver gás suficiente para pagar pela transação.

Para obter o ID do token para nosso novo NFT, precisamos chamar tx.wait(), que aguarda até que a transação tenha sido confirmada. O ID do token está envolto em um evento Transfer, que é emitido pelo contrato base quando um novo token é criado ou transferido para um novo proprietário. Ao inspecionar o recibo da transação retornado de tx.wait(), podemos retirar o ID do token do evento Transfer.

É isso aí! Uma vez que a transação foi confirmada, nosso NFT está na blockchain, com a imagem e metadados servidos a partir do IPFS e armazenados com o Filecoin.

Você pode ver um NFT depois que ele foi cunhado, mudando para a guia "NFT Viewer" e inserindo um ID de token na caixa de texto.

Próximos passos

Cobrimos bastante coisa aqui! Vimos como adicionar ativos ao IPFS e criar metadados NFT, e como vincular nossos metadados a um novo NFT na Ethereum.

Até agora, estivemos brincando em um ambiente de desenvolvimento local (sandbox), então nossos NFTs são bastante efêmeros. Como próximo passo, tente implantar o contrato em uma rede de testes e atualize a IU para se conectar a ela! A documentação de implantação do scaffold-eth pode te ajudar a começar. A documentação da Ethereum tem uma página sobre as diferentes redes que podem te ajudar a escolher a rede de teste certa, e você pode obter alguns ETH de teste para brincar em uma das torneiras públicas da rede de testes. Divirta-se!

Artigo original publicado por nftschool.dev. Traduzido por Paulinho Giovannini.

Top comments (0)