Root + Impact
The owner has complete, unchecked authority to declare any country as the winner through setWinner(), regardless of real-world event outcomes. There is no oracle integration, multi-signature requirement, or verification mechanism. This creates a critical trust assumption where the owner could collude with participants or act maliciously to steal funds.
Impact
Owner can steal all funds by:
Creating multiple addresses and depositing/joining with a specific country
Setting that country as winner regardless of actual results
Withdrawing all funds through controlled addresses
This completely undermines the trustless nature expected in DeFi protocols.
Scenario
address ;
for(uint i = 0; i < 10; i++) {
sybils[i] = address(uint160(0xBEEF0000 + i));
}
for(uint i = 0; i < 10; i++) {
vault.deposit(largeAmount, sybils[i]);
vault.joinEvent(47);
}
vault.setWinner(47);
for(uint i = 0; i < 10; i++) {
vault.withdraw();
}
Affected Code
function setWinner(uint256 countryIndex) public onlyOwner returns (string memory) {
if (block.timestamp <= eventEndDate) {
revert eventNotEnded();
}
require(countryIndex < teams.length, "Invalid country index");
if (_setWinner) {
revert WinnerAlreadySet();
}
winnerCountryId = countryIndex;
winner = teams[countryIndex];
_setWinner = true;
_getWinnerShares();
_setFinallizedVaultBalance();
emit WinnerSet(winner);
return winner;
}
Proposed Fix
Implement a decentralized winner determination mechanism:
function setWinner(uint256 countryIndex) public {
require(msg.sender == governanceContract, "Only governance");
}
function setWinner() public {
require(block.timestamp > eventEndDate + DISPUTE_PERIOD);
uint256 winnerIndex = oracle.getEventWinner(eventId);
}
mapping(address => bytes32) public validatorCommits;
mapping(address => uint256) public validatorReveals;
function commitWinner(bytes32 commitment) public onlyValidator {
validatorCommits[msg.sender] = commitment;
}
function revealWinner(uint256 countryIndex, uint256 nonce) public onlyValidator {
require(keccak256(abi.encode(countryIndex, nonce)) == validatorCommits[msg.sender]);
validatorReveals[msg.sender] = countryIndex;
}