Unpredictable behavior for users due to admin front running or general bad timing
In a number of cases, administrators of contracts can update or upgrade things in the system without warning. This has the potential to violate a security goal of the system.\\nSpecifically, privileged roles could use front running to make malicious changes just ahead of incoming transactions, or purely accidental negative effects could occur due to unfortunate timing of changes.\\nIn general users of the system should have assurances about the behavior of the action they're about to take.\\nAn administrator (deployer) of `MultipleWinners` can change the number of winners in the system without warning. This has the potential to violate a security goal of the system.\\nadmin can change the number of winners during a prize-draw period\\n```\\nfunction setNumberOfWinners(uint256 count) external onlyOwner {\\n  \\_\\_numberOfWinners = count;\\n\\n  emit NumberOfWinnersSet(count);\\n}\\n```\\n\\n`PeriodicPriceStrategy` - admin may switch-out RNG service at any time (when RNG is not in inflight or timed-out)\\n```\\nfunction setRngService(RNGInterface rngService) external onlyOwner {\\n  require(!isRngRequested(), "PeriodicPrizeStrategy/rng-in-flight");\\n\\n  rng = rngService;\\n  emit RngServiceUpdated(address(rngService));\\n}\\n```\\n\\n`PeriodicPriceStrategy` - admin can effectively disable the rng request timeout by setting a high value during a prize-draw (e.g. to indefinitely block payouts)\\n```\\nfunction setRngRequestTimeout(uint32 \\_rngRequestTimeout) external onlyOwner {\\n  \\_setRngRequestTimeout(\\_rngRequestTimeout);\\n}\\n```\\n\\n`PeriodicPriceStrategy` - admin may set new tokenListener which might intentionally block token-transfers\\n```\\nfunction setTokenListener(TokenListenerInterface \\_tokenListener) external onlyOwner {\\n  tokenListener = \\_tokenListener;\\n\\n  emit TokenListenerUpdated(address(tokenListener));\\n}\\n```\\n\\n```\\nfunction setPeriodicPrizeStrategyListener(address \\_periodicPrizeStrategyListener) external onlyOwner {\\n  periodicPrizeStrategyListener = PeriodicPrizeStrategyListener(\\_periodicPrizeStrategyListener);\\n\\n  emit PeriodicPrizeStrategyListenerSet(\\_periodicPrizeStrategyListener);\\n}\\n```\\n\\nout of scope but mentioned as a relevant example: `PrizePool` owner can set new `PrizeStrategy` at any time\\n```\\n/// @notice Sets the prize strategy of the prize pool. Only callable by the owner.\\n/// @param \\_prizeStrategy The new prize strategy\\nfunction setPrizeStrategy(address \\_prizeStrategy) external override onlyOwner {\\n  \\_setPrizeStrategy(TokenListenerInterface(\\_prizeStrategy));\\n}\\n```\\n\\na malicious admin may remove all external ERC20/ERC721 token awards prior to the user claiming them (admin front-running opportunity)\\n```\\nfunction removeExternalErc20Award(address \\_externalErc20, address \\_prevExternalErc20) external onlyOwner {\\n  externalErc20s.removeAddress(\\_prevExternalErc20, \\_externalErc20);\\n  emit ExternalErc20AwardRemoved(\\_externalErc20);\\n}\\n```\\n\\n```\\nfunction removeExternalErc721Award(address \\_externalErc721, address \\_prevExternalErc721) external onlyOwner {\\n  externalErc721s.removeAddress(\\_prevExternalErc721, \\_externalErc721);\\n  delete externalErc721TokenIds[\\_externalErc721];\\n  emit ExternalErc721AwardRemoved(\\_externalErc721);\\n}\\n```\\n\\nthe `PeriodicPrizeStrategy` `owner` (also see concerns outlined in issue 5.4) can transfer external ERC20 at any time to avoid them being awarded to users. there is no guarantee to the user.\\n```\\nfunction transferExternalERC20(\\n  address to,\\n  address externalToken,\\n  uint256 amount\\n)\\n  external\\n  onlyOwner\\n{\\n  prizePool.transferExternalERC20(to, externalToken, amount);\\n}\\n```\\n
The underlying issue is that users of the system can't be sure what the behavior of a function call will be, and this is because the behavior can change at any time.\\nWe recommend giving the user advance notice of changes with a time lock. For example, make all system-parameter and upgrades require two steps with a mandatory time window between them. The first step merely broadcasts to users that a particular change is coming, and the second step commits that change after a suitable waiting period. This allows users that do not accept the change to withdraw immediately.
```\\nfunction setNumberOfWinners(uint256 count) external onlyOwner {\\n  \\_\\_numberOfWinners = count;\\n\\n  emit NumberOfWinnersSet(count);\\n}\\n```\\n