paint-brush
Como construir um portal de colecionáveis digitais usando fluxo e cadência (parte 2)by@johnjvester
213

Como construir um portal de colecionáveis digitais usando fluxo e cadência (parte 2)

John Vester15m2024/02/27
Read on Terminal Reader

Com um portal de colecionáveis no blockchain Flow e implantado na testnet, agora podemos nos concentrar na criação do frontend usando React na conclusão desta série.
featured image - Como construir um portal de colecionáveis digitais usando fluxo e cadência (parte 2)
John Vester HackerNoon profile picture
0-item


Bem-vindo à etapa final na criação do seu portal de colecionáveis! (para a parte 1, veja aqui )


Nesta parte, vamos nos concentrar na construção do frontend – a última peça do quebra-cabeça.


Aqui está o que alcançaremos:


  1. Conecte a carteira Flow.
  2. Inicialize sua conta e crie seu NFT.
  3. Verifique o NFT ID em sua coleção.
  4. Visualize o NFT com o NFT ID que você possui em sua coleção.


Estaremos usando Next.js para construir o frontend.


Vamos começar!


1. Instalação

Configurando

Abra o diretório flow-collectible-portal do seu projeto. Então corra
npx create-next-app@latest frontend no terminal e pressione enter .


Isso fornecerá várias opções. Neste tutorial, não usaremos Typescript , ESLint ou TailwindCSS e usaremos o diretório src e o roteador do aplicativo no momento deste artigo.


Agora você tem um novo aplicativo da web pronto.

Esta é a aparência da sua pasta frontend:



2. Configuração

Para interagir com o blockchain Flow, usaremos a Flow Client Library (FCL) para gerenciar conexões de carteira, executar scripts e enviar transações em nosso aplicativo. Isso nos permitirá escrever funções Cadence completas e executá-las como funções Javascript.


Para começar, vamos instalar o FCL em nosso aplicativo executando o seguinte comando:


 npm install @onflow/fcl --save


Após instalar o FCL, precisamos configurá-lo. Aqui está o que você precisa fazer:


  1. Dentro da pasta app crie uma nova pasta chamada flow e adicione um arquivo chamado config.js .
  2. Neste arquivo, defina a configuração para o FCL, como especificar o nó de acesso e o endpoint de descoberta de carteira. Isso ajuda você a escolher entre usar um testnet ou um emulador local.
  3. Você também desejará especificar o endereço do contrato de colecionáveis que implantamos na Parte 1.


Adicione o seguinte código ao arquivo config.js :


 import { config } from "@onflow/fcl"; config({ "app.detail.title": "Flow Name Service", "app.detail.icon": "https://placekitten.com/g/200/200", "accessNode.api": "https://rest-testnet.onflow.org", "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", "0xCollectibles": "ADD YOUR CONTRACT ACCOUNT ADDRESS", "0xNonFungibleToken": "0x631e88ae7f1d7c20", });


Agora você está pronto para usar o FCL em seu aplicativo.


3. Autenticação

Para verificar a identidade de um usuário em um aplicativo, você pode usar diversas funções:


  1. Para fazer login, chame fcl.logIn() .
  2. Para se inscrever, ligue fcl.signUp() .
  3. Para sair, chame fcl.unauthenticate() .


Vamos aprender como podemos implementar essas funções fcl em seu frontend.


Primeiro, adicionaremos o seguinte código ao nosso arquivo page.js dentro do diretório app. Isso importará algumas dependências, configurará algum useState inicial para partes de nosso aplicativo e construirá uma UI básica.


