ERC-6366 권한 토큰 표준 (Permission Token)
Review · 서명·인증 · 2022-01-19 작성
주소가 가진 권한을 uint256 숫자 하나의 비트들로 저장하고 토큰처럼 이전하거나 위임할 수 있게 하는 표준입니다. 권한 검사를 비트 연산으로 빠르게 처리합니다.
왜 필요한가
스마트 컨트랙트에는 소유자(Owner), 운영자(Operator), 관리자(Manager), 검증자(Validator) 같은 특별한 역할이 흔히 있고 권한을 가진 주소가 컨트랙트를 관리합니다. 그런데 이런 권한이 컨트랙트마다 제각각 관리되면 한 곳에서 모아 볼 수 없어서 감사하기도 어렵고 유지하기도 어렵습니다. 또 기존 접근 제어 목록(ACL, Access Control List) 방식은 문자열이나 keccak256 해시를 비교해 권한을 확인하는데, 이 방식은 비용이 많이 들고 유연하지 않습니다. 이 표준은 권한을 uint256 한 개의 비트로 표현하고 비트 연산자와 비트마스크로 확인하게 해서 훨씬 효율적이고 유연한 대안을 제시합니다. 권한과 역할이 해당 생태계에서 계정이 가진 권한 토큰 잔액으로 드러나므로, 여러 생태계 사이의 상호 운용도 더 단순해집니다.
구현해야 하는 것
event Transfer(address indexed _from, address indexed _to, uint256 indexed _permission);: 권한이 이전될 때 반드시 발생하는 이벤트입니다. 0 권한 이전에도 발생합니다.event Approval(address indexed _owner, address indexed _delegatee, uint256 indexed _permission);: approve 호출이 성공할 때마다 반드시 발생하는 이벤트입니다.function transfer(address _to, uint256 _permission) external returns (bool success);: 권한의 부분집합 _permission을 _to 주소로 이전합니다. 호출자가 그 권한을 갖고 있지 않거나 받는 쪽에 이미 있으면 되돌려야 합니다.function approve(address _delegatee, uint256 _permission) external returns (bool success);: 대리인 _delegatee가 권한 보유자를 대신해 _permission 범위까지 행동하도록 허용합니다. 다시 호출하면 기존 허용을 덮어씁니다.function permissionOf(address _owner) external view returns (uint256 permission);: _owner 주소가 가진 권한 집합을 반환합니다.function permissionRequire(uint256 _permission, uint256 _required) external view returns (bool isPermissioned);: _required가 _permission의 부분집합이면 true, 아니면 false를 반환합니다.function hasPermission(address _owner, address _actor, uint256 _required) external view returns (bool isPermissioned);: _required가 _actor 자신의 권한이나 _owner에게서 위임받은 권한의 부분집합이면 true를 반환합니다.function delegated(address _owner, address _delegatee) external view returns (uint256 permission);: _owner가 _delegatee에게 위임한 권한의 부분집합을 반환합니다.error AccessDenied(address _owner, address _actor, uint256 _permission);: 보유자나 대리인이 필요한 권한을 갖고 있지 않을 때 쓰는 오류입니다.error DuplicatedPermission(uint256 _permission);: 권한 집합 사이에 충돌이 있을 때 쓰는 오류입니다.error OutOfRange();: 데이터가 허용 범위를 벗어났을 때 쓰는 오류입니다.
심층 설명
권한을 uint256 비트로 표현
주소 하나의 권한 전체를 uint256 값 하나에 저장합니다. ERC-6617에서 기술한 대로 권한 하나가 uint256의 비트 하나에 대응합니다. 권한 포함 여부는 비트 연산자와 비트마스크로 판정하며 원문은 이 방식이 문자열이나 keccak256 비교보다 훨씬 효율적이고 유연하다고 설명합니다. 각 권한은 2의 거듭제곱으로 정의하는 것이 권장(RECOMMENDED)되며 그래야 ERC-6617을 이용해 권한 집합 사이의 포함 관계를 검사할 수 있습니다. 준수 컨트랙트는 IEIP6366Core를 반드시(MUST) 구현해야 하고 이 표준은 ERC-6617을 전제 조건(requires)으로 둡니다.
transfer의 동작 규칙
transfer(_to, _permission)는 권한의 부분집합 _permission을 _to로 이전합니다. 호출자 계정의 권한이 이전하려는 권한의 부분집합을 갖고 있지 않으면 되돌려야(SHOULD revert) 합니다. 또 이전하려는 권한 중 어느 하나라도 대상 _to 주소에 이미 존재하면 되돌려야 합니다. Transfer 이벤트는 권한이 이전될 때 반드시(MUST) 발생해야 하며 0 권한 이전에도 발생합니다.
approve와 delegated로 하는 위임
approve(_delegatee, _permission)는 대리인이 권한 보유자를 대신해 _permission 범위까지 행동하도록 허용합니다. 같은 함수를 다시 호출하면 현재 허용된 값이 새 _permission으로 덮어써집니다. 부여하려는 _permission이 보유자가 가진 전체 권한의 부분집합이 아니면 되돌려야(SHOULD revert) 합니다. 성공한 호출마다 Approval 이벤트가 반드시(MUST) 발생해야 합니다. delegated(_owner, _delegatee)는 보유자가 대리인에게 부여한 권한의 부분집합을 반환합니다.
세 가지 조회 함수
permissionOf(_owner)는 해당 주소의 권한 집합을 반환합니다. permissionRequire(_permission, _required)는 _required가 _permission의 부분집합이면 true를 반환하는 순수 집합 비교 함수입니다. hasPermission(_owner, _actor, _required)는 _required가 _actor 자신의 권한의 부분집합이거나 _owner가 위임해 준 권한의 부분집합이면 true를 반환합니다. 즉 본인 권한과 위임 권한을 한 번에 검사할 수 있습니다.
메타데이터와 오류 인터페이스
준수 컨트랙트는 선택 확장인 IEIP6617Meta를 구현하는 것이 권장(RECOMMENDED)됩니다. 기본 권한과 주요 조합에는 설명을 정의해야(SHOULD) 하지만 가능한 모든 하위 조합마다 설명을 정의해서는 안 됩니다(SHOULD NOT). 또 호환 토큰은 IEIP6366Error를 구현할 수 있는데(MAY), 필요한 권한이 없을 때의 AccessDenied, 권한 집합 충돌 시의 DuplicatedPermission, 데이터가 범위를 벗어났을 때의 OutOfRange 세 가지 오류를 정의합니다.
아직 검토 중인 제안
이 제안의 상태는 Review로, 아직 내용이 바뀔 수 있는 단계입니다. 원문의 Rationale 절은 '논의 필요(Needs discussion)', Security Considerations 절은 '추가 논의 필요(Need more discussion)'로만 적혀 있어 설계 근거와 보안 고려 사항이 아직 채워지지 않았습니다. 참조 구현으로 ERC-6366 Core 구현 파일이 제공됩니다.