xanoutas/solidity-security-findings huggingface dataset:
In tokenomics,sol, anyone can become admin and can at the same time alter the values of all input paramaters of the initializeTokenomics() function.
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/main/tokenomics/contracts/Tokenomics.sol#L264-L318


# Vulnerability details

## Impact
This bug report is about a lack of access control checks on initializeTokenomics() functions used to configure the protocol during the deployment. An attacker could exploit this vulnerability by front-running the deployment process and call initializeTokenomics() function to set their own parameter. This could include setting arbitrary contract addresses and modifying intended ownerships. The affected contracts include 
Treasury.sol, Dispenser.sol, and Depository.sol,
The agent registry, component registry, service registry adresses are also affected. 

```
function initializeTokenomics(
        address _olas,
        address _treasury,
        address _depository,
        address _dispenser,
        address _ve,
        uint256 _epochLen,
        address _componentRegistry,
        address _agentRegistry,
        address _serviceRegistry,
        address _donatorBlacklist
    ) external
    {
        // Check if the contract is already initialized
        if (owner != address(0)) {
            revert AlreadyInitialized();
        }

        // Check for at least one zero contract address
        if (_olas == address(0) || _treasury == address(0) || _depository == address(0) || _dispenser == address(0) ||
            _ve == address(0) || _componentRegistry == address(0) || _agentRegistry == address(0) ||
            _serviceRegistry == address(0)) {
            revert ZeroAddress();
        }

        // Initialize storage variables
        owner = msg.sender;
        _locked = 1;
        epsilonRate = 1e17;
        veOLASThreshold = 10_000e18;

        // Check that the epoch length has at least a practical minimal value
        if (uint32(_epochLen) < MIN_EPOCH_LENGTH) {
            revert LowerThan(_epochLen, MIN_EPOCH_LENGTH);
        }

        // Check that the epoch length is not bigger than one year
        if (uint32(_epochLen) > ONE_YEAR) {
            revert Overflow(_epochLen, ONE_YEAR);
        }

        // Assign other input variables
        olas = _olas;
        treasury = _treasury;
        depository = _depository;
        dispenser = _dispenser;
        ve = _ve;
        epochLen = uint32(_epochLen);
        componentRegistry = _componentRegistry;
        agentRegistry = _agentRegistry;
        serviceRegistry = _serviceRegistry;
        donatorBlacklist = _donatorBlacklist;
```



## Tools Used
Manual review, VScode

## Recommended Mitigation Steps
The recommended mitigation for this vulnerability is to implement logic in the contract constructors to save the address of the owner/deployer of the contract and verify it in the initializeTokenomics() function, such as requiring that msg.sender == owner.


## Assessed type

Access Control
Changing the `quorumNumerator` should not be only possible by the governance
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/governance/lib/fx-portal/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol#L86-L88
https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/governance/lib/fx-portal/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol#L99-L119


# Vulnerability details

## Impact
Only the DAO can reduce the `quorumNumerator`. This means that if the participation for proposals in the DAO decreases below the `quorumNumerator`, there is no way to reduce the `quorumNumerator` so the DAO can start making decisions again.


## Proof of Concept

For a proposal to succeed a quorum needs to be reached meaning that a specific number of votes in favour of a proposal need to be casted. This number of forVotes is determined by the `quorumNumerator` which decides how many % of the exiting votes are needed for a proposal to pass. This `quorumNumerator` can be lowered only by the governance.
```java
    function updateQuorumNumerator(uint256 newQuorumNumerator) external virtual onlyGovernance {
        _updateQuorumNumerator(newQuorumNumerator);
    }
``` 

The issue arises when the participation in the governance decreases below this `quorumNumerator`. Since in such a case no new proposal will be passed, not even one that reduced the `quorumNumerator`, the DAO will not be able to pass any new proposals ever.

For example, if the `quorumNumerator` is set to 60% but only 50% of all existing votes take part in the governance, even if all votes vote in favour to reduce the `quorumNumerator`, the proposal will not pass since it misses to reach the current 60% of votes.

## Tools Used
Manual review


## Recommended Mitigation Steps
Add a function that allows the CM to change the `quorumNumerator` so this trusted multisig can reactivate the DAO by lowering the `quorumNumerator` in caste the participation rate has decreased below the current `quorumNumerator`.



## Assessed type

Governance
use of 0.8.20 
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/main/governance/contracts/GovernorOLAS.sol#L2


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

