ERC-6551 NFT가 소유하는 토큰 바운드 계정 (Non-fungible Token Bound Accounts)

Review · NFT·멀티토큰 · 2023-02-23 작성

모든 NFT에 고유한 스마트 컨트랙트 계정을 부여해 NFT가 직접 자산을 보유하고 앱과 상호작용할 수 있게 합니다. 기존 NFT 컨트랙트를 바꿀 필요가 없습니다.

왜 필요한가

NFT(대체 불가능 토큰)는 고유한 자산을 표현할 수 있지만 스스로 무언가를 소유하거나 행동할 수는 없습니다. NFT는 지갑에 담기는 물건일 뿐, 지갑처럼 쓸 수 없다는 뜻입니다. 그래서 시간이 지나며 장비와 능력을 쌓는 게임 캐릭터, 여러 부품으로 이루어진 자동차, 여러 자산을 담은 투자 포트폴리오, 이용 기록이 쌓이는 멤버십 카드 같은 현실의 자산을 NFT 하나로 표현하기 어렵습니다. 캐릭터 NFT에 아이템 토큰을 묶으려면 별도의 컨트랙트 장치를 일일이 만들어야 하고 NFT를 팔 때 딸린 자산을 함께 넘기기도 번거롭습니다. 이 표준은 모든 NFT에 이더리움 사용자와 같은 권리를 주는 것을 목표로 합니다. NFT마다 결정적으로 계산되는 전용 계정 주소를 부여하고 그 계정의 통제권을 NFT 보유자에게 주는 방식입니다.

구현해야 하는 것

심층 설명

싱글턴 레지스트리와 고정 주소

레지스트리는 모든 토큰 바운드 계정 주소 조회의 단일 진입점이 되는 싱글턴 컨트랙트입니다. createAccount와 account 두 함수만 가지며 퍼미션리스하고 불변이며 소유자가 없습니다. 레지스트리는 Nick's Factory(0x4e59b44847b379578588920cA78FbF26c0B4956C)와 salt 0x0000000000000000000000000000000000000000fd8eb4e1dca713016c518e31을 사용해 반드시 주소 0x000000006551c19487814612e58FE06813775758에 배포해야 합니다. 원문에 제시된 트랜잭션 하나로 어떤 EVM 호환 체인에도 같은 주소에 배포할 수 있습니다. 소유자 없는 단일 레지스트리 덕분에 계정이 신뢰해야 할 대상은 구현 컨트랙트 하나로 줄어들고 이벤트와 주소 조회가 한곳에 모여 인덱싱도 단순해집니다.

ERC-1167 프록시와 바이트코드에 새긴 NFT 정보

레지스트리는 각 계정을 ERC-1167 최소 프록시로 배포하되, 바이트코드 뒤에 불변 상수 데이터를 덧붙입니다. 배포된 바이트코드는 ERC-1167 헤더(10바이트), implementation 주소(20바이트), ERC-1167 푸터(15바이트) 다음에 salt(bytes32), chainId(uint256), tokenContract(address), tokenId(uint256)가 각 32바이트씩 이어지는 구조여야 합니다. 구현 컨트랙트는 이 데이터를 extcodecopy로 읽어 자신이 어느 NFT에 묶였는지 알 수 있고 데이터가 코드에 새겨져 있으므로 바뀔 수 없습니다. 모든 계정은 create2로 배포해야 하며 주소는 구현 주소, 토큰 컨트랙트 주소, 토큰 ID, 체인 ID, salt의 조합에서 결정적으로 도출됩니다.

계정 인터페이스: 소유 NFT와 서명자 판별

모든 계정 구현은 ERC-165 인터페이스 감지와 ERC-1271 서명 검증을 구현해야 하고 IERC6551Account 인터페이스(식별자 0x6faff5f1)를 구현해야 합니다. token()은 계정을 소유한 NFT의 체인 ID, 토큰 컨트랙트, 토큰 ID를 돌려주며 이 값은 절대 바뀌면 안 됩니다. state()는 계정 상태가 바뀔 때마다 달라져야 하는 값을 돌려줍니다. isValidSigner는 주어진 주소가 계정을 대신할 권한이 있으면 매직 값 0x523e3260을 돌려줘야 합니다. 기본적으로 NFT 보유자는 유효한 서명자로 간주되어야 하지만 구현에 따라 보유자를 무효화하거나 다른 주소에 서명 권한을 주는 추가 로직을 넣을 수 있습니다.

