ERC-4824 DAO 공통 인터페이스 (Common Interfaces for DAOs)
Review · 기타 · 2022-02-17 작성
DAO가 daoURI 하나로 이름, 구성원, 제안, 활동 기록, 거버넌스 문서의 위치를 표준 형식으로 공개하게 하는 API 표준입니다. ERC-721의 tokenURI처럼 어떤 도구든 같은 방식으로 DAO 정보를 읽을 수 있게 합니다.
왜 필요한가
DAO(탈중앙 자율 조직)는 이더리움 백서에서 처음 언급된 뒤로도 정의가 모호한 채로 남아 있었습니다. 그 결과 다양한 설계 패턴이 생겨났지만 그 위에서 만들어진 프레임워크와 도구 사이에는 표준화나 상호운용성이 거의 없었습니다. 어떤 DAO의 구성원이 누구이고 어떤 제안이 올라와 있는지 같은 기본 정보조차 조직마다 다른 방식으로 공개되기 때문에, 탐색 서비스나 거버넌스 도구는 DAO마다 따로 연동을 만들어야 합니다. ERC-721의 tokenURI와 비슷한 표준 daoURI가 있으면 DAO를 찾기 쉬워지고 내용을 읽기 쉬워집니다. 제안 실행을 미리 시뮬레이션할 수 있고 도구 사이의 상호운용성이 좋아집니다. 생태계 전반에서 데이터가 더 일관되게 공개되는 것은 앞으로 나올 DAO 표준들의 전제 조건이기도 합니다.
구현해야 하는 것
event DAOURIUpdate(address daoAddress, string daoURI);: DAO의 daoURI가 바뀌었음을 알리는 이벤트입니다.function daoURI() external view returns (string memory _daoURI);: ERC-4824 DAO JSON-LD 스키마를 따르는 JSON 객체를 가리키는 URI를 돌려줍니다. 이 JSON은 membersURI, proposalsURI, activityLogURI, governanceURI 네 개의 하위 URI로 나뉩니다.event DAOURIRegistered(address daoAddress);: 인덱서 컨트랙트가 DAO의 등록을 기록할 때 내보내는 이벤트입니다.function logRegistration(address daoAddress) external: 누구나 호출해 DAO를 인덱서에 등록할 수 있습니다. 대상 주소가 IERC4824 인터페이스를 지원하지 않으면 ERC4824InterfaceNotSupported 오류로 되돌립니다.
심층 설명
daoURI와 최상위 JSON-LD 스키마
이 표준을 구현하는 컨트랙트는 IERC4824 인터페이스를 반드시 구현해야 합니다. daoURI()는 ERC-4824 DAO JSON-LD 스키마를 따르는 JSON 객체를 가리키는 URI를 돌려줍니다. 최상위 JSON에는 @context, type, name, description과 함께 membersURI, proposalsURI, activityLogURI, governanceURI, contractsURI가 들어갑니다. governanceURI는 보통 .md 같은 평문 파일을, 나머지는 각자의 JSON-LD 스키마를 따르는 JSON을 가리켜야 하며 이 JSON들은 정적으로 호스팅하거나 동적으로 생성할 수 있습니다. 하위 JSON의 내용을 최상위 JSON 안에 직접 포함할 수도 있는데, 이때는 필드 이름에서 URI 접미사를 빼야 합니다(membersURI는 members로). 접미사가 있는 필드와 없는 필드가 같이 나오면 접미사가 없는 쪽이 우선합니다. 반대로 name, description을 nameURI, descriptionURI로 바꿀 수도 있으며 이때 역참조한 URI는 @context 필드와 원래 키-값 쌍을 담은 JSON-LD 객체를 돌려줘야 합니다. 값이 없는 필드는 null로 두지 말고 빼는 것이 좋습니다.
직접 상속과 외부 등록 컨트랙트
DAO는 IERC4824 인터페이스를 직접 상속할 수도 있고 이 표준을 따르는 외부 등록 컨트랙트를 따로 만들 수도 있습니다. 어느 쪽이든 daoURI를 효율적으로 갱신할 수 있도록 접근 제어 로직을 갖춘 갱신 방법을 정의하는 것이 좋습니다. 외부 등록 컨트랙트를 만드는 경우 그 컨트랙트는 DAO의 대표 주소(보통 주요 거버넌스 컨트랙트의 주소)를 반드시 저장해야 합니다. 기존 컨트랙트를 바꾸거나 이전하지 않고 외부 등록 컨트랙트만으로 표준을 채택할 수 있으므로, 이미 배포되어 운영 중인 DAO에도 적용할 수 있습니다. 표준을 쓰지 않는 기존 컨트랙트는 아무 영향을 받지 않습니다.
인덱싱과 우선순위 규칙
DAO가 4824 호환 팩토리에서 만들어지면 팩토리는 DAO 초기화 과정에서 인덱서 컨트랙트를 호출해 네트워크 인덱싱을 돕는 것이 좋습니다. DAO가 ERC-165를 지원하면 팩토리가 추가 권한 없이 등록할 수 있고 지원하지 않으면 팩토리가 먼저 인덱서의 접근 제어 권한을 얻은 뒤 새 DAO의 주소와 daoURI로 logRegistration을 직접 호출해야 합니다. 참조 구현 ERC4824Index는 logRegistration에서 대상 주소가 IERC4824 인터페이스를 지원하는지 확인하고 아니면 되돌립니다. 이 함수는 DAO 자신을 포함해 누구나 호출할 수 있습니다. daoURI가 컨트랙트에 직접 공개된 것과 등록 팩토리 호출로 공개된 것이 둘 다 있으면 등록 팩토리 쪽의 daoURI와 모든 하위 URI가 우선하고 등록이 여러 건이면 가장 최근 등록이 우선합니다. 온체인 등록 컨트랙트가 DAO의 능동적 의사를 가장 명확히 반영하므로 가장 신뢰할 만한 공개 방식으로 봅니다.
membersURI: 구성원 목록
membersURI는 구성원 목록을 담은 JSON을 가리키는 것이 좋습니다. 각 구성원은 id 하나로 표현하며 CAIP-10 주소, DID 주소, 그 밖의 URI 식별자를 쓸 수 있습니다. 예를 들어 이더리움 메인넷 주소는 CAIP-10으로 eip155:1:0x1234abcd, DID로 did:ethr:0x1234abcd처럼 적습니다. 멤버십 방식은 DAO마다 크게 다릅니다. Gnosis Safe나 Tribute처럼 온체인에 명시적인 구성원 집합을 두는 곳도 있습니다. Moloch, Compound, DAOstack, 1Hive Gardens처럼 토큰 보유가 멤버십의 기준이어서 구성원 목록을 계산하려면 오프체인 인덱싱이 필요한 곳도 많습니다. 그래서 이 표준은 온체인 기능 대신 오프체인 JSON 스키마만 요구해 유연성과 효율을 택했고 활동/비활동 상태나 멤버십 등급 같은 스키마 확장도 권장합니다.
proposalsURI: 제안과 제안 ID 형식
proposalsURI는 제안 목록 JSON을 가리키는 것이 좋습니다. 온체인 제안의 id는 반드시 CAIP10_ADDRESS + "?proposalId=" + PROPOSAL_COUNTER 형식이어야 합니다. PROPOSAL_COUNTER는 uint256 카운터나 해시처럼 해당 CAIP-10 주소 안에서 유일한 임의 식별자이며 이 조합으로 제안 ID가 전역에서 유일해집니다. 오프체인 제안은 CAIP10_ADDRESS 자리에 적절한 URI나 URL을 넣은 비슷한 형식을 쓸 수 있습니다. 각 제안에는 이름, 제안 본문을 돌려주는 contentURI, 포럼 글이나 디스코드 채널 같은 토론 링크를 돌려주는 discussionURI, 상태(status), 실행 호출 데이터를 담는 calls 배열이 들어갑니다. status는 거버넌스 시스템마다 달라 기존 DAO들 사이에 합의된 값이 없으므로 자유 텍스트 필드로 두었고 calls 데이터의 주된 용도는 제안 실행 시뮬레이션입니다.
activityLogURI와 governanceURI
activityLogURI는 구성원과 제안 사이의 상호작용을 기록한 JSON을 가리키는 것이 좋습니다. 각 활동은 id, type과 함께 어느 제안에 대한 것인지(proposal)와 어느 구성원이 한 것인지(member)를 담습니다. 제안 작성과 제출, 투표, 이의 제기 같은 것이 활동의 예입니다. governanceURI는 JSON이 아니라 보통 .md 같은 평문 파일을 가리킵니다. 투표권이나 탈퇴권(ragequit) 같은 멤버십의 권리 상당수가 Snapshot 투표나 디스코드 접근처럼 오프체인에서 실현되기 때문에, 이런 다양한 관행을 표준화하거나 온체인에 올리도록 강제하는 대신, 멤버십의 의미와 제안이 작동하는 방식을 설명하는 문서를 공개하게 한 것입니다. 이런 평문 파일은 Etherscan 같은 서비스가 읽어 DAO의 발견과 이해를 돕는 데 쓸 수 있습니다.
contractsURI와 스팸·사칭 방지, DAO가 아닌 조직
contractsURI는 DAO에 속한 컨트랙트들의 주소(id), 이름, 설명을 담은 JSON을 가리키는 것이 좋습니다. 거버넌스가 여러 컨트랙트, 나아가 여러 체인에 걸쳐 분산된 DAO에서 특히 중요하며 여러 주소가 같은 daoURI를 보고할 수 있습니다. 승인되지 않은 주소가 같은 daoURI나 이름을 사칭하는 것을 인덱서가 걸러낼 수 있도록, 표준을 채택한 DAO는 IERC4824를 상속한 컨트랙트와 등록 팩토리로 배포한 등록 컨트랙트를 포함해 관련된 모든 컨트랙트 주소를 contractsURI로 공개하는 것이 좋습니다. 한편 DAO가 아니거나 DAO로 불리고 싶지 않은 조직도 daoURI를 공개할 수 있습니다. 이때 type 필드에 "DAO" 대신 "Organization", "Foundation", "Person", "Entity" 같은 값을 쓰는 것이 좋습니다. 오프체인에서는 daoURI의 별칭인 orgURI나 entityURI를 쓸 수 있지만 온체인 컨트랙트나 등록으로 URI를 보고할 때는 인덱싱을 위해 IERC4824의 daoURI를 유지해야 합니다.
JSON-LD를 택한 이유와 제안의 현재 상태
단순한 JSON 대신 JSON-LD를 택한 이유는 두 가지입니다. 이더리움 주소가 아닌 다른 식별 방식으로 구성원을 표현하려는 경우를 지원하고 앞으로 나올 멀티체인 표준과 호환되게 하기 위해서입니다. 두 경우 모두 주소에 대한 컨텍스트와 타입이 필요한데 JSON-LD에는 이미 구현되어 있습니다. 또 Synthetix 같은 큰 조직에서 나타나는 subDAO, DAO의 DAO 패턴과 L2·멀티체인 사용례를 고려하면, 여러 DAO가 같은 URI를 가리키며 여러 컨트랙트와 서비스의 데이터로 들어가는 관문으로 쓰는 경우가 예상되는데, JSON-LD가 그런 데이터의 확장과 관리를 쉽게 합니다. 이 초안은 모든 주요 EVM 기반 DAO 프레임워크 대표가 참여한 DAOstar 라운드테이블에서 개발되었습니다. 다만 이 제안은 현재 Review 상태로, 아직 검토 중이어서 내용이 바뀔 수 있습니다.
쓸 때 주의할 점
- URI 갱신 규칙은 표준 밖: 이 표준은 DAO URI의 인터페이스만 정의할 뿐 URI를 정하는 규칙이나 데이터를 준비하는 방식은 정하지 않습니다. 구현자는 DAO의 거버넌스 모델에 맞는 방식으로 데이터를 갱신하고 중앙화된 서비스 제공자에 대한 의존을 최소화하면서 데이터를 최신으로 유지하는 방법을 고민해야 합니다.
- URI가 돌려주는 실행 코드 주의: URI가 돌려주는 데이터에 의존하는 인덱서는 DAO가 URI에서 실행 가능한 코드를 돌려줄 때 주의해야 합니다. 그 코드는 구성원, 제안, 활동 기록의 최신 정보를 얻으려는 용도일 수 있지만 무관한 작업을 실행하는 데 쓰일 수도 있습니다.