🥶Minting and Burning Liquidity Pool Tokens

Code4rena High Bug Bounty Payout

Vulnerability Details

Impact:

The Pool contract permits users to burn liquidity provider (LP) tokens without concurrently withdrawing the corresponding tokens. This ability creates an opportunity for malicious actors to manipulate the pool's rate adversely, rendering it impossible for users to receive any LP tokens when depositing tokens into the pool. Such manipulation primarily hinges on the calculation of liquidity tokens at Utils:calcLiquidityUnits, where a minimal total supply (e.g., 1) leads to all computed units rounding down to zero.

Proof of Concept:

Below is an example script where a user attempts to deposit 1M tokens into a pool with a total supply of just 1:

pythonCopy codedai_pool.functions.burn(init_amount-1).transact()
print('total supply', dai_pool.functions.totalSupply().call())
dai.functions.transfer(dai_pool.address, 1000000 * 10**18).transact()
dai_pool.functions.addForMember(user).transact()
print('lp received from depositing 1M dai: ', dai_pool.functions.balanceOf(user).call())

# Output:
# total supply 1
# lp received from depositing 1M dai:  0

This script demonstrates that a pool with a total supply of 1 yields zero LP tokens for a deposit of 1M tokens, indicating a significant flaw in the system.

How the Vulnerability Works:

Given that any user can initiate a Pool via the PoolFactory, a malicious actor can create a pool, burn their LP tokens, and set the total supply to 1. Consequently, this actor becomes the sole owner of the pool's LP tokens henceforth.

Recommended Mitigation Steps:

  • Consider eliminating the burn functionality or limit its access to only privileged users to prevent arbitrary burning of LP tokens.

  • Implement safeguards within the smart contract to prevent the total supply from dropping to levels that would cause the rounding issue, like establishing a minimum total supply limit.

  • Review and revise the liquidity calculation logic to ensure that it handles edge cases gracefully, without leaving room for exploitation. Ensure thorough testing and auditing of the revised logic to confirm its robustness and security.

Vulnerability Details

Impact:

A malicious actor can monitor the SetPricePerShare event, exploiting it if the price data becomes stale due to a lack of updates, thus manipulating the mint() function to use an outdated pricePerShare that differs from the current market price. This user can then wait for the price to be updated, subsequently using the burn() function with the newly updated pricePerShare. This process allows the actor to make a risk-free profit at the expense of the contract's holdings.

Proof of Concept:

  • Price Updating Mechanism: The pricePerShare variable in WrappedIbbtcEth is updated by the externally invoked updatePricePerShare function. However, the variable is utilized in mint, burn, and transfer functions without any check for its freshness, making it susceptible to being outdated or stalled. This stale data issue can occur if the updatePricePerShare function fails to run due to various reasons, including bugs, system-level dependencies, or network outages. (See: balanceToShares function and updatePricePerShare function)

Recommended Mitigation Steps:

  1. Introduce a Threshold Variable: Implement a threshold variable in the WrappedIbbtcEth contract that defines the maximum allowable time since the last pricePerShare update.

  2. Develop Two Transfer Variants: Create two variants of transferFrom and transfer functions. Both should check if the current time minus the time of the last price update is less than the defined threshold:

    • If the condition is met, both function variants execute the transfer.

    • If the condition is not met, the first variant should revert, while the second one triggers a price update (even though it might be more gas-intensive).

  3. Limit Exposure: With the threshold in place, if a scheduled price update fails (due to network issues or other reasons), the associated risk is confined to the market volatility during the threshold time, effectively capping the exposure.

Last updated