BriVault

First Flight #52
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Faulty `stakedAsset` Tracking in `BriVault::deposit` function Locks Part of User Assets

Fault stakedAsset Tracking in BriVault::deposit function Locks Part of User Assets

Description

In the deposit function, each time a user deposits, the contract updates stakedAsset[receiver] with the new assets, instead of accumulating it.As a result, the previous deposited funds are overwritten and no longer tracked.When a user makes a second deposit, the first deposit becomes effectively locked.If the user deposits a third time, both the first and second deposits are no longer accounted for.

if (minimumAmount + fee > assets) {
revert lowFeeAndAmount();
}
@> uint256 stakeAsset = assets - fee;
@> stakedAsset[receiver] = stakeAsset;
uint256 participantShares = _convertToShares(stakeAsset);

Risk

Likelihood:

When a user attempts to deposit more than once, the contract overwrites their previous staked amount instead of accumulating it.

Impact:

  • Impact 1:Users may be unable to withdraw the full amount they deposited, resulting in potential loss of funds.

  • Impact 2: Vault accounting becomes inconsistent, causing discrepancies between total staked assets and total shares issued.

Proof of Concept

  1. The user approves 10 ETH for the BriVault contract.

  2. The user makes two deposits of 5 ETH each.

  3. The user calls cancelParticipation() to withdraw all previously deposited funds, excluding the participation fee.

Proof Of Code Place the following code in briVault.t.sol.
function testCannotWithdrawAllTheDeposit() public {
vm.startPrank(user1);
// balance of user before deposit should be 20eth
console.log("user balance before withdraw:", mockToken.balanceOf(user1));
mockToken.approve(address(briVault), 10 ether);
// deposite 2 times, each 5 ether
briVault.deposit(5 ether, user1);
briVault.deposit(5 ether, user1);
// calculate the participationFee for 1 time 5 ether
uint256 participationFee = (5 ether * participationFeeBsp) / 10000;
briVault.cancelParticipation();
vm.stopPrank();
uint256 BalanceExpected = 20 ether - (participationFee*2);
uint256 BalanceAfterCancelParticipation = mockToken.balanceOf(user1);
assert(BalanceExpected > BalanceAfterCancelParticipation);
assertEq(BalanceAfterCancelParticipation, (15 ether-participationFee));
}
After calling cancelParticipation(), the user’s balance is expected to be 20 ETH, excluding participation fees for both deposits, but the actual balance is only 15 ETH, excluding the fee for the second deposit, because the first deposit was overwritten.

Recommended Mitigation

Each user can either deposit once or update their existing deposit.

function deposit(uint256 assets, address receiver) public override returns (uint256) {
require(receiver != address(0));
if (block.timestamp >= eventStartDate) {
revert eventStarted();
}
uint256 fee = _getParticipationFee(assets);
// charge on a percentage basis points
if (minimumAmount + fee > assets) {
revert lowFeeAndAmount();
}
- uint256 stakeAsset = assets - fee;
- stakedAsset[receiver] = stakeAsset;
+ uint256 currentStakedAsset = stakedAsset[receiver];
+ uint256 stakeAsset = assets - fee;
+ stakedAsset[receiver] = currentStakedAsset + stakeAsset;
Updates

Appeal created

bube Lead Judge 19 days ago
Submission Judgement Published
Validated
Assigned finding tags:

`stakedAsset` Overwritten on Multiple Deposits

Vault tracks only a single deposit slot per user and overwrites it on every call instead of accumulating the total.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!