승인
이 튜토리얼에서는 다른 사람이 당신을 대신해 NFT를 전송할 수 있도록 액세스 권한을 부여할 수 있는 승인 관리 시스템의 기본 사항을 배웁니다. 이것은 모든 NFT 마켓플레이스의 중추이며, 복잡하지만 아름다운 시나리오가 발생할 수 있도록 합니다. 처음 가입하는 경우 이 레퍼지토리를 자유롭게 복제하고 4.core
브랜치를 확인하세요.
git checkout 4.core
5.approval
브랜치에서 찾을 수 있습니다. :::소개
지금까지 사용자가 열거형(Enumeration) 표준을 사용하여 정보를 쿼리할 뿐만 아니라, NFT를 생성 및 전송할 수 있는 스마트 컨트랙트를 만들었습니다. 이전 튜토리얼에서 수행한 것처럼 문제를 더 작고 이해하기 쉬운 작업으로 분류해 보겠습니다. 먼저 표준의 승인 관리 확장에 따라 달성하고자 하는 일부 최종 목표를 정의해 보겠습니다. 우리는 사용자가 다음과 같은 기능을 갖기를 원합니다.
- 다른 계정에 토큰별로 NFT를 전송할 수 있는 액세스 권한을 부여합니다.
- 계정에 특정 토큰에 대한 액세스 권한이 있는지 확인합니다.
- 특정 계정의 NFT 전송 승인을 취소합니다.
- NFT를 전송할 수 있는 다른 모든 계정의 승인을 취소합니다.
이 모든 목표를 살펴보면, 모두 토큰 기준임을 알 수 있습니다. 이것은 각 토큰에 대한 정보를 추적하는 Token
구조체를 변경해야 한다는 강력한 표시입니다.
계정에서 NFT 전송 허용
첫 번째 목표를 달성하는 것으로 시작해 봅시다. 당신을 대신하여 NFT를 전송할 수 있는 다른 계정 액세스 권한을 어떻게 부여할 수 있을까요?
이를 달성할 수 있는 가장 간단한 방법은 승인된 계정 목록을 Token
구조체에 추가하는 것입니다. NFT를 전송할 때 발신자가 소유자가 아닌 경우 목록에 있는지 확인할 수 있습니다.
전송하기 전에 새 소유자는 원래 소유자가 승인한 계정이 새 NFT를 이전할 수 있는 액세스 권한이 있을 것으로 기대하지 않기 때문에, 승인된 계정 목록을 지워야 합니다.
문제점
표면적으로는 이것이 효과가 있지만, 엣지 케이스에 대해 생각하기 시작하면 몇 가지 문제가 발생합니다. 종종 개발을 수행할 때 일반적인 접근 방식은 가장 쉽고 간단한 솔루션에 대해 생각하는 것입니다. 파악한 후에는 케이스를 나누고 최적화 및 엣지 케이스에 대해 생각할 수 있습니다.
다음 시나리오를 고려해 봅시다. Benji는 NFT를 가지고 있으며 토큰을 전송할 수 있는 두 개의 마켓플레이스에 액세스할 수 있습니다. 그렇게 함으로써 그는 NFT를 판매합니다(자세한 내용은 마켓플레이스 통합 섹션 참조). 그가 NFT를 두 마켓플레이스 모두에서 1 NEAR에 판매한다고 가정해 보겠습니다. 토큰의 승인된 계정 ID 목록은 다음과 같습니다.
Token: {
owner_id: Benji
approved_accounts_ids: [marketplace A, marketplace B]
}
그런 다음 Josh가 와서 마켓플레이스 A에서 1 NEAR에 NFT를 구매합니다. 이렇게 하면 마켓플레이스 A에서 판매가 중단되고 승인된 계정 목록이 지워집니다. 그러나 마켓플레이스 B에는 여전히 1 NEAR에 판매 목록에 있는 토큰이 있으며 Josh가 해당 토큰을 마켓플레이스 A에서 구매했는지 알 방법이 없습니다. 새 토큰 구조체는 다음과 같습니다.
Token: {
owner_id: Josh
approved_accounts_ids: []
}
Josh가 현금이 부족하고 이 NFT를 B 마켓플레이스 가격의 10배에 판매하려고 한다고 가정해 보겠습니다. 토큰을 두 번 판매하기 위해 이전 판매 데이터를 유지합니다. 이는 마켓플레이스 B의 관점에서 토큰이 여전히 1 NEAR(Benji가 원래 상장한 가격)에 판매 중임을 의미합니다.
Josh가 판매를 시도하고 판매하도록 마켓플레이스를 승인했으므로 토큰 구조는 다음과 같습니다.
Token: {
owner_id: Josh
approved_accounts_ids: [marketplace A, marketplace B]
}
그런 다음 Mike가 와서 마켓플레이스 B에서 1 NEAR에 대해서만 NFT를 구매하면 마켓플레이스는 NFT를 전송하려고 시도할 것이고, 기술적으로 Josh가 마켓플레이스를 승인했고 승인된 계정 목록에 있기 때문에 트랜잭션이 제대로 진행됩니다.
해결책
이제 원래 솔루션의 문제를 식별했으므로 문제를 해결할 수 있는 방법에 대해 생각해 봅시다. 승인된 계정 목록을 추적하는 대신 승인된 각 계정과 함께 제공되는 특정 ID를 도입하면 이제 어떻게 될까요? 새로 승인된 계정은 이제 목록이 아닌 맵이 됩니다. 그것은 계정을 그것의 approval id
와 매핑할 것입니다.
이것이 작동하려면, 승인 ID가 항상 고유한 새 ID인지 확인해야 합니다. 만약 이를 계정 승인 시마다 항상 1씩 증가하는 정수로 설정하면 제대로 작동합니다. 새 솔루션으로 동일한 시나리오를 고려해 보겠습니다.
Benji는 마켓플레이스 A와 마켓플레이스 B를 모두 승인하여 자신의 NFT를 1 NEAR에 판매합니다. "다음 승인 ID"는 NFT가 처음 발행될 때 0에서 시작하여 1씩 증가합니다. 그러면 다음과 같은 토큰 구조가 생성됩니다.
Token: {
owner_id: Benji
approved_accounts_ids: {
marketplace A: 0
marketplace B: 1
}
next_approval_id: 2
}
Benji가 마켓플레이스 A를 승인했을 때는, 0에서 시작하는 원래 값의 next_approval_id
를 사용했습니다. 그런 다음 마켓플레이스가 맵에 삽입되고, 다음 승인 ID가 증가했습니다. 이 프로세스는 마켓플레이스 B에 대해 다시 발생했으며 다음 승인 ID는 현재 2인 위치에서 다시 증가했습니다.
Josh가 와서 마켓플레이스 A에서 1 NEAR에 NFT를 구매합니다. 다음 승인 ID가 어떻게 2로 유지되었는지 확인해 보세요.
Token: {
owner_id: Josh
approved_accounts_ids: {}
next_approval_id: 2
}
그런 다음 Josh는 다시 한 번 현금이 부족해 NFT를 판매하려 하고, 마켓플레이스 B를 승인합니다.
Token: {
owner_id: Josh
approved_accounts_ids: {
marketplace B: 2
}
next_approval_id: 3
}
마켓플레이스가 맵에 삽입되고 다음 승인 ID가 증가합니다. 마켓플레이스 B의 관점에서 볼 때는, Benji가 가치가 1인 NFT를 리스팅했을 때 원래 승인 ID를 저장합니다. Mike가 원래 판매 가격(1 NEAR)으로 마켓플레이스 B에서 NFT를 구매하려면 NFT 컨트랙트는 패닉합니다. 이는 마켓플레이스에서 승인 ID 1로 NFT를 전송하려고 하지만 토큰 구조에서 승인 ID가 2여야 한다고 표시하기 때문입니다.
Token
및 JsonToken
구조체 확장
이제 계정에서 NFT를 전송하도록 허용하는, 원래 문제에 대해 제안된 솔루션을 이해했으므로 일부 로직을 구현할 차례입니다. 가장 먼저 해야 할 일은 새 변경 사항을 반영하도록 Token
및 JsonToken
구조체를 수정하는 것입니다. nft-contract/src/metadata.ts
파일로 가보겠습니다.
Loading...
You'll then need to initialize both the approved_account_ids
and next_approval_id
to their default values when a token is minted. Switch to the nft-contract/src/mint.ts
file and when creating the Token
struct to store in the contract, let's set the next approval ID to be 0 and the approved account IDs to be an empty object:
Loading...
계정 승인
이제 토큰 수준에서 승인된 계정 ID 및 다음 승인 ID에 대한 지원을 추가했으므로, nft_approve
라는 함수를 통해 해당 필드를 채우고 변경하는 로직을 추가할 차례입니다. 이 함수는 계정이 특정 토큰 ID에 액세스할 수 있도록 승인해야 합니다. nft-contract/src/approval.ts
파일로 이동하여 internalNftApprove
함수를 편집해 보겠습니다.
Loading...