This is because solidity 0.8.20 introduces the PUSH0 (0x5f) opcode which is only supported on the ETH mainnet and not on any other chains. That's why other chains can't find the PUSH0 (0x5f) opcode and throw this error. Consider using 0.8.19 for other chains.

## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
pragma solidity ^0.8.20;

## Tools Used

## Recommended Mitigation Steps
That's why other chains can't find the PUSH0 (0x5f) opcode and throw this error. Consider using 0.8.19 for other chains.


## Assessed type

Other
Insufficient Fund Guard for Treasury Reward Rebalancing Due to Unrestricted Withdrawals
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/main/tokenomics/contracts/Treasury.sol#L443
https://github.com/code-423n4/2023-12-autonolas/blob/main/tokenomics/contracts/Treasury.sol#L402-L410


# Vulnerability details

## Impact
The potential issue identified in the `Treasury.rebalanceTreasury()`involves the risk of failing to transfer treasury rewards from `ETHFromServices` to `ETHOwned` due to insufficient funds in `ETHFromServices`. This situation can arise when the `withdrawToAccount` function, called by the dispenser contract, excessively depletes the `ETHFromServices` balance, leaving an insufficient amount for the annual reward rebalancing.

This can disrupt the intended economic mechanisms of the contract, potentially affecting the treasury's ability to accumulate and manage its rewards effectively. If left unaddressed, this could lead to financial discrepancies, undermining the contract's economic model.

## Proof of Concept
Here's a typical scenario:

1. `rebalanceTreasury()` is called by `Tokenomics.checkpoint()` typically once a year:

https://github.com/code-423n4/2023-12-autonolas/blob/main/tokenomics/contracts/Tokenomics.sol#L1063

```solidity
        if (incentives[1] == 0 || ITreasury(treasury).rebalanceTreasury(incentives[1])) {
```
2. It transfers a portion of the `ETHFromServices` (ETH collected from service donations) to `ETHOwned` (ETH owned by the treasury), which represents the treasury's share of the rewards.

https://github.com/code-423n4/2023-12-autonolas/blob/main/tokenomics/contracts/Treasury.sol#L441-L457

```solidity
        if (treasuryRewards > 0) {
            uint256 amountETHFromServices = ETHFromServices;
            if (amountETHFromServices >= treasuryRewards) {
                // Update ETH from services value
                amountETHFromServices -= treasuryRewards;
                // Update treasury ETH owned values
                uint256 amountETHOwned = ETHOwned;
                amountETHOwned += treasuryRewards;
                // Assign back to state variables
                ETHOwned = uint96(amountETHOwned);
                ETHFromServices = uint96(amountETHFromServices);
                emit UpdateTreasuryBalances(amountETHOwned, amountETHFromServices);
            } else {
                // There is not enough amount from services to allocate to the treasury
                success = false;
            }
        }
```
3. If (`amountETHFromServices >= treasuryRewards`) evaluates to false, the transfer of rewards from `ETHFromServices` to `ETHOwned` won't happen. This situation could arise if there's an insufficient amount of `ETHFromServices` compared to the `treasuryRewards` expected to be rebalanced.
4. This is primarily due to `Treasury.withdrawToAccount()` that allows the withdrawal of rewards to owners of components / agents. It is called by the `dispenser` contract and has the potential to reduce `ETHFromServices`, as it manages payouts to those owner accounts:

http
The Treasury.sol contract changes the address for the different manager contract in one function call.
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

 https://github.com/code-423n4/2023-12-autonolas/blob/main/tokenomics/contracts/Treasury.sol#L156-L167


# Vulnerability details

## Impact
In a case where either one of the manager addresses the tokenomics, depositiory or dispenser contracts are compromised or deprecated, attempting to replace the compromised manager contract address necessitates an overall replacement of all the other addresses. This not only aggravates the gas consumption of the protocol but will also bring about unnecessary proposal being made by governance for manager addresses which do not need a replacement.

And as such when changes is made to one manager contract, changes are also required for all manager contract addresses.

## Proof of Concept
In a situation whereby either of tokenomics, depository or dispenser contract becomes deprecated or compromised or updates needs to made due to issues in logic, changes need to be made for all contract addresess.

 For example, If the Tokenomics contract address needs to updated but the dispenser and depository contracts needs no update. 
Update to the Tokenomics contract will require additional updates to both the dispenser and depository contract address. 

1. This will require additional proposals being made for the replacement of the two other contracts which isn't needed from the onset.
2. This can also lead to wrong contract addresses being assigned to the other manager address that were not originally intended to be inputted by the owner of the contract.

