ERC-4626 토큰화 금고 표준 (Tokenized Vaults)

Final · 금고·DeFi · 2021-12-22 작성

하나의 ERC-20 토큰을 맡기고 그 지분을 토큰으로 받는 금고(Vault)에 공통 입출금 인터페이스를 정합니다. 지갑과 앱이 금고마다 다른 연동 코드를 짜지 않아도 됩니다.

왜 필요한가

이더리움에는 토큰을 맡기면 지분 토큰을 돌려주는 금고 형태의 서비스가 많습니다. 대출 시장, 여러 곳에 자금을 나눠 넣는 애그리게이터(aggregator), 보유하기만 해도 이자가 붙는 토큰이 대표적인 예입니다. 그런데 이런 금고들은 표준이 없어 구현 세부가 저마다 다릅니다. 그래서 여러 표준을 한꺼번에 맞춰야 하는 애그리게이터나 플러그인 계층에서는 연동이 어렵고 프로토콜마다 자체 어댑터를 따로 만들어야 했습니다. 어댑터는 실수가 생기기 쉽고 개발 자원도 낭비합니다. 이 표준은 지분 토큰을 ERC-20으로 통일하고 입금, 출금, 조회 함수를 정해 수익형 금고를 연동하는 수고를 줄이고 구현 방식을 더 일관되고 튼튼하게 만드는 것을 목표로 합니다.

구현해야 하는 것

심층 설명

지분은 ERC-20 토큰이어야 합니다

표준을 따르는 금고는 반드시 EIP-20을 구현해 지분(share)을 표현합니다. balanceOf, transfer, totalSupply 같은 EIP-20 동작은 모두 금고의 지분에 적용됩니다. 지분은 금고가 보유한 기초 자산 일부에 대한 소유권을 뜻합니다. 지분을 양도 불가로 만들고 싶다면 transfer와 transferFrom 호출을 되돌려도 됩니다(MAY). EIP-20의 선택 사항인 메타데이터 확장은 반드시 구현해야 합니다. name과 symbol은 기초 토큰의 name과 symbol을 어떤 식으로든 반영해야 합니다(SHOULD). 여러 서비스에서 지분 승인 경험을 개선하려면 EIP-2612를 구현할 수 있습니다(MAY).

네 가지 용어: asset, share, fee, slippage

asset은 금고가 관리하는 기초 토큰으로, 단위는 해당 EIP-20 컨트랙트가 정합니다. share는 금고의 토큰이며 mint, deposit, withdraw, redeem 때 기초 자산과 교환되는 비율은 금고가 정합니다. fee는 금고가 사용자에게 물리는 자산 또는 지분의 양으로, 입금, 수익, 운용 자산(AUM), 출금 등 금고가 정한 어느 항목에든 붙을 수 있습니다. slippage는 안내된 지분 가격과 실제 입출금 결과 사이의 차이 가운데 수수료로 설명되지 않는 부분입니다.

조회 함수: asset, totalAssets, convertToShares, convertToAssets

asset은 회계, 입금, 출금에 쓰는 기초 토큰 주소를 돌려주며 반드시 EIP-20 토큰 컨트랙트여야 하고 되돌리면 안 됩니다. totalAssets는 금고가 관리하는 기초 자산 총량으로, 수익에서 생긴 복리를 포함해야 하고(SHOULD) 금고 자산에 부과되는 수수료를 포함해야 하며(MUST) 되돌리면 안 됩니다. convertToShares와 convertToAssets는 모든 조건이 이상적일 때 금고가 교환해 줄 지분 또는 자산의 양입니다. 수수료를 포함하지 않고 호출자에 따라 달라지지 않습니다. 슬리피지 같은 온체인 조건도 반영하지 않습니다. 비정상적으로 큰 입력으로 정수 오버플로가 나는 경우 외에는 되돌리면 안 되고 반드시 0 쪽으로 내림합니다. 이 값은 특정 사용자가 아니라 평균적인 사용자가 기대할 지분당 가격을 보여 줍니다.

max 함수: 지금 가능한 최대량

maxDeposit과 maxMint는 receiver를 위해 deposit 또는 mint로 넣을 수 있는 최대 자산량과 최대 지분량입니다. maxWithdraw와 maxRedeem은 owner 잔고에서 withdraw 또는 redeem으로 꺼낼 수 있는 최대 자산량과 최대 지분량입니다. 네 함수 모두 실제 허용되는 최대치보다 높은 값을 돌려주면 안 되며 필요하면 더 적게 추정합니다. 전역 한도와 사용자별 한도를 모두 반영해야 하고 일시적으로라도 해당 동작이 막혀 있으면 0을 돌려줍니다. maxDeposit과 maxMint는 한도가 없으면 2 ** 256 - 1을 돌려줍니다. 사용자가 자산을 무한히 가진 것으로 가정하므로 asset의 balanceOf에 기대면 안 됩니다. 네 함수 모두 되돌리면 안 됩니다.

