xanoutas/solidity-security-findings huggingface dataset:
The broker should not be fully disabled by GnosisTrade.reportViolation
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/plugins/trading/GnosisTrade.sol#L202
https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/Broker.sol#L119-L123


# Vulnerability details

## Impact
GnosisTrade and DutchTrade are two separate auction systems where the failing of either system should not affect the other one. The current design will have `Broker.sol` disabled when `reportViolation` is invoked by `GnosisTrade.settle()` if the auction's clearing price was below what we assert it should be.

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/plugins/trading/GnosisTrade.sol#L202

```solidity
                broker.reportViolation();
```
https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/Broker.sol#L119-L123

```solidity
    function reportViolation() external notTradingPausedOrFrozen {
        require(trades[_msgSender()], "unrecognized trade contract");
        emit DisabledSet(disabled, true);
        disabled = true;
    }
```
Consequently, both `BackingManager` and `RevenueTrader (rsrTrader and rTokenTrader)` will not be able to call `openTrade()`: 

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/Broker.sol#L97-L98

```soliidty
    function openTrade(TradeKind kind, TradeRequest memory req) external returns (ITrade) {
        require(!disabled, "broker disabled");
        ...
```
till it's resolved by the governance:

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/Broker.sol#L180-L183

```solidity
    function setDisabled(bool disabled_) external governance {
        emit DisabledSet(disabled, disabled_);
        disabled = disabled_;
    }
```
## Proof of Concept
The following `Trading.trytrade()` as inherited by `BackingManager` and `RevenueTrader` will be denied on line 121, deterring recollaterization and boosting of Rtoken and stRSR exchange rate. The former deterrence will have [`Rtoken.redeemTo`](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/RToken.sol#L190) and [`StRSR.withdraw`](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L335) (both [requiring](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/RToken.sol#L190) [`fullyCollateralized`](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L335)) denied whereas the latter will have the Rtoken and stRSR holders divested of intended gains.  

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/mixins/Trading.sol#L113-L126

```solidty
    function tryTrade(Tra
Loss of staking yield for stakers when another user stakes in pause/frozen state
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L222-L232


# Vulnerability details

## Impact
Loss of staking yield for stakers when another user stakes in pause/frozen state.

## Proof of Concept
Issue [#148 from previous audit](https://github.com/code-423n4/2023-01-reserve-findings/issues/148) is present again.
As i can see it was mitigated. But maybe after that new code changes were made, so this issue is present again.

## Tools Used
VsCode
## Recommended Mitigation Steps
In case if you can't call `payoutRewards` when frozen, then do not allow to call stake as well.


## Assessed type

Error
In case when not all RSR was sold on auction users can loose it
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L416-L469
https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/BackingManager.sol#L149-L152
https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/BackingManager.sol#L205-L208


# Vulnerability details

## Impact
In case when not all RSR was sold on auction users can loose it, if era was changed for them.
## Proof of Concept
The purpose of StRSR stakers is to provide RSR tokens, that can back system in case if not enough collateral is present. During rebalance, `BackingManager` [can seize funds from StRSR](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/BackingManager.sol#L151). 
It's possible that the sum that is needed [will make new era begin](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L437-L460), which means that user don't have any stRSR anymore.

But also it's possible that not all amount of RSR will be traded by Gnosis auction, so as result BackingManager will contain RSR, that [will be returned back to StRSR](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/BackingManager.sol#L205-L208).

The problem is that this amount will not be returned to the stakers who were seized, it will be returned to another era stakers. As result old era stakers lost their funds, while new era stakers received more funds.
## Tools Used
VsCode
## Recommended Mitigation Steps
Maybe it's possible to track era that was seized in order to return funds to the stakers of that era, so they can claim them according to their StRSR or drafts in that era.


## Assessed type

Error
User who stakes into StRSRVotes doesn't have any voting power
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSRVotes.sol#L139-L151


# Vulnerability details

## Impact
User who stakes into StRSRVotes doesn't have any voting power. This is not intuitive clear and user who thinks that he can vote, actually will not be able until he will delegate votes to himself.

## Proof of Concept
`StRSRVotes` contract extends `StRSR` which [has `stake` function](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L222-L232) that allows user to get StRSR.
`StRSRVotes` extends `StRSR` with voting power that can be used by staker in governance voting.
In case if user use `stake` function, then StRSR will be minted for him, and then [`_afterTokenTransfer` hook will be called](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSRVotes.sol#L163-L170), which will not create any checkpoint for user, because he has no delegatee right now.

So as result, when user would like to vote, he will find out, that he actually [has no voting power](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSRVotes.sol#L71-L74), even that he has a lot of stRSR. And in order to receive that voting power he will need to delegate his stRSR to himself and only from that block he will be able to vote.

I believe that this is incorrect, because `StRSRVotes` also [stores and updates total supply checkpoints](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSRVotes.sol#L153-L161), which will be definitely used to see voting ratio: `casted votes / total supply of era`.
But because, when user stakes this votes are not written to his checkpoint, that means this voting power will not be possible to use and they should not be counted in total supply for some cases(until this voting power is delegated to someone).

Example.
1.User stakes a lot of RSR through `stake`, such that now he has 20% of voting power.
2.On block 10 proposal is created. Threshold for voting is 81%.
3.This proposal can never be passed, because even if staker wants, he can't vote for it, because his checkpoint will be created for later block, then proposal creation.
## Tools Used
VsCode
## Recommended Mitigation Steps
I believe that you should override `stake` function to do exactly what `stakeAndDelegate` does.


## Assessed type

Error
StRSR.cancelUnstake doesn't call _payoutRewards before minting new shares
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L341-L380


# Vulnerability details

## Impact
StRSR.cancelUnstake doesn't call _payoutRewards before minting new shares. As result this rewards will be distributed for new staker as well.

## Proof of Concept
If user wants to cancel his withdraw, then he can call `StRSR.cancelUnstake` and [mint new shares](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L379) from the RSR amount he wanted to withdraw. This minting will [use current `stakeRate`](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L694) to find out stRSR amount to mint.

The problem is that `_payoutRewards` function is not called before minting. It should be because, this function increases `stakeRSR` param with rewards, which then [changes `stakeRate`](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L586-L588).

As result user that decided to cancel withdraw will receive part of rewards which he should not receive.
## Tools Used
VsCode
## Recommended Mitigation Steps
Call `_payoutRewards`, before minting new stRSR to user.


## Assessed type

Error
RecollateralizationLibP1.basketRange calculates deficit incorrectly
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/mixins/RecollateralizationLib.sol#L240


# Vulnerability details

## Impact
RecollateralizationLibP1.basketRange calculates deficit incorrectly. so recollateralization may be not efficient.

## Proof of Concept
`RecollateralizationLibP1.basketRange` calculates `range.bottom` for pessimistic case.
https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/mixins/RecollateralizationLib.sol#L225-L246
```solidity
            {
                // {tok} = {tok/BU} * {BU}
                uint192 anchor = ctx.quantities[i].mul(ctx.basketsHeld.bottom, FLOOR);


                // (1) Sell tokens at low price
                // {UoA} = {UoA/tok} * {tok}
                uint192 val = low.mul(bal - anchor, FLOOR);


                // (2) Lose minTradeVolume to dust (why: auctions can return tokens)
                // Q: Why is this precisely where we should take out minTradeVolume?
                // A: Our use of isEnoughToSell always uses the low price (lotLow, technically),
                //   so min trade volumes are always assesed based on low prices. At this point
                //   in the calculation we have already calculated the UoA amount corresponding to
                //   the excess token balance based on its low price, so we are already set up
                //   to straightforwardly deduct the minTradeVolume before trying to buy BUs.
                val = (val < ctx.minTradeVolume) ? 0 : val - ctx.minTradeVolume;


                // (3) Buy BUs at their high price with the remaining value
                // (4) Assume maximum slippage in trade
                // {BU} = {UoA} * {1} / {UoA/BU}
                range.bottom += val.mulDiv(FIX_ONE.minus(ctx.maxTradeSlippage), buPriceHigh, FLOOR);
            }
```
It checks that asset has more value than needed to cover `ctx.basketsHeld.bottom` and calculates `val` amount that can be used to sell and increase `range.bottom`.
Because reserve protocol doesn't want to trade dust this line is used: 
`val = (val < ctx.minTradeVolume) ? 0 : val - ctx.minTradeVolume`

The problem is that in case if `val` is not dust, then only `val - ctx.minTradeVolume` is used instead of whole `val` which is incorrect and may affect recollateralization.

## Tools Used
VsCode
## Recommended Mitigation Steps
Change to this:
`val = (val < ctx.minTradeVolume) ? 0 : val`


## Assessed type

Error
StRSR.withdraw can be blocked
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L336


# Vulnerability details

## Impact
StRSR.withdraw can be blocked for user by changing basket's asset to IFFY status. User will not be able to withdraw and his funds can be seized later.

## Proof of Concept
`StRSR.withdraw` function allows user to withdraw only, [when `basketHandler.isReady()`](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#L336). And `assetRegistry.refresh` will not be called each `StRSR.withdraw` call, [because of `leakyRefresh`](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/StRSR.sol#LL330C9-L330C21).

`basketHandler.isReady()` will be true, only [when status is sound and enough time has passed, since status change](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/BasketHandler.sol#L263-L264).
Each time `status` function is called, it [checks the worst status of all assets that are in basket currently](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/BasketHandler.sol#L254-L257).

So it's enough to have at least one iffy asset in basket, to make `isReady` to be false.
This can be easily done by attacker.
Let's check `FiatCollateral` as example.
There is `refresh` function, that can be called by anyone, which is [trying to call oracle](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/plugins/assets/FiatCollateral.sol#L127) and get asset price.
In case if error was catched during the call, then status of asset [will be marked as iffy](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/plugins/assets/FiatCollateral.sol#L151).
So in order to make this asset to be iffy, attacker can call `refresh` function with amount of gas that is not enough to execute oracle call, but is enough to set status to iffy inside catch.

As result, after changing asset's status to iffy, basket handler is not ready anymore, which means that StRSR.withdraw will fail, when there is no asset registry refresh.
So attacker can frontrun user's withdraw in order to block it. He can do that as many times as he wishes. As result user who wanted to leave may be seized.

## Tools Used
VsCode
## Recommended Mitigation Steps
The way you can solve it depends on if asset's code is something that you can control. If yes, then i would recommend to allow refresh assets only for asset registry.
Otherwise, you should refresh registry for each withdraw in StRSR.


## Assessed type

Error
AssetRegistry.swapRegistered can be called with low gas to make basket be disabled
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/AssetRegistry.sol#L86-L115


# Vulnerability details

## Impact
Attacker can disable basket, when swapping or unregistering not basket asset.

## Proof of Concept
AssetRegistry.swapRegistered and AssetRegistry.unregister are both functions that can be called by governance only. It's possible that after proposal is passed, then it can be executed by anyone. Also executor can provide as much gas with the call, as he wishes.

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/AssetRegistry.sol#L86-L96
```solidity
    function swapRegistered(IAsset asset) external governance returns (bool swapped) {
        require(_erc20s.contains(address(asset.erc20())), "no ERC20 collision");


        try basketHandler.quantity{ gas: _reserveGas() }(asset.erc20()) returns (uint192 quantity) {
            if (quantity > 0) basketHandler.disableBasket(); // not an interaction
        } catch {
            basketHandler.disableBasket();
        }


        swapped = _registerIgnoringCollisions(asset);
    }
```

Here, reserve team is checking that after `basketHandler.quantity` call, function still has 900000 gas, which is needed to finish `basketHandler.disableBasket` call.
As you can see, in case if quantity of asset in the basket is 0, then there is no need to disable basket.

However, malicious user still can do that.
What he need to do is to call `swapRegistered` with 900000 + x gas amount. Where x will be the amount that is not enough to execute `basketHandler.quantity` function, which will cause out of gas error and catch block will then call `basketHandler.disableBasket`. As result basket will be disabled if attacker wants it.

## Tools Used
VsCode
## Recommended Mitigation Steps
You need to ensure that you send enough gas to `basketHandler.quantity` function.





## Assessed type

Error
In case Distributor.setDistribution use, revenue from rToken RevenueTrader and rsr token RevenueTrader should be distributed
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/Distributor.sol#L61-L65


# Vulnerability details

## Impact
In case Distributor.setDistribution use, revenue from rToken RevenueTrader and rsr token RevenueTrader should be distributed. Otherwise wrong distribution will be used.
## Proof of Concept
`BackingManager.forwardRevenue` function sends revenue amount to the `rsrTrader` and `rTokenTrader` contracts, [according to the distribution inside `Distributor` contract](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/BackingManager.sol#L236-L249). For example it can 50%/50%. In case if we have 2 destinations in Distributor: strsr and furnace, that means that half of revenue will be received by strsr stakers as rewards.

This distribution [can be changed](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/Distributor.sol#L61-L65) at any time.
The job of `RevenueTrader` is to sell provided token for a `tokenToBuy` and then distribute it using `Distributor.distribute` function. There are 2 ways of auction that are used: dutch and gnosis. Dutch auction will call `RevenueTrader.settleTrade`, which [will initiate distribution](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/RevenueTrader.sol#L50). But Gnosis trade will not do that and user should call `distributeTokenToBuy` manually, after auction is settled.

The problem that i want to discuss is next.
Suppose, that governance at the beginning set distribution as 50/50 between 2 destinations: strsr and furnace. And then later `forwardRevenue` sent some tokens to the rsrTrader and rTokenTrader. Then, when trade was active to exchange some token to rsr token, `Distributor.setDistribution` was set in order to make strsr share to 0, so now everything goes to Furnace only. As result, when trade will be finished in the rsrTrader and `Distributor.distribute` will be called, then those tokens will not be sent to the strsr contract, because their share is 0 now.
They will be stucked inside rsrTrader.

Another problem here is that strsr holders should receive all revenue from the time, where they distribution were created. What i mean is if in time 0, rsr share was 50% and in time 10 rsr share is 10%, then `BackingManager.forwardRevenue` should be called for all tokens that has surplus, because if that will be done after changing to 10%, then strsr stakers will receive less revenue.
## Tools Used
VsCode
## Recommended Mitigation Steps
You need to think how to guarantee fair distribution to the strsr stakers, when distribution params are changed.





## Assessed type

Error
GnosisTrade contract can be frontrunned in order to make it report violation and block broker
Audit: 2023-06-reserve-findings
Severity: MEDIUM

# Lines of code

https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/Broker.sol#L187-L209
https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/plugins/trading/GnosisTrade.sol#L87


# Vulnerability details

## Impact
GnosisTrade contract can be frontrunned in order to make it report violation and block broker. This will stop broker from creating another traders.

## Proof of Concept
When `BackingManager` is rebalancing, then it can open trade, [which can be gnosis trade auction](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/p1/Broker.sol#L187-L209). 

In this case new `GnosisTrade` is created using create opcode.
Note, it's possible to calculate address of next created contract by contract. Attacker needs to know address of creator and his nonce. 
So it's not hard for attacker to frontrun `BackingManager.rebalance` which will create `GnosisTrade` auction.
What attacker will do is top up that address with some small amount of `req.sell` token.

When `GnosisTrade` is initiated, then his [balance is stored to `initBal` variable](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/plugins/trading/GnosisTrade.sol#L87). And also `worstCasePrice` is calculated, which is `req.minBuyAmount/req.sellAmount`. This variable is used inside `settle` function to check that [gnosis executed auction with good price](https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/plugins/trading/GnosisTrade.sol#L201-L203).
https://github.com/reserve-protocol/protocol/blob/c4ec2473bbcb4831d62af55d275368e73e16b984/contracts/plugins/trading/GnosisTrade.sol#L162-L205
```solidity
    //   state' is CLOSED
    function settle()
        external
        stateTransition(TradeStatus.OPEN, TradeStatus.CLOSED)
        returns (uint256 soldAmt, uint256 boughtAmt)
    {
        require(msg.sender == origin, "only origin can settle");


        // Optionally process settlement of the auction in Gnosis
        if (!isAuctionCleared()) {
            // By design, we don't rely on this return value at all, just the
            // "cleared" state of the auction, and the token balances this contract owns.
            // slither-disable-next-line unused-return
            gnosis.settleAuction(auctionId);
            assert(isAuctionCleared());
        }


        // At this point we know the auction has cleared


        // Transfer balances to origin
        uint256 sellBal = sell.balanceOf(address(this));
        boughtAmt = buy.balanceOf(address(this));


        if (sellBal > 0) IERC20Upgradeable(address(sell)).safeTransfer(origin, sellBal);
        if (boughtAmt > 0) IERC20Upgradeable(address(buy)).safeTransfer(origin, boughtAmt);


        // Check clearing prices
        if (sellBal < initBal) {
            soldAmt = initBal - sellBal;