```
  function changeManagers(address _tokenomics, address _depository, address _dispenser) external {
        // Check for the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        // Change Tokenomics contract address
        if (_tokenomics != address(0)) {
            tokenomics = _tokenomics;
            emit TokenomicsUpdated(_tokenomics);
        }
        // Change Depository contract address
        if (_depository != address(0)) {
            depository = _depository;
            emit DepositoryUpdated(_depository);
        }
        // Change Dispenser contract address
        if (_dispenser != address(0)) {
            dispenser = _dispenser;
            emit DispenserUpdated(_dispenser);
        }
    }
```


## Tools Used
Manual review, VSCODE

## Recommended Mitigation Steps
Different functions should be made available for the replacement of each manager addresses instead of just one function being used to replace all three managers all at once.





## Assessed type

Other
Signatures can be replayed to cast with castVoteWithReasonAndParamsBySig() more votes than the user intended in GovernorOLAS
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/fd81a96f01cc42ef1c9a5399364968d0e07e9e90/contracts/governance/Governor.sol#L524-L539
https://github.com/code-423n4/2023-12-autonolas/blob/main/governance/contracts/GovernorOLAS.sol#L14-L15


# Vulnerability details

## Impact

In the "GovernorOLAS.sol" contract, [as the comment line supports](https://github.com/code-423n4/2023-12-autonolas/blob/main/governance/contracts/GovernorOLAS.sol#L14) the OpenZeppelin functions are used as is. However, the inherited OpenZeppelin 4.8.3 library exposes a signature replay vulnerability due to the lack of use of nonce in the `castVoteWithReasonAndParamsBySig()` functions in "Governor.sol".

## Proof of Concept

-  Bob has 1000 votes, and he wants to split his votes between proposals A and B.
-  He signs one signature to give 500 votes to proposal A.
-  He signs a second signature to allocate 500 votes to proposal B.
- castVoteWithReasonAndParamsBySig() is called to submit Bob's first signature:
- This gives proposal A 500 votes.
- After the transaction is executed, Alice sees Bob's signature in the transaction.
- As Alice wants proposal A to be elected, she calls castVoteWithReasonAndParamsBySig() with Bob's first signature again:
- Due to a lack of a nonce, the transaction is executed successfully, giving proposal A another 500 votes.
- Now, when castVoteWithReasonAndParamsBySig() is called with Bob's second signature, it reverts as all his 1000 votes are already allocated to proposal A.
In the scenario above, Alice has managed to allocate all of Bob's votes to proposal A against his will.


Due to the lack of a nonce, `castVoteWithReasonAndParamsBySig()` can be called multiple times with the same signature.

Therefore, if a user provides a signature to use a portion of his votes, an attacker can repeatedly call `castVoteWithReasonAndParamsBySig()` with the same signature to use up more votes than the user originally intended. 

You can also check out this report for the same finding: https://github.com/code-423n4/2023-08-arbitrum-findings/issues/252

## Tools Used

Manual Review

## Recommended Mitigation Steps

Consider adding signature replay protection to the `castVoteWithReasonAndParamsBySig()` function using nonce. You can also use the latest version of Openzeppelin, [which has the nonce feature already added.](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v5.0/contracts/governance/Governor.sol#L577-L608)






## Assessed type

Library
Depository.sol#L291 : Lack of slippage protection when deposit tokens in exchange for a bond from a specified product
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Depository.sol#L291-L346


# Vulnerability details

## Impact
Lack of slippage protection for an user from minting the OLAs for the given token amount. When the price fluctuation is high, user would suffer with huge loss.

## Proof of Concept
`Depository` contract would be used to create a product and for a particular token.
owner creates the product with following parameters.

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Depository.sol#L44-L57

```solidity
struct Product {
    // priceLP (reserve0 / totalSupply or reserve1 / totalSupply) with 18 additional decimals
    // priceLP = 2 * r0/L * 10^18 = 2*r0*10^18/sqrt(r0*r1) ~= 61 + 96 - sqrt(96 * 112) ~= 53 bits (if LP is balanced)
    // or 2* r0/sqrt(r0) * 10^18 => 87 bits + 60 bits = 147 bits (if LP is unbalanced)
    uint160 priceLP;
    // Bond vesting time
    // 2^32 - 1 is enough to count 136 years starting from the year of 1970. This counter is safe until the year of 2106
    uint32 vesting;
    // Token to accept as a payment
    address token;
    // Supply of remaining OLAS tokens
    // After 10 years, the OLAS inflation rate is 2% per year. It would take 220+ years to reach 2^96 - 1
    uint96 supply;
}
```
`priceLP` would be used to calculate OLAs payout to user for their token amount deposit.

User would call the [deposit](https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Depository.sol#L291) function to deposit the allowed token in exchange for the OLA token.

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Depository.sol#L318-L337

```solidity
        // Calculate the payout in OLAS tokens based on the LP pair with the discount factor (DF) calculation
        // Note that payout cannot be zero since the price LP is non-zero, otherwise the product would not be created
        payout = IGenericBondCalculator(bondCalculator).calculatePayoutOLAS(tokenAmount, product.priceLP);

        // Check for the sufficient supply
        if (payout > supply) {
            revert ProductSupplyLow(token, productId, payout, supply);
        }

        // Decrease the supply for the amount of payout
        supply -= payout;
        product.supply = uint96(supply);

        // Create and add a new bond, update the bond counter
        bondId = bondCounter;
        mapUserBonds[bondId] = Bond(msg.sender, uint96(payout), uint32(maturity), uint32(productId));
        bondCounter = uint32(bondId + 1);

        // Deposit that token amount to mint OLAS tokens in exchange
        ITreasury(treasury).depositTokenForOLAS(msg.sender, tokenAmount, token, payout);
```

Now, lets look at the `calculatePayoutOLAS` function which takes the `tokenAmount` and `priceLP` of the LP token.
changeRegistries() from the Tokenomics contract changes different registries at the same time.
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/main/tokenomics/contracts/Tokenomics.sol#L444-L469


# Vulnerability details

## Impact
In a case where either one of the agent, component or service registry are deprecated, attempting to replace the compromised registry necessitates an overall replacement of all the other registries. This not only utilizes excess gas but can also bring about unnecessary proposal being made by governance, because in a case whereby only one registry proposal needed to be made, proposal will need to be made for the other two registries. 


## Proof of Concept
In a situation whereby one of the registries becomes deprecated or needs to be updated due to issues in logic, for example let's say the component registry need to updated but the agent and service registry are still up to per in terms of performance. 
Update to the component registry will require additional updates to the agent and service registry.
This will automatically lead to more gas being used to replace the agent and service registry which were not needed.
This will also lead to proposal being made for the replacement of two other registries which were not needed from the onset.
Below is the code showing the unorthodox replacement of the three registries all at once
```
   function changeRegistries(address _componentRegistry, address _agentRegistry, address _serviceRegistry) external {
        // Check for the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        // Check for registries addresses
        if (_componentRegistry != address(0)) {
            componentRegistry = _componentRegistry;
            emit ComponentRegistryUpdated(_componentRegistry);
        }
        if (_agentRegistry != address(0)) {
            agentRegistry = _agentRegistry;
            emit AgentRegistryUpdated(_agentRegistry);
        }
        if (_serviceRegistry != address(0)) {
            serviceRegistry = _serviceRegistry;
            emit ServiceRegistryUpdated(_serviceRegistry);
        }
    }
```


## Tools Used
Manual review, VSCODE

## Recommended Mitigation Steps
Different functions should be made available for the replacement of each registry instead of just one function be used to replace all three registries all at once.





## Assessed type

Other
Frequent donations can cause DOS
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Tokenomics.sol#L892-L893


# Vulnerability details

## Impact
User's might be unable to withdraw pending rewards

## Proof of Concept
If a donation is made before the `checkpoint()` call in the same block, the `checkpoint` call will revert. This is done in order to prevent flash loans. 

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Tokenomics.sol#L892-L893
```solidity
    function checkpoint() external returns (bool) {
       
        ......

        // Check the last donation block number to avoid the possibility of a flash loan attack
        if (lastDonationBlockNumber == block.number) {
            revert SameBlockNumberViolation();
        }
```

But such a scenario may occur else-wise due to the following:
1. High activity and lot of donations
2. Attacker griefing

Griefing for time can be done by an attacker without much loss if the `rewardTreasuryFraction` is set to 0 by donating to the attacker's own addresses. Although permenant locking is not costwise expected from the attacker, a special case scenario ie. when the current epochLength is close to 1 year, can motivate an attacker to extend the checkpoint call beyond 1 year after which the `checkpoint` call will always fail.

## Tools Used
Manual review

## Recommended Mitigation Steps
Making the `depositServiceDonationsETH` function pausable can guarantee safety


## Assessed type

DoS