paint-brush
Comment créer un portail d'objets de collection numériques à l'aide de Flow et de Cadence (Partie 2)by@johnjvester
213

Comment créer un portail d'objets de collection numériques à l'aide de Flow et de Cadence (Partie 2)

John Vester15m2024/02/27
Read on Terminal Reader

Avec un portail Collectibles sur la blockchain Flow et déployé sur le testnet, nous pouvons désormais nous concentrer sur la création du frontend à l'aide de React dans la conclusion de cette série.
featured image - Comment créer un portail d'objets de collection numériques à l'aide de Flow et de Cadence (Partie 2)
John Vester HackerNoon profile picture
0-item


Bienvenue dans la dernière étape de la création de votre portail d'objets de collection ! (pour la première partie, voir ici )


Dans cette partie, nous nous concentrerons sur la construction du frontend, la dernière pièce du puzzle.


Voici ce que nous allons réaliser :


  1. Connectez le Flow Wallet.
  2. Initialisez votre compte et créez votre NFT.
  3. Vérifiez l'identifiant NFT dans votre collection.
  4. Affichez le NFT avec l'identifiant NFT que vous avez dans votre collection.


Nous utiliserons Next.js pour créer le frontend.


Commençons!


1.Installation

Configuration

Ouvrez le répertoire flow-collectible-portal de votre projet. Ensuite, courez
npx create-next-app@latest frontend dans le terminal et appuyez sur enter .


Cela vous offrira plusieurs options. Dans ce tutoriel, nous n'utiliserons pas Typescript , ESLint ou TailwindCSS , et nous utiliserons le répertoire src et le routeur App au moment de cet article.


Vous avez maintenant une nouvelle application Web prête.

Voici à quoi ressemble votre dossier frontend :



2.Configuration

Pour interagir avec la blockchain Flow, nous utiliserons la bibliothèque client Flow (FCL) pour gérer les connexions du portefeuille, exécuter des scripts et envoyer des transactions dans notre application. Cela nous permettra d'écrire des fonctions Cadence complètes et de les exécuter en tant que fonctions Javascript.


Pour commencer, installons FCL pour notre application en exécutant la commande suivante :


 npm install @onflow/fcl --save


Après avoir installé FCL, nous devons le configurer. Voici ce que vous devez faire :


  1. Dans le dossier app , créez un nouveau dossier nommé flow et ajoutez un fichier nommé config.js .
  2. Dans ce fichier, configurez la configuration du FCL, par exemple en spécifiant le nœud d'accès et le point de terminaison de découverte de portefeuille. Cela vous aide à choisir entre utiliser un testnet ou un émulateur local.
  3. Vous souhaiterez également spécifier l’adresse du contrat Collectibles que nous avons déployé dans la partie 1.


Ajoutez le code suivant au fichier 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", });


Vous êtes maintenant prêt à utiliser le FCL dans votre application.


3. Authentification

Pour vérifier l'identité d'un utilisateur dans une application, vous pouvez utiliser plusieurs fonctions :


  1. Pour vous connecter, appelez fcl.logIn() .
  2. Pour vous inscrire, appelez fcl.signUp() .
  3. Pour vous déconnecter, appelez fcl.unauthenticate() .


Apprenons comment nous pouvons implémenter ces fonctions fcl dans votre frontend.


Tout d’abord, nous ajouterons le code suivant à notre fichier page.js dans le répertoire de l’application. Cela importera certaines dépendances, configurera un useState initial pour certaines parties de notre application et créera une interface utilisateur de base.


Pour vous assurer qu'il est joli, supprimez le fichier page.module.css dans le répertoire de l'application et créez à la place un fichier appelé page.css. Collez ensuite le contenu de ce fichier à l'intérieur. Nous pouvons maintenant rédiger notre première page.


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


Après avoir ajouté ce code, exécutez npm run dev pour vous assurer que tout se charge correctement.


4. Interrogation de la blockchain Flow

Avant d'approfondir la façon dont nous pouvons utiliser fcl pour interroger la blockchain Flow, ajoutez ces codes de script Cadence après la fonction handleInput dans le fichier 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) }


