paint-brush
Как создать портал цифровых предметов коллекционирования, используя поток и ритм (часть 2)к@johnjvester
222 чтения

Как создать портал цифровых предметов коллекционирования, используя поток и ритм (часть 2)

к John Vester15m2024/02/27
Read on Terminal Reader

Слишком долго; Читать

Имея портал Collectibles на блокчейне Flow и развернутый в тестовой сети, мы теперь можем сосредоточиться на создании внешнего интерфейса с использованием React в заключение этой серии статей.
featured image - Как создать портал цифровых предметов коллекционирования, используя поток и ритм (часть 2)
John Vester HackerNoon profile picture
0-item


Добро пожаловать на последний шаг в создании портала коллекционирования! (часть 1 смотрите здесь )


В этой части мы сосредоточимся на создании внешнего интерфейса — последней части головоломки.


Вот чего мы достигнем:


  1. Подключите кошелек Flow.
  2. Инициализируйте свою учетную запись и создайте свой NFT.
  3. Проверьте идентификатор NFT в своей коллекции.
  4. Просмотрите NFT с идентификатором NFT, который есть в вашей коллекции.


Мы будем использовать Next.js для создания интерфейса.


Давайте начнем!


1. Установка

Настройка

Откройте каталог flow-collectible-portal вашего проекта. Затем запустите
npx create-next-app@latest frontend в терминале и нажмите enter .


Это предоставит вам несколько вариантов. В этом руководстве мы не будем использовать Typescript , ESLint или TailwindCSS , а будем использовать каталог src и маршрутизатор приложений на момент написания этой статьи.


Теперь у вас готово свежее веб-приложение.

Вот как выглядит ваша папка внешнего интерфейса:



2. Конфигурация

Для взаимодействия с блокчейном Flow мы будем использовать клиентскую библиотеку Flow (FCL) для управления соединениями кошелька, запуска сценариев и отправки транзакций в нашем приложении. Это позволит нам писать полные функции Cadence и запускать их как функции Javascript.


Для начала давайте установим FCL для нашего приложения, выполнив следующую команду:


 npm install @onflow/fcl --save


После установки FCL нам необходимо его настроить. Вот что вам нужно сделать:


  1. Внутри папки app создайте новую папку с именем flow и добавьте файл с именем config.js .
  2. В этом файле настройте конфигурацию FCL, например указав узел доступа и конечную точку обнаружения кошелька. Это поможет вам выбрать между использованием тестовой сети или локального эмулятора.
  3. Вам также потребуется указать адрес контракта на коллекционирование, который мы использовали в части 1.


Добавьте следующий код в файл 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", });


Теперь все готово для использования FCL в вашем приложении.


3. Аутентификация

Чтобы подтвердить личность пользователя в приложении, вы можете использовать несколько функций:


  1. Для входа в систему вызовите fcl.logIn() .
  2. Для регистрации вызовите fcl.signUp() .
  3. Для выхода из системы вызовите fcl.unauthenticate() .


Давайте узнаем, как мы можем реализовать эти функции fcl в вашем интерфейсе.


Сначала мы добавим следующий код в наш файл page.js внутри каталога приложения. Это позволит импортировать некоторые зависимости, настроить начальное состояние useState для частей нашего приложения и создать базовый пользовательский интерфейс.


Чтобы убедиться, что все выглядит хорошо, удалите файл page.module.css из каталога приложения и вместо этого создайте файл с именем page.css. Затем вставьте в него содержимое этого файла . Теперь мы можем написать нашу начальную страницу.


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


После добавления этого кода запустите npm run dev , чтобы убедиться, что все загружается правильно.


4. Запрос к блокчейну Flow

Прежде чем углубиться в то, как мы можем использовать fcl для запроса блокчейна Flow, добавьте эти коды сценариев Cadence после функции handleInput в файле 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) }


Когда наши сценарии Cadence готовы к работе, мы можем объявить некоторые функции Javascript и передать константы Cadence в запросы `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); }


Теперь давайте посмотрим на все функции, которые мы написали. Есть две вещи, на которые следует обратить внимание:


  1. fcl.query
  2. И args: (arg,t) => [arg(addr,t.Address)], line.


Поскольку сценарии аналогичны функциям view в Solidity и не требуют каких-либо комиссий за запуск, мы, по сути, просто опрашиваем блокчейн. Поэтому мы используем fcl.query для запуска сценариев в Flow.


Чтобы запросить что-либо, нам нужно передать аргумент. Для этого мы используем arg — функцию, принимающую строковое значение, представляющее аргумент, и t — объект, содержащий все различные типы данных, которые есть в Cadence. Таким образом, мы можем указать arg , как кодировать и декодировать передаваемый аргумент.

5. Мутация блокчейна Flow

В то время как наши предыдущие функции были просто «только для чтения», наши следующие будут иметь действия, которые могут изменять состояние блокчейна и писать в него; он же «чеканить NFT».


Для этого мы напишем еще один скрипт Cadence в качестве константы.


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


Теперь добавьте приведенную ниже функцию после кода транзакции в файл 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); }


Что касается функции, синтаксис fcl.mutate такой же, как и fcl.query . Однако мы предоставляем несколько дополнительных параметров, таких как следующие:


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


  • Это специфичные для Flow вещи, которые определяют, какой аккаунт будет платить за транзакцию (плательщик), транслировать транзакцию (предлагающий) и учетные записи, от которых нам нужны авторизации. (Если к учетной записи прикреплено несколько ключей, она может вести себя как кошелек с мультиподписью.)
  • fcl.authz относится к текущей подключенной учетной записи.
  • limit похож на gasLimit в мире Ethereum, который устанавливает верхний предел максимального объема вычислений. Если вычисление превысит предел, транзакция завершится неудачей.


Нам нужно добавить еще одну функцию, которая будет вызывать и обрабатывать только что созданную функцию mintNFT .


 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. Окончательный код

Теперь, когда наши основные функции готовы, мы можем подключить их к нашему пользовательскому интерфейсу.


Однако прежде чем мы это сделаем, мы добавим несколько вызовов useEffect , которые помогут загрузить начальное состояние. Вы можете добавить их прямо над уже существующим вызовом useEffect .


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


Вернувшись в раздел return с пользовательским интерфейсом, мы можем добавить наши функции в соответствующие части приложения.


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


Проверьте окончательный код здесь .


Теперь, когда приложение готово, давайте рассмотрим, как им пользоваться!


Сначала подключите свой кошелек, нажав кнопку «Подключить кошелек» в правом верхнем углу.


Теперь вы можете чеканить NFT! Введите имя вашего NFT и вставьте ссылку на изображение, которое вы хотите использовать. После того, как вы нажмете «mint», вам будет предложено подписать транзакцию с вашим кошельком.


Завершение транзакции может занять некоторое время. После завершения вы сможете нажать нижнюю кнопку, чтобы просмотреть идентификаторы ваших NFT. Если это ваш первый, то идентификатор должен быть просто «1».


Теперь вы можете скопировать идентификатор вашего NFT, вставить его в раздел «Просмотр» и нажать «Просмотреть NFT».


Заключение

Отличная работа! Вы завершили вторую часть проекта портала «Коллекционирование». Подводя итог, мы сосредоточились на создании интерфейса нашего портала коллекционирования.


Мы сделали это:


  • Создание приложения с помощью Next.js
  • Подключение кошелька Flow
  • Создание наших собственных NFT для чеканки
  • Просмотр вашего NFT


Хорошего дня!


Также опубликовано здесь.