WEB3DEV

Cover image for Permitindo que os Usuários Criem NFTs Específicos
Paulo Gio
Paulo Gio

Posted on

Permitindo que os Usuários Criem NFTs Específicos

https://blog.thirdweb.com/content/images/size/w1000/2023/03/Enable-users-to-mint-specific-NFTs-2.png

Este guia mostrará como criar um aplicativo descentralizado onde os usuários finais podem escolher qual NFT desejam cunhar.

Vamos percorrer o seguinte:

  1. Criando um Contrato de Coleção de NFTs
  2. Mostrando os NFTs disponíveis para os usuários cunharem
  3. Cunhando os NFTs usando a assinatura mint

Vamos começar!

Implantando um contrato ERC721

Primeiro, implantaremos um Contrato de Coleção de NFTs que usaremos para assinar os NFTs.

Para começar, vá para a página de Contratos em seu Painel da Thirdweb e clique em "Implantar novo contrato" (Deploy new contract):

https://blog.thirdweb.com/content/images/size/w1000/2023/03/image-37.png

Você será levado para nossa página Explore (Exploração) - onde você pode navegar pelos contratos inteligentes construídos pelos principais protocolos web3 e implantá-los com apenas alguns cliques!

Observação: Você também pode usar a CLI da Thirdweb para configurar um ambiente de contrato inteligente executando o comando abaixo a partir do seu terminal:

npx thirdweb create contract
Enter fullscreen mode Exit fullscreen mode

Isso o levará por uma sequência de etapas fáceis de seguir para criar seu contrato. Saiba mais sobre isso em nosso guia CLI.

Caso contrário, vamos voltar para a página de exploração:

https://blog.thirdweb.com/content/images/size/w1000/2023/03/SCR-20230304-rle-2.png

Aqui, selecione o contrato inteligente de sua escolha. Para este guia, vamos usar o contrato de Coleção de NFTs para criar nossa coleção de NFTs:

https://blog.thirdweb.com/content/images/size/w1000/2023/03/SCR-20230304-u2y-2.png

Configure seu contrato inteligente com uma imagem, nome, descrição, etc., e defina qual endereço de carteira receberá os fundos das vendas primárias e secundárias:

https://blog.thirdweb.com/content/images/size/w1000/2023/03/image-23.png

Você pode selecionar qualquer rede que desejar; para este guia, estou escolhendo a Goerli. Saiba mais sobre as diferentes redes disponíveis abaixo:

https://blog.thirdweb.com/guides/which-network-should-you-use/

Assim que o contrato for implantado, estamos prontos para prosseguir. Não precisamos fazer nada com o contrato por enquanto.

Criando o Aplicativo Full Stack do Next.js

Agora, vamos criar um aplicativo da web de staking de NFTs em que os usuários podem conectar suas carteiras, escolher o NFT que desejam criar e criar o NFT.

Antes de começarmos, você pode acessar o código-fonte completo deste modelo no GitHub.

Usando a CLI da Thirdweb, crie um novo projeto Next.js em TypeScript com o SDK do React já pré-configurado usando o seguinte comando:

npx thirdweb create app --next --ts
Enter fullscreen mode Exit fullscreen mode

Por padrão, a rede é a Rede Principal (mainnet). Você precisará alterá-la para a rede em que implantou seus contratos inteligentes dentro do arquivo _app.tsx.

// Este é o chainId em que seu dApp funcionará.
const activeChainId = ChainId.Mumbai;
Enter fullscreen mode Exit fullscreen mode

Agora, adicione as variáveis ​​de ambiente em um novo arquivo .env.local assim:

PRIVATE_KEY=<sua-chave-privada>
Enter fullscreen mode Exit fullscreen mode

IMPORTANTE: O uso de chaves privadas como variáveis ​​de ambiente é vulnerável a ataques e não é a melhor prática. Estamos fazendo isso neste guia por brevidade, mas recomendamos fortemente usar um gerenciador de segredos para armazenar sua chave privada.

IMPORTANTE: Chaves Privadas.

Se você estiver usando variáveis ​​de ambiente para armazenar sua chave privada (não recomendado), nunca comprometa sua chave privada com o Git.

Se você enviar sua chave privada para o GitHub, sua carteira será esvaziada!

Crie um novo arquivo chamado data/address.ts e adicione seu endereço assim, porque vamos precisar dele em alguns lugares:

export const nftCollectionAddress =
  "0x02Fe95daB242625924B03819FB4Ab25d533EDdCA";
Enter fullscreen mode Exit fullscreen mode

Mostrando os NFTs

Agora vamos adicionar os NFTs que queremos disponibilizar. Para isso, crie um arquivo data/nfts.ts e adicione seus NFTs no seguinte formato:

import { NFT } from "../types/NFT";

