ERC-5507 환불 가능한 토큰 (Refundable Tokens)
Final · 토큰 · 2022-08-19 작성
ERC-20, ERC-721, ERC-1155 토큰의 첫 판매에 환불 기능을 더하는 표준입니다. 판매 대금은 정해진 시점까지 예치되고 그 전에는 구매자가 토큰을 돌려주고 이더를 환불받을 수 있습니다.
왜 필요한가
NFT와 토큰 시장에는 책임을 묻는 장치가 부족합니다. 프로젝트가 토큰을 팔고 사라지는 러그풀(rugpull)을 막을 더 나은 수단이 생태계 전체의 건강을 위해 필요합니다. 환불을 제공하면 구매자는 더 잘 보호받고 창작자는 신뢰를 얻습니다. 또 환불 방식이 제각각이면 지갑이나 마켓플레이스 같은 앱이 이를 공통으로 다룰 수 없습니다. 표준 인터페이스가 있으면 온라인 구매 상품에 14일 환불 기간을 요구하는 EU 통신판매 규정을 지키기 쉬워집니다. 마켓플레이스는 아직 환불 가능한 NFT에 배지를 달거나 판매 대신 환불을 제안할 수 있으며 탈중앙 거래소(DEx)는 환불이 더 유리할 때 환불을 권할 수 있습니다. 지갑은 환불이라는 행위를 사용자에게 또렷하게 보여 주는 확인 화면을 만들 수 있습니다.
구현해야 하는 것
function refund(uint256 amount) external;: 환불이 활성 상태인 동안 호출자에게 amount만큼 환불합니다. ERC-20 확장의 함수입니다.function refundFrom(address from, uint256 amount) external;: 환불이 활성 상태이고 충분한 승인(approval)이 있으면 from의 토큰을 환불하고 이더는 msg.sender에게 보냅니다.function refundOf() external view returns (uint256 _wei);: 토큰 1단위(10**decimals 최소 단위)당 환불받을 이더 금액을 웨이(wei) 단위로 돌려줍니다.function refundDeadlineOf() external view returns (uint256 block);: 환불이 유효하지 않게 되는 첫 블록 번호를 돌려줍니다.function refund(uint256 tokenId) external;: 해당 tokenId의 환불이 활성 상태인 동안 호출자에게 환불합니다. ERC-721 확장의 함수입니다.function refundFrom(address from, uint256 tokenId) external;: 승인이 있으면 from의 tokenId를 환불하고 이더는 msg.sender에게 보냅니다. ERC-721 확장의 함수입니다.function refundOf(uint256 tokenId) external view returns (uint256 _wei);: 특정 tokenId를 환불하면 받을 이더 금액을 웨이 단위로 돌려줍니다.function refundDeadlineOf(uint256 tokenId) external view returns (uint256 block);: 해당 tokenId의 환불이 끝나는 첫 블록 번호를 돌려줍니다.function refund(uint256 tokenId, uint256 amount) external;: ERC-1155 확장의 함수로, tokenId의 토큰을 amount만큼 환불합니다.function refundFrom(address from, uint256 tokenId, uint256 amount) external;: 승인이 있으면 from이 가진 tokenId 토큰을 amount만큼 환불하고 이더는 msg.sender에게 보냅니다.function refundBatch(uint256[] tokenIds) external;: 선택 확장으로, 여러 tokenId를 한 번에 환불합니다. 전부 성공하거나 전부 실패해야 하며 부분 환불은 없습니다.function refundFromBatch(address from, uint256[] tokenIds) external;: 선택 확장으로, 승인이 있으면 from의 여러 토큰을 한 번에 환불합니다. 부분 환불은 없습니다.
심층 설명
세 가지 토큰 표준별 확장
이 표준은 ERC-20, ERC-721, ERC-1155 각각에 환불 확장을 정의합니다. ERC-20용 ERC20Refund의 ERC-165 식별자는 0xf0ca2917, ERC-721용 ERC721Refund는 0xe97f3c83, ERC-1155용 ERC1155Refund는 0x94029f5c입니다. 모든 구현은 ERC-165를 사용하고 그 지침을 따라야 합니다(MUST). Rationale에 따르면 ERC-165가 없으면 DApp의 인터페이스 탐지가 크게 어려워지기 때문입니다.
refund와 refundFrom의 동작
refund는 환불이 활성 상태인 동안 호출자의 토큰을 환불합니다. ERC-20은 amount, ERC-721은 tokenId, ERC-1155는 tokenId와 amount를 받습니다. refundFrom은 환불이 활성 상태이고 호출자에게 충분한 승인이 있을 때 from의 자산을 환불하는데, 이때 이더는 from이 아니라 msg.sender에게 갑니다. 두 함수 모두 사용자가 토큰을 실제로 보유하는지 확인하고 재진입(re-entrancy) 경로에 주의하라고 명시합니다. 성공 시 각각 Refund, RefundFrom 이벤트를 발생시킵니다.
refundOf와 refundDeadlineOf 조회
refundOf는 환불 금액을 웨이 단위로 돌려줍니다. ERC-20에서는 토큰 1단위, 곧 10**decimals개의 최소 단위에 대한 금액이고 ERC-721과 ERC-1155에서는 tokenId별로 조회합니다. refundDeadlineOf는 환불이 더 이상 불가능해지는 첫 블록 번호를 돌려줍니다. 기한을 타임스탬프가 아닌 블록 번호로 둔 이유는 타임스탬프가 블록 번호보다 신뢰성이 낮기 때문입니다. refund, refundOf, refundDeadlineOf라는 이름은 기존 ERC-20, ERC-721, ERC-1155의 작명 방식에 맞춰 정했습니다.
선택 사항인 배치 환불 확장
ERC-721과 ERC-1155에는 여러 토큰을 한 번에 환불하는 refundBatch, refundFromBatch를 담은 선택 확장이 있습니다. 배치 환불은 전부 성공하거나 전부 실패해야 하며 부분 환불은 없습니다. 배치를 선택 사항으로 둔 이유는 계정 추상화(account abstraction)가 이런 원자적 작업을 훨씬 쉽게 만들 것이기 때문인데, 그래도 제대로 구현하면 가스 비용을 줄일 수 있다고 설명합니다. 두 배치 확장의 ERC-165 식별자는 원문에 비어 있습니다.
커스텀 ERC-20 결제는 지원하지 않음
환불 대금은 이더로만 정의되어 있고 임의의 ERC-20 토큰으로 환불하는 방식은 지원하지 않습니다. 복잡성이 불필요하게 커지기 때문이며, refundFrom을 탈중앙 거래소와 결합하면 같은 효과를 낼 수 있다고 설명합니다. 하위 호환성 문제는 발견되지 않았고 이 표준은 Final 상태로 확정되었습니다.
쓸 때 주의할 점
- refund 함수의 재진입 위험: refund 함수에는 재진입 공격 위험이 있습니다. 이더 전송은 반드시 토큰을 소각한 뒤에 수행해야 합니다. 곧 검사, 효과, 상호작용(checks, effects, interactions) 패턴을 지켜야 합니다.