ERC-5247 스마트 컨트랙트 실행 제안 인터페이스 (Smart Contract Executable Proposal Interface)
Review · 기타 · 2022-07-13 작성
실행하고 싶은 컨트랙트 호출 목록을 온체인에 제안으로 등록해 두고 나중에 승인되면 그대로 실행할 수 있게 하는 공통 인터페이스입니다.
왜 필요한가
스마트 컨트랙트에서는 어떤 코드를 실행할지 정하는 일과 그 코드를 실제로 실행하는 일을 분리해야 할 때가 많습니다. 예를 들어 탈중앙 자율 조직(DAO)에서는 제안자가 먼저 실행 내용을 제안으로 올리고 구성원들이 투표로 동의 여부를 정한 뒤에야 실행합니다. 신탁 관리자나 법정 대리인처럼 믿고 맡기는 관계에서도 제안을 먼저 작성해 논의하고 승인한 다음 실행에 옮깁니다. 한 사람이 다른 사람에게 조건이 붙은 제안을 건네고 상대가 받아들일 때만 실행하는 경우도 있습니다. 그런데 이런 제안을 온체인에 기록하고 실행하는 공통 방식이 없으면 서비스마다 제안의 형식과 처리 방법이 제각각이 되어 투표나 승인 도구를 만들 때마다 제안 처리 부분을 따로 맞춰야 합니다. 이 표준은 제안의 생성과 실행을 하나의 인터페이스로 정해 이 문제를 풉니다.
구현해야 하는 것
function executeProposal(uint256 proposalId, bytes calldata extraParams) external;: 지정한 번호의 제안에 담긴 호출들을 실행합니다.
심층 설명
제안에 담기는 정보
제안은 함수 호출의 묶음입니다. 각 호출마다 대상 컨트랙트 주소(targets), 함께 보낼 이더 값(values), 가스 한도(gasLimits), 호출 데이터(calldatas)를 배열로 담습니다. 하나의 제안이 임의 개수의 함수 호출을 담을 수 있게 배열을 썼습니다. 호출자는 proposalId를 제시하지만 실제 등록된 번호는 createProposal의 반환값 registeredProposalId로 돌려받습니다. 구현체가 자신만의 제안 번호 형식을 정할 수 있도록 한 설계입니다. extraParams는 생성과 실행 양쪽에 있는 추가 매개변수 자리입니다.
투표 표준과의 분리
이 인터페이스는 원래 투표 표준인 ERC-1202의 일부였습니다. 그러나 제안 자체는 투표 밖에서도 쓰임새가 많고 투표가 꼭 특정 형식의 제안을 전제로 할 필요도 없습니다. 그래서 투표 인터페이스와 제안 인터페이스를 분리하기로 했습니다. 덕분에 DAO 투표 외에도 수탁자나 대리인이 승인 뒤 실행하는 구조, 상대가 수락하면 실행되는 조건부 제안 같은 사용례에 같은 인터페이스를 쓸 수 있습니다.
참조 구현의 동작
참조 구현 ProposalRegistry.sol의 createProposal은 targets, values, gasLimits, calldatas 네 배열의 길이가 서로 같은지 require로 확인하고 내부 카운터 proposalCount를 registeredProposalId로 쓴 뒤 1 올립니다. 제안 내용은 제안자(by)와 함께 저장되고 ProposalCreated 이벤트가 발생합니다. executeProposal은 저장된 제안의 targets를 순서대로 돌며 각 대상에 value와 calldata를 붙여 call을 보내고 Address.verifyCallResult로 호출 성공 여부를 검증한 뒤 ProposalExecuted 이벤트를 냅니다.
테스트 사례로 보는 사용 모습
테스트에서는 ERC-721 컨트랙트의 mint 호출 두 건을 하나의 제안으로 등록합니다. 제안 번호 0으로 createProposal을 부른 직후에는 잔액이 0 그대로이고 executeProposal(0, [])을 부른 뒤에야 토큰 2개가 발행되어 잔액이 2가 됩니다. 제안의 등록과 실행이 별개의 트랜잭션으로 나뉜다는 점을 보여 줍니다.
제안 상태와 보안 논의
이 제안의 원문 상태는 Review로, 아직 내용이 바뀔 수 있는 단계입니다. 원문의 Security Considerations 절도 논의가 필요하다(Needs discussion)고만 적혀 있어 보안 지침이 확정되지 않았습니다.