Para ter certeza de que está bonito, exclua o arquivo page.module.css dentro do diretório do aplicativo e, em vez disso, crie um arquivo chamado page.css. Em seguida, cole o conteúdo deste arquivo dentro dele. Agora podemos escrever nossa página inicial.


 "use client"; import React, { useState, useEffect, useRef } from "react"; import * as fcl from "@onflow/fcl"; import "./page.css"; import "./flow/config"; export default function Page() { const [currentUser, setCurrentUser] = useState({ loggedIn: false, addr: undefined, }); const urlInputRef = useRef(); const nameInputRef = useRef(); const idInputRef = useRef(); const [isInitialized, setIsInitialized] = useState(); const [collectiblesList, setCollectiblesList] = useState([]); const [loading, setLoading] = useState(false); const [ids, setIds] = useState([]); const [nft, setNFT] = useState({}); useEffect(() => fcl.currentUser.subscribe(setCurrentUser), []); function handleInputChange(event) { const inputValue = event.target.value; if (/^\d+$/.test(inputValue)) { idInputRef.current = +inputValue; } else { console.error("Invalid input. Please enter a valid integer."); } } return ( <div> <div className="navbar"> <h1>Flow Collectibles Portal</h1> <span>Address: {currentUser?.addr ?? "NO Address"}</span> <button onClick={currentUser.addr ? fcl.unauthenticate : fcl.logIn}> {currentUser.addr ? "Log Out" : "Connect Wallet"} </button> </div> {currentUser.loggedIn ? ( <div className="main"> <div className="mutate"> <h1>Mutate Flow Blockchain</h1> <form onSubmit={(event) => { event.preventDefault(); }} > <input type="text" placeholder="enter name of the NFT" ref={nameInputRef} /> <input type="text" placeholder="enter a url" ref={urlInputRef} /> <button type="submit">Mint</button> </form> <mark>Your Collection will be initialized while minting NFT.</mark> </div> <div className="query"> <h1>Query Flow Blockchain</h1> <mark>Click below button to check 👇</mark> <button>Check Collection</button> <p> Is your collection initialized: {isInitialized ? "Yes" : "No"} </p> <button onClick={viewIds}> View NFT IDs you hold in your collection </button> <p>NFT Id: </p> </div> <div className="view"> <h1>View Your NFT</h1> <input type="text" placeholder="enter your NFT ID" onChange={handleInputChange} /> <button>View NFT</button> <div className="nft-card"> <p>NFT id: </p> <p>NFT name: </p> <img src="" alt="" /> </div> </div> </div> ) : ( <div className="main-2"> <h1>Connect Wallet to mint NFT!!</h1> </div> )} </div> ); }


Depois de adicionar este código, execute npm run dev para garantir que tudo carregue corretamente.


4. Consultando o blockchain Flow

