발행
이것은 모든 NEAR NFT 표준을 준수하는 완전한 NFT 스마트 컨트랙트를 처음부터 만드는 시리즈의 많은 튜토리얼 중 첫 번째입니다. 오늘은 NFT를 생성하고 NEAR 지갑에 표시하는 데 필요한 로직을 생성하는 방법을 배웁니다. 여기서는, 발행 함수를 추가하는 데 필요한 필수 코드 스니펫을 작성하여 중요한 스마트 컨트랙트의 뼈대를 수정하게 됩니다.
소개
시작하려면 레퍼지토리 내 1.skeleton
브랜치로 전환하세요. 레퍼지토리를 복제하지 않은 경우 컨트랙트 아키텍처를 참조하여 시작하세요.
git checkout 1.skeleton
튜토리얼의 발행 부분에 대한 완성된 코드를 보려면, 2.minting
브랜치에서 찾을 수 있습니다.
뼈대 컨트랙트 수정
발행에 필요한 로직을 구현하려면, 발행 프로세스를 더 작은 작업으로 나누고 하나씩 처리해야 합니다. 한 걸음 물러나 NFT를 발행한다는 것은 무엇을 의미합니까?
대체 불가능 토큰(NFT)을 발행하려면, 가능한 가장 간단한 방법으로는 컨트랙트에서 블록체인의 소유자와 토큰을 연결할 수 있어야 합니다. 즉, 다음과 같은 것들이 필요합니다.
- 컨트랙트에 대한 토큰 및 기타 정보를 추적하는 방법.
metadata
(나중에 자세히 설명)와 같은 각 토큰에 대한 정보를 저장하는 방법.- 소유자와 토큰을 연결하는 방법.
이게 다입니다! 이제 우리는 더 큰 문제를 더 작고 덜 어려운 하위 작업으로 분류했습니다. 첫 번째 문제를 해결하는 것으로 시작하여 나머지 작업까지 진행해 봅시다.
컨트랙트에 정보 저장
nft-contract/src/lib.rs
로 가서 일부 코드 블록을 채우는 것으로 시작해 봅시다. 여기서 계정이 보유한 토큰 목록과 같은 컨트랙트에 대한 중요한 정보를 저장할 수 있어야 합니다.
컨트랙트 구조
가장 먼저 할 일은 struct
컨트랙트를 다음과 같이 수정하는 것입니다.
loading...
This allows you to get the information stored in these data structures from anywhere in the contract. The code above has created 3 token specific storages:
- tokens_per_owner: 모든 계정이 소유한 토큰을 추적할 수 있습니다.
- tokens_by_id: 특정 토큰에 대한 모든 정보를 반환합니다.
- token_metadata_by_id: 특정 토큰에 대한 메타데이터만 반환합니다.
In addition, you'll keep track of the owner of the contract as well as the metadata for the contract.
You might be confused as to some of the types that are being used. In order to make the code more readable, we've introduced custom data types which we'll briefly outline below:
- AccountId: 특수 문자나 지원되지 않는 문자가 없는 문자열입니다.
- TokenId: 단순한 문자열입니다.
As for the Token
, TokenMetadata
, and NFTContractMetadata
data types, those are structs that we'll define later in this tutorial.
초기화 함수
Next, create what's called an initialization function; you can name it new
. This function needs to be invoked when you first deploy the contract. It will initialize all the contract's fields that you've defined above with default values. Don't forget to add the owner_id
and metadata
fields as parameters to the function, so only those can be customized.
This function will default all the collections to be empty and set the owner
and metadata
equal to what you pass in.
loading...
개발을 할 때 종종 컨트랙트를 여러 번 배포해야 합니다. 컨트랙트를 초기화할 때마다 메타데이터를 전달해야 하는 것이 지루할 수 있다고 생각할 수 있습니다. 이러한 이유로, 기본 metadata
집합으로 컨트랙트를 초기화할 수 있는 함수를 만들어 봅시다. 당신은 이를 new_default_meta
로 부를 수 있고, 매개 변수로 owner_id
만 취할 것입니다.
loading...
이 함수는 단순히 이전 new
함수를 호출하고, 지정한 소유자를 전달하며, 일부 기본 메타데이터도 전달합니다.
메타데이터 및 토큰 정보
이제 컨트랙트 자체에 저장할 정보를 정의하고 컨트랙트를 초기화하는 몇 가지 방법을 정의했으므로, Token
, TokenMetadata
, 및 NFTContractMetadata
자료형에 들어갈 정보를 정의해야 합니다.
nft-contract/src/metadata.rs
파일로 이동해 보겠습니다. 여기가 해당 정보가 들어갈 위치입니다. 메타데이터에 대한 표준을 살펴보면, TokenMetadata
및 NFTContractMetadata
모두에 대해 저장해야 하는 모든 필수 정보를 찾을 수 있습니다. 다음 코드를 입력하기만 하면 됩니다.
loading...
이제 Token
구조체와 JsonToken
이라는 것이 남습니다. Token
구조체는 메타데이터를 제외하고 토큰과 직접 관련된 모든 정보를 보유합니다. 이를 통해 토큰의 ID를 전달하기만 하면 모든 토큰에 대한 메타데이터를 빠르게 가져올 수 있습니다. 기억한다면, 메타데이터는 컨트랙트 내 맵에 tokenMetadataById
이라는 이름의 자료 구조로 저장됩니다.
Token
구조체의 경우, 지금은 소유자만 추적합니다.
loading...
JsonToken
의 목적은 누군가 View 호출을 할 때마다 JSON 형태로 다시 보내려는 NFT에 대한 모든 정보를 보유하는 것입니다. 즉, 소유자, 토큰 ID 및 메타데이터를 저장해야 합 니다.
loading...
Token
구조체에 모든 정보를 저장하지 않는 거죠?" 라고 생각할 수도 있습니다. 그 이유는 토큰 구조에 모든 정보를 저장하는 것보다 필요할 때만 즉시 JSON 토큰을 구성하는 것이 실제로 더 효율적이기 때문입니다. 또한 일부 작업에는 토큰에 대한 메타데이터만 필요할 수 있으므로 메타데이터를 별도의 자료 구조에 두는 것이 더 적합합니다. :::컨트랙트 메타데이터 쿼리를 위한 함수
이제 이전 섹션에서 사용된 일부 자료형을 정의했으므로, 첫 번째 View 함수 nft_metadata
를 만들어 보겠습니다. 이를 통해 사용자는 메타데이터 표준에 따라 컨트랙트의 메타데이터를 쿼리할 수 있습니다.
loading...
이 함수는 컨트랙트에서 NFTContractMetadata
자료형의 metadata
객체를 가져와 반환합니다.
이와 같이 처음 두 작업을 완료했으며 튜토리얼의 마지막 부분으로 이동할 준비가 되었습니다.
발행 로직
이제 모든 정보와 자료형이 정의되었으므로, 생성 로직이 어떻게 실행될지 브레인스토밍을 시작하겠습니다. 결국 특정 소유자에게 Token
및 TokenId
를 연결해야 합니다. lib.rs
파일로 돌아가 이를 연결할 수 있는지 확인해보겠습니다. 유용할 수 있는 몇 가지 자료 구조를 살펴보겠습니다.
//keeps track of all the token IDs for a given account
pub tokens_per_owner: LookupMap<AccountId, UnorderedSet<TokenId>>,
//keeps track of the token struct for a given token ID
pub tokens_by_id: LookupMap<TokenId, Token>,
//keeps track of the token metadata for a given token ID
pub token_metadata_by_id: UnorderedMap<TokenId, TokenMetadata>,
이러한 자료 구조를 살펴보면 다음을 수행할 수 있습니다.
- 수신자가 소유한 토큰 집합에 토큰 ID를 추가합니다. 이는
tokens_per_owner
필드에서 이루어질 것입니다. - 토큰 객체를 만들고 토큰 ID를
tokens_by_id
필드의 해당 토큰 개체에 매핑합니다. token_metadata_by_id
를 사용하여 토큰 ID를 메타데이터에 매핑합니다.
스토리지 구현
이 단계에서는 NFT 발행의 스토리지 비용을 고려하는 것이 중요합니다. 자료 구조에 항목이 생성되어 컨트랙트에 바이트를 추가하므로, 컨트랙트에서 스토리지 비용을 충당해야 합니다. 모든 사용자가 무료로 NFT를 발행할 수 있도록 만든 경우, 해당 시스템은 쉽게 남용될 수 있으며 사용자는 본질적으로 수천 개의 NFT를 발행하여 모든 컨트랙트 내 자금을 "탈취"할 수 있습니다. 이러한 이유로 사용자가 스토리지 비용을 충당하기 위해 호출에 보증금을 첨부해야 하도록 만들 것입니다. 아무것도 추가되기 전에, 초기 스토리지 사용량을 측정하고 모든 로직이 완료된 후 최종 스토리지 사용량을 측정합니다. 그런 다음 사용자가 해당 비용을 충당하기에 충분한 $NEAR를 첨부했는지 확인하고, 너무 많이 첨부된 경우 환불합니다.
이제 모든 것이 어떻게 진행되어야 하는지 잘 이해했으므로, 필요한 코드를 입력해 보겠습니다.
loading...
여기서 refund_deposit
과 internal_add_token_to_owner
와 같은 몇 가지 내부 메서드를 사용하고 있음을 알 수 있습니다. 우리는 refund_deposit
의 기능에 대해 설명했습니다. 또한 internal_add_token_to_owner
도, 계정이 컨트랙트의 tokens_per_owner
자료 구조에 대해 소유한 토큰 집합에 토큰을 추가합니다. internal.rs
라는 파일에서 이 함수들을 만들 수 있습니다. 계속해서 파일을 만드세요. 새 컨트랙트 아키텍처는 다음과 같아야 합니다.
nft-contract
├── Cargo.lock
├── Cargo.toml
├── README.md
├── build.sh
└── src
├── approval.rs
├── enumeration.rs
├── internal.rs
├── lib.rs
├── metadata.rs
├── mint.rs
├── nft_core.rs
└── royalty.rs
새로 만든 internal.rs
파일에 다음을 추가합니다.
loading...
그런 다음 빠르게 lib.rs
파일로 이동하여, 방금 만든 함수를 다른 파일에서 호출할 수 있도록 만들어 보겠습니다. 아래와 같이 내부 크레이트를 추가하고 파일을 수정합니다.
loading...
이 시점에서 NFT를 발행할 수 있는 핵심 로직이 모두 준비되었습니다. 이제 다음 매개변수를 사용하는 nft_mint
함수를 사용할 수 있습니다.
- token_id: 발행하려는 토큰의 ID(문자열).
- metadata: 생성 중인 토큰의 메타데이터(
metadata.rs
파일 내 에서 찾을 수 있는TokenMetadata
자료형). - receiver_id: 토큰 소유자를 지정.
내부적으로, 함수는 다음과 같이 동작할 것입니다.
- 컨트랙트에 무엇이든 추가하기 전에, 초기 스토리지를 계산합니다.
- 소유자 ID로
Token
객체를 만듭니다. tokens_by_id
필드에 토큰 ID를 삽입하여 새로 만든 토큰 객체에 토큰 ID를 연결합니다.- 토큰 ID를
token_metadata_by_id
필드에 삽입하여 전달된 메타데이터에 연결합니다 internal_add_token_to_owner
함수를 호출하여 소유자가 소유한 토큰 목록에 토큰 ID를 추가합니다.- 사용자가 이러한 비용을 위해 호출에 충분한 NEAR를 첨부했는지 확인하려면 최종 및 순 스토리지를 계산합니다.
토큰 정보 쿼리
계속 진행하여 이 컨트랙트를 배포하고 초기화하여 NFT를 생성한다면, 방금 생성한 토큰에 대한 정보를 알거나 쿼리할 방법이 없습니다. 특정 NFT의 정보를 쿼리하는 방법을 빠르게 추가해 보겠습니다. nft-contract/src/nft_core.rs
파일로 이동하여 nft_token
함수를 편집합니다.
이는 토큰 ID를 매개변수로 사용하고 해당 토큰에 대한 정보를 반환할 것입 니다. JsonToken
에는 토큰 ID, 소유자 ID 및 토큰의 메타데이터가 포함됩니다.
loading...
완료되면 첫 NFT를 생성할 수 있도록 컨트랙트를 구축하고 배포할 차례입니다.