엘리시아 개발팀이 Compound 거버넌스에 이어 OpenZeppelin 의 온체인 거버넌스 컨트랙트를 뜯어본 2편이다. 투표권 토큰(ERC20Votes)부터 Governor 본체와 부속 모듈, 그리고 Wizard 의 설정 항목까지 각 조각이 무엇을 담당하는지 정리한다.
핵심 포인트- OpenZeppelin 4.3 부터 Governance 가 정식 출시됐고, 온체인 거버넌스에 필요한 컨트랙트가 모듈 단위로 나뉘어 있다.
- ERC20Votes 는 중복 투표를 막는 checkpoint 기능을 제공해 투표권 집계를 가능하게 한다. 이것이 없으면 거버넌스 토큰이어도 투표권 역할을 못 한다.
- 이미 있는 토큰에 투표 기능이 없다면 ERC20Wrapper 로 감싸 거버넌스 기능이 있는 새 토큰으로 교환하게 할 수 있다.
- 단순 ERC20 전송으로는 voting power 가 집계되지 않는다. `delegate` 로 자신이나 타인에게 위임해야 하며, 이는 가스비 절감을 위한 설계다.
- Governor 는 Proposal 구조체를 통째로 저장하지 않고 인자들을 해시한 id 만 저장해 가스 비용을 줄인다. Compound 방식과 다른 지점이다.
상세 정리- 맥락: AAVE·Maker·Compound·Uniswap 등 디파이 서비스들이 세부는 달라도 비슷한 절차로 온체인 거버넌스를 구현하고 있다는 배경을 먼저 깐다.
- ERC20Votes 가 제공하는 함수 목록을 나열한다. `checkpoints`, `numCheckpoints`, `delegates`, `getVotes`, `getPastVotes`, `getPastTotalSupply`, `delegate`, `delegateBySig` 등이다.
- 서명 위임: 개인 키로 위임 의사를 서명하면 대리인이 그 서명으로 투표권을 위임받아 대신 투표할 수 있다. 투표 자체도 같은 방식으로 위임 가능하다.
- 서명 생성 코드는 엘리시아 거버넌스 컨트랙트를, 클라이언트 활용 예제는 Compound 블로그를 참고하라고 안내한다.
- GovernorVotes: 투표권 집계 시 ERC20Votes 와 상호작용하는 함수를 구현한 모듈이다.
- GovernorCountingSimple: 기본 Governor 는 `_voteSucceeded`, `_countVote` 같은 함수가 비어 있어 단독으로 못 쓴다. 이 모듈이 그 부분을 간단히 채운다.
- GovernorTimelockController: 투표 통과 후 실행까지 지연을 두는 Timelock 과 연결한다. `state`, `timelock`, `proposalEta`, `queue`, `_execute`, `_cancel`, `updateTimelock` 등을 제공한다.
- GovernorVotesQuorumFraction: 정족수를 제안 시점 전체 투표권 대비 비율로 두거나 절대값으로 둘 수 있게 한다.
- Wizard 설정 항목: Name(EIP712 서명 기반 위임에 필요), Voting delay(제안 후 투표권 집계 시점까지의 블록 수), Voting period(투표 기간), proposalThreshold(제안 생성에 필요한 최소 투표권), Quorum(비율 또는 절대량).
- Voting delay 예시: 현재 blockNumber 가 1000 이고 votingDelay 가 50 이면 1050 기준으로 투표권을 집계한다. 시간 환산은 blockTime 13.2초 기준이다.
- Votes 옵션이 갈리는 이유: Compound 의 COMP 는 최대 발행량이 2^96−1 로 설정돼 연산 최적화를 위해 변수 타입이 다르므로, ERC20Votes 와 ERC20VotesComp 중 선택해야 한다.
- 나머지 옵션은 Timelock 사용 여부(및 Compound 버전 사용 여부)와 업그레이드 가능 여부다.
왜 읽나DAO 거버넌스를 직접 짜기 전에 OpenZeppelin 모듈이 각각 무엇을 채워 주는지 지도를 먼저 갖고 싶은 스마트 컨트랙트 개발자에게 맞다.