paint-brush
Cómo crear un portal de coleccionables digitales utilizando flujo y cadencia (Parte 2)por@johnjvester
222 lecturas

Cómo crear un portal de coleccionables digitales utilizando flujo y cadencia (Parte 2)

por John Vester15m2024/02/27
Read on Terminal Reader

Demasiado Largo; Para Leer

Con un portal de Coleccionables en la cadena de bloques Flow e implementado en la red de prueba, ahora podemos concentrarnos en crear la interfaz usando React al final de esta serie.
featured image - Cómo crear un portal de coleccionables digitales utilizando flujo y cadencia (Parte 2)
John Vester HackerNoon profile picture
0-item


¡Bienvenido al paso final en la creación de su portal de Coleccionables! (para la parte 1, ver aquí )


En esta parte, nos centraremos en construir la interfaz, la última pieza del rompecabezas.


Esto es lo que lograremos:


  1. Conecte la billetera Flow.
  2. Inicialice su cuenta y acuñe su NFT.
  3. Verifique el ID de NFT en su colección.
  4. Vea el NFT con el ID de NFT que tiene en su colección.


Usaremos Next.js para construir la interfaz.


¡Empecemos!


1. Instalación

Configuración

Abra el directorio flow-collectible-portal de su proyecto. Entonces corre
npx create-next-app@latest frontend en la terminal y presione enter .


Esto le proporcionará varias opciones. En este tutorial, no usaremos Typecript , ESLint o TailwindCSS , y usaremos el directorio src y el enrutador de la aplicación al momento de escribir este artículo.


Ahora tienes lista una nueva aplicación web.

Así es como se ve tu carpeta frontend:



2. Configuración

Para interactuar con la cadena de bloques Flow, usaremos la biblioteca Flow Client (FCL) para administrar conexiones de billetera, ejecutar scripts y enviar transacciones en nuestra aplicación. Nos permitirá escribir funciones de Cadencia completas y ejecutarlas como funciones de Javascript.


Para comenzar, instalemos FCL para nuestra aplicación ejecutando el siguiente comando:


 npm install @onflow/fcl --save


Después de instalar FCL, debemos configurarlo. Esto es lo que debes hacer:


  1. Dentro de la carpeta app , cree una nueva carpeta llamada flow y agregue un archivo llamado config.js .
  2. En este archivo, establezca la configuración para FCL, como especificar el nodo de acceso y el punto final de descubrimiento de billetera. Esto le ayuda a elegir entre utilizar una red de prueba o un emulador local.
  3. También querrás especificar la dirección del contrato de Coleccionables que implementamos en la Parte 1.


Agregue el siguiente código al archivo 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", });


Ahora ya está todo configurado para usar FCL en su aplicación.


3. Autenticación

Para verificar la identidad de un usuario en una aplicación, puede utilizar varias funciones:


  1. Para iniciar sesión, llame fcl.logIn() .
  2. Para registrarse, llame fcl.signUp() .
  3. Para cerrar sesión, llame fcl.unauthenticate() .


Aprendamos cómo podemos implementar estas funciones fcl en su interfaz.


Primero, agregaremos el siguiente código a nuestro archivo page.js dentro del directorio de la aplicación. Esto importará algunas dependencias, configurará un useState inicial para partes de nuestra aplicación y creará una interfaz de usuario básica.


Para asegurarse de que se vea bien, elimine el archivo page.module.css dentro del directorio de la aplicación y, en su lugar, cree un archivo llamado page.css. Luego pegue el contenido de este archivo dentro de él. Ahora podemos escribir nuestra 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> ); }


Después de agregar este código, ejecute npm run dev para asegurarse de que todo se cargue correctamente.


4. Consultar la cadena de bloques Flow

Antes de profundizar en cómo podemos usar fcl para consultar la cadena de bloques Flow, agregue estos códigos de script de Cadence después de la función handleInput en el archivo 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) }


Con nuestros scripts de Cadence listos para funcionar, ahora podemos declarar algunas funciones de Javascript y pasar las constantes de Cadence a las 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); }


Ahora echemos un vistazo a todas las funciones que hemos escrito. Hay dos cosas a tener en cuenta:


  1. La fcl.query
  2. Y los args: (arg,t) => [arg(addr,t.Address)], línea.


Dado que los scripts son similares a las funciones view en Solidity y no requieren ninguna tarifa de gas para ejecutarse, básicamente solo estamos consultando la cadena de bloques. Entonces usamos fcl.query para ejecutar scripts en Flow.


Para consultar algo, necesitamos pasar un argumento. Para eso, usamos arg, que es una función que toma un valor de cadena que representa el argumento, y t , que es un objeto que contiene todos los diferentes tipos de datos que tiene Cadence. Entonces podemos decirle a arg cómo codificar y decodificar el argumento que estamos pasando.

5. Mutando la cadena de bloques Flow

Si bien nuestras funciones anteriores eran solo de “solo lectura”, las siguientes tendrán acciones que pueden mutar el estado de la cadena de bloques y escribir en ella; también conocido como "acuñar un NFT".


Para hacer esto, escribiremos otro script de 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) } }


Ahora agregue la siguiente función después del código de transacción al archivo 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); }


En cuanto a la función, la sintaxis fcl.mutate es la misma que la fcl.query . Sin embargo, proporcionamos varios parámetros adicionales como los siguientes:


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


  • Estas son cosas específicas de Flow que definen qué cuenta pagará la transacción (pagador), transmitirá la transacción (proponente) y las cuentas de las cuales necesitamos autorizaciones. (En caso de que una cuenta tenga varias claves adjuntas, puede comportarse como una billetera multifirma).
  • fcl.authz se refiere a la cuenta actualmente conectada.
  • limit es como gasLimit en el mundo Ethereum, que impone un límite superior a la cantidad máxima de cálculo. Si el cálculo cruza el límite, la transacción fallará.


Necesitaremos agregar una función más que llame y maneje la función mintNFT que acabamos de crear.


 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

Con nuestras funciones principales implementadas, ahora podemos conectarlas a nuestra interfaz de usuario.


Sin embargo, antes de hacer eso, agregaremos algunas llamadas useEffect para ayudar a cargar el estado inicial. Puede agregarlos justo encima de la llamada useEffect ya existente.


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


Ahora, de vuelta en nuestra sección return con la interfaz de usuario, podemos agregar nuestras funciones a las partes apropiadas de la aplicación.


 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> );


Consulta el código final aquí .


Ahora que la aplicación está completa, ¡veamos cómo usarla!


Primero, conecte su billetera haciendo clic en el botón "Conectar billetera" en la parte superior derecha.


¡Ahora puedes crear un NFT! Ingrese el nombre de su NFT y pegue un enlace a la imagen que desea usar. Después de hacer clic en "mint", se le pedirá que firme una transacción con su billetera.


Es posible que la transacción tarde un poco en completarse. Una vez que se complete, debería poder hacer clic en el botón inferior para ver las ID de sus NFT. Si este es el primero, entonces el ID debe ser solo "1".


Ahora puede copiar la ID de su NFT, pegarla en la sección Ver y hacer clic en "Ver NFT".


Conclusión

¡Bien hecho! Has terminado la parte 2 del proyecto del portal Coleccionables. En resumen, nos centramos en construir la interfaz de nuestro portal de Coleccionables.


Hicimos esto por:


  • Creando una aplicación con Next.js
  • Conexión de la billetera Flow
  • Creando nuestros propios NFT para acuñar
  • Ver su NFT


¡Que tengas un gran día!


También publicado aquí.