export const nfts: NFT[] = [
  {
    id: 0,
    name: "NFT 1",
    description: "Este é o nosso primeiro NFT incrível.",
    url: "https://bafybeihgfxd5f5sqili34vyjyfai6kezlagrya43e6bkgw6hnxucxug5ya.ipfs.nftstorage.link/",
    price: 0.01,
  },
  {
    id: 1,
    name: "NFT 2",
    description: "Este é o nosso segundo NFT incrível.",
    url: "https://bafybeida2kkclur4345iihiqb6pepfnwse7ko7pvrft4duxwxxwo2jqqjq.ipfs.nftstorage.link/",
    price: 0.02,
  },
  {
    id: 2,
    name: "NFT 3",
    description: "Este é o nosso terceiro NFT incrível.",
    url: "https://bafybeidegtxcfpr43d6vbrippnm2csxqst7stxaxl3rp5vd27ss6yd3s5e.ipfs.nftstorage.link/",
    price: 0.03,
  },
  {
    id: 3,
    name: "NFT 4",
    description: "Este é o nosso quarto NFT incrível.",
    url: "https://bafybeieicywyvnaher24isrxoagjxbro6qr6kbzcz2feldbquoqeag7ivm.ipfs.nftstorage.link/",
    price: 0.01,
  },
  {
    id: 4,
    name: "NFT 5",
    description: "Este é o nosso quinto NFT incrível.",
    url: "https://bafybeieufjiaqny6q6kis2ehv2w6epwqzkeoscfc3ltck67dunrbvseczq.ipfs.nftstorage.link/",
    price: 0.02,
  },
  {
    id: 5,
    name: "NFT 6",
    description: "Este é o nosso sexto NFT incrível.",
    url: "https://bafybeiftcf7xruf4gmlbme6bos5tznlrvz46xfxdnofp3auibvzbizysoy.ipfs.nftstorage.link/",
    price: 0.03,
  },
];
Enter fullscreen mode Exit fullscreen mode

Você pode adicionar mais propriedades se desejar, mas estou adicionando apenas essas. Você pode ver que também adicionamos o tipo para cada NFT, portanto, crie um arquivo types/NFT.ts e adicione este tipo:

export interface NFT {
  id: number;
  name: string;
  description: string;
  url: string;
  price: number;
  minted?: boolean;
}
Enter fullscreen mode Exit fullscreen mode

Vamos criar uma rota de API para verificar se algum NFT já foi criado e retornar os dados com base nisso. Então, crie um arquivo dentro de pages/api chamado get-nfts.ts e adicione o seguinte:

import { ThirdwebSDK } from "@thirdweb-dev/sdk";
import type { NextApiRequest, NextApiResponse } from "next";
import { nftCollectionAddress } from "../../data/address";
import { nfts } from "../../data/nfts";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method === "GET") {
    const sdk = ThirdwebSDK.fromPrivateKey(process.env.PRIVATE_KEY!, "goerli");

    const nftCollection = await sdk.getContract(
      nftCollectionAddress,
      "nft-collection"
    );

    try {
      const mintedNfts = await nftCollection?.erc721.getAll();

      if (!mintedNfts) {
        return res.status(200).json(nfts);
      }

      mintedNfts.forEach((nft) => {
        const nftIndex = nfts.findIndex(
          // @ts-ignore
          (nftItem) => nftItem.id === nft.metadata.attributes[0].id
        );
        if (nftIndex !== -1) {
          nfts[nftIndex].minted = true;
        }
      });

      return res.status(200).json(nfts);
    } catch (error) {
      return res.status(500).json({ error });
    }
  }

  return res.status(405).json({ error: "Método não permitido" });
}
Enter fullscreen mode Exit fullscreen mode

Aqui, primeiro verificamos se a solicitação é uma solicitação get e, se não for, retornamos um erro, mas se for uma solicitação get, avançamos. Primeiramente, inicializamos o sdk da thirdweb, em seguida, obtemos a coleção de NFTs usando o endereço que adicionamos anteriormente. Finalmente, obtemos todos os NFTs da coleção e, se algum dos NFTs tiver sido cunhado, definimos como "minted" e retornamos os NFTs.

Agora vamos renderizar os NFTs para os usuários. Para isso, vamos buscar os NFTs da seguinte forma:

const [nftMetadata, setNftMetadata] = useState<NFT[] | []>([]);

const fetchNfts = async () => {
  try {
    const response = await fetch("/api/get-nfts");
    const data = await response.json();

    setNftMetadata(data);
  } catch (error) {
    console.error(error);
  }
};

useEffect(() => {
  fetchNfts();
}, []);
Enter fullscreen mode Exit fullscreen mode

Então, vamos verificar se o usuário conectou sua carteira e mapear os NFTs da seguinte forma:

<div className={styles.container}>
  {address ? (
    <>
      <h1> Selecione um NFT para cunhar</h1>
      <div className={styles.NFTs}>
        {nftMetadata &&
          nftMetadata.map((nft) => <Nft key={nft.id} nft={nft} />)}
      </div>
    </>
  ) : (
    <ConnectWallet />
  )}
</div>
Enter fullscreen mode Exit fullscreen mode

Aqui, criamos um novo componente para o NFT. Então crie um novo arquivo components/Nft.tsx e adicione o seguinte:

import { MediaRenderer, Web3Button } from "@thirdweb-dev/react";
import { nftCollectionAddress } from "../data/address";
import styles from "../styles/Home.module.css";
import { NFT } from "../types/NFT";