preview 함수: 같은 블록에서의 정확한 모의 계산

previewDeposit, previewMint, previewWithdraw, previewRedeem은 현재 블록의 온체인 조건에서 실제 호출 결과를 미리 계산합니다. previewDeposit은 deposit이 발행할 지분보다 많지 않은 값을, previewRedeem은 redeem이 돌려줄 자산보다 많지 않은 값을 돌려줍니다. previewMint는 mint가 가져갈 자산보다 적지 않은 값을, previewWithdraw는 withdraw가 태울 지분보다 적지 않은 값을 돌려줍니다. 즉 같은 거래 안에서 실제 함수는 preview보다 사용자에게 같거나 유리한 결과를 냅니다. 입금 또는 출금 수수료를 포함해야 하고 max 함수가 주는 한도나 승인 여부는 무시한 채 항상 받아들여진다고 가정합니다. 금고의 한도 때문에 되돌리면 안 되지만 실제 함수를 되돌리게 하는 다른 조건으로는 되돌릴 수 있습니다. convertTo 값과 preview 값이 불리하게 차이 나면 지분 가격의 슬리피지로 보아야 합니다.

입출금 함수: deposit, mint, withdraw, redeem

deposit은 정확히 assets만큼 기초 토큰을 맡기고 그에 해당하는 지분을 receiver에게 발행합니다. mint는 정확히 shares만큼 지분을 발행하고 필요한 자산을 가져갑니다. 둘 다 Deposit 이벤트를 내야 하고 asset에 대한 EIP-20 approve와 transferFrom 흐름을 지원해야 합니다. 실행 전에 기초 토큰이 금고로 미리 옮겨진 흐름도 추가로 지원할 수 있습니다. 전부 처리하지 못하면 되돌려야 합니다. withdraw는 owner의 지분을 태워 정확히 assets만큼 receiver에게 보냅니다. redeem은 정확히 shares만큼 태워 자산을 보냅니다. 둘 다 Withdraw 이벤트를 내야 하며 owner가 msg.sender인 경우와 msg.sender가 owner 지분에 EIP-20 승인을 받은 경우를 모두 지원해야 합니다. msg.sender가 owner의 자금을 쓸 수 있는지 allowance로 확인해야 합니다(SHOULD). withdraw는 자산을 지분으로 바꾼 뒤 그 지분에 대해 확인합니다. 일부 구현은 출금 전에 금고에 미리 요청하는 절차가 필요하며 그 절차는 별도로 수행합니다.

Deposit과 Withdraw 이벤트

Deposit 이벤트는 sender가 assets를 shares로 바꿔 그 지분을 owner에게 전달했음을 뜻합니다. mint와 deposit으로 토큰이 금고에 들어올 때 반드시 발생합니다. sender와 owner는 indexed이고 assets와 shares는 indexed가 아닙니다. Withdraw 이벤트는 sender가 owner 소유의 shares를 assets로 바꿔 그 자산을 receiver에게 전달했음을 뜻합니다. redeem과 withdraw로 지분이 빠져나갈 때 반드시 발생합니다. sender, receiver, owner가 indexed이고 assets와 shares는 indexed가 아닙니다.

설계 의도와 호환성

인터페이스는 연동하는 쪽에 맞춰 기능은 갖추되 최소한으로 설계했습니다. 맡긴 토큰의 회계와 배분 방식은 일부러 정하지 않았습니다. 금고는 온체인에서는 블랙박스로 다루고 쓰기 전에 오프체인에서 살펴보는 것을 전제로 합니다. EIP-20을 강제한 이유는 승인과 잔고 계산 같은 구현 세부가 지분 회계에 그대로 이어지고 기존 EIP-20 용도 전부와 바로 호환되기 때문입니다. mint는 대칭성과 완결성을 위해 넣었습니다. 지금은 특정 지분 수를 노리는 경우가 드물지만 지분 자체에 고유한 의미가 생기는 전략을 상상할 수 있기 때문입니다. convertTo 함수는 수수료를 고려하지 않는 대략적 추정치로 프런트엔드용입니다. 정확한 값은 변경 함수마다 짝지은 preview 함수가, 한도는 max 함수가 맡습니다. preview가 한도를 반영하지 않는 것은 조합하기 쉽게 하려는 선택입니다. 이 표준은 EIP-20과 완전히 호환되며 표준을 쓰지 않는 기존 금고는 래퍼 어댑터로 감쌀 수 있습니다. 상태는 Final입니다.

쓸 때 주의할 점

ERC 원문 · ← ERCs