Artigo original: How to Make an NFT in 14 Lines of Code

Se você é um desenvolvedor interessado no desenvolvimento de blockchains, deve saber algo sobre NFTs, ou tokens não fungíveis. Portanto, neste artigo, aprenderemos sobre a engenharia por trás deles para que você possa começar a construir o seu próprio blockchain.

No final do projeto, você terá sua própria carteira Ethereum, com um novo NFT dentro dela. Este tutorial é amigável para iniciantes e não requer nenhum conhecimento prévio da rede Ethereum ou de contratos inteligentes (em inglês, smart contracts).

image-46
O contrato do NFT tem apenas 14 linhas de código

O que é um NFT?

NFT significa token não fungível. Esta citação da ethereum.org explica bem:

NFTs são tokens que podemos usar para representar a propriedade de itens exclusivos. Eles nos permitem tokenizar coisas como arte, colecionáveis e até imóveis. Eles só podem ter um proprietário oficial de cada vez e são protegidos pelo blockchain Ethereum – ninguém pode modificar o registro de propriedade ou copiar/colar um novo NFT para fazê-lo existir.

O que é um NFT padrão ou ERC-721?

O ERC-721 é o padrão NFT mais comum. Se o seu contrato inteligente implementar determinados métodos de API padronizados, ele poderá ser chamado de contrato de token não fungível ERC-721.
Esses métodos são especificados no EIP-721. Projetos de código aberto, como o OpenZeppelin, simplificaram o processo de desenvolvimento ao implementar os padrões ERC mais comuns como uma biblioteca reutilizável.

O que é cunhar um NFT?

Ao cunhar um NFT, você publica um token exclusivo em um blockchain. Este token é uma instância do seu contrato inteligente.

Cada token tem um tokenURI exclusivo, que contém metadados de seu ativo em um arquivo JSON em conformidade com determinado esquema. Os metadados são onde você armazena informações sobre seu NFT, como nome, imagem, descrição e outros atributos.

Um exemplo de arquivo JSON para o "ERC721 Metadata Schema" se parece com este:

{
	"attributes": [
		{
			"trait_type": "Shape",
			"value": "Circle"
		},
		{
			"trait_type": "Mood",
			"value": "Sad"
		}
	],
	"description": "A sad circle.",
	"image": "https://i.imgur.com/Qkw9N0A.jpeg",
	"name": "Sad Circle"
}

Como armazeno os metadados do meu NFT?

Existem três maneiras principais de armazenar os metadados de um NFT.

Primeiro, você pode armazenar as informações on-chain (em cadeia). Em outras palavras, você pode estender seu ERC-721 e armazenar os metadados no blockchain, o que pode ser caro.

O segundo método é usar IPFS. A terceira maneira é simplesmente fazer com que sua API retorne o arquivo JSON.

O primeiro e o segundo métodos geralmente são os preferidos, pois você não pode modificar o arquivo JSON subjacente. Para o escopo deste projeto, optaremos pelo terceiro método.

Para um bom tutorial sobre como usar NFTs com IPFS, leia  este artigo da equipe Alchemy.

O que vamos construir

emotionalshapes

Neste tutorial, criaremos e cunharemos nosso próprio NFT. O tutorial é simples para iniciantes e não requer nenhum conhecimento prévio da rede Ethereum ou de contratos inteligentes. Ainda assim, ter uma boa compreensão desses conceitos ajudará você a entender o que está acontecendo nos bastidores.

Em um próximo tutorial, construiremos um aplicativo em React para a web totalmente funcional, onde você poderá exibir e vender seus NFTs.


Se você está apenas começando com o desenvolvimento de dApps, comece lendo os tópicos principais e assista a este curso incrível de Patrick Collins.

Este projeto foi escrito intencionalmente com código de fácil compreensão e não é adequado para uso em produção.

Pré-requisitos

Metamask

image-32

Precisamos de um endereço Ethereum para interagir com nosso contrato inteligente. Usaremos o Metamask como nossa carteira. É uma carteira virtual gratuita que gerencia seus endereços Ethereum. Vamos precisar dele para enviar e receber transações (leia mais sobre isso aqui). Por exemplo, cunhar um NFT é uma transação.

Faça o download da extensão do Chrome e do aplicativo para dispositivos móveis. Precisaremos de ambos, pois a extensão do Chrome não exibe seus NFTs.

image-34