const Nft = ({ nft }: { nft: NFT }) => {
  return (
    <div className={styles.NFT}>
      {nft?.url && <MediaRenderer src={nft.url} className={styles.NFTImage} />}

      <div>
        <h2>{nft?.name}</h2>
        <p>{nft?.description}</p>
        <p>{nft?.price} ETH</p>
      </div>

      {nft?.minted ? (
        <b>Este NFT já foi cunhado</b>
      ) : (
        <Web3Button contractAddress={nftCollectionAddress} action={() => {}}>
          Cunhar
        </Web3Button>
      )}
    </div>
  );
};

export default Nft;
Enter fullscreen mode Exit fullscreen mode

Isso cria cartões de NFT simples como estes:

https://blog.thirdweb.com/content/images/size/w1000/2023/03/image-24.png

Mas uma coisa a acrescentar aqui é a funcionalidade de cunhagem! Então vamos adicionar isso. Precisamos criar outra API para gerar a assinatura, então crie um novo arquivo, generate-signature.ts e adicione o seguinte:

import { ThirdwebSDK } from "@thirdweb-dev/sdk";
import type { NextApiRequest, NextApiResponse } from "next";
import { nftCollectionAddress } from "../../data/address";
import { nfts } from "../../data/nfts";

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  const { id, address } = JSON.parse(req.body);

  try {
    const sdk = ThirdwebSDK.fromPrivateKey(process.env.PRIVATE_KEY!, "goerli");

    const nftCollection = await sdk.getContract(
      nftCollectionAddress,
      "nft-collection"
    );

    const mintedNfts = await nftCollection?.erc721.getAll();

    if (mintedNfts) {
      const mintedNft = mintedNfts.find(
        // @ts-ignore
        (nft) => nft.metadata.attributes[0].id === id
      );

      if (mintedNft) {
        return res.status(400).json({ error: "NFT já cunhado" });
      }
    }

    const { name, description, url, price } = nfts[id];

    const metadata = {
      metadata: {
        name,
        description,
        image: url,
        attributes: [{ id }],
      },
      price,
      to: address,
    };

    const signature = await nftCollection?.signature.generate(metadata);

    return res.status(200).json({ signature });
  } catch (error) {
    return res.status(500).json({ error });
  }
};

export default handler;
Enter fullscreen mode Exit fullscreen mode

Aqui, obtemos o tokenID do request body (corpo da requisição). Primeiro, usamos para verificar se o NFT já foi cunhado, caso contrário, usamos para obter os metadados do NFT. Também obtemos o preço do corpo que está sendo usado no parâmetro to. Finalmente, usando esses metadados, geramos a assinatura e a passamos para o frontend.

No componente Nft, adicione estes ganchos (hooks) e esta função mintNft:

const { data: nftCollection } = useContract(
    nftCollectionAddress,
    "nft-collection"
  );
  const address = useAddress();
  const [loading, setLoading] = useState(false);

  const mintNft = async (id: number) => {
    setLoading(true);

    try {
      const response = await fetch("/api/generate-signature", {
        method: "POST",
        body: JSON.stringify({ id, address }),
      });

      if (response) {
        const data = await response.json();

        await nftCollection?.signature.mint(data.signature);
        alert("NFT cunhado com sucesso!");
      }
    } catch (error) {
      alert("Falha ao cunhar NFT!");
    } finally {
      setLoading(false);
    }
  };
Enter fullscreen mode Exit fullscreen mode

Este código está adquirindo a Coleção de NFTs usando o gancho useContract. Em seguida, na função real, obtemos o id dos parâmetros e fazemos uma requisição de post para api/generate-signature com o id e endereço. Por fim, ela recebe a assinatura e cria o NFT. Agora, anexe-a ao web3Button:

<Web3Button
  action={() => mintNft(nft?.id)}
  contractAddress={nftCollectionAddress}>
  Cunhar
</Web3Button>
Enter fullscreen mode Exit fullscreen mode

Também vamos usar o estado de carregamento para mostrar um texto de carregamento:

{loading ? (
    <p
      style={{
        textAlign: "center",
      }}
    >
      Cunhando...
    </p>
  ) : nft?.minted ? (
    <b>Este NFT já foi cunhado</b>
  ) : (
    <Web3Button
      action={() => mintNft(nft?.id)}
      contractAddress={nftCollectionAddress}
    >
      Cunhar
    </Web3Button>
  )}
Enter fullscreen mode Exit fullscreen mode

Agora podemos cunhar o NFT.

https://blog.thirdweb.com/content/images/size/w1000/2023/03/image-25.png

Conclusão

Este guia nos ensinou como criar um aplicativo descentralizado onde os usuários podem escolher quais NFTs cunhar usando a assinatura mint.

Você aprendeu muito! Agora dê um tapinha nas costas e compartilhe seus aplicativos incríveis conosco no discord da thirdweb! Se você quiser ver o código, confira nosso Repositório do GitHub.

Artigo original publicado por Thirdweb. Traduzido por Paulinho Giovannini.

Oldest comments (0)