sherlock-audit / 2023-01-derby-judging

4 stars 1 forks source link

josephdara - deposit function #406

Closed sherlock-admin closed 1 year ago

sherlock-admin commented 1 year ago

josephdara

high

deposit function

Summary

In MainVault.sol the deposit function can be exploited https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/MainVault.sol#L106

Vulnerability Detail

` function deposit( uint256 _amount, address _receiver ) external nonReentrant onlyWhenVaultIsOn returns (uint256 shares) { if (training) { require(whitelist[msg.sender]); uint256 balanceSender = (balanceOf(msg.sender) * exchangeRate) / (10 ** decimals()); require(_amount + balanceSender <= maxTrainingDeposit); }

uint256 balanceBefore = getVaultBalance() - reservedFunds;
vaultCurrency.safeTransferFrom(msg.sender, address(this), _amount);
uint256 balanceAfter = getVaultBalance() - reservedFunds;

uint256 amount = balanceAfter - balanceBefore;
shares = (amount * (10 ** decimals())) / exchangeRate;

_mint(_receiver, shares);

}`

Can be exploited through the Vault.sol function;

function getVaultBalance() public view returns (uint256) { return vaultCurrency.balanceOf(address(this)); } by using the IERC20 interface to return a different amount the second time getVaultBalance() is called

Impact

A false balance is calculated and false shares are given

Code Snippet

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract Exploit { IERC20 private vaultCurrency; MainVault private mainvault; constructor(address _contract, address _vaultCurrency) { mainvault = MainVault(_contract); vaultCurrency = IERC20(_vaultCurrency) } function hack() external { mainVault.deposit(uint256 _amount,address _receiver); } function getVaultBalance() public view returns (uint256) { if (vaultCurrency.Currency.balanceOf(address(this)) = 0 ){return 10000000000000000000} return vaultCurrency.balanceOf(address(this)); } }```

Tool used

Remix, VScode Manual Review

Recommendation

The function deposit should look like this


  function deposit(
    uint256 _amount,
    address _receiver
  ) external nonReentrant onlyWhenVaultIsOn returns (uint256 shares) {
    if (training) {
      require(whitelist[msg.sender]);
      uint256 balanceSender = (balanceOf(msg.sender) * exchangeRate) / (10 ** decimals());
      require(_amount + balanceSender <= maxTrainingDeposit);
    }

    uint256 balanceBefore = getVaultBalance() - reservedFunds;
    vaultCurrency.safeTransferFrom(msg.sender, address(this), _amount);
    uint256 balanceAfter = getVaultBalance() - reservedFunds;
    uint256 amount = balanceAfter - balanceBefore;
    require( _amount == amount )
    shares = (amount * (10 ** decimals())) / exchangeRate;

    _mint(_receiver, shares);
  }