실행 인터페이스는 자유롭게, 단 ERC-165로 알린다

모든 계정은 유효한 서명자가 임의의 작업을 실행할 수 있는 실행 인터페이스를 구현해야 하고 그 지원 사실을 ERC-165로 알려야 합니다. 다만 특정 인터페이스를 강제하지는 않습니다. 선택지로 제시된 IERC6551Executable(식별자 0x51945447)의 execute는 operation 값으로 0(CALL), 1(DELEGATECALL), 2(CREATE), 3(CREATE2)을 받아들여야 하며 추가 연산을 지원하거나 특정 서명자의 실행을 제한할 수 있습니다. 실행이 실패하면 오류를 그대로 올리며 되돌립니다. 실행 인터페이스를 고정하지 않은 것은 이미 존재하는 다양한 실행 인터페이스를 수용하고 미래에 표준화될 인터페이스와의 호환성을 유지하기 위해서입니다.

반사실적 계정과 크로스체인 주소

모든 계정이 create2로 만들어지므로, 계정은 실제 배포 전에도 주소가 확정된 반사실적(counterfactual) 상태로 존재할 수 있고 그 주소로 자산을 미리 받을 수 있습니다. 또한 알려진 고정 주소의 싱글턴 레지스트리 덕분에 같은 계정이 여러 체인에 존재할 수도 있습니다. createAccount가 chainId를 파라미터로 받기 때문에 지원되는 어느 체인에서든 같은 주소에 계정 컨트랙트 배포가 가능하고 한 체인의 NFT가 다른 체인의 자기 계정을 제어하는 크로스체인 실행도 구현할 수 있습니다. 토큰 식별자는 한 체인 안에서만 유일하므로, NFT를 식별할 때 컨트랙트 주소와 토큰 ID에 체인 ID를 함께 씁니다.

NFT 하나에 계정 여러 개를 허용한 이유

이 표준은 NFT마다 계정을 하나로 제한하지 않습니다. salt와 구현 주소를 달리하면 한 NFT가 여러 계정을 가질 수 있습니다. 설계 과정에서 NFT당 계정 하나를 두는 대안도 검토됐지만 채택되지 않았습니다. 첫째, 스마트 컨트랙트는 퍼미션리스하므로 누군가 레지스트리를 추가 배포하면 어차피 하나로 제한할 수 없습니다. 둘째, 하나로 제한하려면 고정된 신뢰 구현을 표준에 포함해야 하는데, 이는 계정의 능력에 제약을 걸게 되어 시기상조라고 봤습니다. 셋째, 온체인에서 활동하는 주체는 일상용 핫 계정과 보관용 콜드 계정처럼 여러 계정을 쓰는 것이 일반적이므로 NFT도 같은 능력을 가져야 한다는 판단입니다.

하위 호환성과 제안 상태

이 표준은 ERC-721을 확장하지 않으며 기존 NFT 컨트랙트에 어떤 변경도 요구하지 않습니다. 레지스트리는 계정을 만들기 전에 해당 토큰이 ERC-721인지 ERC-165로 검사하지 않습니다. 덕분에 ERC-721 이전에 나온 크립토키티 같은 컨트랙트나 ERC-721 인터페이스 일부만 구현한 ENS NameWrapper 이름과도 호환되고 반대체성·대체성 토큰에도 쓸 수 있습니다(다만 그 용도는 이 제안의 범위 밖입니다). 필요하면 계정 구현 쪽에서 ERC-721 인터페이스 검사를 넣을 수 있습니다. 이 제안은 현재 Review 상태로, 내용이 아직 바뀔 수 있는 단계입니다.

쓸 때 주의할 점

ERC 원문 · ← ERCs