ERC-4626: Tokenized Vault Standard
ERC-4626 是一个以太坊代币化金库(Tokenized Vault)标准,它定义了一个用于代币化金库的接口,这些金库代表对底层代币(如 ERC-20)的份额。该标准由 Joey Santoro 等人于 2022 年 3 月提出。
标准概述
ERC-4626 的主要目标是标准化代币化金库的接口,使得:
- 金库可以统一地表示和管理资产
- 集成者可以构建通用的工具来与任何 ERC-4626 金库交互
- 用户可以轻松比较不同金库的特性
核心接口
interface IERC4626 is IERC20, IERC165 {
// 返回底层代币的地址
function asset() external view returns (address assetTokenAddress);
// 返回金库管理的总资产数量
function totalAssets() external view returns (uint256 totalManagedAssets);
// 将资产转换为份额
function convertToShares(uint256 assets) external view returns (uint256 shares);
// 将份额转换为资产
function convertToAssets(uint256 shares) external view returns (uint256 assets);
// 返回用户可以存入的最大资产数量
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
// 返回用户可以铸造的最大份额数量
function maxMint(address receiver) external view returns (uint256 maxShares);
// 返回用户可以提取的最大资产数量
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
// 返回用户可以赎回的最大份额数量
function maxRedeem(address owner) external view returns (uint256 maxShares);
// 预览存款操作将铸造的份额数量
function previewDeposit(uint256 assets) external view returns (uint256 shares);
// 预览铸造操作所需的资产数量
function previewMint(uint256 shares) external view returns (uint256 assets);
// 预览提取操作将赎回的份额数量
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
// 预览赎回操作将提取的资产数量
function previewRedeem(uint256 shares) external view returns (uint256 assets);
// 存款资产并铸造份额
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
// 铸造份额
function mint(uint256 shares, address receiver) external returns (uint256 assets);
// 提取资产
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
// 赎回份额
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
主要功能
-
资产转换:
convertToShares
和convertToAssets
用于在资产和份额之间进行转换- 这些函数考虑了金库的费用和滑点
-
存款和铸造:
deposit
允许用户存入资产并获得相应份额mint
允许用户直接铸造特定数量的份额
-
提取和赎回:
withdraw
允许用户提取特定数量的资产redeem
允许用户赎回特定数量的份额
-
预览功能:
- 提供预览函数来估算操作结果
- 帮助用户了解操作的具体影响
安全考虑
-
重入攻击防护:
- 实现时需要注意防止重入攻击
- 建议使用重入锁或检查-效果-交互模式
-
精度损失:
- 在资产和份额转换时需要注意精度损失
- 建议使用足够大的精度(如 18 位小数)
-
权限控制:
- 需要正确实现权限控制
- 特别是
withdraw
和redeem
函数的所有者检查
应用场景
-
收益聚合器:
- 自动将资产分配到最佳收益机会
- 用户通过持有金库代币获得收益
-
借贷协议:
- 作为抵押品的代币化表示
- 简化借贷流程
-
流动性池:
- 代币化流动性提供者的份额
- 便于追踪和交易
-
保险库:
- 代币化保险策略
- 便于保险产品的交易和转移
最佳实践
-
实现检查:
- 实现所有必需的功能
- 确保符合 ERC-165 标准
-
事件记录:
- 记录所有重要操作
- 包括存款、提取、铸造和赎回
-
错误处理:
- 提供清晰的错误信息
- 使用 revert 而不是 require
-
测试覆盖:
- 编写完整的测试用例
- 包括边界条件和错误情况
总结
ERC-4626 为代币化金库提供了一个标准化的接口,使得不同协议之间的互操作性成为可能。它简化了金库的集成和使用,同时保持了足够的灵活性以适应各种用例。在实现时,需要注意安全性、精度和用户体验等方面。
ABI 定义
[
{
"inputs": [],
"name": "asset",
"outputs": [{ "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalAssets",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "assets", "type": "uint256" }],
"name": "convertToShares",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "shares", "type": "uint256" }],
"name": "convertToAssets",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "receiver", "type": "address" }],
"name": "maxDeposit",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "receiver", "type": "address" }],
"name": "maxMint",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "owner", "type": "address" }],
"name": "maxWithdraw",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "owner", "type": "address" }],
"name": "maxRedeem",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "assets", "type": "uint256" }],
"name": "previewDeposit",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "shares", "type": "uint256" }],
"name": "previewMint",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "assets", "type": "uint256" }],
"name": "previewWithdraw",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "name": "shares", "type": "uint256" }],
"name": "previewRedeem",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "name": "assets", "type": "uint256" },
{ "name": "receiver", "type": "address" }
],
"name": "deposit",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "name": "shares", "type": "uint256" },
{ "name": "receiver", "type": "address" }
],
"name": "mint",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "name": "assets", "type": "uint256" },
{ "name": "receiver", "type": "address" },
{ "name": "owner", "type": "address" }
],
"name": "withdraw",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "name": "shares", "type": "uint256" },
{ "name": "receiver", "type": "address" },
{ "name": "owner", "type": "address" }
],
"name": "redeem",
"outputs": [{ "name": "", "type": "uint256" }],
"stateMutability": "nonpayable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "caller", "type": "address" },
{ "indexed": true, "name": "owner", "type": "address" },
{ "indexed": false, "name": "assets", "type": "uint256" },
{ "indexed": false, "name": "shares", "type": "uint256" }
],
"name": "Deposit",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "caller", "type": "address" },
{ "indexed": true, "name": "receiver", "type": "address" },
{ "indexed": true, "name": "owner", "type": "address" },
{ "indexed": false, "name": "assets", "type": "uint256" },
{ "indexed": false, "name": "shares", "type": "uint256" }
],
"name": "Withdraw",
"type": "event"
}
]