paint-brush
Flow와 Cadence를 사용하여 디지털 수집품 포털을 구축하는 방법(2부)~에 의해@johnjvester
222 판독값

Flow와 Cadence를 사용하여 디지털 수집품 포털을 구축하는 방법(2부)

~에 의해 John Vester15m2024/02/27
Read on Terminal Reader

너무 오래; 읽다

Flow 블록체인의 수집품 포털을 테스트넷에 배포함으로써 이제 이 시리즈의 결론에서 React를 사용하여 프런트엔드를 만드는 데 집중할 수 있습니다.
featured image - Flow와 Cadence를 사용하여 디지털 수집품 포털을 구축하는 방법(2부)
John Vester HackerNoon profile picture
0-item


수집품 포털 생성의 마지막 단계에 오신 것을 환영합니다! (1부 내용은 여기를 참조하세요)


이 부분에서는 퍼즐의 마지막 조각인 프런트엔드 구축에 중점을 둘 것입니다.


우리가 달성할 내용은 다음과 같습니다.


  1. Flow 지갑을 연결하세요.
  2. 계정을 초기화하고 NFT를 발행하세요.
  3. 컬렉션에서 NFT ID를 확인하세요.
  4. 컬렉션에 있는 NFT ID로 NFT를 확인하세요.


우리는 프론트엔드를 구축하기 위해 Next.js를 사용할 것입니다.


시작하자!


1. 설치

설정

프로젝트 flow-collectible-portal 디렉터리를 엽니다. 그런 다음 실행
터미널에서 npx create-next-app@latest frontend 입력하고 enter 누르세요.


그러면 몇 가지 옵션이 제공됩니다. 이 튜토리얼에서는 Typescript , ESLint 또는 TailwindCSS를 사용하지 않을 것이며, 이 글을 작성할 당시에는 src 디렉토리와 앱 라우터를 사용할 것입니다.


이제 새로운 웹 앱이 준비되었습니다.

프런트엔드 폴더는 다음과 같습니다.



2. 구성

Flow 블록체인 과 상호 작용하기 위해 FCL(Flow 클라이언트 라이브러리)을 사용하여 지갑 연결을 관리하고, 스크립트를 실행하고, 애플리케이션에서 트랜잭션을 보냅니다. 이를 통해 완전한 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 설정하고, 기본 UI가 구축됩니다.


멋지게 보이도록 하려면 앱 디렉터리에서 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 블록체인을 쿼리하는 방법을 자세히 알아보기 전에 page.js 파일의 handleInput 함수 뒤에 이러한 Cadence 스크립트 코드를 추가하세요.


 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.


스크립트는 Solidity의 view 기능과 유사하고 실행하는 데 가스 요금이 필요하지 않으므로 기본적으로 블록체인에 쿼리만 하면 됩니다. 그래서 우리는 fcl.query 사용하여 Flow에서 스크립트를 실행합니다.


무언가를 쿼리하려면 인수를 전달해야 합니다. 이를 위해 인수를 나타내는 문자열 값을 취하는 함수인 arg와 Cadence가 가지고 있는 다양한 데이터 유형을 모두 포함하는 객체인 t 사용합니다. 따라서 우리는 전달하는 인수를 인코딩하고 디코딩하는 방법을 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,


  • 이는 거래에 대한 비용을 지불할 계정(지불자), 거래를 브로드캐스팅하는 계정(제안자) 및 승인이 필요한 계정을 정의하는 흐름 관련 항목입니다. (계정에 여러 개의 키가 연결된 경우 다중 서명 지갑처럼 작동할 수 있습니다.)
  • fcl.authz 현재 연결된 계정을 나타냅니다.
  • limit 최대 계산량에 상한선을 설정하는 이더리움 세계의 gasLimit과 같습니다. 계산이 한도를 초과하면 트랜잭션이 실패합니다.


방금 만든 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. 최종 코드

주요 기능이 준비되었으므로 이제 이를 UI에 연결할 수 있습니다.


하지만 그 전에 초기 상태를 로드하는 데 도움이 되는 몇 가지 useEffect 호출을 추가하겠습니다. 이미 존재하는 useEffect 호출 바로 위에 이를 추가할 수 있습니다.


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


이제 UI가 있는 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 이름을 입력하고 사용하려는 이미지의 링크를 붙여넣으세요. "민트"를 클릭하면 지갑으로 거래에 서명하라는 메시지가 표시됩니다.


거래가 완료되는 데 약간의 시간이 걸릴 수 있습니다. 완료되면 하단 버튼을 클릭하여 NFT의 ID를 볼 수 있습니다. 이것이 첫 번째인 경우 ID는 "1"이어야 합니다.


이제 NFT의 ID를 복사하여 보기 섹션에 붙여넣고 “NFT 보기”를 클릭할 수 있습니다.


결론

잘하셨어요! 수집품 포털 프로젝트의 2부를 완료했습니다. 요약하자면, 우리는 수집품 포털의 프런트엔드를 구축하는 데 중점을 두었습니다.


우리는 다음과 같이 이를 수행했습니다.


  • Next.js로 앱 만들기
  • Flow 지갑 연결
  • 주조를 위한 자체 NFT 생성
  • NFT 보기


정말 좋은 하루 보내세요!


여기에도 게시되었습니다 .