Some functionalities would often revert, due to protocol's assumption that the amount specified in a transfer is directly what's been received
Audit: 2024-06-renzo-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/Renzo-Protocol/Contracts/blob/74a6c9963d4e9359c542901fdd2dd3f5a6864f16/contracts/Delegation/OperatorDelegator.sol#L139


# Vulnerability details



## Proof of Concept

In multiple instances, protocol directly transfers out tokens that were received or in some instances the "exact difference", however this would be problematic for tokens that have features similar to `fee on transfer`, protocol does not support any fee on transfer tokens, however protocol does support the `stETH` token. And the `stETH` token has a special feature when being transferred, quotig lido's offiicial docs from here: https://docs.lido.fi/guides/lido-tokens-integration-guide/#1-2-wei-corner-case, quoting them:

> stETH balance calculation includes integer division, and there is a common case when the whole stETH balance can't be transferred from the account while leaving the last 1-2 wei on the sender's account. The same thing can actually happen at any transfer or deposit transaction. In the future, when the stETH/share rate will be greater, the error can become a bit bigger. To avoid it, one can use `transferShares` to be precise.

Now before diving deep to this issue, I'd like to indicate that this is not the same as the [controversial issue](https://github.com/code-423n4/2024-04-renzo-findings/issues/10) from the previous contest around the DOS of the depositing/withdrawing channel due to the usage of `safeApprove()` on the `stETH` asset. After some research and with the help of other wardens that bug case is indeed invalid, cause whenever a transfer is being made on the `stETH` asset, the allowance specified in the function call first gets engulfed even if the transferred amount end up being 1-2 wei less, this is because in a `transferFrom()` call the entire allowance gets used up via `_spendAllowance` before attempting the transfer, see https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code:

```solidity
    function transferFrom(address _sender, address _recipient, uint256 _amount) external returns (bool) {
        _spendAllowance(_sender, msg.sender, _amount);
        _transfer(_sender, _recipient, _amount);
        return true;
    }
```

However the `stETH` token's transfer mechanism is still special as [documented by Lido](https://docs.lido.fi/guides/lido-tokens-integration-guide/#1-2-wei-corner-case) and also we can confirm this from the contract code on Etherscan: https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code:
Whenever a transfer is to be executed the function below is called:

```solidity
    function getSharesByPooledEth(uint256 _ethAmount) public view returns (uint256) {
        return _ethAmount
            .mul(_getTotalShares())
            .div(_getTotalPooledEther());
    }
```

This function, rounds down the amount to be returned by 1.

And when the final transfer is done this `- 1` would be reflected in the amount that's received, i.e:

```solidity

    function