Avec nos scripts Cadence prêts à l'emploi, nous pouvons maintenant déclarer certaines fonctions Javascript et transmettre les constantes Cadence dans les requêtes `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); }


Jetons maintenant un œil à toutes les fonctions que nous avons écrites. Il y a deux choses à remarquer :


  1. La fcl.query
  2. Et les args: (arg,t) => [arg(addr,t.Address)], ligne.


Étant donné que les scripts sont similaires aux fonctions view dans Solidity et ne nécessitent aucun frais de gaz pour s'exécuter, nous interrogeons essentiellement simplement la blockchain. Nous utilisons donc fcl.query pour exécuter des scripts sur Flow.


Pour interroger quelque chose, nous devons passer un argument. Pour cela, nous utilisons arg, qui est une fonction qui prend une valeur de chaîne représentant l'argument, et t , qui est un objet qui contient tous les différents types de données de Cadence. Nous pouvons donc dire à arg comment encoder et décoder l’argument que nous transmettons.

5. Mutation de la blockchain Flow

Alors que nos fonctions précédentes étaient simplement « en lecture seule », nos prochaines auront des actions qui peuvent muter l'état de la blockchain et y écrire ; alias « créer un NFT ».


Pour ce faire, nous allons écrire un autre script Cadence comme 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) } }


Ajoutez maintenant la fonction ci-dessous après le code de transaction au fichier 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); }


Quant à la fonction, la syntaxe fcl.mutate est la même que fcl.query . Cependant, nous fournissons plusieurs paramètres supplémentaires tels que les suivants :


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


  • Il s'agit d'éléments spécifiques à Flow qui définissent quel compte paiera la transaction (payeur), diffusera la transaction (proposant) et les comptes pour lesquels nous avons besoin d'autorisations. (Dans le cas où un compte est associé à plusieurs clés, il peut se comporter comme un portefeuille multi-signatures.)
  • fcl.authz fait référence au compte actuellement connecté.
  • limit est comme gasLimit dans le monde Ethereum, qui impose une limite supérieure à la quantité maximale de calcul. Si le calcul dépasse la limite, la transaction échouera.


Nous devrons ajouter une fonction supplémentaire qui appellera et gérera la fonction mintNFT que nous venons de créer.


 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. Code final

Une fois nos principales fonctions en place, nous pouvons désormais les intégrer à notre interface utilisateur.


Cependant, avant de faire cela, nous ajouterons quelques appels useEffect pour aider à charger l'état initial. Vous pouvez les ajouter juste au-dessus de l'appel useEffect déjà existant.


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


De retour dans notre section return avec l'interface utilisateur, nous pouvons ajouter nos fonctions aux parties appropriées de l'application.


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


Vérifiez le code final ici .


Maintenant que l'application est terminée, voyons comment l'utiliser !


Tout d’abord, connectez votre portefeuille en cliquant sur le bouton « Connecter le portefeuille » en haut à droite.


Vous pouvez désormais créer un NFT ! Entrez le nom de votre NFT et collez un lien vers l'image que vous souhaitez utiliser. Après avoir cliqué sur « menthe », il vous sera demandé de signer une transaction avec votre portefeuille.


La finalisation de la transaction peut prendre un peu de temps. Une fois l'opération terminée, vous devriez pouvoir cliquer sur le bouton du bas pour afficher les identifiants de vos NFT. S'il s'agit de votre premier, l'ID ne doit être que « 1 ».


Vous pouvez maintenant copier l'ID de votre NFT, le coller dans la section Affichage et cliquer sur « Afficher NFT ».


Conclusion

Bien joué! Vous avez terminé la partie 2 du projet de portail Objets de collection. En résumé, nous nous sommes concentrés sur la création de l’interface de notre portail Objets de collection.


Nous l'avons fait en :


  • Créer une application avec Next.js
  • Connexion du portefeuille Flow
  • Créer nos propres NFT pour la frappe
  • Visualisation de votre NFT


Passez une très bonne journée !


Également publié ici.