Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Latest commit

 

History

History
112 lines (78 loc) · 3.23 KB

072.md

File metadata and controls

112 lines (78 loc) · 3.23 KB

ctf_sec

high

User can inject the tokenX direclty to the BufferBinaryPool to inflate the totalTokenXBalance to manipulate the share value

Summary

User can inject the tokenX direclty to the BufferBinaryPool to inflate the totalTokenXBalance to manipulate the share value

Vulnerability Detail

User can deposit tokenX into BufferBinaryPool and get liqudity token.

The amount of the liquidity token is calculated below

  function _provide(
      uint256 tokenXAmount,
      uint256 minMint,
      address account
  ) internal returns (uint256 mint) {
      uint256 supply = totalSupply();
      uint256 balance = totalTokenXBalance();

      require(
          balance + tokenXAmount <= maxLiquidity,
          "Pool has already reached it's max limit"
      );

      if (supply > 0 && balance > 0)
          mint = (tokenXAmount * supply) / (balance);
      else mint = tokenXAmount * INITIAL_RATE;

the balance is calculated below:

  /**
   * @notice Returns the total balance of X provided to the pool
   */
  function totalTokenXBalance()
      public
      view
      override
      returns (uint256 balance)
  {
      return tokenX.balanceOf(address(this)) - lockedPremium;
  }

if we look back to the calculation for minting amount:

mint = (tokenXAmount * supply) / (balance);

the larger than the balance, the smaller the share minted.

Because of the use tokenX.balanceOf(this), user can inject the tokenX directly to the BufferBinaryPool to inflate the totalTokenXBalance(), which decrease the minted amount for new user that provides the liqudity.

On the other hand, when user burn the liqudity token in exchange for the tokenX, we are calling the withdraw.

function _withdraw(uint256 tokenXAmount, address account)
    internal
    returns (uint256 burn)
{
    require(
        tokenXAmount <= availableBalance(),
        "Pool: Not enough funds on the pool contract. Please lower the amount."
    );
    uint256 totalSupply = totalSupply();
    uint256 balance = totalTokenXBalance();

    uint256 maxUserTokenXWithdrawal = (balanceOf(account) * balance) /
        totalSupply;

        uint256 tokenXAmountToWithdraw = maxUserTokenXWithdrawal < tokenXAmount
            ? maxUserTokenXWithdrawal
            : tokenXAmount;

        burn = divCeil((tokenXAmountToWithdraw * totalSupply), balance);

note the calculation:

uint256 maxUserTokenXWithdrawal = (balanceOf(account) * balance) / totalSupply;

inflating the totalTokenXBalance() increase the max tokenX user can withdraw.

Impact

By sending the tokenX directly to the pool, hacker decreases further user's liquidity token minted amount, yet increase the share of the current liquidity token.

In fact, because the tokenX is either USDC or the Buffer token, if the tokenX is USDC, user can take USDC flash loan to manipulate the price per share.

Code Snippet

https://github.com/sherlock-audit/2022-11-buffer/blob/main/contracts/contracts/core/BufferBinaryPool.sol#L215-L235

https://github.com/sherlock-audit/2022-11-buffer/blob/main/contracts/contracts/core/BufferBinaryPool.sol#L290-L308

Tool used

Manual Review

Recommendation

We recommend the project not use the balanceOf check and take snapshot of the balance.