什么是ERC4626

ERC4626是一种以太坊上的标准化代币,这种类型的合约首先是基于ERC20的,但是在普通ERC20代币的基础上增加了份额的概念。

每一个ERC4626的参与者根据自身支付的潜在资产的数量获得相应比例的份额,假设存在三个参与者:

  • alice -> 1e18
  • bob -> 2e18
  • eve -> 3e18 分别支付了1~3e18的ETH ,那么他们获得的份额应该也是按照这个比例,这使得用户在将份额转化为潜在资产的时候也是按照比例兑付的。

这种潜在资产转化为份额和份额转化为潜在资产的计算公式可以简单的总结为:


shares = shares * (totalAssets() + 1) / totalSupply

assets = assets * totalSupply / (totalAssets() + 1)

其中share表示份额,totalAssets代表当前合约中存在的潜在资产的总额,totalSupply代表总的shares数量也就是当前合约的mint数量的总和。

常用函数

deposit

    function deposit(uint256 assets, address receiver) public virtual returns (uint256) {
        uint256 maxAssets = maxDeposit(receiver);
        if (assets > maxAssets) {
            revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets);
        }

        uint256 shares = previewDeposit(assets);
        _deposit(_msgSender(), receiver, assets, shares);

        return shares;
    }

根据用户支付的潜在资产的数量,计算接收者最终获得的份额数量。

mint

    function mint(uint256 shares, address receiver) public virtual returns (uint256) {
        uint256 maxShares = maxMint(receiver);
        if (shares > maxShares) {
            revert ERC4626ExceededMaxMint(receiver, shares, maxShares);
        }

        uint256 assets = previewMint(shares);
        _deposit(_msgSender(), receiver, assets, shares);

        return assets;
    }

和deposit不同这里直接输入的是用户想要获得的份额,根据这个份额的值和上诉的计算公式获得用户需要支付的潜在资产的数量。 这里一般需要用户先将潜在资产ERC20像当前合约进行授权。

redeem

    function redeem(uint256 shares, address receiver, address owner) public virtual returns (uint256) {
        uint256 maxShares = maxRedeem(owner);
        if (shares > maxShares) {
            revert ERC4626ExceededMaxRedeem(owner, shares, maxShares);
        }

        uint256 assets = previewRedeem(shares);
        _withdraw(_msgSender(), receiver, owner, assets, shares);

        return assets;
    }

redeem的时候输入用户的份额,根据这个份额计算用户可以获得的潜在资产。

withdraw

    function withdraw(uint256 assets, address receiver, address owner) public virtual returns (uint256) {
        uint256 maxAssets = maxWithdraw(owner);
        if (assets > maxAssets) {
            revert ERC4626ExceededMaxWithdraw(owner, assets, maxAssets);
        }

        uint256 shares = previewWithdraw(assets);
        _withdraw(_msgSender(), receiver, owner, assets, shares);

        return shares;
    }

withdraw和redeem相反,根据最终想要获得的资产数量去计算用户需要burn的share数量。

总结

在DEFI中,有很多的场景需要像协议的参与者发放一定的奖励。假设我们的合约中有很多的参与者,协议在获得收益的时候需要像每个参与者按照比例发放奖励。如果单独去计算每个用户的奖励金额效率就太低了,而且会使得链上的计算变得异常复杂。 这就是ERC4626需要解决的问题,我们只需要知道合约中总的资产数量和合约中总的share数量就可以计算出下一个投资者潜在资产数量和份额的数量。 当需要像所有的参与者发送奖励也变得异常简单,我们只需要像合约中donate对应的资产资产即可,我们的公式会直接根据当前总资产去计算。