ERC-7144 검증 단계를 거치는 ERC-20 토큰 (ERC-20 with transaction validation step.)
Review · 토큰 · 2023-05-07 작성
ERC-20 토큰의 전송(transfer)과 승인(approve)을 바로 실행하지 않고 검증 대기 상태로 만들어 두는 확장입니다. 별도의 검증을 거쳐야 실제로 실행되므로 지갑 키를 도둑맞아도 토큰이 곧바로 빠져나가지 않습니다.
왜 필요한가
이더리움에서는 개인 키를 가진 사람이 곧 자산의 주인입니다. 블록체인의 힘은 사용자에게 데이터의 전적인 책임을 맡기는 데서 나오는데, 이는 동시에 약점이기도 합니다. 키가 유출되면 도둑이 전송이나 승인을 한 번 호출하는 것만으로 지갑의 토큰을 모두 빼낼 수 있고 실제로 토큰 도난 사례가 많습니다. 지금까지의 도난 방지책, 예를 들어 토큰을 인터넷과 분리된 보관용 지갑(cold wallet)으로 옮겨 두는 방식은 토큰을 쓰기 불편하게 만듭니다. 모든 전송과 승인 앞에 검증 단계를 두면, 도둑이 토큰을 훔치려면 사용자의 주소와 검증자 주소를 동시에 손에 넣어야 하므로 훨씬 안전한 체계를 만들 수 있습니다. 이 표준은 그런 도난 방지 체계를 만들 수 있는 공통 기반을 정의합니다.
구현해야 하는 것
event ValidateTransfer(address indexed from, address indexed to, uint256 amount, uint256 indexed transferValidationId);: 새 전송 검증 요청이 만들어졌을 때 발생하는 이벤트입니다. 보내는 주소, 받는 주소, 수량, 검증 건 ID를 담습니다.event ValidateApproval(address indexed owner, address indexed spender, uint256 amount, uint256 indexed approvalValidationId);: 새 승인 검증 요청이 만들어졌을 때 발생하는 이벤트입니다. 소유자, 승인 대상 주소, 수량, 검증 건 ID를 담습니다.function isValidatorContract() external view returns (bool);: 이 컨트랙트가 검증 기능을 가진 ERC-20이면 true를 돌려줍니다.function transferValidation(uint256 transferId) external view returns (TransferValidation memory);: 전송 ID로 해당 전송 검증 건의 내용을 돌려줍니다.function approvalValidation(uint256 approvalId) external view returns (ApprovalValidation memory);: 승인 ID로 해당 승인 검증 건의 내용을 돌려줍니다.function totalTransferValidations() external view returns (uint256);: 지금까지 만들어진 전송 검증 건의 총 개수를 돌려줍니다.function totalApprovalValidations() external view returns (uint256);: 지금까지 만들어진 승인 검증 건의 총 개수를 돌려줍니다.
심층 설명
전송과 승인은 바로 실행되지 않습니다
토큰 소유권을 바꾸는 모든 동작, 즉 transfer나 transferFrom은 토큰을 옮기는 대신 검증 대기 상태의 TransferValidation을 만들고 ValidateTransfer 이벤트를 발생시켜야 하며 토큰을 옮겨서는 안 됩니다(SHALL NOT). 토큰 관리 권한을 주는 approve도 마찬가지로 ApprovalValidation을 만들고 ValidateApproval 이벤트를 발생시키며 승인을 바로 켜서는 안 됩니다. TransferValidation 구조체에는 보내는 주소 from, 받는 주소 to, 수량 amount, 검증 여부 valid가 담기고 ApprovalValidation에는 owner, spender, amount, valid가 담깁니다.
승인된 계정의 전송은 예외입니다
transfer를 소유자가 아니라 이미 승인된 계정이 호출하면 검증 없이 즉시 실행되어야 합니다(MUST). 승인(approve)으로 토큰을 직접 옮기는 것을 전제로 돌아가는 기존 프로젝트들에 맞추기 위한 규칙입니다. 다만 그 승인 자체가 검증 단계를 거쳐야 켜지므로, 사용자가 검증하지 않은 승인으로는 이 경로를 쓸 수 없습니다. 참고 구현에서는 _transfer 안에서 호출자(_msgSender())가 from과 같으면 검증 대기 건을 만들고 다르면 부모 컨트랙트의 _transfer를 그대로 실행하는 방식으로 두 경우를 구분합니다.
검증 동작의 규칙
TransferValidation이나 ApprovalValidation을 검증할 때는 valid 필드를 true로 바꿔야 하고(MUST), 같은 건을 다시 검증해서는 안 됩니다(MUST NOT). TransferValidation을 검증하는 동작이 실제로 토큰 소유권을 바꾸고, ApprovalValidation을 검증하는 동작이 승인을 켭니다. 참고 구현의 _validateTransfer와 _validateApproval은 이미 valid인 건이면 실행을 되돌리고 아니면 부모의 _transfer나 _approve를 실행한 뒤 valid를 true로 기록합니다. 두 함수 모두 internal로 정의되어 있어, 누가 어떤 권한으로 호출할지는 구현하는 쪽이 정합니다.
인터페이스와 가시성 요건
표준 인터페이스 IERC7144는 검증 대기 건을 조회하는 함수들로 이루어집니다. transferValidation(transferId)과 approvalValidation(approvalId)은 ID로 각 검증 건의 내용을 돌려주고, totalTransferValidations()와 totalApprovalValidations()는 지금까지 만들어진 검증 건의 총 개수를 돌려줍니다. isValidatorContract()는 이 컨트랙트가 검증형 ERC-20임을 알리는 함수로 반드시 public으로 구현해야 합니다(MUST). 두 조회 함수는 public이나 external로, 두 개수 함수는 pure나 view로 구현할 수 있습니다(MAY).
검증 방식은 표준이 정하지 않습니다
표준은 검증 기능 자체만 정의하고 누가 어떻게 검증할지는 정하지 않습니다. 검증은 internal로 정의하고 관리 방법은 사용자가 정하도록 맡깁니다. 원문이 드는 예로는 dApp에 연결된 검증자 주소를 두어 사용자가 검증을 관리하게 하는 방식이 있고 이 검증자를 모든 토큰에 쓸 수도, 일부 사용자에게만 쓸 수도 있습니다. 기존 ERC-20을 감싸는 래퍼(wrapped) 컨트랙트로 만들어 기존 토큰과 1대1로 교환하게 하는 것도 가능합니다. 제3자 프로토콜이 이 함수들을 원하는 방식으로 호출하도록 자유롭게 정의할 수 있습니다.
기존 ERC-20과의 호환성
이 표준은 ERC-20의 확장으로, transfer, transferFrom, approve를 제외한 모든 동작과 호환됩니다. 이 세 동작만 토큰을 옮기거나 승인을 켜는 대신 검증 요청을 만들도록 재정의(override)됩니다. 즉 기존 ERC-20 인터페이스는 그대로 유지하면서 전송과 승인의 동작 방식만 두 단계로 바뀌는 구조입니다. ERC-20을 따르는 컨트랙트는 선택적으로(MAY) 이 표준을 구현할 수 있습니다.
아직 검토 중인 제안입니다
이 제안은 2023년 5월에 만들어졌고 현재 상태가 Review입니다. 아직 검토 단계라 내용이 바뀌거나 진행이 멈출 수 있으므로, 실제로 구현하기 전에 최신 원문을 확인해야 합니다. ERC-20을 전제 조건으로 요구하며(requires: 20), 명세의 핵심 규칙인 검증 대기 건 생성, 승인된 계정의 즉시 전송, 재검증 금지 등은 RFC 2119의 MUST, SHALL 같은 용어로 정의되어 있습니다.
쓸 때 주의할 점
- 검증 동작은 최대한 강하게 보호해야 합니다: 전송과 승인은 검증 대기 건만 만들고 실제 실행은 검증 동작이 맡으므로, TransferValidation이나 ApprovalValidation을 검증하는 동작은 적용하는 시스템이 요구하는 최대 수준의 보안으로 보호해야 합니다.
- 허락 없는 검증이 불가능해야 합니다: 선택한 시스템의 허락 없이는 어떤 주소도 검증을 실행할 수 없어야 합니다. 이것이 보안의 핵심입니다. 원문은 검증자 주소 하나가 거래를 검증하는 시스템이나 사용자마다 자기 검증자 주소를 고르는 시스템을 올바른 예로 듭니다.