ERC-5725 양도 가능한 베스팅 NFT (Transferable Vesting NFT)

Final · 금고·DeFi · 2022-09-08 작성

시간이 지나면서 잠긴 토큰이 조금씩 풀리는 베스팅(vesting) 계약을 NFT로 만들어 사고팔거나 옮길 수 있게 하는 표준입니다.

왜 필요한가

토큰을 일정 기간 잠가 두었다가 조금씩 풀어 주는 베스팅 계약과 타임락(timelock) 계약은 프로젝트마다 인터페이스와 구현이 제각각입니다. 그래서 지갑이나 분석 도구가 이런 계약을 한 가지 방식으로 다룰 수 없고 사용자는 프로젝트마다 다른 화면에서 자기 베스팅 일정을 확인해야 합니다. 또 기존 베스팅은 특정 주소에 묶여 있어 받을 권리를 다른 사람에게 넘기기 어렵고 토큰 선매수 계약(SAFT)처럼 여러 사람에게 지분을 나눠 주는 일도 복잡합니다. 이 표준은 베스팅 권리를 ERC-721 NFT로 표현해 양도할 수 있게 하고 잠긴 양과 풀린 양을 조회하는 공통 함수를 정의해 이런 문제를 풉니다.

구현해야 하는 것

심층 설명

ERC-721 확장 구조

IERC5725는 IERC721을 상속하는 인터페이스로, 인터페이스 ID는 0xbd3a202b입니다. 기존 ERC-721 통합이나 마켓플레이스와 완전히 호환되도록 설계되었고 ERC-165 supportsInterface 검사로 ERC-721 호환성과 베스팅 NFT 호환성을 모두 탐지할 수 있습니다. 베스팅 곡선은 선형, 클리프(cliff), 지수형, 그 밖의 결정적(deterministic) 곡선을 자유롭게 구현할 수 있습니다.

네 가지 상태값의 회계 관계

원문은 vesting(미래에 풀릴 양), vested(지금까지 풀린 총량), claimable(풀렸지만 아직 안 받은 양), claimed(이미 받은 총량)라는 용어를 정의합니다. vestedPayout과 vestingPayout의 합은 항상 총 지급량이어야 하며(SHOULD), 이는 timestamp에 type(uint256).max를 넣은 vestedPayoutAtTime 값과 같습니다. 또 vestedPayout - claimedPayout - claimablePayout = lockedPayout이라는 식으로 풀렸지만 잠겨 있는 양을 계산할 수 있습니다. claimablePayout은 vestedPayout에서 claimedPayout을 뺀 값으로 계산하는 것이 권장되며(RECOMMENDED), 특정 시각 전까지 0을 돌려주는 방식으로 해제 클리프를 표현할 수 있습니다.

claim의 필수 규칙

claim(tokenId)은 호출 시점의 claimablePayout 값을 msg.sender에게 지급해야 하고(MUST), 토큰 소유자나 승인된 주소가 아닌 호출은 되돌려야 하며(MUST revert), PayoutClaimed 이벤트를 발생시켜야 합니다(MUST). 받을 것이 없으면 되돌리는 것이 권장됩니다(SHOULD). 과거 수령 내역은 체인 상태로는 남지 않으므로, 과거 수령 그래프를 만들려면 PayoutClaimed 이벤트를 조회해 재구성해야 합니다.

결정적 곡선과 vestedPayoutAtTime

vestedPayoutAtTime(tokenId, timestamp)의 timestamp는 과거와 미래 모두 넣을 수 있으며(MAY), NFT 발행 전 시점이면 0을 돌려줘야 합니다(MUST). vestedPayout은 block.timestamp를 넣은 vestedPayoutAtTime 호출과 같은 값을 돌려주는 것이 권장됩니다. 곡선이 결정적이면 vestingPeriod 구간을 훑으며 온체인 또는 오프체인에서 해제 곡선을 시각화할 수 있다는 것이 설계 의도입니다. 커스텀 곡선의 내부 구현은 표준이 제약하지 않습니다.

블록 번호 대신 타임스탬프를 쓰는 이유

솔리디티 개발에서는 채굴자가 block.timestamp를 조작할 수 있어 상태 의존 변수로 쓰지 말라는 조언이 일반적이지만 이 표준은 블록 번호 대신 타임스탬프를 택했습니다. EVM 호환 네트워크마다 블록 생성 시간이 달라서 타임스탬프 기준이어야 여러 체인에서 같은 인터페이스가 동작하기 때문입니다. 크게 조작된 타임스탬프의 블록은 노드들이 거부하므로 악용 여지는 무시할 수준이라고 설명합니다. 대신 참조 구현은 NFT별 수령량을 내부에서 추적해 배정량 초과 수령을 막습니다.

전송 승인과 분리된 수령 승인

이 표준은 ERC-721의 전송 승인과 별도로 수령(claim) 전용 승인 체계를 둡니다. setClaimApprovalForAll은 호출자의 모든 토큰을, setClaimApproval은 특정 tokenId 하나를 관리할 운영자를 지정하며 각각 ClaimApprovalForAll과 ClaimApproval 이벤트를 발생시킵니다. isClaimApprovedForAll과 getClaimApproved로 승인 상태를 조회할 수 있습니다. ERC-5725 승인을 받은 운영자는 풀린 토큰을 수령할 수 있을 뿐 NFT를 소유자에게서 옮겨 갈 수는 없습니다.

쓸 때 주의할 점

ERC 원문 · ← ERCs