Certifique-se de alterar a rede para "Ropsten Test Network" para fins de desenvolvimento. Você precisará de algum Eth para cobrir as taxas de implantação e cunhagem de seu NFT. Vá para o Ropsten Ethereum Faucet e digite seu endereço. Você logo deverá ver alguns Eth de teste em sua conta do Metamask.

image-35

Alchemy

Para interagir com a rede Ethereum, você precisará estar conectado a um Ethereum Node.

Executar seu próprio Node e manter a infraestrutura é um projeto à parte. Felizmente, existem provedores do tipo node-as-a-service que hospedam a infraestrutura para você. Existem muitas opções, como Infura, BlockDaemon e Moralis. Usaremos a Alchemy como nosso provedor de nodes.

Vá até o site deles, crie uma conta, escolha Ethereum como sua rede e crie seu aplicativo. Escolha Ropsten como sua rede.

image-36

No seu painel, clique em "ver detalhes" no seu aplicativo e, em seguida, clique em "ver chave". Salve sua chave http em algum lugar, pois precisaremos disso mais tarde.

image-38

NodeJS/NPM

Usaremos NodeJS para o projeto. Se você não o tiver instalado, siga este tutorial simples do freeCodeCamp (texto em inglês).

Inicialize o projeto

No seu terminal, execute este comando para criar um novo diretório para seu projeto:

mkdir nft-project
cd nft-project

Agora, vamos criar outro diretório, ethereum/, dentro de nft-project/ e inicializá-lo com o Hardhat. O Hardhat é uma ferramenta de desenvolvimento que facilita a implantação e o teste do seu software Ethereum.

mkdir ethereum
cd ethereum
npm init

Responda as perguntas como quiser. Em seguida, execute esses comandos para criar um projeto Hardhat:

npm install --save-dev hardhat
npx hardhat

Você verá este prompt:

888    888                      888 888               888
888    888                      888 888               888
888    888                      888 888               888
8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
888    888     "88b 888P"  d88" 888 888 "88b     "88b 888
888    888 .d888888 888    888  888 888  888 .d888888 888
888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888

Welcome to Hardhat v2.0.8

? What do you want to do? …
  Create a sample project
❯ Create an empty hardhat.config.js
  Quit

Selecione Create an empty hardhat.config.js. Isso gerará um arquivo vazio hardhat.config.js que atualizaremos posteriormente.

Para a aplicação da web, usaremos o Next.js para inicializar uma aplicação da web totalmente funcional. Volte para o diretório raiz nft-project/ e inicialize um boilerplate do Next.js app, chamado web:

cd ..
mkdir web
cd web
npx create-next-app@latest

Seu projeto, agora, tem esta aparência:

nft-project/
	ethereum/
	web/

Ótimo! Estamos prontos para entrar na parte da programação de verdade.

Como definir nossas variáveis .env

Você se lembra da chave de Alchemy que pegamos em nosso projeto de teste anterior? Nós a usaremos junto com as chaves públicas e privadas da nossa conta Metamask para interagir com o blockchain.

Execute os comandos a seguir, crie um arquivo chamado.env  dentro do seu diretório ethereum/, e instale o dotenv. Vamos usá-los mais tarde.

cd ..
cd ethereum
touch .env
npm install dotenv --save

Para o seu arquivo .env,  coloque a chave que você exportou do Alchemy e siga estas instruções para pegar a chave privada do seu Metamask.

Aqui está seu arquivo .env :

DEV_API_URL = YOUR_ALCHEMY_KEY
PRIVATE_KEY = YOUR_METAMASK_PRIVATE_KEY
PUBLIC_KEY = YOUR_METAMASK_ADDRESS

O Smart Contract para NFT

Na pasta ethereum/ crie mais dois diretórios: contracts e scripts. Um projeto hardhat simples contém essas pastas.

  • contracts/ contém os arquivos de origem de seus contratos
  • scripts/ contém os scripts para implantar e cunhar nossos NFTs
mkdir contracts
mkdir scripts

Então, instale o OpenZeppelin. O OpenZeppelin Contract é uma biblioteca de código aberto com código reutilizável pré-testado para facilitar o desenvolvimento dos Smart Contracts (contratos inteligentes).

npm install @openzeppelin/contracts

Por fim, escreveremos o Smart Contract para o nosso NFT. Navegue até o diretório de contratos e crie um arquivo intitulado EmotionalShapes.sol.  Você pode nomear seus NFTs como achar melhor.

