ERC-6672 다회 교환 가능 NFT (Multi-redeemable NFTs)
Final · NFT·멀티토큰 · 2023-02-21 작성
NFT 하나를 여러 시나리오에서 실물 상품이나 디지털 혜택으로 여러 번 교환(redeem)할 수 있게 하고 각 교환 기록을 블록체인에 남기는 ERC-721 확장 표준입니다.
왜 필요한가
NFT 교환은 보유자가 소유권과 자격을 증명하고 그 대가로 실물이나 디지털 물품을 받는 행위입니다. 기존에는 NFT 하나당 한 번만 교환할 수 있다는 한계가 있어 같은 NFT를 여러 행사나 캠페인에서 반복해 쓰기 어려웠습니다. 예를 들어 디지털 콘서트 티켓 NFT라면 온라인 공연 입장에 한 번, 한정판 굿즈 수령에 또 한 번, 아티스트와의 만남에 또 한 번 쓰는 식으로 교환마다 다른 경험과 혜택을 담을 수 있어야 합니다. 또 어떤 NFT가 어떤 운영자의 어떤 캠페인에서 이미 교환되었는지를 체인 위에서 확인할 방법도 필요합니다. 이 표준은 운영자, 토큰, 교환 건을 조합한 기록 구조로 이런 다회 교환을 가능하게 합니다.
구현해야 하는 것
function isRedeemed(address _operator, bytes32 _redemptionId, uint256 _tokenId) external view returns (bool);: 특정 운영자의 특정 교환 건에서 해당 NFT가 이미 교환되었는지를 반환합니다.function getRedemptionIds(address _operator, uint256 _tokenId) external view returns (bytes32[]);: 해당 운영자가 해당 NFT에 대해 만든 교환 건의 식별자 목록을 반환합니다.function redeem(bytes32 _redemptionId, uint256 _tokenId, string _memo) external;: NFT를 교환 처리합니다. 호출자(msg.sender)가 그 교환의 운영자로 기록됩니다.function cancel(bytes32 _redemptionId, uint256 _tokenId, string _memo) external;: 교환을 취소합니다. 교환을 만든 운영자만 호출할 수 있습니다.function tokenURI(uint256 _tokenId) external view returns (string);: 선택 사항인 메타데이터 확장의 함수로, 토큰의 메타데이터 JSON 위치(URI)를 반환합니다.
심층 설명
운영자 권한과 msg.sender 규칙
운영자는 자신이 만든 교환 기록만 수정할 수 있어야 합니다(SHALL). 이를 강제하기 위해 redeem()과 cancel() 함수에는 _operator 파라미터가 없고 호출자 주소인 msg.sender를 반드시 _operator로 사용해야 합니다(MUST). 즉 어떤 운영자가 만든 교환 건을 다른 주소가 대신 교환 처리하거나 취소할 수 없습니다.
교환 플래그의 키 구조
교환 여부는 키-값 쌍으로 저장합니다. 키로는 _operator, _tokenId, _redemptionId 세 값의 조합을 반드시 사용해야 합니다(MUST). 값은 isRedeemed() 함수로 조회합니다. 세 값을 모두 쓰는 이유는 각각 다릅니다. 같은 NFT를 여러 당사자가 교환에 쓸 수 있으므로 운영자 주소가 필요하고(예: MisterPunks NFT가 서로 다른 운영자가 운영하는 Event-X와 Event-Y 티켓으로 각각 교환), 보유자마다 같은 운영자가 만든 기록이 다르므로 토큰 식별자가 필요하며 같은 NFT를 같은 운영자의 여러 캠페인에서 교환할 수 있도록 교환 식별자가 필요합니다(예: Operator-X의 캠페인 A와 B에서 MisterPunk #7을 각각 피규어로 교환).
필수 인터페이스와 식별자
이 표준을 따르는 컨트랙트는 ERC6672와 ERC721 인터페이스를 모두 구현해야 합니다(MUST). IERC6672 인터페이스의 ERC-165 식별자는 0x4dddf83f입니다. 인터페이스는 Redeem과 Cancel 이벤트, 조회 함수 isRedeemed()와 getRedemptionIds(), 실행 함수 redeem()과 cancel()로 구성됩니다. 이 표준은 ERC-721과 호환됩니다.
선택적 메타데이터 확장
IERC6672Metadata는 선택 사항(OPTIONAL)으로, tokenURI(uint256 _tokenId)가 ERC-6672 메타데이터 JSON 스키마를 따르는 JSON 파일을 가리킬 수 있습니다. 유효하지 않은 토큰이면 예외를 던집니다. 스키마에는 기본 name, description, image 외에 redemptions 항목이 있으며 그 키는 operator-tokenId-redemptionId 형식으로 반드시 표준화해야 합니다(MUST). 각 키의 값은 status와 description을 담은 객체입니다.
status와 description 필드
메타데이터의 교환 상태(status)는 단순한 true·false 플래그보다 세분화할 수 있습니다. 실물 상품 교환이라면 redeemed, paid, shipping 같은 단계가 필요할 수 있습니다. 운영자와 마켓플레이스 등 상태를 표시하려는 쪽 모두가 이해할 수 있는 문자열 열거형(enum) 사용이 권장됩니다(RECOMMENDED). description은 콘서트 티켓 정보나 피규어의 상세 설명처럼 교환 내용의 세부 정보를 제공하는 데 써야 합니다(SHOULD).
쓸 때 주의할 점
- 운영자 간 권한 격리: 잘못 구현하면 권한 없는 운영자가 다른 운영자의 교환 플래그에 접근해 남의 교환 절차를 취소할 수 있습니다. msg.sender로 식별되는, 교환을 만든 운영자만 redeem()과 cancel()로 교환 플래그를 바꿀 수 있도록 구현해야 합니다.
- ERC-721 승인 모델과 분리: redeem()과 cancel() 함수는 ERC-721의 승인(approval) 모델과 격리하는 것이 권장됩니다. 한편 이 토큰은 ERC-721과 호환되므로 표준 ERC-721을 다룰 수 있는 지갑과 컨트랙트는 비호환 구현으로 인한 자산 손실 위험이 없습니다.