ERC-7818 유효기간이 있는 ERC-20 토큰 (Expirable ERC-20)

Final · 토큰 · 2024-11-13 작성

ERC-20 토큰에 유효기간을 붙이는 확장 표준입니다. 정해진 기간이 지나면 토큰이 만료되어 더 이상 전송하거나 쓸 수 없게 만듭니다.

왜 필요한가

기본 ERC-20 토큰에는 시간 개념이 없습니다. 한번 발행된 토큰은 영원히 유효해서, 만기가 있는 채권이나 일정 기간이 지나면 사라져야 하는 적립 포인트, 게임 아이템, 선불 크레딧 같은 자산을 표현하기 어렵습니다. 예를 들어 통신사 데이터 쿠폰이나 캐시백처럼 정해진 기간 안에 써야 하는 혜택을 토큰으로 만들려면, 발행자가 만료 시점마다 직접 토큰을 회수하거나 별도 서버에서 유효 여부를 관리해야 합니다. 이런 방식은 서로 호환되지 않는 제각각의 구현을 낳고 지갑이나 앱 입장에서는 토큰이 언제 만료되는지 표준적인 방법으로 확인할 길이 없습니다. 이 표준은 만료 규칙을 컨트랙트 수준에서 강제하면서도 기존 ERC-20과 그대로 호환되는 공통 인터페이스를 정의해 이 문제를 풉니다.

구현해야 하는 것

심층 설명

에포크 메커니즘

이 표준의 핵심 단위는 에포크(epoch)입니다. 에포크는 토큰이 유효한 특정 기간 또는 블록 범위를 나타내며 두 종류가 있습니다. 블록 기반(BLOCKS_BASED)은 특정 블록 수(예: 1000 블록)로, 시간 기반(TIME_BASED)은 초 단위 기간(예: 1000초, UNIX 시간)으로 정의합니다. 에포크에 묶인 토큰은 그 에포크가 활성인 동안 유효합니다. 정해진 블록 수나 시간이 지나면 에포크가 만료되면서 거기에 속한 토큰도 만료된 것으로 취급됩니다. 어느 방식을 쓰는지는 epochType으로, 에포크 하나의 길이는 epochLength로 조회합니다.

과거 에포크를 거슬러 보는 잔액 계산

사용 가능한 잔액은 현재 에포크부터 과거 n개 에포크까지 유효한 토큰을 합산해 구합니다. n은 validityDuration이 돌려주는 유효기간(에포크 개수)입니다. 원문 예시에서는 에포크 1에 100, 에포크 2에 150, 에포크 3에 200이 있을 때 현재 에포크가 3이고 과거 1에포크까지 유효하면 에포크 2와 3의 토큰만 합쳐 사용 가능 잔액이 350이 됩니다. balanceOf는 이렇게 만료되지 않은 토큰의 총합만 돌려줘야 하고 만료된 토큰을 포함해서는 안 됩니다. balanceOfAtEpoch는 특정 에포크의 잔액을 돌려주되 그 에포크가 만료됐으면 이전에 토큰이 있었더라도 0을 돌려줘야 합니다.

전송 규칙

transfer와 transferFrom은 거래 시점에 만료되지 않은 토큰만 전송해야 합니다. 만료된 토큰을 보내려는 시도는 트랜잭션을 되돌리거나 false를 돌려줘야 합니다. 구현체는 만료가 가장 가까운 토큰부터 자동으로 먼저 쓰는 우선순위 로직을 넣을 수 있습니다(MAY). 에포크를 지정하는 transferAtEpoch와 transferFromAtEpoch는 지정한 에포크에 보유한 토큰을 지정 수량만큼 받는 사람에게 옮겨야 하며 그 에포크가 만료됐으면 역시 revert하거나 false를 돌려줘야 합니다. 실패 사유를 분명히 하기 위해 ERC7818TransferredExpiredToken 또는 ERC7818TransferredExpiredToken(address sender, uint256 epoch) 같은 표준화된 커스텀 에러를 쓸 수 있습니다(MAY).

totalSupply 처리와 선택 함수

만료되지 않은 토큰만 추적해 총량을 유지하기는 어렵기 때문에, totalSupply는 0 또는 type(uint256).max로 두는 것이 권장됩니다(SHOULD). 필수는 아니지만 쓸모 있는 선택 함수도 제시합니다. getEpochBalance는 만료된 에포크를 포함해 특정 에포크에 저장된 토큰 양을 돌려주고 getEpochInfo는 에포크의 시작과 끝을 돌려줍니다. getNearestExpiryOf는 만료가 가장 가까운 토큰 양과 epochType에 따른 예상 만료 블록 번호 또는 타임스탬프를, getRemainingDurationBeforeEpochChange는 다음 에포크 전환까지 남은 시간이나 블록 수를 돌려줍니다.

에포크를 추상 개념으로 둔 이유

에포크라는 용어를 추상적으로 정의한 덕분에 다양한 구현이 가능합니다. 에포크 안에서 토큰을 더 세밀하게 추적해 유효와 만료 시점을 정교하게 제어할 수도 있고 같은 에포크의 토큰을 한꺼번에 만료시키는 일괄 만료 방식을 택할 수도 있습니다. 또 에포크는 만료 추적을 게으른(lazy) 방식으로 처리하게 해 줍니다. 사용자나 별도 서비스가 쓰기(write) 연산으로 만료 상태를 계속 갱신하는 대신, 현재 에포크를 읽기(read) 연산으로 계산할 수 있어 가스 효율이 좋습니다.

참조 구현의 설계 선택

참조 구현은 정렬된 리스트로 만료가 가장 가까운 토큰을 선입선출(FIFO) 방식으로 자동 선택하고 block.timestamp 대신 block.number 기반의 슬라이딩 윈도 알고리즘을 씁니다. 원문은 block.timestamp가 보안성과 회복력 면에서 비판받아 왔다고 지적합니다. 특히 L2 네트워크 사용이 늘어나는 상황에서 다수의 L2가 중앙화되고 불안정해 네트워크가 멈추는 동안에도 타임스탬프에 의존하면 자산 무결성이 직접 영향을 받아 사실상 쓸 수 없게 될 수 있기 때문입니다. 이 표준은 ERC-20과 완전히 호환됩니다.

쓸 때 주의할 점

ERC 원문 · ← ERCs