A extensão .sol  refere-se à linguagem Solidity, que usaremos para programar nosso Smart Contract. Escreveremos apenas 14 linhas de código com o Solidity. Então, não se preocupe se você ainda não viu isso antes.
Comece com este artigo para saber mais sobre as linguagens de Smart Contract. Você também pode pular diretamente para esta ficha informativa do Solidity, que contém a sintaxe principal.

cd contracts
touch EmotionalShapes.sol

Este é o nosso Smart Contract:

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

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

contract EmotionalShapes is ERC721 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIdCounter;

    constructor() ERC721("EmotionalShapes", "ESS") {}

    function _baseURI() internal pure override returns (string memory) {
        return "YOUR_API_URL/api/erc721/";
    }

    function mint(address to)
        public returns (uint256)
    {
        require(_tokenIdCounter.current() < 3); 
        _tokenIdCounter.increment();
        _safeMint(to, _tokenIdCounter.current());

        return _tokenIdCounter.current();
    }
}

Vamos passar pelo código e entender o que está acontecendo.

  1. Na parte superior do arquivo, especificamos qual módulo do OpenZeppelin importar. Precisamos do contrato ERC721, pois é a 'base' do nosso Smart Contract. Ele já implementou todos os métodos especificados no EIP-721 para que possamos usá-lo com segurança.
  2. Um contador é útil para gerar ids incrementais para nossos NFTs. Nós nomeamos a variável _tokenIdCounter
  3. No construtor, inicializamos nosso ERC721 com seu nome e seu símbolo. Eu escolhi EmotionalShapes e ESS.
  4. Substituímos a função padrão baseURI, retornando a nossa. Vamos começar a construir isso logo após. Em resumo, é o URL que será adicionado como 'prefixo' a todos os nossos tokenURIs. No exemplo acima, os metadados de nossos NFTs ficarão em um arquivo JSON em URL_DA_SUA_API/api/erc721/1.  
  5. Implementamos a função 'mint'. É a função que permite publicar uma instância desse Smart Contract no blockchain. Eu exigi que a variável _tokenIdCounter fosse menor que 3, pois criarei apenas três instâncias do meu NFT. Você pode remover isso se quiser cunhar mais.
  6. Finalmente, dentro da função mint, incrementamos a variável _tokenIdCounter em 1. Então, nosso id será 1, seguido de 2, depois de 3. Então, chamamos a função fornecida pelo OpenZeppelin _safeMint para publicar o token.

Não se preocupe se você se sentir perdido. Você pode participar de um workshop liderado por voluntários do freeCodeCamp, onde convidamos desenvolvedores de níveis de habilidade semelhantes para construir coisas juntos, incluindo esse projeto de NFT.

Os eventos são gratuitos e remotos, então você pode tirar qualquer dúvida diretamente. Você pode se registrar aqui. As vagas são limitadas, então você será convidado para os próximos eventos disponíveis.

Como criar os metadados para nosso NFT

Como mencionado anteriormente, existem três maneiras principais de armazenar seu tokenURI. Construiremos um endpoint de API simples que resolve as informações do nosso NFT como JSON.

Nosso projeto do Next.js nos oferece uma maneira prática de desenvolver rotas de API. Vá para a pasta web/, encontre a pasta api/ dentro da pasta pages/  e faça nossa rota dinâmica [id].js em uma pasta erc721/  (leia mais sobre roteamento  aqui):

// web/pages/api/erc721/[id].js

const metadata = {
  1: {
    attributes: [
      {
        trait_type: "Shape",
        value: "Circle",
      },
      {
        trait_type: "Mood",
        value: "Sad",
      },
    ],
    description: "A sad circle.",
    image: "https://i.imgur.com/Qkw9N0A.jpeg",
    name: "Sad Circle",
  },
  2: {
    attributes: [
      {
        trait_type: "Shape",
        value: "Rectangle",
      },
      {
        trait_type: "Mood",
        value: "Angry",
      },
    ],
    description: "An angry rectangle.",
    image: "https://i.imgur.com/SMneO6k.jpeg",
    name: "Angry Rectangle",
  },
  3: {
    attributes: [
      {
        trait_type: "Shape",
        value: "Triangle",
      },
      {
        trait_type: "Mood",
        value: "Bored",
      },
    ],
    description: "An bored triangle.",
    image: "https://i.imgur.com/hMVRFoJ.jpeg",
    name: "Bored Triangle",
  },
};

export default function handler(req, res) {
  res.status(200).json(metadata[req.query.id] || {});
}

