During block reorgs, malicious user can grief unsuspecting stakers by frontrunning the deployment of surrogate contract, resulting in delegatee not having any votes.
Audit: 2024-02-uniswap-foundation-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-02-uniswap-foundation/blob/491c7f63e5799d95a181be4a978b2f074dc219a5/src/UniStaker.sol#L605-L616


# Vulnerability details

## Impact

Delegatees will not get their votes.

## Proof of Concept

UNI token has a function called delegate, which gives the delegatee votes for governance.

```
UNI token: https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code

    /**
     * @notice Delegate votes from `msg.sender` to `delegatee`
     * @param delegatee The address to delegate votes to
     */
    function delegate(address delegatee) public {
        return _delegate(msg.sender, delegatee);
    }

    function _delegate(address delegator, address delegatee) internal {
        address currentDelegate = delegates[delegator];
        uint96 delegatorBalance = balances[delegator];
        delegates[delegator] = delegatee;

        emit DelegateChanged(delegator, currentDelegate, delegatee);

        _moveDelegates(currentDelegate, delegatee, delegatorBalance);
    }
```

When a user stakes token into UniStaker.sol, a surrogate contract will be deployed (if it is not yet created) and the UNI tokens will be transferred to the surrogate contract. When deploying the surrogate contract, the constructor will call `_token.delegate(_delegatee);`.

```
  function _stake(address _depositor, uint256 _amount, address _delegatee, address _beneficiary)
    internal
    returns (DepositIdentifier _depositId)
  {
    _revertIfAddressZero(_delegatee);
    _revertIfAddressZero(_beneficiary);


    _checkpointGlobalReward();
    _checkpointReward(_beneficiary);


>   DelegationSurrogate _surrogate = _fetchOrDeploySurrogate(_delegatee);
    ...
    ...
>   _stakeTokenSafeTransferFrom(_depositor, address(_surrogate), _amount);
```

Note that if the surrogate contract is already deployed, then the UNI tokens will just be transferred to the surrogate contract but `delegate()` will not be called.

```
  constructor(IERC20Delegates _token, address _delegatee) {
    _token.delegate(_delegatee);
    _token.approve(msg.sender, type(uint256).max);
  }
```

This is how the DelegationSurrogate contract is created, using the STAKE_TOKEN, which is UNI, and the `_delegatee`, which is a user input.

```
  function _fetchOrDeploySurrogate(address _delegatee)
    internal
    returns (DelegationSurrogate _surrogate)
  {
    _surrogate = surrogates[_delegatee];


    if (address(_surrogate) == address(0)) {
>     _surrogate = new DelegationSurrogate(STAKE_TOKEN, _delegatee);
      surrogates[_delegatee] = _surrogate;
      emit SurrogateDeployed(_delegatee, address(_surrogate));
    }
```

In the event of a block reorganization, a malicious user can grief an unsuspecting staker by creating the surrogate contract for him.

- Bob the staker attempts to stake 10000 UNI tokens and chooses himself as a delegatee. 
- Malicious Alice notice that there is a block reorg.
- Malicious Alice stakes 1 wei of UNI tokens and chooses Bob as