ERC-6982 효율적 기본 잠금 토큰 (Efficient Default Lockable Tokens)
Final · NFT·멀티토큰 · 2023-05-02 작성
NFT(ERC-721)에 잠금 기능을 더하되, 토큰마다 이벤트를 내보내는 대신 기본 잠금 상태를 한 번만 알려 가스를 아끼는 표준입니다.
왜 필요한가
NFT를 잠글 수 있게 만드는 기존 제안들은 토큰을 민팅(발행)할 때마다 잠금 상태를 알리는 이벤트를 내보내도록 요구합니다. 그런데 소울바운드 토큰이나 양도 불가 배지처럼 처음 만들어질 때부터 소각될 때까지 영구히 잠겨 있는 토큰이라면, 모든 토큰이 같은 상태인데도 하나하나 이벤트를 발생시켜야 해서 가스(수수료)가 불필요하게 소모됩니다. 이 표준은 컨트랙트를 배포할 때 모든 토큰에 적용되는 기본 잠금 상태를 이벤트 한 번으로 알리고 그 뒤에는 개별 토큰의 상태가 실제로 바뀔 때만 이벤트를 내보내는 방식으로 가스를 아낍니다. 또한 잠금 상태를 조회하는 함수를 함께 정의해 다른 컨트랙트나 마켓플레이스가 토큰의 현재 상태를 쉽게 확인할 수 있게 합니다.
구현해야 하는 것
event DefaultLocked(bool locked);: 모든 토큰에 적용되는 기본 잠금 상태를 알립니다. 배포 시 반드시 내보내야 하고 기본 상태가 바뀌면 다시 내보내야 합니다.event Locked(uint256 indexed tokenId, bool locked);: 특정 토큰의 잠금 상태가 바뀔 때 내보냅니다. 이 상태는 해당 토큰에 한해 기본 상태를 덮어씁니다.function defaultLocked() external view returns (bool);: 현재의 기본 잠금 상태를 반환합니다. 가장 최근 DefaultLocked 이벤트가 알린 값과 일치해야 합니다.function locked(uint256 tokenId) external view returns (bool);: 특정 토큰의 잠금 상태를 반환합니다. Locked 이벤트가 없었던 토큰은 기본 상태를 반환하고 존재하지 않는 토큰이면 되돌려야(revert) 합니다.
심층 설명
DefaultLocked 이벤트의 역할
DefaultLocked(bool locked)는 컨트랙트가 배포될 때 반드시(MUST) 내보내 모든 토큰의 기본 잠금 상태를 확정합니다. 기본 상태가 바뀌면 다시 내보내야 하며 그러면 개별 Locked 이벤트가 없는 모든 토큰의 상태가 한 번에 갱신됩니다. 원문 Rationale은 이 이벤트가 Locked 이벤트보다 먼저만 나와야 하는 것이 아니라 언제든 다시 나올 수 있다고 명시합니다. 리빌 이후처럼 토큰의 동작이 바뀌는 상황에서 토큰마다 Locked 이벤트를 내보내는 대신 DefaultLocked 하나로 처리해 가스를 아끼는 것이 핵심 목적입니다.
Locked 이벤트와 개별 상태 우선
Locked(uint256 indexed tokenId, bool locked)는 특정 토큰의 잠금 상태가 바뀔 때 반드시 내보내야 합니다. 이 이벤트로 기록된 상태는 해당 토큰에 한해 기본 잠금 상태를 덮어씁니다(override). 따라서 외부에서 이벤트 로그만으로 상태를 재구성할 때는 가장 최근 DefaultLocked 값을 기본으로 두고 토큰별 Locked 이벤트가 있으면 그 값을 우선 적용하면 됩니다.
조회 함수 두 개의 규칙
defaultLocked()는 현재의 기본 잠금 상태를 반환하며 가장 최근에 발생한 DefaultLocked 이벤트가 알린 값을 반드시 반영해야 합니다. locked(uint256 tokenId)는 특정 토큰의 잠금 상태를 반환하는데, 그 토큰에 대해 Locked 이벤트가 한 번도 발생하지 않았다면 현재 기본 상태를 반환해야 하고 토큰이 존재하지 않으면 반드시 revert해야 합니다. 원문 Rationale은 defaultLocked 함수가 다른 컨트랙트와의 상호작용을 돕고 이미 Final 단계인 ERC-5192와의 잠재적 충돌을 피하는 역할을 한다고 설명합니다.
ERC-165 인터페이스 식별자
이 인터페이스의 ERC-165 interfaceId는 0x6b61a747입니다. ERC-165를 요구 조건(requires)으로 두고 있으므로, 마켓플레이스나 다른 컨트랙트는 supportsInterface 조회로 어떤 컨트랙트가 이 표준을 구현했는지 확인한 뒤 locked, defaultLocked를 호출할 수 있습니다.
잠금이 곧 양도 불가는 아님
원문은 토큰이 locked로 표시됐다고 해서 반드시 완전히 양도 불가능한 것은 아니라고 강조합니다. 잠금 상태는 주로 마켓플레이스와 외부 거래소에서 거래가 가능한지에 관한 것이며 특정 조건에서는 잠긴 상태에서도 전송이 일어날 수 있습니다. 예로 든 Cruna 프로토콜에서는 NFT 소유자가 protector라는 보조 지갑을 지정하면 토큰이 locked 상태가 되지만 그 protector가 시작한 전송은 여전히 가능합니다.
하위 호환성과 참조 구현
이 표준은 기존 ERC-721 컨트랙트와 완전히 하위 호환되며 기존 컨트랙트에 충돌 없이 통합할 수 있습니다. 참조 구현은 자산을 풀에 스테이킹하면 소유권을 잃게 되는 문제를 다루는데, 풀이 자산을 잠그되 소유권은 원래 소유자에게 남겨 두는 방식을 보여 줍니다. 구현 예시는 제안의 assets 디렉터리에 있습니다. 이 제안의 상태는 Final로, 명세가 확정된 표준입니다.
쓸 때 주의할 점
- 알려진 보안 문제는 없으나 구현은 신중하게: 원문은 이 제안 자체가 새로 만드는 알려진 보안 고려사항은 없다고 밝힙니다. 다만 다른 스마트 컨트랙트 표준과 마찬가지로, 이 인터페이스를 구현할 때는 엄격한 보안 조치를 적용해야 한다고 당부합니다.