BriVault

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

Inconsistent Use of `receiver` Parameter, user can't join the event even though they deposit

The deposit() function keeps track of stakedAsset mapping using the parameter receiver, and user won't be able to join the event due to the checks

Description

The `deposit()` function tracks staked assets to the `receiver` address but mints shares to `msg.sender`. This creates a critical mismatch that prevents users from joining events. When a user deposits, their shares are minted to their address, but if `receiver != msg.sender`, the `stakedAsset` mapping is updated for the wrong address. Since `joinEvent()` checks `stakedAsset[msg.sender]`, users who deposited will be unable to join events.

@>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 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;
}
function joinEvent(uint256 countryId) public {
@> if (stakedAsset[msg.sender] == 0) {
revert noDeposit();
}

Risk

Likelihood:

  • High, since user expecting that they can join the event after depositing

Impact:

  • Users who call deposit(amount, differentAddress) (even accidentally) will have shares but cannot join events, resulting in locked funds

  • Users lose their participation fee (1.5%) permanently without gaining any event participation rights

  • Breaks core protocol functionality where deposits should automatically grant event participation rights

Proof of Concept

add this function to your test suite:


function test_userCantJoin() public {
vm.prank(owner);
briVault.setCountry(countries);
uint256 deposit = 0.1 ether;
vm.startPrank(user1);
mockToken.approve(address(briVault), deposit);
//user1 expect user2 to receive the money instead
briVault.deposit(deposit, user2);
assert(briVault.stakedAsset(user1) != deposit);
assertEq(briVault.balanceOf(user1), 0);
assertEq(briVault.stakedAsset(user1), 0);
assertEq(briVault.stakedAsset(user2), 0);
assertEq(briVault.balanceOf(user2), 0);
briVault.joinEvent(1);
vm.expectRevert(BriVault.noDeposit.selector);
vm.stopPrank();
// user2 also cannot join (no shares despite stakedAsset tracking)
vm.startPrank(user2);
vm.expectRevert(BriVault.noDeposit.selector);
briVault.joinEvent(1);
vm.stopPrank();
}

Recommended Mitigation


Option 1: Track stakedAsset for msg.sender

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;
+ stakedAsset[msg.sender] = 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);
+ emit deposited(msg.sender, stakeAsset);
return participantShares;
}

Option 2: Remove receiver parameter entirely

- function deposit(uint256 assets, address receiver) public override returns (uint256) {
+ function deposit(uint256 assets) public returns (uint256) {
+ address receiver = msg.sender;
require(receiver != address(0));
Updates

Appeal created

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

Shares Minted to msg.sender Instead of Specified Receiver

Support

FAQs

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

Give us feedback!