Description
The vault has a custom _convertToShares function that aims at minting 1 share per deposited token to the first depositor, as per the inline comment.
If someone sent tokens to the vault (calling the ERC20's transfer function) the first depositor would mint more than one share per token.
function _convertToShares(uint256 assets) internal view returns (uint256 shares) {
uint256 balanceOfVault = IERC20(asset()).balanceOf(address(this));
uint256 totalShares = totalSupply();
if (totalShares == 0 || balanceOfVault == 0) {
return assets;
}
shares = Math.mulDiv(assets, totalShares, balanceOfVault);
}
Risk
Likelihood:
Impact:
Proof of Concept
The following PoC shows how the first depositor would capture a donation made to the vault before any deposits and subsequent users would just mint the expected amounts.
function testDonationCaptureByFirstDepositor() public {
deal(address(mockToken), address(briVault), 1 ether);
uint256 depositAmount = 5 ether;
vm.startPrank(user1);
mockToken.approve(address(briVault), depositAmount);
uint256 shares = briVault.deposit(depositAmount, user1);
vm.stopPrank();
uint256 userShares = briVault.convertToAssets(shares);
console2.log("User shares:", userShares);
assertGt(userShares, depositAmount);
vm.startPrank(user2);
mockToken.approve(address(briVault), depositAmount);
uint256 shares2 = briVault.deposit(depositAmount, user2);
vm.stopPrank();
console2.log("User2 shares:", briVault.convertToAssets(shares2));
vm.startPrank(user3);
mockToken.approve(address(briVault), depositAmount);
uint256 shares3 = briVault.deposit(depositAmount, user3);
vm.stopPrank();
console2.log("User3 shares:", briVault.convertToAssets(shares3));
}
Recommended Mitigation
Simply remove the custom implementation, since the standard _convertToShares already handles all edge cases solvently.
- function _convertToShares(uint256 assets) internal view returns (uint256 shares) {
- // @audit-low: don't reinvent the wheel, use the ERC4626 contract's _convertToShares() function for this
- uint256 balanceOfVault = IERC20(asset()).balanceOf(address(this));
- uint256 totalShares = totalSupply(); // total minted BTT shares so far
- if (totalShares == 0 || balanceOfVault == 0) {
- // First depositor: 1:1 ratio
- return assets;
- }
- shares = Math.mulDiv(assets, totalShares, balanceOfVault);
- }