# Non-functional vote() if there is one bribe rewarder for this pool

BribeRewarder.deposit() checks msg.sender owns the NFT, but the Voter contract calls it, so vote() reverts for any pool with a bribe rewarder.

- Payout: Contest reward
- Severity: high
- Program: Magicsea
- Credited: 0uts1der
- Disclosed: 2024-07-15
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2024-06-magicsea-judging/issues/39
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-06-magicsea%3AH-1
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic vuln:governance

**Target:** Voter/BribeRewarder staking contracts
**Root cause:** BribeRewarder._modify() enforces IVoter.ownerOf(tokenId, msg.sender), but deposit() is invoked by the Voter contract, so msg.sender is the Voter, not the NFT owner.
**Steps:**
1. Alice creates a position (NFT tokenId=1) and stakes in mlum
2. Alice funds a bribe rewarder for pool via fundAndBribe(1,2,10e18)
3. DEV calls _voter.startNewVotingPeriod()
4. Alice calls _voter.vote(1, _getDummyPools(), _getDeltaAmounts())
5. Voter._notifyBribes calls rewarder.deposit(periodId, tokenId, deltaAmount)
6. _modify() calls IVoter(_caller).ownerOf(tokenId, msg.sender) where msg.sender=Voter, reverts BribeRewarder__NotOwner
**How found:** Code reading of vote() -> _notifyBribes() -> BribeRewarder.deposit() -> _modify() revealed the owner check uses msg.sender, which is the Voter contract during bribe notification rather than the NFT owner.
**Insight:** When a contract calls a rewarder on behalf of a user, any ownerOf(tokenId, msg.sender) style check inside the callee will see the intermediary contract as msg.sender; trace msg.sender through every internal call path, not just the entrypoint.
