hats-finance / Intuition-0x538dbadc50cc87b281cd655f1edbc6ebda02a66a

The smart contracts of the Intuition protocol v1.
https://intuition.systems
Other
0 stars 1 forks source link

Exit Fee Not Deducted from Total Assets in Redeem Function #70

Open hats-bug-reporter[bot] opened 3 days ago

hats-bug-reporter[bot] commented 3 days ago

Github username: -- Twitter username: -- Submission hash (on-chain): 0xfe48c86ee5fde1eaae0770dab56021baee6c579c2aa94c61a309134d82982c86 Severity: high

Description: Description\ In the _redeem function of the EthMultiVault contract, there's a critical issue where the exit fee is not deducted from the total assets when updating the vault totals. This discrepancy can lead to an accounting mismatch between the actual assets in the vault and the recorded total assets, potentially causing fund imbalances and incorrect share price calculations.

Attack Scenario\

  1. A user calls the redeemAtom or redeemTriple function to withdraw their shares.
  2. The _redeem function calculates the assets to be returned to the user, including the exit fee and protocol fee.
  3. When updating the vault totals, the function deducts the assetsForReceiver and protocolFee from the total assets, but fails to deduct the exitFee.
  4. Over time, as more users redeem their shares, the discrepancy between the recorded total assets and the actual assets in the vault grows.
  5. This can lead to:
    • Inflated share prices for remaining users
    • Potential insolvency of the vault if all users try to redeem
    • Incorrect calculations in other functions that rely on the total assets value

Attachments

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./EthMultiVault.sol";

contract EthMultiVaultExploit {
    EthMultiVault public vault;

    constructor(address _vaultAddress) {
        vault = EthMultiVault(_vaultAddress);
    }

    function exploitRedeem(uint256 vaultId, uint256 shares) external {
        // Assume we have shares in the vault
        uint256 initialTotalAssets = vault.vaults(vaultId).totalAssets;

        vault.redeemAtom(shares, address(this), vaultId);

        uint256 finalTotalAssets = vault.vaults(vaultId).totalAssets;

        // The difference between initialTotalAssets and finalTotalAssets
        // will be less than it should be, as the exit fee is not deducted

        // Over time, this discrepancy will grow, leading to an inflated
        // totalAssets value in the vault
    }
}
  1. Revised Code File (Optional)

    function _redeem(uint256 id, address owner, uint256 shares) internal returns (uint256, uint256) {
    // ... (previous code remains the same)
    
    (, uint256 assetsForReceiver, uint256 protocolFee, uint256 exitFee) = getRedeemAssetsAndFees(shares, id);
    
    // Corrected: Include exitFee in the totalAssetsDelta calculation
    _setVaultTotals(
        id,
        vaults[id].totalAssets - (assetsForReceiver + protocolFee + exitFee), // totalAssetsDelta
        vaults[id].totalShares - shares // totalSharesDelta
    );
    
    // ... (rest of the function remains the same)
    }