ERC-7066 ERC-721 잠금 확장 (Lockable Extension for ERC-721)
Final · NFT·멀티토큰 · 2023-05-25 작성
NFT를 소유자 지갑에 둔 채 잠가서 판매·전송만 막는 표준입니다. 잠금 해제 권한을 가진 주소(locker)를 지정해 대출, 대여 같은 금융 활용을 가능하게 합니다.
왜 필요한가
지금까지 NFT(블록체인 위의 고유한 디지털 자산)를 담보 대출이나 대여에 쓰려면 해당 서비스의 스마트 컨트랙트(블록체인에서 자동 실행되는 프로그램)로 NFT를 옮겨 맡겨야 했습니다. 이렇게 하면 세 가지 문제가 생깁니다. 첫째, NFT가 내 지갑을 떠나므로 커뮤니티 입장 권한이나 게임 내 사용 같은 활용 가치를 잃습니다. 둘째, 하나의 NFT로 대출과 대여를 동시에 하는 식의 조합이 어려워 시장의 유동성이 떨어집니다. 셋째, 맡긴 컨트랙트에 버그나 취약점이 있으면 NFT를 도난당하거나 잃을 수 있습니다. 이 표준은 NFT를 옮기는 대신 소유자 지갑 안에서 잠그는 방식을 제안합니다. 잠긴 동안 전송만 제한되고 다른 속성은 그대로 유지되므로, 소유자는 담보로 맡긴 집에 계속 사는 것처럼 NFT의 활용 가치를 계속 누릴 수 있습니다.
구현해야 하는 것
event Lock (uint256 indexed tokenId, address _locker);: 토큰이 잠길 때 발생하는 이벤트입니다. 잠긴 토큰 번호와 잠금 해제 권한자 주소를 알립니다.event Unlock (uint256 indexed tokenId);: 토큰의 잠금이 풀릴 때 발생하는 이벤트입니다.function lock(uint256 tokenId) external;: 호출자가 소유자 또는 승인받은 주소이면 토큰을 잠그고 호출자 자신을 잠금 해제 권한자로 설정합니다.function lock(uint256 tokenId, address _locker) external;: 호출자가 소유자이면 토큰을 잠그고 지정한 _locker 주소를 잠금 해제 권한자로 설정합니다.function unlock(uint256 tokenId) external;: 호출자가 잠금 해제 권한자이면 토큰의 잠금을 풉니다.function transferAndLock(uint256 tokenId, address from, address to, bool setApprove) external;: 호출자가 소유자 또는 승인받은 주소이면 토큰을 전송한 뒤 잠그고 호출자를 잠금 해제 권한자로 설정합니다. setApprove가 true이면 호출자에게 승인도 부여합니다.function lockerOf(uint256 tokenId) external view returns (address);: 해당 토큰의 잠금 해제 권한자 주소를 돌려줍니다. address(0)이면 잠기지 않은 상태이고 다른 주소이면 잠긴 상태입니다.
심층 설명
잠금과 해제의 기본 규칙
lock 함수는 두 가지입니다. lock(uint256 tokenId, address _locker)는 소유자가 호출할 수 있고 locker를 _locker로 설정해야 합니다(MUST). lock(uint256 tokenId)는 소유자 또는 승인받은(approved) 주소가 호출할 수 있고 locker를 msg.sender로 설정해야 합니다. unlock은 locker만 호출할 수 있으며 locker 매핑을 삭제해 address(0)으로 되돌려야 합니다. 이미 잠긴 토큰에 lock을 호출하면 되돌려야(revert) 하고 잠기지 않은 토큰에 unlock을 호출해도 되돌려야 합니다.
lockerOf로 잠금 상태 조회
lockerOf 함수는 토큰이 잠겨 있으면 잠금을 풀 수 있는 locker 주소를 돌려줘야 하고 잠겨 있지 않으면 address(0)을 돌려줘야 합니다. 해제 시 매핑을 삭제해 address(0)으로 만드는 설계는 저장 공간을 비우는 동시에, 컨트랙트 내부에서 잠금 여부를 판별하는 기준으로도 쓰입니다.
잠긴 토큰의 전송·승인 제한
토큰이 잠겨 있으면 ERC-721의 approve 함수는 되돌려야 합니다. 소유권을 옮기는 ERC-721 전송 함수들도 되돌려야 하지만 예외가 하나 있습니다. msg.sender가 approved이면서 동시에 locker이면 전송할 수 있습니다. 전송 함수가 실행된 뒤에는 locker와 approved 값이 모두 지워져야 합니다. 즉 토큰이 새 주인에게 넘어가면 이전의 잠금·승인 권리는 모두 사라집니다.
transferAndLock과 setApprove
transferAndLock(uint256 tokenId, address from, address to, bool setApprove)는 토큰을 전송한 뒤 받는 쪽 주소에서 잠그는 함수입니다. setApprove가 true이면 locker에게 승인(approval)까지 부여해, locker가 나중에 토큰을 회수할 수 있게 합니다. 회수 조건은 각 컨트랙트에서 정의할 수 있습니다. 이렇게 하면 받는 사람은 전송 권한 없는 조건부 소유권을 갖게 되므로, 전송 후 회수가 필요한 할부 구매(BNPL) 같은 사례에 권장됩니다(RECOMMENDED).
다른 잠금 제안과의 차이
이 제안은 lock과 unlock의 최소 구현만 담습니다. 시간 제한 잠금 같은 조건은 토큰 컨트랙트에 넣지 않아도 별도 스마트 컨트랙트로 구현할 수 있다고 보고 상환이나 만료 등 어떤 조건이든 잠금·해제의 근거로 쓸 수 있게 열어 둡니다. 또 locker와 승인자(approver)의 권리를 분리합니다. 승인과 함께 잠그면 approved가 잠금을 풀고 토큰을 가져갈 수 있어 대여, 대출, 할부 구매가 가능해집니다. 회수 권한 없이 잠그되 필요하면 풀 수만 있게 하면 계정 귀속형(account-bound) NFT도 만들 수 있습니다.
활용 사례
원문이 제시하는 사례로는 NFT를 지갑에 둔 채 담보로 쓰는 NFT 담보 대출, 빌린 사람이 쓸 수는 있지만 전송할 수 없는 무담보 NFT 대여, 할부를 다 내기 전까지 팔 수 없는 할부 구매(BNPL), 대출과 대여를 동시에 조합하는 활용, 부분 결제로 먼저 민팅하는 1차 판매, 조직이 locker를 자신으로 지정해 발행하는 소울바운드(양도 불가) 토큰이 있습니다. 보안 용도로는 콜드월렛을 잠금 해제 권한자로 지정해 두면, 평소 쓰는 지갑이 해킹당해도 콜드월렛 없이는 NFT를 전송할 수 없습니다.
호환성과 상태
이 표준은 ERC-721과 호환되며 ERC-165와 ERC-721이 필요합니다. 기존 업그레이드 가능한 ERC-721 컨트랙트는 이 표준으로 업그레이드해 잠금 기능과 유동성 활용을 더할 수 있습니다. 이 제안은 최종 확정(Final) 상태입니다.
쓸 때 주의할 점
- 잠긴 토큰은 승인·전송 불가: 한번 잠긴 토큰은 추가로 승인하거나 전송할 수 없습니다. 이를 전제로 연동 컨트랙트를 설계해야 합니다.
- locker 겸 approved는 전송 가능: 토큰이 잠겨 있어도 호출자가 locker이면서 approved이면 토큰을 전송할 수 있습니다.
- 영구 잠금 위험: 접근할 수 없는 계정이나 검증되지 않은 컨트랙트 주소를 locker로 지정하면 토큰이 영구히 잠길 수 있습니다.
- MEV 관련: 잠금과 해제는 권한 있는 주체만 할 수 있으므로 잠금 가능 토큰의 MEV 고려 사항은 없습니다.