Para fins deste projeto, tornei o código o mais fácil de entender possível. Isso definitivamente não é adequado para produção (por favor, não use um URL do Imgur para o seu NFT). Certifique-se de definir os metadados para todos os NFTs que você pretende cunhar.

Agora, vá para o diretório da web e inicie seu aplicativo Next.js com este comando:

npm run dev

Sua aplicação deve ser executada no localhost:3000. Para garantir que nosso endpoint funcione, vá para http://localhost:3000/api/erc721/1 e ele deve ser resolvido com um objeto JSON dos metadados do seu primeiro NFT.

Como expor os metadados para nosso NFT

Como nossa aplicação está hospedada localmente, outras aplicações não podem acessá-la. Usando uma ferramenta como o ngrok, podemos expor nosso host local a um URL acessível publicamente.

image-39
  1. Vá para ngrok.com e complete o processo de registro
  2. Descompacte o pacote baixado
  3. No seu terminal, certifique-se que você executou o comando cd na pasta que você descomprimiu seu pacote do ngrok
  4. Siga as instruções do painel de controle e execute
./ngrok authtoken SEU_TOKEN_DE_AUTENTICACAO

5.  Então, execute este comando para criar um túnel para sua aplicação da web, hospedada em localhost:3000

./ngrok http 3000

6.  Você está quase lá! Em seu terminal, você deverá ver algo como isto:

ngrok by @inconshreveable                                                                            (Ctrl+C to quit)
                                                                                                                     
Session Status                online                                                                                 
Account                       YOUR_ACCOUNT (Plan: Free)                                                                       
Version                       2.3.40                                                                                 
Region                        United States (us)                                                                     
Web Interface                 http://127.0.0.1:4040                                                                  
Forwarding                    http://SEU_ENDERECO_DO_NGROK -> http://localhost:3000                             
Forwarding                    https://SEU_ENDERECO_DO_NGROK -> http://localhost:3000                             

Vá para  SEU_ENDERECO_DO_NGROK/api/erc721/1 para ter certeza que o endpoint funciona corretamente.

Como fazer o deploy de nosso NFT

Agora que fizemos todo o trabalho de base (ufa), vamos voltar para nossa pasta e  ethereum/ e nos preparar para implantar nosso  NFT.

Mude a função _baseURI no seu arquivo ethreum/contracts/NOME_DO_SEU_NFT.sol para retornar ao seu endereço do ngrok.

// ethereum/conrtacts/EmotionalShapes.sol

contract EmotionalShapes is ERC721 {
...
	function _baseURI() internal pure override returns (string memory) {
		return "https://SEU_ENDERECO_DO_NGROK/api/erc721/";
	}
...
}

Para fazer o deploy do nosso NFT, precisamos primeiro compilá-lo usando Hardhat. Para que o processo seja mais fácil, instalaremos o ethers.js.

npm install @nomiclabs/hardhat-ethers --save-dev

Vamos atualizar nosso hardhat.config.js:

require("dotenv").config();
require("@nomiclabs/hardhat-ethers");

module.exports = {
  solidity: "0.8.0",
  defaultNetwork: "ropsten",
  networks: {
    hardhat: {},
    ropsten: {
      url: process.env.DEV_API_URL,
      accounts: [`0x${process.env.PRIVATE_KEY}`],
    },
  },
};

Para saber mais sobre a configuração do arquivo hardhat dê uma olhada na sua  documentação. Configuramos a rede ropsten com nosso URL do Alchemy e fornecemos a chave privada de sua conta do metamask.

Finalmente, execute:

npx hardhat compile

Isto permite que o hardhat gere dois arquivos por contrato compilado. Devemos ver uma pasta recém-criada artifacts/, que contém seus contratos compilados na pasta contracts/. Para saber mais sobre como isso funciona, leia este tutorial da equipe do Hardhat.

Agora, vamos escrever um script para finalmente implantar nosso NFT na rede de teste. Na pasta scripts/ , crie um arquivo chamado deploy.js.

// ethereum/scripts/deploy.js

