Deposits can be potentially frontrun and stolen
Description
The shares minted in deposit() are calculated as a ratio of totalVaultFunds() and totalSupply(). The totalVaultFunds() can be potentially inflated, reducing the amounts of shares minted (even zero).
function deposit(uint256 amountIn, address receiver)
...
shares = totalSupply() > 0
? (totalSupply() * amountIn) / totalVaultFunds()
: amountIn;
IERC20(wantToken).safeTransferFrom(receiver, address(this), amountIn);
_mint(receiver, shares);
}
...
function totalVaultFunds() public view returns (uint256) {
return
IERC20(wantToken).balanceOf(address(this)) + totalExecutorFunds();
}By transferring wantToken tokens directly, totalVaultFunds() would be inflated (because of balanceOf()) and as the division result is floored, there could be a case when it would essentially mint zero shares, causing a loss for the depositing user. If an attacker controls all of the share supply before the deposit, they would be able to withdraw all the user-deposited tokens.
Impact
Consider the following attack scenario:
The
Vaultcontract is deployed.The governance sets
batcherOnlyDeposittofalse.The attacker deposits
Xstakeable tokens and receivesXLP tokens.The victim tries to deposit
Ystakeable tokens.The attacker frontruns the victim's transaction and transfers
X * (Y - 1) + 1stakeable tokens to theVaultcontract.The victim's transaction is executed, and the victim receives 0 LP tokens.
The attacker redeems her LP tokens, effectively stealing
Ystakeable tokens from the victim.
The foregoing is just an example. Variations of the foregoing attack scenario are possible.
The impact of this finding is mitigated by the fact that the default value of batcherOnlyDeposit is true, which allows the keeper of the Batcher contract to 1) prevent the attacker from acquiring 100% of the total supply of LP tokens and 2) prevent the attacker from redeeming their LP tokens for stakeable tokens.
Recommendations
Consider
adding an
amountOutMinparameter to thedeposit(uint256 amountIn, address receiver)function of theVaultcontract;adding a
requirestatement that ensures that thedeposit()function never mints zero or less thanamountOutMinLP tokens.
Remediation
The issue has been acknowledged by Brahma and mitigated in commit 413b9cc↗.