BriVault

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

Shares are minted incorrectly inside `deposit::BriVault` function.

Root + Impact : Shares are minted to msg.sender in the deposit function instead of receiver ,making it impossible to sponsor assets for someone, hence losing deposited assets everytime someone sponsor for another person (i.e. address).

Description

  • In the deposit::BriVault function, there are two parameters: uint256 assets and address receiver .

  • the assets are being transfered by msg.sender , but in the bet receiver's address is stored .

  • Which means that either a person deposit by themself and hence passing the receiver's address same as msg.sender .In this case, function will work fine.

  • But in another scenario, where the msg.sender is sponsoring the assets for receiver , which means it is intended that receiver will be registered for the bet and the shares will be minted to receiver .

  • In the current scenario, this is not possible as instead of minting the shares to receiver ,it is being minted to msg.sender ,and msg.sender can't join the event too, as the registered person is receiver who doesn't have any shares, hence have no chance to win the bet.

contract BriVault is ERC4626, Ownable {
...
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: High/Medium

  • It is likely possible that assets are being sponsored.

  • It is highly assumed by looking at the function that the address receiver parameter is for sponsership reason.

Impact: High

  • Funds are completey lost and both msg.sender and receiver have abosultely no change of winning if both are different.

  • msg.sender can't join the event .

  • receiver has no way to win, as shares are zero even if he is registered.

Proof of Concept

  • alice is sposoring assets for bob.

  • alice and bob -> shares before = 0.

  • alice calls the deposit(5e18,bob).

  • alice shares after the function call : 4.925e18 (excluding the fee).

  • bob shares after the function call : 0e18.

  • alice calls joinEvent(countryId) in hope that he could join if he got shares.

  • function revets with error--> noDeposit().

  • bob can join but has no shares, hence can't win.

    function testDepositFailsWhenAssetsAreSponsored() public {
    //assets alice is willing to sponsor for bob: 5e18.
    uint256 etherToDeposit = 5e18;
    // shares of both of them before: 0e18
    uint256 sharesOfBobBeforeDeposit = briVault.balanceOf(bob);
    uint256 sharesOfAliceBeforeDeposit = briVault.balanceOf(alice);
    assertEq(sharesOfBobBeforeDeposit, 0);
    assertEq(sharesOfAliceBeforeDeposit, 0);
    //alice starts the transaction
    vm.startPrank(alice);
    mockToken.approve(address(briVault), etherToDeposit);
    briVault.deposit(etherToDeposit, bob);
    vm.stopPrank();
    //fee calculation
    uint256 fee = (5e18 * 150) / 10000;
    //share of Alice after deposit:4.925e18
    uint256 sharesOfAliceAfterDeposit = briVault.balanceOf(alice);
    assertEq(
    sharesOfAliceAfterDeposit,
    sharesOfAliceBeforeDeposit + (etherToDeposit - fee) //4925000000000000000
    );
    //share of Bob after deposit:0e18
    uint256 sharesOfBobAfterDeposit = briVault.balanceOf(bob);
    assertEq(sharesOfBobAfterDeposit, sharesOfBobBeforeDeposit);
    //alice try to call `joinEvent` hoping he has shares, so atleast he can bet.
    uint256 countryId = 25;
    //but it reverts with `noDeposit Error`
    vm.startPrank(alice);
    vm.expectRevert(BriVault.noDeposit.selector);
    briVault.joinEvent(countryId);
    vm.stopPrank();
    }

Recommended Mitigation

  • It is highly recommended to mint the tokens to receiver address instead of msg.sender .

  • This simple change will fix the vulnerbility.

contract BriVault is ERC4626, Ownable {
...
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);
+ _mint(receiver, participantShares);
emit deposited(receiver, stakeAsset);
return participantShares;
}
...
}
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!