Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERC4626 Implementation Standard Inconsistency #348

Open
Zer0dot opened this issue Dec 14, 2022 · 2 comments
Open

ERC4626 Implementation Standard Inconsistency #348

Zer0dot opened this issue Dec 14, 2022 · 2 comments

Comments

@Zer0dot
Copy link

Zer0dot commented Dec 14, 2022

Found after discussions with @BenSparksCode, @donosonaumczuk and @vicnaum.

We are not certain whether this is a lack of clarity in the standard's description or an inconsistency in the implementation. The standard states that the totalAssets() function "MUST be inclusive of any fees that are charged against assets in the Vault."

However, doing so would include the charged fees in the calculation of the asset <=> share rate in the current implementation, giving an artificially reduced share rate. This either means that, by "inclusive," the EIP means that it should include the removal of fees, or that the implementation should instead remove fees before using the totalAssets() function in conversion calculations.

Relevant code:

    function totalAssets() public view virtual returns (uint256);

    function convertToShares(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

    function convertToAssets(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
    }

    function previewDeposit(uint256 assets) public view virtual returns (uint256) {
        return convertToShares(assets);
    }

    function previewMint(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
    }

    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());
    }

    function previewRedeem(uint256 shares) public view virtual returns (uint256) {
        return convertToAssets(shares);
    }
@transmissions11
Copy link
Owner

ugh yes this seems valid, idk why we made totalAssets account for fees

@androolloyd
Copy link

androolloyd commented Dec 15, 2022

Depending on where the vault fee rake is being captured, asset side or vault share supply side, you may have to adjust your totalSupply to be a function that accounts for this, especially if lazy minting the fee rake later.

going through the spec was def a headache

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants