ERC-5521 참조형 NFT (rNFT) (Referable NFT)
Final · NFT·멀티토큰 · 2022-08-10 작성
ERC-721 NFT에 참조(referring)와 피참조(referred) 관계, 생성 시각을 기록해 NFT 사이의 인용 관계를 방향성 비순환 그래프(DAG)로 만들고 누구나 조회할 수 있게 하는 확장 표준입니다.
왜 필요한가
기존 NFT 표준에는 어떤 NFT가 어떤 작품을 바탕으로 만들어졌는지 기록하는 방법이 없습니다. 예술가가 기존 NFT를 발전시켜 새 작품을 만들거나 DJ가 두 곡을 섞어 리믹스를 내더라도, 원작과 새 작품 사이의 관계가 체인에 남지 않습니다. 이 때문에 각 NFT는 서로 고립되고 판매는 한 번으로 끝나는 거래가 되며 원작자는 자신의 지식재산이 이후에 만들어 내는 가치를 이어서 얻기 어렵습니다. 원문은 이 공백을 메우기 위해 NFT 사이에 참조 관계를 넣어 인용을 효율적으로 조회할 수 있게 하고 창작과 이용과 홍보를 계속하도록 장려하는 경제 모델의 바탕을 만들자고 제안합니다. 새 창작자는 처음부터 다시 만들 필요 없이 기존 작품 위에 쌓아 올릴 수 있고 원작 NFT는 자신이 어디에 인용되었는지 알 수 있게 됩니다.
구현해야 하는 것
function setNode(uint256 tokenId, address[] memory addresses, uint256[][] memory tokenIds) external;: rNFT의 참조(referring) 목록을 설정하고 참조된 각 rNFT의 피참조(referred) 목록을 갱신합니다.function referringOf(address _address, uint256 tokenId) external view returns(address[] memory, uint256[][] memory);: 지정한 컨트랙트 주소와 토큰 ID의 rNFT가 참조하고 있는 목록을 돌려줍니다.function referredOf(address _address, uint256 tokenId) external view returns(address[] memory, uint256[][] memory);: 지정한 rNFT를 참조하고 있는 쪽의 목록을 돌려줍니다.function createdTimestampOf(address _address, uint256 tokenId) external view returns(uint256);: 해당 rNFT가 생성될 때의 타임스탬프를 uint256으로 돌려줍니다.function supportsInterface(bytes4 interfaceId) external view returns (bool);: ERC-165에 따라 이 컨트랙트가 해당 인터페이스를 지원하는지 확인합니다.function setNodeReferredExternal(address _address, uint256 tokenId, uint256[] memory _tokenIds) external;: 외부 컨트랙트에서 호출되어, 그 컨트랙트의 rNFT가 이 컨트랙트의 rNFT들을 참조했음을 피참조 목록에 기록합니다.
심층 설명
두 개의 참조 지표와 DAG 구조
이 표준은 ERC-721 확장으로, 각 토큰에 referring(내가 참조하는 목록, 나가는 간선)과 referred(나를 참조하는 목록, 들어오는 간선), 그리고 생성 시각 createdTimestamp를 기록합니다. 참조는 반드시 먼저 만들어진 토큰을 향해야 하므로 전체 관계는 방향성 비순환 그래프(DAG)를 이룹니다. 참조 구현에서는 Relationship 구조체에 referring, referred 매핑과 이벤트용 키 배열 referringKeys, referredKeys, createdTimestamp를 담고 privityOfAgreement나 profitSharing 같은 선택 속성을 확장할 수 있습니다.
setNode의 필수 요구사항
setNode(tokenId, addresses, tokenIds)는 rNFT의 referring 목록을 설정하고 참조된 각 rNFT의 referred 목록을 갱신합니다. 요구사항은 네 가지입니다. addresses의 크기는 tokenIds의 크기와 같아야 하고(MUST), tokenIds의 크기가 0이 아니면 내부 배열 크기도 0이 아니어야 하며(MUST), tokenId는 같은 컨트랙트 안에서 고유해야 하고(MUST), addresses[i]가 address(this)일 때 tokenId는 tokenIds[i][j]와 같아서는 안 됩니다(MUST NOT). 즉 자기 자신을 참조할 수 없습니다. addresses와 tokenIds의 중복 검사는 권장(RECOMMENDED) 사항입니다. 내부적으로는 setNodeReferring이 referring 목록을, setNodeReferred가 referred 목록을 처리합니다.
크로스 컨트랙트 참조와 TargetContract 인터페이스
다른 컨트랙트의 rNFT를 참조할 때는 TargetContract 인터페이스의 setNodeReferredExternal(_address, tokenId, _tokenIds)를 사용합니다. 호출 전에 ERC-165의 supportsInterface로 상대 컨트랙트가 이 인터페이스를 지원하는지 확인하고 지원할 때만 호출합니다. 이런 조건부 호출은 기존 컨트랙트와의 하위 호환과 통합을 보장합니다. 요구사항으로 _address는 인터페이스를 구현한 외부 컨트랙트에서 실행될 때 address(this)와 같아서는 안 됩니다(MUST NOT). TargetContract에는 referringOf, referredOf, createdTimestampOf, supportsInterface도 포함되어 외부에서 같은 방식으로 조회할 수 있습니다.
createdTimestamp와 시간 순서 보장
이 표준은 rNFT가 이미 커뮤니티에 받아들여진 콘텐츠, 즉 참여자들이 아는 시간 순서상 앞선 콘텐츠를 참조해야 한다는 것을 핵심 원칙으로 삼습니다. 이를 위해 createdTimestamp = block.timestamp로 블록 수준의 전역 타임스탬프를 기록하고 참조 구현에서는 참조되는 rNFT의 createdTimestamp가 현재 블록 시각보다 크거나 같으면 되돌려서(revert) 참조 대상이 선행 토큰임을 강제합니다. 다만 참조의 세밀한 정도가 블록 타임스탬프에 묶여 있어 같은 블록 안에서 만들어진 두 rNFT의 선후는 가릴 수 없습니다. createdTimestamp는 호출자가 어떤 방법으로도 수정할 수 없어야 합니다.
UpdateNode 이벤트의 정보량
UpdateNode 이벤트는 setNode가 호출될 때 발생하며 rNFT의 토큰 ID, 소유자, 그리고 이 rNFT를 참조하거나 이 rNFT가 참조하는 컨트랙트 주소 목록과 토큰 ID 목록을 모두 담습니다. 이해관계자는 이 정보로 rNFT 생태계의 복잡한 관계망을 효율적으로 관리하고 탐색할 수 있습니다. 저장 방식은 구현자가 자유롭게 선택할 수 있습니다. 구조체를 쓰든 별도의 매핑 여러 개를 쓰든, 출력이 UpdateNode 이벤트를 채울 수 있다면 컨트랙트 동작에 차이가 없습니다. 참조 구현의 convertMap은 구조체 안의 매핑 전체 내용을 키 배열과 값 배열로 꺼내는 함수로, 이벤트 발생 요건을 채우는 데 필요합니다.
조회 함수와 데이터 공개 범위
referringOf와 referredOf는 컨트랙트 주소와 토큰 ID를 받아, 해당 주소가 자기 자신이면 내부 저장소에서, 외부 컨트랙트면 인터페이스 확인 후 그 컨트랙트에 물어서 목록을 돌려줍니다. _relationship 상태 변수에 직접 접근하는 방식으로는 이런 크로스 컨트랙트 조회를 할 수 없습니다. 프라이버시가 문제되지 않는다면 _relationship을 public으로 두고 솔리디티가 자동 생성하는 getter에 맡겨 컨트랙트를 단순화할 수 있지만 사용자의 상호작용 내역이나 확장 파라미터 같은 정보가 들어 있다면 상태 변수를 private으로 두고 전용 getter를 제공하는 편이 좋습니다. 항상 공개하면 사용자의 행동 패턴이나 선호가 드러나 프라이버시 침해로 이어질 수 있기 때문입니다.
ERC-721 호환성과 활용 가능성
이 표준은 확장 함수 집합을 더하는 방식이어서 ERC-721과 완전히 호환될 수 있습니다. 원문이 드는 장점은 네 가지입니다. 소유권 상속이 분명해져 창작자가 고립되어 작업하지 않아도 되고 참조 관계가 명확해져 원작 소유자와 새 창작자 모두를 위한 상위 인센티브 모델을 얹을 수 있습니다. 또 기존 토큰 표준이나 제3자 프로토콜과 통합하기 쉽고(예를 들어 ERC-5006과 결합해 계층적 대여 시장을 만드는 경우) 컨트랙트 간 참조로 확장성 있는 상호운용이 가능합니다. 이 표준은 Final 상태로 확정되어 있습니다.
쓸 때 주의할 점
- 블록 수준 타임스탬프의 한계: createdTimestamp는 블록 헤더 기반의 블록 수준 타임스탬프만 담으므로, 트랜잭션 수준 같은 더 세밀한 선후 비교는 지원하지 않습니다.
- 소유권 변경과 참조 관계는 별개: 소유권이 바뀌어도 참조 관계에는 영향이 없습니다. 수익 분배는 보통 NFT가 만들어질 때의 합의를 따르며 합의에 따로 명시하지 않는 한 소유권 변경과 무관합니다.
- 참조는 자손 토큰까지 미치지 않음: 토큰을 참조해도 기본적으로 그 자손 토큰까지 참조되지는 않습니다. 특정 자식 토큰만 참조하면 계약의 당사자 관계는 그 자식 토큰 소유자에게만 미칩니다. 수익 분배를 명시하려면 루트에서 말단까지의 참조 사슬을 referring에 기록하는 방법을 쓸 수 있습니다.
- 개방형 민팅의 위험: safeMint는 누구나 제한 없이 발행하고 관계를 설정할 수 있도록 의도적으로 설계되었습니다. 그만큼 승인되지 않았거나 잘못된 참조가 만들어질 수 있고 악의적 행위자가 관계를 조작하거나 토큰 공급을 부풀릴 수 있습니다. 원문은 이를 설계 결함이 아니라 유연성과 신뢰성 사이의 의도적 트레이드오프로 봅니다.
- 온체인 무결성의 범위: 온체인 데이터 무결성 보장은 블록체인에 기록된 것에만 미치며 오프체인의 오류나 조작 가능성을 막지 못합니다. 사용자와 통합자는 이 시스템이 제공하는 관계 데이터를 해석하고 쓸 때 주의와 판단이 필요합니다.