
NFT(Non-Fungible Token) 시장과 함께절정에 이르다, 상대적으로 초기 NFT를 되돌아보고 회상CryptoKitties도전은 재미 있습니다. 이것은Dapper Labs팀이 구축한 최초의 대규모 사용 사례는 이더리움을 처음으로 트래픽 압박에 빠뜨렸습니다.
그리고Rarible,OpenSea,Foundation그리고Sorare이와 같은 플랫폼이 등장하기 시작했습니다. 매달 수백만 달러의 자금이 이러한 플랫폼을 통해 흐르지만 대부분은 이더리움 블록체인에서 발생합니다. 그러나 Dapper Labs 팀은 CryptoKitties 개발 경험을 쌓은 후새로운 퍼블릭 체인 생성, 퍼블릭 체인은 보편적일 뿐만 아니라 NFT 개발에도 매우 적합합니다. 이것의 목표는 이더리움의 NFT에서 발생하는 많은 문제를 해결하는 동시에 공간의 개발자와 수집가에게 더 나은 경험을 제공하는 것입니다. 그들의 새로운 블록체인인 Flow는 이미 일부 유명 브랜드와 파트너십을 맺을 수 있음을 입증했습니다. 예를 들어NBA, UFC, 심지어 Dr. Seuss도 흐름에 있습니다.
우리는 최근에 대해 썼습니다IPFS에 내장된 자산 지원으로 NFT 생성기사를 읽고 NFT 공간의 책임 문제와 IPFS가 어떻게 도움이 될 수 있는지에 대해 논의합니다. 이제 IPFS 기반 흐름에서 nft를 생성하는 방법에 대해 논의할 시간입니다. Flow 블록체인의 주요 초기 응용 프로그램 중 하나는NBA Top Shot. 매우 기본적인 예제를 빌드한 다음 NFT의 메타데이터를 IPFS에 백업합니다.
우리가 좋아하기 때문에piñatas, NBA 하이라이트 동영상이 아니라 파티에서 거래 가능한 피냐타를 부수는 동영상을 만듭니다.
이것은 세 부분으로 구성된 자습서입니다.
1. 계약 및 민트 토큰 생성
2. 이 계약으로 생성된 NFT를 볼 수 있는 앱 생성
3. NFT를 다른 사람에게 양도할 수 있는 시장을 만들고, 이 NFT의 기초 자산도 IPFS에서 양도합니다.
첫 번째 튜토리얼을 시작하겠습니다.
구성
Flow CLI를 설치해야 합니다. Flow의 문서에는 좋은 설치 지침이 있지만 여기에서 재현하겠습니다.
애플계
brew install flow-cli
Linux
sh -ci “$(curl -fsSL https://storage.googleapis.com/flow-cli/install.sh)"
Windows
iex “& { $(irm ‘https://storage.googleapis.com/flow-cli/install.ps1') }”
IPFS에 자산 파일을 저장합니다. 단순화하기 위해 다음을 사용할 수 있습니다.Pinata. 여기에서 가입할 수 있습니다.무료 계정, 여기에서 API 키를 가져옵니다. 이 자습서의 두 번째 기사에서는 다음을 사용합니다.API, 하지만 이 기사에서는 Pinata 웹 사이트를 사용합니다.
또한 Flow 스마트 계약 코드를 강조 표시하는 데 도움이 되는 NodeJS와 텍스트 편집기를 설치해야 합니다(Cadence언어) 구문. 여기에서 노드를 설치할 수 있습니다. 비주얼 스튜디오 코드는Cadence 확장 지원。
프로젝트를 시작할 디렉토리를 만들어 봅시다.
mkdir pinata-party
해당 디렉터리로 변경하고 새 흐름 프로젝트를 초기화합니다.
cd pinata-party
flow project init
이제 선호하는 코드 편집기에서 프로젝트를 열고(역시 Visual Studio Code를 사용하는 경우 Cadence 확장 설치) 개발을 시작합니다.
곧 사용할 flow.json 파일이 표시됩니다. 먼저 cadence라는 폴더를 만듭니다. 해당 폴더 안에 contracts라는 다른 폴더를 추가합니다. 마지막으로 계약 폴더에 PinataPartyContract.cdc라는 파일을 만듭니다.
계속 진행하기 전에 지금부터 Flow 블록체인으로 수행하는 모든 작업이 에뮬레이터에서 수행된다는 점을 지적하는 것이 중요합니다. 그러나 테스트넷이나 메인넷에 프로젝트를 배포하는 것은 flow.json 파일의 구성 설정을 업데이트하는 것만큼 쉽습니다. 이제 이 파일을 에뮬레이터 환경용으로 설정한 다음 계약 작성을 시작할 수 있습니다.
다음과 같이 flow.json의 계약을 업데이트합니다.
"contracts": {
"PinataPartyContract": "./cadence/contracts/PinataPartyContract.cdc"
}
그런 다음 다음과 같이 flow.json에서 배포를 업데이트합니다.
"deployments": {
"emulator": {
"emulator-account": ["PinataPartyContract"]
}
}
이것은 실제로 Flow CLI에 에뮬레이터를 사용하여 계약을 배포하도록 지시하고 있으며, 계정(에뮬레이터에서)과 우리가 작성하려는 계약도 참조합니다.
계약
계약
Flow는 NFT 계약 생성에 대한 훌륭한 자습서를 제공합니다. 이것은 좋은 기준점이지만 흐름지적한대로, 그들은 아직 NFT 메타데이터 문제를 해결하지 않았습니다. 그들은 메타데이터를 온체인에 저장하기를 원합니다. 그것은 좋은 생각이며 그들은 확실히 논리적 접근 방식을 제시할 것입니다. 그러나 이제 메타데이터로 일부 토큰을 생성하고 NFT와 연결된 미디어 파일을 원합니다. 메타데이터는 하나의 구성 요소일 뿐입니다. 또한 토큰이 궁극적으로 나타내는 미디어 파일을 표시해야 합니다.
Ethereum 블록체인의 NFT에 익숙하다면 이러한 토큰이 반환하는 많은 자산이기존 데이터 스토리지 및 클라우드 서비스 제공업체가운데. 내려가지 않는 한 괜찮습니다. 우리는 과거에 기존 클라우드 플랫폼과 블록체인에서 콘텐츠를 찾고 저장하는 방법에 대해 글을 썼습니다. 두 가지로 요약됩니다.
자산은 검증 가능해야 합니다.
저장소 이전이 쉬워야 합니다.
IPFS두 가지 측면을 모두 고려합니다. 그런 다음 Pinata는 콘텐츠를 IPFS에 장기간 저장하기 쉬운 방식으로 계층화됩니다. 그것이 바로 우리가 NFT를 지원하려는 미디어에 필요한 것입니다. 그렇죠? 우리는 소유권(NFT)을 증명하고 NFT(NFT)에 대한 데이터를 제공하며 복제본이 아닌 기본 자산(IPFS)(미디어 파일 등)을 제어할 수 있는지 확인하고 싶습니다. 이 모든 것을 염두에 두고 NFT를 생성하고, 메타데이터를 NFT와 연결하고, 메타데이터가 IPFS에 저장된 기본 자산을 가리키도록 하는 계약을 작성해 보겠습니다.
PinataPartyContract.cdc를 열고 작업을 시작하겠습니다.
pub contract PinataPartyContract {
pub resource NFT {
pub let id: UInt64
init(initID: UInt64) {
self.id = initID
}
}
}
첫 번째 단계는 계약을 정의하는 것입니다. 여기에 더 추가하겠지만 먼저 PinataPartyContract를 정의하고 그 안에 리소스를 생성합니다. 리소스는 사용자 계정에 저장된 항목이며 액세스 제어를 통해 액세스할 수 있습니다. 이 경우 NFT 리소스는 궁극적으로 NFT를 나타내는 데 사용되는 것을 소유함으로써 소유됩니다. NFT는 고유하게 식별할 수 있어야 합니다. id 속성을 사용하면 토큰을 식별할 수 있습니다.
다음으로 다른 사람(즉, 계약 소유자가 아닌 사람)이 사용할 수 있는 기능을 정의하는 데 사용할 리소스 인터페이스를 만들어야 합니다.
pub resource interface NFTReceiver {
pub fun deposit(token: @NFT, metadata: {String : String})
pub fun getIDs(): [UInt64]
pub fun idExists(id: UInt64): Bool
pub fun getMetadata(id: UInt64) : {String : String}
}
NFT 리소스 코드 아래에 넣으십시오. NFTReceiver 인터페이스는 리소스에 대한 액세스 권한이 있다고 정의한 사람은 누구나 다음 메서드를 호출할 수 있음을 의미합니다.
deposit
getIDs
idExists
getMetadata
다음으로 토큰 수집 인터페이스를 정의해야 합니다. 사용자의 모든 NFT를 보관하는 지갑으로 생각하십시오.
pub resource Collection: NFTReceiver {
pub var ownedNFTs: UInt64: NFT}
pub var metadataObjs: {UInt64: { String : String }}
init () {
self.ownedNFTs <- {}
self.metadataObjs = {}
}
pub fun withdraw(withdrawID: UInt64): @NFT {
let token <- self.ownedNFTs.remove(key: withdrawID)!
return <-token }
pub fun deposit(token: @NFT, metadata: {String : String}) {
self.ownedNFTs[token.id] <-! token }
pub fun idExists(id: UInt64): Bool {
return self.ownedNFTs[id] != nil }
pub fun getIDs(): [UInt64] {
return self.ownedNFTs.keys }
pub fun updateMetadata(id: UInt64, metadata: {String: String}) {
self.metadataObjs[id] = metadata }
pub fun getMetadata(id: UInt64): {String : String} {
return self.metadataObjs[id]!
}
destroy() {
destroy self.ownedNFTs }}
이 리소스에는 많은 일이 있습니다. 먼저 소유NFTs라는 변수가 있습니다. 이것은 매우 간단합니다. 해당 계약에서 사용자가 소유한 모든 NFT를 추적합니다.
다음으로, metadataObjs라는 변수가 있습니다. 이는 Flow NFT 계약 기능을 확장하여 각 NFT에 대한 메타데이터 매핑을 저장한다는 점에서 약간 독특합니다. 이 변수는 토큰 ID를 연결된 메타데이터에 매핑합니다. 즉, 토큰 ID를 설정하려면 먼저 설정해야 합니다.
그런 다음 변수를 초기화합니다. 이는 Flow의 리소스에 정의된 변수에 필요합니다.
마지막으로 NFT 수집 리소스에 사용할 수 있는 모든 기능이 있습니다. 이러한 기능 중 일부는 사용할 수 없습니다. NFTReceiver 리소스 인터페이스에서 이전에 누구나 사용할 수 있는 기능을 정의한 것을 기억해 보십시오.
예금 기능을 지적하고 싶습니다. 기본 Flow NFT 계약을 확장하여 metadataObjs 맵을 포함하는 것처럼 추가 매개변수 메타데이터를 가져오도록 기본 입금 기능도 확장하고 있습니다. 여기서 왜 이러는 거지? 우리는 토큰 발행인만이 해당 메타데이터를 토큰에 추가할 수 있도록 해야 합니다. 프라이버시를 유지하기 위해 채굴 실행에 대한 메타데이터의 초기 추가를 제한합니다.
계약 코드가 거의 완성되었습니다. 따라서 컬렉션 리소스 아래에 다음을 추가합니다.
pub fun createEmptyCollection(): @Collection {
return <- create Collection()}pub resource NFTMinter {
pub var idCount: UInt64
init() {
self.idCount = 1
}
pub fun mintNFT(): @NFT {
var newNFT <- create NFT(initID: self.idCount)
self.idCount = self.idCount + 1 as UInt64 return <-newNFT }}
첫째, 호출 시 빈 NFT 컬렉션을 생성하는 함수가 있습니다. 이렇게 하면 처음으로 계약과 상호 작용하는 사용자는 우리가 정의한 리소스 컬렉션에 저장 위치를 생성하게 됩니다.
그런 다음 다른 리소스를 만듭니다. 이것 없이는 토큰을 발행할 수 없기 때문에 이것은 중요합니다. NFTinter 리소스에는 NFT에 중복 ID가 없도록 증가되는 idCount가 포함되어 있습니다. 또한 NFT를 실제로 생성하는 기능도 있습니다.
NTMinter 리소스 아래에 기본 계약 이니셜라이저를 추가합니다.
init() {
self.account.save(<-self.createEmptyCollection(), to: /storage/NFTCollection)
self.account.link<&{NFTReceiver}>(/public/NFTReceiver, target: /storage/NFTCollection)
self.account.save(<-create NFTMinter(), to: /storage/NFTMinter)
}
이 초기화 함수는 계약이 배포될 때만 호출됩니다. 세 가지 작업을 수행합니다.
1. 계약 소유자가 계약의 NFT를 생성하고 NFT를 소유할 수 있도록 컬렉션 배포자를 위한 빈 컬렉션을 생성합니다.
2.Collection Reference NFTReceiver 처음에 만든 인터페이스인 이 리소스는 공개 위치에 게시됩니다. 이것이 NFTReceiver 에 정의된 함수를 누구나 호출할 수 있다고 계약에 알리는 방법입니다.
3. NTMinter 리소스는 계정 스토리지 계약 작성자에 저장됩니다. 이는 계약 작성자만이 토큰을 발행할 수 있음을 의미합니다.
완전한 계약여기에서 찾을 수 있습니다.
이제 컨트랙트가 준비되었으니 배포해 볼까요? 글쎄, 우리는 아마도Flow Playground그것을 테스트하십시오. 거기로 이동하여 왼쪽 사이드바에서 첫 번째 계정을 클릭합니다. 예제 계약의 모든 코드를 계약 코드로 바꾸고 배포를 클릭합니다. 모두 잘 되었다면 화면 하단의 로그 창에 다음과 같은 로그가 표시됩니다.
16:48:55 Deployment Deployed Contract To: 0x01
이제 로컬에서 실행되는 에뮬레이터에 계약을 배포할 준비가 되었습니다. 명령줄에서 다음 명령을 실행합니다.
flow project start\-emulator
이제 에뮬레이터가 실행되고 flow.json 파일이 올바르게 구성되었으므로 계약을 배포할 수 있습니다. 다음 명령을 실행하십시오.
flow project deploy
모두 제대로 진행되면 다음과 유사한 출력이 표시됩니다.
계정에 대해 1개의 계약 배포: 에뮬레이터 계정
Deploying 1 contracts for accounts: emulator-account
PinataPartyContract -> 0xf8d6e0586b0a20c7
NFT 발행
NFT 발행
이 튜토리얼의 두 번째 기사에서는 애플리케이션 및 사용자 인터페이스를 통해 캐스팅 프로세스를 보다 사용자 친화적으로 만드는 작업을 할 것입니다. 메타데이터가 Flow에서 NFT와 작동하는 방식을 설명하고 보여주기 위해 Cadence 스크립트와 명령줄을 사용합니다.
pinata-party 프로젝트의 루트에 새 디렉토리를 만들고 트랜잭션이라고 부르겠습니다. 폴더를 만든 후 그 안에 MintPinataParty.cdc라는 새 파일을 만듭니다.
트랜잭션을 작성하려면 NFT에 제공된 메타데이터에서 파일을 참조해야 합니다. 이를 위해 Pinata를 통해 파일을 IPFS에 업로드합니다. 이 튜토리얼에서는 NFT가 파티에서 부서진 피냐타의 거래 가능한 비디오에 초점을 맞추고 있으므로 생일 파티에서 피냐타를 치는 아이의 비디오를 업로드할 것입니다. 원하는 비디오 파일을 업로드할 수 있습니다. 실제로 모든 자산 파일을 업로드하고 NFT와 연결할 수 있지만 이 자습서 시리즈의 두 번째 기사에서는 비디오 콘텐츠를 기대합니다. 동영상 파일을 재생할 준비가 되면여기에 업로드하십시오. 파일을 업로드하면 IPFS 해시(종종 콘텐츠 식별자 또는 CID라고 함)가 제공됩니다. 이 해시를 복사하여 채굴 과정에서 사용할 것입니다.
이제 MintPinataParty.cdc 파일에 다음을 추가합니다.
import PinataPartyContract from 0xf8d6e0586b0a20c7transaction {
let receiverRef: &{PinataPartyContract.NFTReceiver}
let minterRef: &PinataPartyContract.NFTMinter
prepare(acct: AuthAccount) {
self.receiverRef = acct.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
.borrow()
?? panic("Could not borrow receiver reference")
self.minterRef = acct.borrow<&PinataPartyContract.NFTMinter>(from: /storage/NFTMinter)
?? panic("could not borrow minter reference")
}
execute {
let metadata : {String : String} = {
"name": "The Big Swing",
"swing_velocity": "29",
"swing_angle": "45",
"rating": "5",
"uri": "ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6"
}
let newNFT <- self.minterRef.mintNFT()
self.receiverRef.deposit(token: <-newNFT, metadata: metadata)
log("NFT Minted and deposited to Account 2's Collection")
}}
Flow가 일을 쉽게 하기 위해 수행한 작업 덕분에 이것은 매우 간단한 일이지만 자세히 살펴보겠습니다. 먼저 상단에 import 문이 있음을 알 수 있습니다. 계약을 배포할 때 계정을 받습니다. 그것이 우리가 참조해야 할 것입니다. 따라서 0xf8d6e0586b0a20c7을 배포의 계정 주소로 바꿉니다.
다음으로 트랜잭션을 정의합니다. 여기에서 일어나는 모든 일은 우리가 실행하려는 트랜잭션과 관련이 있습니다.
트랜잭션에서 가장 먼저 하는 일은 두 개의 참조 변수인 receiverRef와 minterRef를 정의하는 것입니다. 이 경우 우리는 NFT의 수신자이자 NFT의 발행자입니다. 이 두 변수는 계약에서 생성한 리소스를 나타냅니다. 트랜잭션을 수행하는 사람이 리소스에 대한 액세스 권한이 없으면 트랜잭션이 실패합니다.
다음으로 준비 기능이 있습니다. 이 기능은 거래를 수행하려는 사람의 계정 정보를 가져와 일부 확인을 수행합니다. 우리는 정의한 NFTInter와 두 리소스에서 사용할 수 있는 NFTReceiver 함수를 "차용"하려고 합니다. 트랜잭션을 수행하는 사람이 해당 리소스에 액세스할 수 없으면 작업이 실패합니다.
마지막으로 실행 기능이 있습니다. 이 기능은 NFT에 대한 메타데이터를 구축하고 NFT를 생성한 다음 NFT를 계정에 입금하기 전에 메타데이터를 연결하는 곳입니다. 눈치채셨다면 저는 메타데이터 변수를 만들었습니다. 해당 변수에 토큰에 대한 정보를 추가했습니다. 우리의 토큰은 파티에서 피자를 부수는 이벤트를 나타내고 NBA Top Shot에서 볼 수 있는 대부분의 것을 복제하려고 하기 때문에 메타데이터에 몇 가지 통계를 정의했습니다. 아이가 스틱을 휘두르며 피냐타 속도, 스윙 각도, 등급을 맞춥니다. 저는 이 통계를 가지고 놀고 있습니다. 그러나 유사한 방식으로 토큰에 적합한 정보를 입력합니다.
uri 메타데이터에 속성도 정의했음을 알 수 있습니다. 이는 NFT와 관련된 자산 파일을 호스팅하는 IPFS 해시를 가리킵니다. 이 경우 실제 피냐타를 치는 영상입니다. 이전에 파일을 업로드한 후 받은 해시로 해시를 교체할 수 있습니다.
해시 앞에 ipfs:// 를 붙입니다. 이것은 IPFS의 파일에 대한 적절한 참조이며 데스크탑 클라이언트 및 IPFS용 브라우저 확장과 함께 사용할 수 있습니다. 용감한 또한 그것에 대한 지원을 제공합니다, 우리는 또한 그것을 직접 붙여 넣을 수 있습니다브레이브 브라우저에서。
토큰을 생성하는 mintNFT 함수를 호출합니다. 그런 다음 입금 기능을 호출하여 계좌에 입금해야 합니다. 메타데이터를 전달하는 곳이기도 합니다. 연결된 토큰 ID에 메타데이터를 추가하는 예금 기능에서 변수 연결을 정의했음을 기억하십시오.
이제 트랜잭션을 전송하고 NFT를 생성할 준비가 거의 끝났습니다. 하지만 먼저 계정을 준비해야 합니다. 프로젝트 루트 폴더의 명령줄에서 서명을 위한 새 개인 키를 생성해 보겠습니다. 다음 명령을 실행합니다.
flow keys generate
이렇게 하면 공개 키와 개인 키가 제공됩니다. 개인 키를 항상 보호
트랜잭션에 서명하려면 프라이빗 키가 필요하므로 이를 flow.json 파일에 붙여넣을 수 있습니다. 서명 알고리즘도 지정해야 합니다. 이제 flow.json 파일의 계정 개체가 다음과 같이 표시됩니다.
“ accounts”:{
“ emulator-account”:{
"address": "계정 주소",
"privateKey": "개인 키",
"chain": "스트림 에뮬레이터",
“ sigAlgorithm”:“ ECDSA_P256”,
“ hashAlgorithm”:“ SHA3_256”
}
},
이 프로젝트를 github 또는 원격 git 저장소에 저장하려는 경우 개인 키를 포함하지 않도록 하십시오. .gitignore에 flow.json을 추가할 수 있습니다. 로컬 에뮬레이터만 사용하고 있지만 키를 보호하는 것이 좋습니다.
이제 업데이트했으므로 거래를 보낼 수 있습니다. 다음 명령을 실행하는 것만큼 쉽습니다.
flow transactions send --code ./transactions/MintPinataParty.cdc --signer emulator-account
우리는 flow.json에서 작성한 트랜잭션 파일과 서명자 계정을 참조합니다. 모두 제대로 진행되면 다음과 유사한 출력이 표시됩니다.
Getting information for account with address 0xf8d6e0586b0a20c7 ...
Submitting transaction with ID
4a79102747a450f65b6aab06a77161af196c3f7151b2400b3b3d09ade3b69823 ...
Successfully submitted transaction with ID
4a79102747a450f65b6aab06a77161af196c3f7151b2400b3b3d09ade3b69823
이제 마지막으로 해야 할 일은 토큰이 계정에 있는지 확인하고 메타데이터를 가져오는 것입니다. 이를 위해 매우 간단한 스크립트를 작성하고 명령줄에서 호출합니다.
프로젝트의 루트에서 scripts라는 새 폴더를 만듭니다. 그 안에 CheckTokenMetadata.cdc라는 파일을 만듭니다. 해당 파일에 다음을 추가합니다.
import PinataPartyContract from 0xf8d6e0586b0a20c7pub fun main() : {String : String} {
let nftOwner = getAccount(0xf8d6e0586b0a20c7)
// log("NFT Owner")
let capability = nftOwner.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
let receiverRef = capability.borrow()
?? panic("Could not borrow the receiver reference")
return receiverRef.getMetadata(id: 1)}
이 스크립트는 Ethereum 스마트 계약의 읽기 전용 방법과 유사한 방식으로 생각할 수 있습니다. 그들은 무료이며 계약에서 데이터를 반환하기만 하면 됩니다.
스크립트에서 배포된 주소에서 계약을 가져옵니다. 그런 다음 기본 기능(스크립트를 실행하는 데 필요한 기능의 이름)을 정의합니다. 이 함수 내에서 세 가지 변수를 정의합니다.
nftOwner: 이것은 NFT를 소유한 계정일 뿐입니다. 계약을 배포한 계정에서 NFT를 발행했으므로 예제에서 두 주소는 동일합니다. 향후 계약 설계에 따라 이것이 항상 사실이 아닐 수도 있습니다.
기능: 배포된 계약에서 "빌려"야 합니다. 이러한 함수는 액세스 제어되므로 차용하려는 주소에서 함수를 사용할 수 없으면 스크립트가 실패합니다. NFTReceiver 리소스에서 차용하고 있습니다.
receiverRef: 이 변수는 우리의 능력을 활용하고 배포된 계약에서 차용하도록 스크립트에 지시합니다.
이제 함수(사용 가능한 함수)를 호출할 수 있습니다. 이 경우 문제의 주소가 우리가 발행한 NFT를 실제로 수신했는지 확인한 다음 토큰과 관련된 메타데이터를 살펴보고 싶습니다.
스크립트를 실행하고 결과를 확인합시다. 명령줄에서 다음 명령을 실행합니다.
flow scripts execute --code ./scripts/CheckTokenMetadata.cdc
메타데이터 출력의 경우 다음과 유사한 출력이 표시되어야 합니다.
{"name": "The Big Swing", "swing_velocity": "29", "swing_angle": "45", "rating": "5", "uri": "ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6"}
축하해요! Flow 스마트 계약을 성공적으로 생성하고, 토큰 및 해당 토큰과 연결된 메타데이터를 생성하고, 토큰의 기본 디지털 자산을 IPFS에 저장했습니다. 튜토리얼의 첫 번째 부분은 나쁘지 않습니다.
다음으로 프런트 엔드 React 앱 구축에 대한 자습서가 있습니다. 메타데이터를 가져오고 해당 메타데이터를 구문 분석하여 NFT를 표시할 수 있습니다.。