async function main() {
  const EmotionalShapes = await ethers.getContractFactory("EmotionalShapes");
  const emotionalShapes = await EmotionalShapes.deploy();

  console.log("EmotionalShapes deployed:", emotionalShapes.address);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

Este código é  inspirado pelo tutorial de deploy do hardhat.

Uma ContractFactory em ethers.js é uma abstração usada para implantar novos contratos inteligentes, então EmotionalShapes aqui é uma factory para instâncias do nosso contrato de token. Invocar deploy() na ContractFactory iniciará o deploy e retornará uma Promise que então é resolvida para Contract. Este é o objeto que possui um método para cada uma de suas funções de contrato inteligente.

Como visualizar o NFT no blockchain

Execute o script de deploy:

node ./scripts/deploy.js

Você deverá ver em seu terminal EmotionalShapes deployed: UM_ENDERECO. Este é o endereço onde seu Smart Contract está implantado na rede de teste ropsten.

Se você for para https://ropsten.etherscan.io/address/UM_ENDERECO, você deve ver seu NFT recém-implantado. Sim! Você conseguiu!

Se você estiver confuso em algum ponto do tutorial ou se sentindo perdido, novamente, pode participar de nossos workshops ao vivo, onde construiremos este projeto juntos em uma chamada de Zoom.

Como cunhar seu NFT

Agora que você fez o deploy do seu NFT, é hora de cunhá-lo para você! Crie um novo arquivo chamado mint.js na sua pasta scripts/.Usaremos o ethers.js para nos auxiliar.

Comece adicionando o pacote ethers.js :

npm install --save ethers

Em seguida, preencha o arquivo mint.js :

require("dotenv").config();
const { ethers } = require("ethers");

const contract = require("../artifacts/contracts/EmotionalShapes.sol/EmotionalShapes.json");
const contractInterface = contract.abi;

// https://docs.ethers.io/v5/api/providers
const provider = ethers.getDefaultProvider("ropsten", {
  alchemy: process.env.DEV_API_URL,
});

// https://docs.ethers.io/v5/api/signer/#Wallet
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

//https://docs.ethers.io/v5/api/contract/contract
const emotionalShapes = new ethers.Contract(
  YOUR_NFT_ADDRESS,
  contractInterface,
  wallet
);

const main = () => {
  emotionalShapes
    .mint(process.env.PUBLIC_KEY)
    .then((transaction) => console.log(transaction))
    .catch((e) => console.log("something went wrong", e));
};

main();

Eu deixei comentários para onde você pode encontrar mais informações sobre os diferentes métodos. Primeiro, pegamos a interface do contrato (ABI). Na ethereum.org, vemos que:

Uma interface binária de aplicativo, ou ABI, é a maneira padrão de interagir com contratos no ecossistema Ethereum, tanto de fora do blockchain quanto para interações contrato a contrato.

Sua ABI define como os outros interagem com seu contrato. Então, criamos nosso provedor com Alchemy (lembre-se dos node-as-a-service). Por fim, inicializamos nossa carteira com nossa chave privada.

A função  main() executa o método mint no Smart Contract que acabamos de implementar. O método mint recebe apenas um parâmetro, to, que indica o receptor do token. Como estamos cunhando para nós mesmos, colocamos o endereço público da nossa conta Metamask.

Se tudo correr bem, você deverá ver a transação registrada em seu terminal. Pegue a propriedade hash vá para https://ropsten.etherscan.io/tx/SEU_HASH. Você deve ver a transação de cunhagem lá!

Como visualizar o NFT em sua carteira Metamask

Você precisa começar baixando a versão móvel do Metamask. Em seguida, faça login na sua conta.

Você deve ver uma guia de NFTs junto com um botão Add NFT. Clique no botão e insira o endereço do seu Smart Contract junto com os ids que você cunhou. Se você seguiu o tutorial, você deve começar com um id de 1.

IMG_0376
Veja os NFTs em sua carteira do Metamask

Conclusão

Parabéns! Você acabou de cunhar seu próprio NFT. Na próxima parte do projeto, construiremos o aplicativo em React para o front-end que interaja com nosso contrato. O objetivo final é construir um aplicativo da web totalmente funcional onde você possa vender seus próprios NFTs.

Por fim, você pode  participar de nossos workshops ao vivo com voluntários do freeCodeCamp, onde construiremos este projeto junto com outros.

Os eventos são gratuitos para todos em qualquer lugar do mundo e os convites são enviados por ordem de chegada. Se você gostaria de liderar os workshops, envie uma mensagem no Twitter, adoraríamos contar com você! Também organizamos outros tipos de eventos como feiras de contratação e encontros sociais.

Gostaria de saber o que você quer criar. Os NFTs ainda estão em seus estágios iniciais e novas ideias são mais do que bem-vindas. Mal posso esperar para ver que ideia maluca você tem!