Você provavelmente já ouviu falar de NFTs antes, mas apenas no caso de não ter ouvido, tokens não-fungíveis (NFTs) são identificadores digitais únicos que não podem ser copiados, substituídos ou subdivididos. Eles são registrados em uma blockchain para certificar autenticidade e propriedade.
À medida que a popularidade dos NFTs cresceu, o mercado de NFTs alcançou um valor superior a US$40 bilhões. E atualmente, a melhor maneira de comprar e vender NFTs é por meio de mercados de NFTs.
Mercados de NFTs como o OpenSea, Axie Marketplace, NBA Top Shot, Rarible, Nifty Gateway, Sudoswap entre outros, são todos líderes nesse espaço. Eles atuam como sua porta de entrada para participar da compra e venda de ativos digitais, desde arte até música e até mundos virtuais inteiros.
Na Lazer, trabalhamos com muitos projetos de mercado de NFTs, incluindo Sudoswap, Stardust, Genies, NFL All Day, e pensamos que seria ótimo fazer um tutorial sobre como construir uma versão simplificada de um mercado de NFTs.
Neste tutorial, construiremos um mercado de NFTs na rede de teste Polygon Mumbai usando a estrutura Next.js com Typescript e o SDK Thirdweb.
O resultado final será semelhante às imagens abaixo:
Depois de construir o mercado de NFTs, ele deve ser capaz de:
- Ver todos os NFTs disponíveis para venda
- Visualizar NFTs individuais e seus detalhes
- Permitir que os usuários comprem os NFTs
- (Bônus) Ver todos os NFTs em uma carteira
Pré-requisitos necessários para realizar isso:
- Uma carteira digital (por exemplo, Metamask)
- A carteira está conectada a rede de teste Polygon Mumbai, com mais de 1 MATIC na carteira. Se não estiver, vá para a torneira Mumbai da Alchemy's para solicitar 1 MATIC https://mumbaifaucet.com/
- Conhecimento básico de Nextjs e Typescript
- Conhecimento básico de NFTs e Contratos Inteligentes
Passo 1: Crie e cunhe seus NFTs na Thirdweb
Antes de podermos criar o mercado de NFTs, primeiro precisamos criar um contrato de coleção de NFTs e cunharr alguns NFTs. O contrato de coleção de NFTs é adequado quando você deseja ter uma coleção de NFTs exclusivos, mas não "lançá-los" ou "liberá-los" para sua comunidade reivindicar.
- Vá para o painel da Thirdweb.
- Crie um novo contrato de coleção de NFTs. Clique em Deploy new contract → NFT Collection → Deploy now. Mantenha todas as configurações iguais, selecione a rede Mumbai (MATIC).
- Acesse o contrato de coleção de NFTs que você acabou de implantar e cunhealguns NFTs diferentes. Por exemplo:
Passo 2: Crie e implante um contrato de mercado de NFTs na Thirdweb
Agora que você cunhou alguns NFTs, vamos criar e implantar um contrato de mercado de NFTs. Um contrato de mercado de NFTs é um contrato em que você pode comprar e vender NFTs, como o OpenSea ou o Rarible. O contrato do mercado permite que os usuários listem NFTs para venda direta ou leilão. Outros usuários podem fazer ofertas ou comprar os NFTs pelo valor especificado na lista. O mercado pode ser configurado para permitir apenas que determinados usuários listem NFTs para venda, ou permitir que qualquer usuário liste NFTs para venda.
- Vá para o painel da Thirdweb.
- Crie um novo contrato de mercado de NFTs. Deploy new contract → NFT Marketplace → Deploy now. Mantenha todas as configurações iguais, selecione a rede Mumbai (MATIC).
- Vá para o contrato de mercado que você acabou de implantar e crie listas. Para este tutorial, selecione o tipo de listagem Direta.
Passo 3: Vamos escrever algum código Typescript!
Primeiro, vamos clonar um repositório do GitHub que já tem o estilo pronto para você.
Isenção de responsabilidade: Este não é um tutorial de CSS/HTML, então vamos começar clonando este repositório do GitHub que já possui estilo: https://github.com/LazerTechnologies/nft-marketplace-tutorial
Depois de clonado, execute:
Se você estiver preso, mude para a filial principal para ver o produto final.
git checkout blank
npm install
npm run dev
Configurando os SDKs da Thirdweb em nosso aplicativo
Dentro do arquivo _app.tsx
, envolva tudo com ThirdwebProvider como abaixo, com o ID da cadeia sendo Mumbai.
const MyApp: AppType = ({ Component, pageProps }) => {
return (
<ThirdwebProvider desiredChainId={ChainId.Mumbai}>
<Component {...pageProps} />
</ThirdwebProvider>
);
};
Configurar a autenticação Web3 usando a Thirdweb
Crie um arquivo chamado components/AuthProvider.tsx
import { ReactElement, useEffect, useState } from "react";
import { ConnectWallet, useAddress } from "@thirdweb-dev/react";
export default function AuthProvider({
children,
}: {
children: React.ReactNode;
}): ReactElement {
const [isLoggedin, setIsLoggedin] = useState(false);
const address = useAddress();
useEffect(() => {
if (address) {
setIsLoggedin(true);
} else {
setIsLoggedin(false);
}
}, [address]);
if (!isLoggedin) {
return (
<div className={"flex h-screen w-full items-center justify-center"}>
<div>
<h1 className={"text-lg"}>Por favor, faça o login para continuar...</h1>
<ConnectWallet />
</div>
</div>
);
}
return <>{children}</>;
}
Também envolva o <Component> em _app.tsx
com AuthProvider.
const MyApp: AppType = ({ Component, pageProps }) => {
return (
<ThirdwebProvider desiredChainId={ChainId.Mumbai}>
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
</ThirdwebProvider>
);
};
Agora o usuário verá isso quando não estiver conectado.
Obtendo os NFTs listados em seu contrato de Mercado
No arquivo index.tsx
, obtenha o contrato de mercado usando useContract
, e obtenha as listagens ativas usando useActiveListings
.
import type { NextPage } from "next";
import { useActiveListings, useContract } from "@thirdweb-dev/react";
const Home: NextPage = () => {
const { contract } = useContract(
"ENDEREÇO DO CONTRATO DO SEU MERCADO>",
"MERCADO"
);
const { data, isLoading } = useActiveListings(contract);
console.log(data);
return (
<div>NFT Marketplace</div>
);
};
export default Home;
Abra o console da web e você deverá ver os dados do NFT 😊
Agora vamos criar um componente para mostrar cada um desses NFTs.
Vamos criar o arquivo components/NFTCard.tsx
e adicionar o seguinte:
import Image from "next/image";
import { MediaRenderer } from "@thirdweb-dev/react";
export default function NFTCard({
nft,
}: {
nft: {
tokenUri: string;
name: string;
price?: string;
};
}) {
return (
<div
className={`relative flex cursor-pointer
flex-col overflow-hidden rounded-lg bg-white shadow-lg
transition-all duration-300 hover:shadow-2xl dark:bg-[#333333]`}
>
<MediaRenderer
src={nft.tokenUri}
style={{
objectFit: "cover",
}}
className={
"h-[244px] rounded-lg transition duration-300 ease-in-out hover:scale-105"
}
/>
<div className={`flex flex-col gap-y-3 p-3`}>
<div className={`text-sm font-semibold`}>{nft.name}</div>
{nft.price && (
<div>
<div className={`text-xs font-semibold`}>Price</div>
<div className={`flex items-center gap-x-1`}>
<Image src={"/matic-logo.png"} height={16} width={16} />
<p className={`text-base font-semibold`}>{nft.price}</p>
</div>
</div>
)}
</div>
</div>
);
}
Vamos exibir esses dados adequadamente, adicionando o seguinte ao arquivo styles/global.css.
@tailwind base;
@tailwind components;
@tailwind utilities;
html {
font-family: "DM Sans", sans-serif;
background: white;
}
.nft-grid {
display: grid;
--template-column-gutters: 8px;
--template-columns: 1;
--template-column-compact-multiplier: 1;
--template-reduced-columns: 0;
--template-reduced-columns-multiplier: 1;
gap: var(--template-column-gutters);
grid-auto-rows: minmax(0px, 1fr);
grid-template-columns: repeat( calc(var(--template-columns) - (var(--
template-reduced-columns) * var(--template-reduced-columns-multiplier))), minmax(0, 1fr) );
}
@media (min-width: 20rem) {
.nft-grid {
--template-columns: 2;
}
}
@media (min-width: 30rem) {
.nft-grid {
--template-columns: 3;
}
}
@media (min-width: 40rem) {
.nft-grid {
--template-columns: 4;
}
}
@media (min-width: 768px) {
.nft-grid {
--template-column-gutters: 16px;
}
}
Agora substitua o conteúdo de index.tsx
pelo código abaixo:
import type { NextPage } from "next";
import { useActiveListings, useContract } from "@thirdweb-dev/react";
import NFTCard from "../components/NFTCard";
const Home: NextPage = () => {
const { contract } = useContract(
"SEU CONTRATO DE MERCADO",
"mercado"
);
const { data: nfts, isLoading } = useActiveListings(contract);
if (isLoading)
return (
<div className={"mb-3 flex w-screen justify-center"}>Loading ...</div>
);
return (
<div className={"space-y-4 p-2"}>
<div className={"text-2xl font-semibold"}>Active Listings</div>
<div className={`nft-grid`}>
{nfts &&
nfts.map((nft) => {
return (
<a>
<NFTCard
nft={{
name: nft.asset.name as string,
tokenUri: nft.asset.image as string,
price: nft.buyoutCurrencyValuePerToken?.displayValue,
}}
/>
</a>
);
})}
</div>
</div>
);
};
export default Home;
Agora sua página inicial deve se parecer com a imagem abaixo!
Agora que temos a página inicial, vamos exibir as listagens individuais de NFT.
Para isso, vamos criar um arquivo chamado: pages/assets/[listingid].tsx
.
import { useRouter } from "next/router";
import { useContract, useListing } from "@thirdweb-dev/react";
import Image from "next/image";
import { AiOutlineClockCircle } from "react-icons/ai";
import { BigNumber } from "ethers";
export default function NFT() {
const router = useRouter();
const { listingId } = router.query;
const { contract } = useContract(
"SEU CONTRATO DE MERCADO",
"mercado"
);
const { data: nft, isLoading } = useListing(contract, listingId as string);
const buyoutListing = async () => {
try {
await contract?.buyoutListing(BigNumber.from(listingId), 1);
} catch (e) {
alert(e);
}
};
if (isLoading || !nft)
return (
<div className={"flex h-screen items-center justify-center"}>
Loading ...
</div>
);
return (
<div className="flex justify-center">
<div className="flex max-w-[500px] flex-col justify-center gap-y-4 p-2">
<div className={"text-2xl font-semibold"}>{nft?.asset?.name}</div>
<div className={"flex flex-col rounded-lg border border-[#e8ebe5]"}>
<div className={`flex items-center justify-start p-3`}>
<Image src={`/matic-logo.png`} height={20} width={20} />
</div>
<Image
className={"rounded-2xl"}
src={nft?.asset.image as string}
width={500}
height={500}
objectFit={"cover"}
/>
</div>
<div className={"flex space-x-1 text-sm"}>
<div className={"text-gray-500"}>Owned by</div>
<div className="cursor-pointer text-blue-500">
{nft?.sellerAddress}
</div>
</div>
{/*Bottom Section*/}
<div className={"flex flex-col rounded-lg border border-[#e8ebe5]"}>
<div className={"border-b border-[#e8ebe5] p-3"}>
<div
className={
"flex items-center space-x-2 text-sm text-gray-700 md:text-base"
}
>
<AiOutlineClockCircle size={24} />
<p>Sale ends November 26, 2022 at 7:39pm GMT+11</p
</div>
</div>
<div className={"flex flex-col gap-y-2 bg-slate-50 p-3"}>
<div className={"text-sm text-gray-500"}>Current Price</div>
<div className={`flex items-center space-x-3`}>
<Image src={`/matic-logo.png`} height={24} width={24} />
<p className={`text-3xl font-semibold`}>
{nft?.buyoutCurrencyValuePerToken?.displayValue}
</p>
</div>
<button
type="button"
className="rounded-lg bg-blue-700 px-5 py-4 text-base font-bold text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
onClick={buyoutListing}
>
Purchase
</button>
</div>
</div>
</div>
</div>
);
}
Agora adicione o link para esta página no index.tsx.
const Home: NextPage = () => {
...
return (
...
<Link
href={`/assets/${nft.id}`}
key={nft.assetContractAddress + nft.id} >
<a>
<NFTCard
nft={{
name: nft.asset.name as string,
tokenUri: nft.asset.image as string,
price: nft.buyoutCurrencyValuePerToken?.displayValue,
}}
/>
</a>
</Link>
...
);
};
Agora esta página deve parecer com a imagem abaixo:
Agora, quando você clicar em comprar, deve abrir a carteira Metamask.
Bônus) Visualizar todos os NFTs em sua carteira
Agora que temos a página inicial e uma página de NFTs, vamos criar uma página que mostra todos os NFTs existentes em nossa carteira. Para isso, a abordagem mais fácil é usar a API Web3 da Moralis. É grátis! Por favor, cadastre-se em seu site e crie sua chave de API.
Assim que você tiver suas chaves de API, crie um arquivo .env
na pasta raiz e adicione:
MORALIS_API_KEY=<YOUR API KEY>
Vamos utilizar a funcionalidade de backend do Next.js e criar a página pages/api/wallet/[walletAddress]/nfts.ts
com o seguinte código:
import { NextApiRequest, NextApiResponse } from "next";
import axios from "axios";
export default async function handle(
req: NextApiRequest,
res: NextApiResponse
) {
const { walletAddress } = req.query;
const options = {
method: "GET",
url: `https://deep-index.moralis.io/api/v2/${walletAddress}/nft`,
params: { chain: "mumbai", format: "decimal" },
headers: {
accept: "application/json",
"X-API-Key": process.env.MORALIS_API_KEY,
},
};
try {
const { data } = await axios.request(options);
const results: { tokenUri: any; name: any }[] = data.result.map(
(nft: any) => ({
name: JSON.parse(nft.metadata)?.name,
tokenUri: JSON.parse(nft.metadata)?.image,
})
);
const filteredResults = results.filter(
(data) => !!data?.tokenUri && !!data?.name
);
res.status(200).json(filteredResults);
} catch (error) {
console.error(error);
res.status(500).json({ error: error });
}
}
Aqui, nós buscamos os NFTs fornecendo um endereço de carteira. Em seguida, reestruturamos/filtramos os dados e os retornamos para o cliente.
Agora que temos nossa API de NFTs, vamos criar a página pages/profile/[walletAddress].tsx
no frontend com o seguinte código:
import { useRouter } from "next/router";
import NFTCard from "../../components/NFTCard";
import Image from "next/image";
import { fetcher } from "../../utils/utils";
import useSWR from "swr";
export default function Profile() {
const router = useRouter();
const { walletAddress } = router.query;
const { data } = useSWR(`/api/wallet/${walletAddress}/nfts`, fetcher);
if (!data)
return (
<div className={"flex h-screen w-screen items-center justify-center"}>
Loading ...
</div>
);
return (
<div className={"flex w-screen flex-col justify-center gap-y-2 p-4"}>
<div className={"space-y-2"}>
<div className={"text-3xl font-semibold"}>Sua coleção</div>
<div>
<div className={"flex items-center space-x-1"}>
<Image src={`/matic-logo.png`} height={16} width={16} />
<p className={"w-1/4 truncate text-slate-400"}>{walletAddress}</p>
</div>
</div>
</div>
{data?.length === 0 ? (
<div>Nenhum NFT foi encontrado...</div>
) : (
<div className={`nft-grid`}>
{data?.map((nft: any, index: number) => {
return (
<NFTCard
key={index}
nft={{
name: nft.name
tokenUri: nft.tokenUri,
}}
/>
);
})}
</div>
)}
</div>
);
}
Agora vamos adicionar um link para a página profile/[walletAddress]
em nosso index.tsx
.
import type { NextPage } from "next";
import {
useActiveListings,
useAddress,
useContract,
} from "@thirdweb-dev/react";
import Link from "next/link";
import NFTCard from "../components/NFTCard";
const Home: NextPage = () => {
const address = useAddress();
...
return (
<div className={"space-y-4 p-2"}>
<div className={"flex space-x-4"}>
<div className={"text-2xl font-semibold"}>Listagens ativas</div>
<Link href={`profile/${address}`}>
<div className={"cursor-pointer text-2xl font-semibold"}>
Minhas coleções
</div>
</Link>
</div>
…
E isso é tudo! Você tem seu mercado de NFTs, construído com Next.js e Thirdweb na rede Polygon.
Este guia foi escrito por Zain Manji e Nam Dao, e foi publicado pela primeira vez no blog da Lazer. A Lazer é um estúdio de produtos digitais que projeta, constrói e envia produtos incríveis para algumas das melhores marcas do mundo.
Visite o site da Lazer aqui e entre em contato com eles no Twitter ou envie um e-mail para [email protected].
Esse artigo foi escrito por Zain Manji e Nam Dao e traduzido por Arnaldo Campos. Seu original pode ser lido aqui.
Latest comments (0)