You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Jan 12, 2025. It is now read-only.
Users can't vote due to permanent BribeRewarder__NotOwner DoS
Summary
Users can't vote due to permanent BribeRewarder__NotOwner DoS
Vulnerability Detail
In scenario where user has mlum staking position and wants to vote in current period, he executes Voter::vote. Trough vote execution Voter::_notifyBribes is called to deposit the deltaAmounts into BribeRewarder.
function vote(uint256tokenId, address[] calldatapools, uint256[] calldatadeltaAmounts) external {
.....
for (uint256 i =0; i < pools.length; ++i) {
.....
_notifyBribes(_currentVotingPeriodId, pool, tokenId, deltaAmount); // msg.sender, deltaAmount);
}
.....
}
function _notifyBribes(uint256periodId, addresspool, uint256tokenId, uint256deltaAmount) private {
.....
for (uint256 i =0; i < rewarders.length; ++i) {
.....
rewarders[i].deposit(periodId, tokenId, deltaAmount);
.....
}
}
It is intended that onlyVoter is able(be the msg.sender) to execute BribeRewarder::deposit, but after that _modify is executed and checks if the current msg.sender is owner of the tokenId. There is no way for Voter to be the owner of the token so the deposit function will revert every time it is called.
function deposit(uint256periodId, uint256tokenId, uint256deltaAmount) public onlyVoter {
_modify(periodId, tokenId, deltaAmount.toInt256(), false);
emitDeposited(periodId, tokenId, _pool(), deltaAmount);
}
modifier onlyVoter() {
_checkVoter();
_;
}
function _checkVoter() internalviewvirtual {
if (msg.sender!=address(_caller)) {
revertBribeRewarder__OnlyVoter();
}
}
function _modify(uint256periodId, uint256tokenId, int256deltaAmount, boolisPayOutReward)
privatereturns (uint256rewardAmount)
{
if (!IVoter(_caller).ownerOf(tokenId, msg.sender)) {
revertBribeRewarder__NotOwner();
}
.....
}
function claim(uint256 tokenId) external override {
uint256 endPeriod = IVoter(_caller).getLatestFinishedPeriod();
uint256 totalAmount;
// calc emission per period cause every period can every other durations
for (uint256 i = _startVotingPeriod; i <= endPeriod; ++i) {
+++ if (!IVoter(_caller).ownerOf(tokenId, msg.sender)) {+++ revert BribeRewarder__NotOwner();+++ }
totalAmount += _modify(i, tokenId, 0, true);
}
emit Claimed(tokenId, _pool(), totalAmount);
}
sherlock-admin4
changed the title
Stable Grape Panda - Users can't vote due to permanent BribeRewarder__NotOwner DoS
radin200 - Users can't vote due to permanent BribeRewarder__NotOwner DoS
Jul 29, 2024
radin200
High
Users can't vote due to permanent
BribeRewarder__NotOwner
DoSSummary
Users can't vote due to permanent
BribeRewarder__NotOwner
DoSVulnerability Detail
In scenario where user has mlum staking position and wants to vote in current period, he executes
Voter::vote
. Trough vote executionVoter::_notifyBribes
is called to deposit the deltaAmounts into BribeRewarder.It is intended that onlyVoter is able(be the msg.sender) to execute
BribeRewarder::deposit
, but after that _modify is executed and checks if the current msg.sender is owner of the tokenId. There is no way for Voter to be the owner of the token so the deposit function will revert every time it is called.Impact
Permanent voting DoS, due to bad validation
Code Snippet
https://github.com/sherlock-audit/2024-06-magicsea/blob/42e799446595c542eff9519353d3becc50cdba63/magicsea-staking/src/rewarders/BribeRewarder.sol#L264-L266
Tool used
Manual Review
Recommendation
BribeRewarder::deposit
anyway.BribeRewarder::claim
before callingBribeRewarder::_modify
Duplicate of #39
The text was updated successfully, but these errors were encountered: