`_alterBeneficiary` would be used to abuse the reward accumulation. Same beneficiary can be swapped before any reward accumulation operation.
Audit: 2024-02-uniswap-foundation-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-02-uniswap-foundation/blob/5298812a129f942555466ebaa6ea9a2af4be0ccc/src/UniStaker.sol#L704-L718


# Vulnerability details

## Impact
A user who deposit or withdraw to claim reward will miss these rewards. This can be made deliberately by malicious user.

## Proof of Concept
https://github.com/code-423n4/2024-02-uniswap-foundation/blob/5298812a129f942555466ebaa6ea9a2af4be0ccc/src/UniStaker.sol#L704-L718

```solidity
  function _alterBeneficiary(
    Deposit storage deposit,
    DepositIdentifier _depositId,
    address _newBeneficiary
  ) internal {
    _revertIfAddressZero(_newBeneficiary);
    _checkpointGlobalReward();
    _checkpointReward(deposit.beneficiary);
    earningPower[deposit.beneficiary] -= deposit.balance;

    _checkpointReward(_newBeneficiary);
    emit BeneficiaryAltered(_depositId, deposit.beneficiary, _newBeneficiary);
    deposit.beneficiary = _newBeneficiary;
    earningPower[_newBeneficiary] += deposit.balance;
  }
```

As shown above the same beneficiary used to update as new one.

This can be done just before stake, claim or withdraw. So reward calculation will not accrue anything since the lackCheckPoint and lastewardTime is same.

Lets see this issue in detail.

https://github.com/code-423n4/2024-02-uniswap-foundation/blob/5298812a129f942555466ebaa6ea9a2af4be0ccc/src/UniStaker.sol#L645-L646

```solidity
    _checkpointGlobalReward();
    _checkpointReward(_beneficiary);
```

Current reward calculation depend on `lastCheckpointTime`. This is updated inside the function `_checkpointGlobalReward()`.

Lets see how this would impact the reward accumulation.

https://github.com/code-423n4/2024-02-uniswap-foundation/blob/5298812a129f942555466ebaa6ea9a2af4be0ccc/src/UniStaker.sol#L753-L756

```solidity
  function _checkpointGlobalReward() internal {
    rewardPerTokenAccumulatedCheckpoint = rewardPerTokenAccumulated();
    lastCheckpointTime = lastTimeRewardDistributed();
  }
```

`rewardPerTokenAccumulatedCheckpoint ` is computed using the function `rewardPerTokenAccumulated()`. 

Further the updated `lastCheckpointTime ` is the current_time. --->>> @@audit

`lastTimeRewardDistributed()` - returns the last updated reward time.

https://github.com/code-423n4/2024-02-uniswap-foundation/blob/5298812a129f942555466ebaa6ea9a2af4be0ccc/src/UniStaker.sol#L220-L223

```solidity
  function lastTimeRewardDistributed() public view returns (uint256) {
    if (rewardEndTime <= block.timestamp) return rewardEndTime;
    else return block.timestamp;
  }
``` 

when this function is called before the rewardEndTime, it would return the current time. ------>>> @@ audit

Now, lets see the function `_checkpointReward(_beneficiary)`.

https://github.com/code-423n4/2024-02-uniswap-foundation/blob/5298812a129f942555466ebaa6ea9a2af4be0ccc/src/UniStaker.sol#L764-L767

```solidity
  function _checkpointReward(address _beneficiary) internal {
    unclaimedRewardCheckpoint[_beneficiary] = unclaimedReward(