ERC-173 컨트랙트 소유권 표준 (Contract Ownership Standard)
Final · 기타 · 2018-06-07 작성
스마트 컨트랙트의 소유자가 누구인지 읽고 소유권을 다른 주소로 넘기는 방법을 통일합니다. 지갑과 앱이 어떤 컨트랙트든 같은 방식으로 소유자를 확인하고 관리할 수 있습니다.
왜 필요한가
많은 스마트 컨트랙트는 자금을 꺼내거나 관리 작업을 하기 위해 누군가가 소유하거나 제어해야 합니다. 그런데 소유자를 확인하고 넘기는 방식이 컨트랙트마다 다르면 소유권을 다루는 도구를 범용으로 만들 수 없습니다. 원문은 이런 표준이 필요한 예로 네 가지를 듭니다. 컨트랙트를 사고팔거나 경매하는 거래소는 소유자를 읽고 소유권을 넘기는 표준이 있어야 널리 운영할 수 있습니다. 여러 컨트랙트의 소유권을 보관하고 옮기는 컨트랙트 지갑도 마찬가지입니다. 컨트랙트 등록소(registry)는 소유자만 자기 컨트랙트를 등록하거나 지울 수 있게 하려면 제출자가 진짜 소유자인지 확인할 표준이 필요합니다. 소유권을 보여 주고 옮기는 사용자 화면도 같은 인터페이스를 전제로 해야 만들 수 있습니다. 이 표준은 이런 호환성을 위해 소유권 인터페이스를 하나로 정합니다.
구현해야 하는 것
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);: 컨트랙트의 소유권이 바뀔 때 이전 소유자와 새 소유자 주소를 기록합니다.function owner() view external returns(address);: 현재 소유자의 주소를 돌려줍니다.function transferOwnership(address _newOwner) external;: 새 소유자 주소를 설정합니다. 영 주소를 넘기면 소유권을 포기합니다.function supportsInterface(bytes4 interfaceID) external view returns (bool);: ERC-165 함수로, 컨트랙트가 해당 인터페이스를 구현하는지 알려 줍니다.
심층 설명
인터페이스 구성과 ERC-165 식별자
ERC-173을 따르는 컨트랙트는 반드시 ERC173 인터페이스를 구현해야 합니다. 이 인터페이스는 OwnershipTransferred 이벤트 하나와 owner(), transferOwnership(address _newOwner) 함수 둘로 이루어집니다. 또한 ERC-173 인터페이스에 대해 ERC-165도 구현하기를 권장합니다(should). ERC-165 인터페이스 식별자는 0x7f5828d0입니다. supportsInterface(bytes4 interfaceID)는 해당 interfaceID를 구현하고 그 값이 0xffffffff가 아니면 true를, 아니면 false를 돌려줍니다. 이 값으로 다른 컨트랙트나 화면이 소유권 함수를 호출하기 전에 지원 여부를 확인할 수 있습니다.
owner(): 소유자 조회
owner()는 소유자의 주소를 돌려주는 조회 함수입니다. 인터페이스에는 view external로 선언되어 있지만 원문은 pure로 구현해도 된다고 명시합니다. 소유자를 상태 변수에서 읽는 대신 코드에 고정해 두는 구현도 허용된다는 뜻입니다. 반환값은 address 하나이며 거래소나 등록소는 이 값을 호출자 주소와 비교해 제출자가 소유자인지 판단할 수 있습니다.
transferOwnership(): 이전과 포기
transferOwnership(address _newOwner)는 컨트랙트의 새 소유자 주소를 설정합니다. 인터페이스에는 external로 선언되어 있지만 public으로 구현해도 됩니다. 소유권을 포기하려면 _newOwner에 영 주소를 넣어 transferOwnership(address(0))을 호출합니다. 이렇게 하면 그 컨트랙트는 더 이상 아무도 소유하지 않는 상태가 됩니다. 원문은 함수 시그니처와 동작의 의미만 정하고 누가 이 함수를 호출할 수 있는지에 대한 접근 제어 방식은 따로 규정하지 않습니다.
OwnershipTransferred 이벤트
OwnershipTransferred(address indexed previousOwner, address indexed newOwner)는 컨트랙트의 소유권이 바뀔 때 발생합니다. 두 매개변수 모두 indexed로 선언되어 있어 특정 주소가 넘기거나 받은 소유권 변경을 로그에서 걸러 찾을 수 있습니다. 원문은 컨트랙트가 생성될 때도 이 이벤트를 발생시키는 것이 좋다고(should) 적습니다. 그래야 첫 소유자가 누구인지도 이벤트 기록만으로 알 수 있습니다.
설계 근거: 최소 함수, 하위 호환, 가스 효율
표준을 정할 때 고려한 핵심 요소는 네 가지입니다. 컨트랙트가 비대해지지 않도록 인터페이스 함수 수를 최소로 유지하는 것, 기존 컨트랙트와의 하위 호환, 단순함, 가스 효율입니다. 여러 소유권 방식을 검토한 끝에 단순하고 가스 비용이 낮으며 기존 컨트랙트와 호환되는 현재 방식을 골랐습니다. 이 표준은 다른 소유권 방식을 배제하지 않습니다. 한 컨트랙트가 이 표준과 다른 방식을 같이 구현해 소유권을 여러 경로로 관리하고 넘길 수 있습니다. 또 다른 표준이 이 표준을 확장해 소유권 기능을 더할 수 있으며 실제로 그렇게 확장되어 왔다고 원문은 적습니다.
검토했지만 채택하지 않은 방식
첫째는 ENS(Ethereum Name Service) 도메인 이름을 컨트랙트에 연결하는 방식입니다. owner()가 특정 ENS 이름의 소유자 주소를 조회해 그것을 컨트랙트 소유자로 삼고 ENS 이름의 소유권을 옮기면 컨트랙트도 넘어가는 구조입니다. 기존 컨트랙트와 호환되지 않고 소유자 주소를 얻기 위해 ENS 관련 컨트랙트를 외부 호출해야 해 가스가 든다는 단점이 있습니다. 둘째는 ERC-721 기반 NFT(대체 불가능 토큰)를 컨트랙트에 연결하는 방식입니다. 기존 ERC-721 인프라로 컨트랙트를 사고팔거나 경매할 수 있다는 장점이 있지만 복잡도와 추가 인프라가 필요합니다. NFT가 컨트랙트를 추적하도록 따로 프로그래밍하지 않으면 NFT 쪽에서는 자기가 컨트랙트를 소유한다는 사실을 모르고 이 방식 역시 하위 호환이 되지 않습니다.
하위 호환성과 제안 상태
원문은 많은 기존 컨트랙트가 이미 이 표준을 구현하고 있다고 적습니다. 표준이 기존 컨트랙트와의 하위 호환을 핵심 요소로 삼은 이유도 여기에 있습니다. 이 표준은 Standards Track의 ERC 범주에 속하고 상태는 Final입니다. 2018년 6월 7일에 만들어졌고 제안자는 Nick Mudge와 Dan Finlay입니다. Final 상태이므로 명세는 확정되었고 더 바뀌지 않습니다.
쓸 때 주의할 점
- 외부 소유 계정의 개인 키 관리: owner()가 돌려주는 주소가 외부 소유 계정(EOA)이라면, 그 계정의 개인 키를 잃어버리거나 유출당해서는 안 됩니다. 소유자 키가 곧 컨트랙트의 관리 권한이기 때문입니다.