Antes de nos aprofundarmos em como podemos usar fcl para consultar o blockchain Flow, adicione esses códigos de script Cadence após a função handleInput no arquivo page.js


 const CHECK_COLLECTION = ` import NonFungibleToken from 0xNonFungibleToken import Collectibles from 0xCollectibles pub fun main(address: Address): Bool? { return Collectibles.checkCollection(_addr: address) }` const GET_NFT_ID = ` import NonFungibleToken from 0xNonFungibleToken import Collectibles from 0xCollectibles pub fun main(user: Address): [UInt64] { let collectionCap = getAccount(user).capabilities.get <&{Collectibles.CollectionPublic}>(/public/NFTCollection) ?? panic("This public capability does not exist.") let collectionRef = collectionCap.borrow()! return collectionRef.getIDs() } ` const GET_NFT = ` import NonFungibleToken from 0xNonFungibleToken import Collectibles from 0xCollectibles pub fun main(user: Address, id: UInt64): &NonFungibleToken.NFT? { let collectionCap= getAccount(user).capabilities.get<&{Collectibles.CollectionPublic}>(/public/NFTCollection) ?? panic("This public capability does not exist.") let collectionRef = collectionCap.borrow()! return collectionRef.borrowNFT(id: id) }


Com nossos scripts Cadence prontos, agora podemos declarar algumas funções Javascript e passar as constantes Cadence para as consultas `fcl` .


 async function checkCollectionInit() { const isInit = await fcl.query({ cadence: CHECK_COLLECTION, args: (arg,t) => [arg(currentUser?.addr, t.Address)], }); console.log(isInit); } async function viewNFT() { console.log(idInputRef.current); const nfts = await fcl.query({ cadence: GET_NFT, args: (arg,t) => [arg(currentUser?.addr,t.Address), arg(idInputRef.current, t.UInt64)] }); setNFT(nfts); console.log(nfts); } async function viewIds() { const ids = await fcl.query({ cadence: GET_NFT_ID, args: (arg,t) => [arg(currentUser?.addr,t.Address)] }); setIds(ids); console.log(ids); }


Agora vamos dar uma olhada em todas as funções que escrevemos. Há duas coisas a serem observadas:


  1. O fcl.query
  2. E os args: (arg,t) => [arg(addr,t.Address)], linha.


Como os scripts são semelhantes às funções de view no Solidity e não exigem nenhuma taxa de gás para serem executados, estamos essencialmente apenas consultando o blockchain. Portanto, usamos fcl.query para executar scripts no Flow.


Para consultar algo, precisamos passar um argumento. Para isso, usamos arg, que é uma função que recebe um valor de string que representa o argumento, e t , que é um objeto que contém todos os diferentes tipos de dados que o Cadence possui. Assim, podemos dizer arg como codificar e decodificar o argumento que estamos passando.

5. Mutação do blockchain Flow

Embora nossas funções anteriores fossem apenas “somente leitura”, nossas próximas terão ações que podem alterar o estado do blockchain e gravar nele; também conhecido como “cunhar um NFT”.


Para fazer isso, escreveremos outro script Cadence como constante.


 const MINT_NFT = ` import NonFungibleToken from 0xNonFungibleToken import Collectibles from 0xCollectibles transaction(name:String, image:String){ let receiverCollectionRef: &{NonFungibleToken.CollectionPublic} prepare(signer:AuthAccount){ // initialise account if signer.borrow<&Collectibles.Collection>(from: Collectibles.CollectionStoragePath) == nil { let collection <- Collectibles.createEmptyCollection() signer.save(<-collection, to: Collectibles.CollectionStoragePath) let cap = signer.capabilities.storage.issue<&{Collectibles.CollectionPublic}>(Collectibles.CollectionStoragePath) signer.capabilities.publish( cap, at: Collectibles.CollectionPublicPath) } //takes the receiver collection refrence self.receiverCollectionRef = signer.borrow<&Collectibles.Collection>(from: Collectibles.CollectionStoragePath) ?? panic("could not borrow Collection reference") } execute{ let nft <- Collectibles.mintNFT(name:name, image:image) self.receiverCollectionRef.deposit(token: <-nft) } }


Agora adicione a função abaixo após o código de transação ao arquivo page.js


 async function mint() { try{ const txnId = await fcl.mutate({ cadence: MINT_NFT, args: (arg,t) => [arg(name,t.String), arg(image, t.String)], payer: fcl.authz, proposer: fcl.authz, authorizations: [fcl.authz], limit:999,}); } catch(error){ console.error('Minting failed:' error) } console.log(txnId); }


Quanto à função, a sintaxe fcl.mutate é igual a fcl.query . No entanto, fornecemos vários parâmetros extras, como os seguintes:


 payer: fcl.authz, proposer: fcl.authz, authorizations: [fcl.authz], limit: 50,


  • São coisas específicas do Flow que definem qual conta pagará pela transação (pagador), transmitirá a transação (proponente) e as contas das quais precisamos de autorizações. (Caso uma conta tenha várias chaves anexadas, ela pode se comportar como uma carteira multi-sig.)
  • fcl.authz refere-se à conta atualmente conectada.
  • limit é como gasLimit no mundo Ethereum, que coloca um limite superior na quantidade máxima de computação. Se o cálculo ultrapassar o limite, a transação falhará.


Precisaremos adicionar mais uma função que irá chamar e manipular a função mintNFT que acabamos de criar.


 const saveCollectible = async () => { if (urlInputRef.current.value.length > 0 && nameInputRef.current.value.length > 0) { try { setLoading(true); const transaction = await mintNFT(nameInputRef.current.value, urlInputRef.current.value); console.log('transactionID:', transaction); // Handle minting success (if needed) } catch (error) { console.error('Minting failed:', error); // Handle minting failure (if needed) } finally { setLoading(false); } } else { console.log('Empty input. Try again.'); } };


6. Código final

Com nossas funções principais implementadas, agora podemos conectá-las à nossa IU.


No entanto, antes de fazermos isso, adicionaremos algumas chamadas useEffect para ajudar a carregar o estado inicial. Você pode adicioná-los logo acima da chamada useEffect já existente.


 useEffect(() => { checkCollectionInit(); viewNFT(); }, [currentUser]); useEffect(() => { if (currentUser.loggedIn) { setCollectiblesList(collectiblesList); console.log('Setting collectibles...'); } }, [currentUser]);


Agora, de volta à nossa seção return com a UI, podemos adicionar nossas funções às partes apropriadas do aplicativo.


 return ( <div> <div className="navbar"> <h1>Flow Collectibles Portal</h1> <span>Address: {currentUser?.addr ?? "NO Address"}</span> <button onClick={currentUser.addr ? fcl.unauthenticate : fcl.logIn}> {currentUser.addr ? "Log Out" : "Connect Wallet"} </button> </div> {currentUser.loggedIn ? ( <div className="main"> <div className="mutate"> <h1>Mutate Flow Blockchain</h1> <form onSubmit={(event) => { event.preventDefault(); saveCollectible(); }} > <input type="text" placeholder="enter name of the NFT" ref={nameInputRef} /> <input type="text" placeholder="enter a url" ref={urlInputRef} /> <button type="submit">Mint</button> </form> <mark>Your Collection will be initialized while minting NFT.</mark> </div> <div className="query"> <h1>Query Flow Blockchain</h1> <mark>Click below button to check 👇</mark> <button onClick={checkCollectionInit}>Check Collection</button> <p> Is your collection initialized: {isInitialized ? "Yes" : "No"} </p> <button onClick={viewIds}> View NFT IDs you hold in your collection </button> <p>NFT Id: </p> {ids.map((id) => ( <p key={id}>{id}</p> ))} </div> <div className="view"> <h1>View Your NFT</h1> <input type="text" placeholder="enter your NFT ID" onChange={handleInputChange} /> <button onClick={viewNFT}>View NFT</button> <div className="nft-card"> <p>NFT id: {nft.id}</p> <p>NFT name: {nft.name}</p> <img src={nft.image} alt={nft.name} /> </div> </div> </div> ) : ( <div className="main-2"> <h1>Connect Wallet to mint NFT!!</h1> </div> )} </div> );


Verifique o código final aqui .


Agora com o aplicativo completo, vamos ver como usá-lo!


Primeiro, conecte sua carteira clicando no botão “Conectar carteira” no canto superior direito.


Agora você pode cunhar um NFT! Digite o nome do seu NFT e cole um link para a imagem que deseja usar. Depois de clicar em “mint”, você será solicitado a assinar uma transação com sua carteira.


Pode demorar um pouco para a transação ser concluída. Após a conclusão, você poderá clicar no botão inferior para visualizar os IDs de seus NFTs. Se este for o seu primeiro, o ID deverá ser apenas “1”.


Agora você pode copiar o ID do seu NFT, colá-lo na seção Visualizar e clicar em “Visualizar NFT”.


Conclusão

Bom trabalho! Você concluiu a parte 2 do projeto do portal Colecionáveis. Em resumo, nos concentramos na construção do frontend do nosso portal de colecionáveis.


Fizemos isso por:


  • Criando um aplicativo com Next.js
  • Conectando a Carteira Flow
  • Criando nossos próprios NFTs para cunhagem
  • Visualizando seu NFT


Tenha um ótimo dia!


Também publicado aqui.