ERC-5646 토큰 상태 지문 (Token State Fingerprint)
Final · 토큰 · 2022-09-11 작성
상태가 변할 수 있는 토큰의 현재 상태를 32바이트 지문(fingerprint) 하나로 요약해 주는 표준입니다. 외부 프로토콜이 토큰 내부 구현을 몰라도 상태가 바뀌었는지 확인할 수 있습니다.
왜 필요한가
유동성 포지션처럼 내부 상태가 계속 바뀌는 토큰이 있습니다. 어떤 프로토콜이 이런 토큰을 다루려면, 지금은 그 토큰에 어떤 상태 값이 있는지 구현 세부까지 알아야 토큰을 정확히 식별할 수 있습니다. 그 결과 새로운 토큰이 나올 때마다 프로토콜이 하나하나 따로 지원 작업을 해야 하는 병목이 생깁니다. 신뢰가 더 큰 문제입니다. 예를 들어 어떤 토큰에 매수 제안을 걸어 두었는데, 제안을 수락하기 직전에 소유자가 토큰의 상태를 몰래 바꿀 수 있다면 제안자는 생각했던 것과 다른 토큰을 받게 됩니다. 상태 변화를 밖에서 확실하게 감지할 공통 방법이 없으면 이런 가변 토큰을 믿고 거래하기 어렵습니다.
구현해야 하는 것
function getStateFingerprint(uint256 tokenId) external view returns (bytes32);: 토큰 id를 받아 그 토큰의 현재 상태를 요약한 32바이트 지문을 돌려줍니다. 상태가 바뀌면 값이 달라집니다.
심층 설명
인터페이스는 함수 하나입니다
ERC5646 인터페이스는 getStateFingerprint(uint256 tokenId) 하나로 구성되며 ERC165를 상속합니다. view 함수이고 bytes32를 반환합니다. 토큰 id가 가리키는 토큰의 현재 상태 지문을 돌려주는 것이 전부이며 상태 값 자체를 노출하는 함수는 없습니다. 목표가 상태 내용을 알리는 것이 아니라 상태가 바뀌었는지만 밖에서 판별할 수 있게 하는 것이기 때문입니다.
지문이 지켜야 하는 규칙
getStateFingerprint는 토큰 상태가 바뀌면 반드시 다른 값을 반환해야 하고(MUST), 상태가 같으면 다른 값을 반환해서는 안 됩니다(MUST NOT). 또 토큰 수명 주기 동안 바뀔 수 있는 모든 상태 속성, 즉 불변이 아닌 속성을 전부 지문 계산에 포함해야 합니다(MUST). 이 세 규칙이 지켜져야 지문이 상태의 명확한 식별자 역할을 합니다.
계산 값과 메타데이터도 넣을 수 있습니다
지문에는 현재 타임스탬프에 따라 달라지는 계산 값을 포함할 수 있습니다(MAY). 원문은 만기(expiration, maturity)를 예로 듭니다. 예를 들어 만기가 지났는지 여부를 지문에 넣으면, 저장된 값이 그대로여도 시간이 흘러 만기가 지나는 순간 지문이 달라집니다. 토큰 메타데이터 URI도 포함할 수 있습니다(MAY).
ERC-165 지원 선언
구현 컨트랙트는 supportsInterface(0xf5112315) 호출에 반드시 true를 반환해야 합니다(MUST). 외부 프로토콜은 이 호출로 토큰이 상태 지문 표준을 구현했는지 먼저 확인한 뒤 getStateFingerprint를 사용할 수 있습니다.
불변 속성은 지문에서 빼도 됩니다
배포 후 절대 바뀌지 않는 속성은 토큰 id만으로 안전하게 식별되므로 지문 계산에 넣을 필요가 없습니다. 프로토콜은 지문을 토큰 식별자의 일부로 사용해, 상태 구현 세부를 전혀 모른 채 가변 토큰을 지원할 수 있습니다. 다만 이 표준은 상태 속성의 내용 자체를 알아야 하는 용도에는 맞지 않습니다. 그런 경우는 결국 토큰별 지원이 필요한 병목 문제를 피할 수 없다고 원문이 밝힙니다.
참조 구현: LP 토큰 예시
참조 구현 LPToken은 ERC721과 ERC5646을 구현하며, 토큰별 State 구조체에 asset1, asset2, amount1, amount2, fee, operator, expiration을 저장합니다. getStateFingerprint는 keccak256(abi.encode(...))로 지문을 만드는데, 불변인 fee와 operator는 계산에서 제외하고 expiration은 값 자체 대신 block.timestamp >= state.expiration이라는 만기 경과 여부를 넣습니다. supportsInterface는 type(ERC5646).interfaceId를 추가로 인정합니다.
쓸 때 주의할 점
- 다른 컨트랙트끼리 지문을 비교하면 안 됩니다: 서로 다른 컨트랙트가 만든 토큰 상태 지문은 우연히 같은 값이 될 수 있습니다. 지문 비교는 하나의 토큰 컨트랙트 안에서만 해야 합니다.
- 빠진 속성이 있으면 신뢰가 깨집니다: 구현이 상태를 바꿀 수 있는 모든 파라미터를 지문에 포함하지 않으면, 소유자가 지문은 그대로 둔 채 토큰 상태를 바꿀 수 있습니다. 매수 제안을 받는 프로토콜이라면 소유자가 제안 수락 직전에 상태를 바꾸는 식으로 신뢰 가정이 깨질 수 있습니다.