BriVault

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

Deposits for different receiver addresses make funds unusable and participation impossible

The root cause of this issue is an inconsistency between how deposits and shares are assigned in the deposit() function. When a user deposits for another address (receiver), the contract records the deposited assets under the receiver in stakedAsset, but mints ERC4626 shares to the depositor (msg.sender). This desynchronizes ownership between the staked assets and the minted shares.

Description

  • The deposit() function should correctly associate the staked amount and the minted ERC4626 shares with the same address.

  • This creates a mismatch between the stored stake and the ownership of shares.

  • As a result:

    • The depositor fails the joinEvent() validation (noDeposit() revert) because stakedAsset[msg.sender] == 0.

    • The receiver cannot participate either because they hold no shares.

  • The deposited funds become permanently unusable and locked in the vault.

// Deposit function
function deposit(uint256 assets, address receiver) public override returns (uint256) {
// Rest of the deposit function
// @> stakedAsset is recorded for the `receiver`
stakedAsset[receiver] = stakeAsset;
uint256 participantShares = _convertToShares(stakeAsset);
IERC20(asset()).safeTransferFrom(msg.sender, participationFeeAddress, fee);
IERC20(asset()).safeTransferFrom(msg.sender, address(this), stakeAsset);
// @> Shares are minted to the `msg.sender` (depositor) — mismatch with stakedAsset
_mint(msg.sender, participantShares);
emit deposited(receiver, stakeAsset);
return participantShares;
}
// JoinEvent Function
function joinEvent(uint256 countryId) public {
// @> This check expects the caller (msg.sender) to have an entry in stakedAsset
if (stakedAsset[msg.sender] == 0) {
revert noDeposit();
}
// Rest of the function
}

Risk

Likelihood:

  • Occurs whenever a user deposits on behalf of a different address (receiver != msg.sender) — a legitimate use case.

  • No warnings or validation prevent this usage; thus, normal users can easily make this mistake.

Impact:

  • The depositor cannot participate in the event (noDeposit() revert).

  • The receiver also cannot participate or withdraw since no shares were minted to them.

  • Deposited tokens become permanently locked in the vault.

Proof of Concept

  • In the test I have used vm.expectRevert so you might not be able to see the revert error in the output

  • In the output neither can the person join the contest and neither can claim refunds.

function test_unable_to_participate() public {
vm.startPrank(user1);
mockToken.approve(address(briVault), 5 ether);
briVault.deposit(2 ether, user2);
vm.expectRevert();
briVault.joinEvent(2);
vm.stopPrank();
uint stakedAssetb4 = briVault.stakedAsset(user2);
uint balance_token_before = mockToken.balanceOf(user1);
vm.startPrank(user1);
briVault.cancelParticipation();
vm.stopPrank();
uint stakedAssetafter = briVault.stakedAsset(user2);
uint balance_token_after = mockToken.balanceOf(user1);
console.log("Staked asset before cancel:", stakedAssetb4);
console.log("Staked asset after cancel:", stakedAssetafter);
console.log("Balance before cancel:", balance_token_before);
console.log("Balance after cancel:", balance_token_after);
}
// Output for the test
Ran 1 test for test/briVault.t.sol:BriVaultTest
[PASS] test_unable_to_participate() (gas: 175579)
Logs:
Staked asset before cancel: 1970000000000000000
Staked asset after cancel: 1970000000000000000
Balance before cancel: 19998000000000000000000
Balance after cancel: 19998000000000000000000
Traces:
├─ [0] VM::expectRevert(custom error 0xf4844814)
│ └─ ← [Return]
├─ [2799] BriVault::joinEvent(2)
│ └─ ← [Revert] noDeposit()
├─ [0] VM::stopPrank()
│ └─ ← [Return]

Recommended Mitigation

  • Modify the check that if msg.sender have BTT tokens or stakedAsset then the address can join event.

- if (stakedAsset[msg.sender] == 0) {
+ ((stakedAsset[msg.sender] == 0) && (balanceOf(msg.sender) == 0)) {rest works the same}
Updates

Appeal created

bube Lead Judge 21 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!