# Rewards cannot be withdrawn

IncentiveDistribution.withdrawReward indexes accruedReward by msg.sender (the incentive reporter) instead of the trader recipient, so no trader can ever withdraw earned rewards.

- Payout: Audit contest
- Severity: high
- Program: Marginswap
- Disclosed: 2021-05-03
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2021-04-marginswap-findings/issues/26
- Library page: https://bugbountylibrary.com/r/c4%3A2021-04-marginswap%3AH-08
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** IncentiveDistribution.sol reward withdrawal function
**Root cause:** Rewards are accrued under the trader's address in accruedReward[recipient], but withdrawReward reads accruedReward[msg.sender] and additionally requires msg.sender to be the incentive reporter, an address that is never the trader.
**Steps:**
1. Trader accrues rewards via updateAccruedReward, stored in `accruedReward[recipient]` keyed by the trader account.
2. Trader calls `withdrawReward`; function checks `isIncentiveReporter(msg.sender)` and reads `accruedReward[msg.sender]`.
3. Since msg.sender is the trader, not the incentive reporter, the check reverts and the balance lookup targets the wrong key.
4. Result: no trader can withdraw; rewards remain permanently locked.
**How found:** Code review of the reward accounting: noticed the accrual mapping is keyed by recipient (trader) while the withdrawal path uses msg.sender and an incentive-reporter-only guard, making the two paths inconsistent.
**Insight:** When a contract stores balances keyed by a beneficiary, verify every read/write path uses that same key; a msg.sender-based access guard on a withdrawal function is a red flag that the caller and the beneficiary are conflated.

