Skip to content

Instantly share code, notes, and snippets.

@nican0r
Last active February 19, 2025 16:57
Rounding issue identified in Credit Coop engagement with invariant testing

Medium - Rounding allows bypassing minting cap

The _baseMint function implements a convertToAssets function which converts the amount of shares being minted into the vault's equivalent underlying asset.

    function _baseMint(uint256 shares, address controller) internal returns (uint256 assets) {
        _isWhitelisted();
        _onlyOwnerOrOperator(controller);

        CreditStrategy(creditStrategy).accrueFees(); // accrue fees before minting new shares

        assets = convertToAssets(shares);
        uint256 maxShares = maxMint(controller);
        if (shares > maxShares) {
            revert ERC4626ExceededMaxMint(controller, shares, maxShares);
        }

        claimableDepositRequest[REQUEST_ID][controller] -= assets;
        totalPendingAssets -= assets;
    }

The conversion in convertToAssets rounds down, resulting in an amount of assets that's smaller than the amount that it should be for the amount of shares that the user is able to mint.

This allows the user to bypass the if (shares > maxShares) check which restricts the minting cap.

The user is also subsequently able to mint more more shares of the vault than they should for the amount of underlying asset that they deposited, allowing them to steal value from the vault.

Reproducer

The following unit test was generated from the Echidna job that broke the property_mint_more_than_max_reverts property, which was traced to the issue identified above.

 function test_property_mint_more_than_max_reverts_4() public {

    target_deployNewVaultAndStrategies(10,1,0,0,false);

    lendingVault_requestDeposit_clamped(15824861138544471049183522,5126449573802124063641740424571421993873283090572071904972);

    lendingVault_processDepositRequest_clamped(1064585729394055104088963594211526076999680138,5182720750843422510890579234475641313971507048);

    lendingVault_deposit_for_receiver_clamped(1518015215476408580341739907892527095673747330795017148,185568137856059954905389924900423478233619527327573568);

     vm.roll(block.number + 1);
     vm.warp(block.timestamp + 32);
    property_mint_more_than_max_reverts(1);

 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment