BriVault

First Flight #52
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

List of Countries can be updated anytime and result can be manipulated, no timestamp check in `setCountry::BriVault`

Root + Impact : setCountry::BriVault does not have any timestamp check, admin can manipulate list of countries anytime between the event, leading to centralization risk and result manipulation.

Description

  • In setCountry::BriVault function, there is no check for deadline of setting final list of countries.

  • Admin can manipulate and change the list/order of countries.

  • This can lead to potential loss of asset for users who are betting on a specific country .

function setCountry(string[48] memory countries) public onlyOwner {
@> // no check regarding the deadline of setting the final list of countries before the event starts
for (uint256 i = 0; i < countries.length; ++i) {
teams[i] = countries[i];
}
emit CountriesSet(countries);
}

Risk

Likelihood: High

  • It is highly possible that some dishonest admin can manipulate the list of countries in between or after the event.

  • It is also possible that admin might also have set a bet on a country and that country is not winning, so admin can change the order to get the Incentive.

Impact: High

  • Loss of funds for users who have bet on the actual winner country .

Proof of Concept

  • Suppose a list of countries is uploaded initially : string[48] countries=["United States","Canada","Mexico",......];.

  • All the users have joined the event and the event started.

  • owner has also joined the event .

  • Suppose there are 3 users for example with the countries they have bet on-> 1. owner(United States) 2. alice(Canada) 3. bob(Mexico).

  • All three have deposited 5e18 .

  • In actual, Canada won the event and the event is ended.

  • But the owner bet on United States ,so admin will call the function setCountry with this new updated list of countries: string[48] countriesManipulated=["Canada","United States", "Mexico",.....] .

  • Now owner called the function setWinner with countryIndex as 1.

    function testSetCountryHaveNoTimeChecks() public {
    //owner Balance Initially
    uint256 ownerAssetBalanceBefore = IERC20(briVault.asset()).balanceOf(owner);
    uint256 fee = (5e18 * 150) / 10000;
    //owner set the country list
    vm.startPrank(owner);
    briVault.setCountry(countries);
    vm.stopPrank();
    //owner deposited and joined betting for US
    vm.startPrank(owner);
    mockToken.approve(address(briVault), 5 ether);
    uint256 ownerShares = briVault.deposit(5 ether, owner);
    briVault.joinEvent(0); //US
    console.log("owners's shares", ownerShares);
    vm.stopPrank();
    //alice deposited and joined betting for Canada
    vm.startPrank(alice);
    mockToken.approve(address(briVault), 5 ether);
    uint256 aliceShares = briVault.deposit(5 ether, alice);
    briVault.joinEvent(1); //CANADA
    console.log("alice shares", aliceShares);
    vm.stopPrank();
    //bob deposited and joined betting for Mexico
    vm.startPrank(bob);
    mockToken.approve(address(briVault), 5 ether);
    uint256 bobShares = briVault.deposit(5 ether, bob);
    vm.warp(eventStartDate);// last user to enter
    briVault.joinEvent(2); //MEXICO
    console.log("bob's shares", bobShares);
    vm.stopPrank();
    //now no one can join the event.
    //Event ended and CANADA is the winner, hence should get the winning funds back.
    vm.warp(eventEndDate + 1);
    //owner manipulated the list
    vm.startPrank(owner);
    briVault.setCountry(countriesManipulated);//changed from countries -> countriesManipulated
    briVault.setWinner(1); //US IS THE WINNER NOW.Hence alice won't be able to withdraw and will lose his assets, while owner rug pulled the users.
    string memory winnerCountry = briVault.getWinner();
    console.log("winner country:", winnerCountry); //US
    vm.stopPrank();
    //alice can't withdraw
    vm.expectRevert(BriVault.didNotWin.selector);
    vm.prank(alice);
    briVault.withdraw();
    vm.prank(owner);
    briVault.withdraw();
    uint256 ownerAssetBalanceAfter = IERC20(briVault.asset()).balanceOf(owner);
    console.log("OWNER Balance After winning:",ownerAssetBalanceAfter);
    assertEq(ownerAssetBalanceBefore-5e18 +(5e18-fee)*3, ownerAssetBalanceAfter);//calculation and comparision on gains by owner
    }

Recommended Mitigation

  • It is highly recommended to include a check in the starting of the setCountry function to strictly set the countries 1 day before the eventStartDate.

contract BriVault is ERC4626, Ownable {
...
function setCountry(string[48] memory countries) public onlyOwner {
+ if (block.timestamp > eventStartDate - 1 days) {
+ revert CantSetTheCountriesBeforeOneDayOfEvent();
+ }
for (uint256 i = 0; i < countries.length; ++i) {
teams[i] = countries[i];
}
emit CountriesSet(countries);
...
}
}
Updates

Appeal created

bube Lead Judge 20 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

setCountry() Can Be Called After Users Join

This is owner action.

Support

FAQs

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

Give us feedback!