如果你曾为借出资产获得「cDAI」「aDAI」、或因质押 xSUSHI 而惊叹收益累计的魔法,那么你其实已经接触过「收益型代币」——也就是 DeFi 收益凭证。
ERC-4626 就是专门为这些凭证而设计的通用接口,让开发者像在玩乐高一样,快速搭建或集成任何 生息资产 vault。
为什么需要 ERC-4626?
传统方案 vs. 统一标准
在传统场景,不同协议会把同一件事做成不同的接口:
- Compound 的 cToken、Aave 的 aToken、Yearn 的 yVault 各自维护自己的函数名称与计算逻辑。
- 链上聚合器要想同时接入多个协议,需要写一堆「适配器」,不仅耗时,审计风险也水涨船高。
ERC-4626 的目标就是:终结碎片化、降低开发成本、提高安全性,把“收益凭证”这件事写成一套人人共享的接口。
Vault 架构速览:一枚代币,两重身份
- 基础资产(underlying):DAI、USDC、WETH 等普通 ERC-20。
- Vault 代币(shares):也是 ERC-20,但随区块高度动态增值,代表对 vault 资产的按比例所有权。
当用户在 vault 内 deposit(存入) 或 mint(铸份额) 时,系统按即时换算率发放 shares;
当用户 redeem(赎回份额) 或 withdraw(提取底层资产) 时,就燃烧 shares 换回对应价值的底层资产。
核心函数一览
资金入口:deposit & mint
- deposit(uint256 assets, address receiver) returns (uint256 shares)
喂入底层资产数量,按实时汇率获得 shares。 - mint(uint256 shares, address receiver) returns (uint256 assets)
指定想要获得的 shares 数量,反手计算需要花费多少底层资产。
资金出口:redeem & withdraw
- redeem(uint256 shares, address receiver, address owner)
燃烧 shares,实时换回底层资产。 - withdraw(uint256 assets, address receiver, address owner)
提出指定数量底层资产,系统倒推所需 shares 并燃烧。
👉 想快速测试链上 vault 行为?点开即用浏览器模拟环境。
只读工具箱:max, preview, convert
| 作用 | 函数名 | 典型调用场景 |
|---|---|---|
| 检查上限 | maxDeposit / maxMint / maxWithdraw / maxRedeem | 前端按钮灰化、提币限额提示 |
| 预演结果 | previewDeposit / previewMint / previewWithdraw / previewRedeem | 预估滑点,避免链上 revert |
| 单位换算 | convertToShares / convertToAssets | 官方 DApp 汇率实时展示 |
手把手示范:极简 vault 源码拆解
以下合约在 Solmate 版本基础上做了缩减,去繁就简,方便阅读。
pragma solidity ^0.8.13;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract SimpleVault is ERC20 {
IERC20 public immutable asset;
event Deposit(address indexed caller, address indexed owner,
uint256 assets, uint256 shares);
event Withdraw(address indexed caller, address indexed receiver,
address indexed owner, uint256 assets, uint256 shares);
constructor(IERC20 _asset, string memory _name, string memory _symbol)
ERC20(_name, _symbol) {
asset = _asset;
}
/*------------------入口函数------------------*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares) {
shares = _convertToShares(assets, supplyBefore());
require(shares != 0, "ZERO_SHARES");
asset.transferFrom(msg.sender, address(this), assets);
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
}
function mint(uint256 shares, address receiver) external returns (uint256 assets) {
assets = _convertToAssets(shares, supplyBefore());
_mint(receiver, shares);
asset.transferFrom(msg.sender, address(this), assets);
emit Deposit(msg.sender, receiver, assets, shares);
}
/*------------------出口函数------------------*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares) {
shares = _convertToShares(assets, supplyBefore());
_spendAllowance(owner, msg.sender, shares);
_burn(owner, shares);
asset.transfer(receiver, assets);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
}
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets) {
_spendAllowance(owner, msg.sender, shares);
_burn(owner, shares);
assets = _convertToAssets(shares, supplyAfterBurn(shares));
asset.transfer(receiver, assets);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
}
/*------------------辅助函数------------------*/
function totalAssets() public view returns (uint256) {
return asset.balanceOf(address(this));
}
function _convertToShares(uint256 assets, uint256 supply) internal view returns (uint256) {
return supply == 0 ? assets : assets * totalSupply() / totalAssets();
}
function _convertToAssets(uint256 shares, uint256 supply) internal view returns (uint256) {
return supply == 0 ? shares : shares * totalAssets() / totalSupply();
}
/* 仅作展示,省略 max 系列与 preview 系列 */
}👉 想用实战演练币安智能链部署此合约?立即进入在线 IDE。
FAQ:三分钟扫盲高频疑问
Q1:有了 ERC-4626,收益会自动再投资吗?
A:标准本身仅定义接口,并不会强制收益再投资。是否复利取决于 vault 合约的实现者,调用者在链下就能看到每个 totalAssets() 区块高度的变化。
Q2:为什么还需要 previewX 系列?直接看 convertToShares 不香吗?
A:previewX 会 snapshot 当前链上状态做原子级计算,考虑在未执行交易时的瞬时滑点或流动性限制,确保前端预期与链上实际一致。
Q3:直接把所有资产挂 ERC-4626 vault 会不会被闪电贷掏空?
A:取决于业务逻辑。例子中 vault 并未暴露“白嫖式提款”,如想防闪电贷攻击,可在 deposit 与 withdraw 之间加 nonReentrant 或在收益策略合约里维护时间锁。
Q4:可以用 LP Token 当底层资产吗?
A:完全可以。底层资产只要求是 ERC-20 即可,无论是 USDC、Sushi LP,还是更复杂的 LP token,都能被 vault 封装成带收益的 ERC-4626 shares。
Q5:ERC-4626 vault 还能叠加杠杆吗?
A:可以。收益策略合约若能超额抵押、借入再质押,就会把杠杆逻辑隐藏于策略层, ERC-4626 仍是可交互的统一出入口。
小结:三步记忆法
- 记住“4 进 4 出”:deposit/mint/redeem/withdraw。
- 记住“重载”:函数后带
Max/Preview/Convert即只读体验。 - 记住“乐高统一底座”:任何收益项目、聚合器、钱包、行情页面想接入,只需遵守 ERC-4626。
把 收益凭证 做成像 USB-C 一样的通用接口,ERC-4626 正在让 DeFi 的每个环节都变得更安全、更简单、更可组合。