Skip to content

Latest commit

 

History

History
111 lines (78 loc) · 5.13 KB

069.md

File metadata and controls

111 lines (78 loc) · 5.13 KB

Atomic Wool Tuna

High

Attacker will manipulate Vault share price to steal funds from subsequent depositors.

Summary

The failure to segregate externally donated tokens from actual Vault deposits in the share calculation will cause an inflated token balance, resulting in a skewed share price for legitimate Vault depositors as an attacker donates tokens directly to the Strategy and then withdraws shares at an unfair value.

Root Cause

In the Vault contract, the _calcDeposit function calculates shares based on idleBalances which is the Strategy's current token balances.

/// @notice Calculates the deposit amounts
    /// @param bal0 The current token0 balance of the strategy
    /// @param bal1 The current token1 balance of the strategy
    /// @param depositAmount0 The amount of token0 user wishes to deposit
    /// @param depositAmount1 The amount of token1 user wishes to deposit
    /// @return shares The amount of shares to be minted to the user
    /// @return amount0 The actual amount of token0 which the user will deposit
    /// @return amount1 The actual amount of token1 which the user will deposit
    function _calcDeposit(uint256 bal0, uint256 bal1, uint256 depositAmount0, uint256 depositAmount1)
        internal
        view
        returns (uint256 shares, uint256 amount0, uint256 amount1)
    {
        uint256 totalSupply = totalSupply();

        // If total supply > 0, vault can't be empty
        assert(totalSupply == 0 || bal0 > 0 || bal1 > 0);

        if (totalSupply == 0) {
            // For first deposit, just use the amounts desired
            amount0 = depositAmount0;
            amount1 = depositAmount1;
            shares = (amount0 > amount1 ? amount0 : amount1) - (1000);
        } else if (bal0 == 0) {
            amount1 = depositAmount1;
            shares = amount1 * totalSupply / bal1;
        } else if (bal1 == 0) {
            amount0 = depositAmount0;
            shares = amount0 * totalSupply / bal0;
        } else {
            uint256 cross0 = depositAmount0 * bal1;
            uint256 cross1 = depositAmount1 * bal0;
            uint256 cross = cross0 > cross1 ? cross1 : cross0;
            require(cross > 0, "cross");

            // Round up amounts
            amount0 = (cross - 1) / bal1 + 1;
            amount1 = (cross - 1) / bal0 + 1;
            shares = cross * totalSupply / bal0 / bal1;
        }
    }

However, the Strategy does not distinguish between deposited tokens and direct transfers, allowing attackers to artificially inflate balances by donating tokens. This skews the share price, enabling theft from subsequent depositors.

Internal Pre-conditions

  1. The attacker needs to make an initial minimal deposit via the Vault to set the baseline share price.
  2. The Strategy must hold tokens (either deposited or donated) for the attack to manipulate balances.
  3. The attacker must have access to one of the Vault's underlying tokens (token0 or token1).

External Pre-conditions

The Vault must have sufficient liquidity for the attacker to withdraw their shares.

Attack Path

  1. Attacker deposits a minimal amount of both token0 and token1 into the Vault, setting the initial share price.
  2. Attacker donates a large amount of token0 directly to the Strategy, increasing its token0 balance without minting shares.
  3. A legitimate user deposits funds into the Vault. The Vault calculates shares based on the inflated token0 balance via _calcDeposit function, minting fewer shares relative to their actual deposit.
  4. The attacker withdraws their shares from the Vault.
  5. Due to the manipulated share price, the attacker receives a disproportionate amount of the donated token token0, effectively stealing funds from the legitimate depositor.

Impact

Legitimate Vault depositors suffer a financial loss as their deposit value is diluted by the manipulated share calculation. The attacker gains an unfair advantage by capturing a significant portion of the inflated token balance, potentially resulting in a complete loss of value for the affected deposits if the manipulation is large enough.

PoC

Step 1: Attacker makes a minimal deposit to establish share price Step 2: Attacker donates a large amount of token0 directly to the Strategy Step 3: A legitimate user makes a deposit, unaware of the manipulated balances Step 4: Attacker withdraws their shares, receiving an inflated portion of token0 funded by the legitimate user

Mitigation

Introduce a dedicated depositedBalance variable within the Strategy that increments only when tokens are deposited via the Vault. Use this balance for share calculations instead of idleBalances

uint256 depositedBalance0;
uint256 depositedBalance1;

function deposit(uint256 amount0, uint256 amount1) external onlyVault {
    depositedBalance0 += amount0;
    depositedBalance1 += amount1;
}

Likewise, it is also viable to prevent or properly account for direct token transfers by overriding the transfer function in the Strategy.