xanoutas/solidity-security-findings huggingface dataset:
Swap Input Validation
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/MaxHeap.sol#L86


# Vulnerability details

Input Validation:

    - The swap function assumes that fpos and spos are valid positions within the heap. 
    - Ensure that you are providing valid positions, and consider adding checks to verify that fpos and spos are within the bounds of your heap.

require(fpos < size && spos < size, "Invalid positions provided");


## Assessed type

Invalid Validation
Anyone can initialize contract
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/CultureIndex.sol#L109


# Vulnerability details

The `initialize` function allows anyone to initialize the contract. This could enable an attacker to gain ownership of the contract by initializing it before the owner does.

**Recommendation**: Only allow the contract owner/admin to initialize.

```diff
function initialize(/* params */) public initializer {

-  // No access control 

+  require(msg.sender == owner() || msg.sender == admin, "Only authorized");
   
   // Init logic
}
```



## Assessed type

Access Control
Input Validation
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/MaxHeap.sol#L78


# Vulnerability details

Your require statement checks that pos is not equal to 0, which is a good check to ensure that you don't attempt to find the parent of the root node.
However, you might also want to check if pos is an even number (assuming the binary tree structure is zero-indexed), as odd-numbered positions should not have a left child. This additional check can further improve the safety of the function.

require(pos != 0, "Position should not be zero");
require(pos % 2 == 0, "Position should be an even number");




## Assessed type

Invalid Validation
Missing slippage protection in vote weight calculations
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/CultureIndex.sol#L284


# Vulnerability details

The `_calculateVoteWeight` function calculates a voter's vote weight based on their ERC20 and ERC721 token balances. However, there are no checks to prevent manipulations of the vote weight through rapid changes in token balance. 

This could enable an attack where an attacker rapidly acquires voting tokens before a vote, casts their vote, and then dumps the tokens afterwards.

**Recommendation**: Implement min/max checks on vote weight based on historical voting power.

```diff
function _calculateVoteWeight(uint256 erc20Balance, uint256 erc721Balance) internal view returns (uint256) {

+   // Fetch historical erc20 vote weight
+   uint256 historicalERC20Weight = getPastVotes(msg.sender, 2); // 2 blocks ago

+   // 10% max vote weight slippage allowed
+   uint256 minWeight = historicalERC20Weight - (historicalERC20Weight / 10);
+   uint256 maxWeight = historicalERC20Weight + (historicalERC20Weight / 10);

+   // Apply slippage check
+   if (erc20Balance < minWeight || erc20Balance > maxWeight) {
+     revert("Vote weight slippage check failed"); 
+   }

   return erc20Balance + (erc721Balance * erc721VotingTokenWeight * 1e18); 
 }
```



## Assessed type

Invalid Validation
THE `AuctionHouse.renounceOwnership` IS NOT OVERRIDDEN TO REVERT IN THE EVENT IT IS CALLED THUS PUTTING THE CONTRACT IN DANGER OF GETTING DoS
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/AuctionHouse.sol#L34
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/AuctionHouse.sol#L39-L46


# Vulnerability details

## Impact

The `AuctionHouse.sol` contract inherits from the `Ownable2StepUpgradeable.sol` contract for its ownerhsip related implementation. The `Ownable2StepUpgradeable` inherits from the `OwnableUpgradeable.sol` contract which has the `renounceOwnership` function as shown below:

    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

But this `renounceOwnership` is not overridden in the `AuctionHouse` function to `revert` in the event it is being called. Hence if an owner address is compramised or owner acts maliciously he can renounce the ownership of the contract thus DoS the `onlyOwner` controlled functions in hte `AuctionHosue` contract thus breaking the expected contract functionality.

## Proof of Concept

```solidity
import { Ownable2StepUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
```

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/AuctionHouse.sol#L34

```solidity
contract AuctionHouse is
    IAuctionHouse,
    VersionedContract,
    UUPS,
    PausableUpgradeable,
    ReentrancyGuardUpgradeable,
    Ownable2StepUpgradeable
{
```

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/AuctionHouse.sol#L39-L46

## Tools Used
Manual Review and VSCode

## Recommended Mitigation Steps

Hence it is recommended to override the `renounceOwnership` function inside the `AuctionHouse.sol` contract to revert in the event it is called as shown below:

    function renounceOwnership() public override onlyOwner {
        revert;
    }


## Assessed type

Access Control
`reservePrice` can be changed during ongoing auction
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/AuctionHouse.sol#L287-L291
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/AuctionHouse.sol#L348-L356


# Vulnerability details

## Impact

The `reservePrice` parameter can be changed during an ongoing auction, this can cause problems as if the owner sets this parameter to be greater than the current auction contract ETH balance this will lead to the burning of the auctionned token which was supposed to go to the highest bidder of the ongoing auction.

## Proof of Concept

The issue can arise because the owner can change the `reservePrice` parameter during an ongoing auction by calling `setReservePrice`.

If the owner sets the `reservePrice` to be greater than the current auction contract ETH balance then even if the highest bidder bid was greater than the previous `reservePrice` amount, he will not receive the NFT as it would be burned according to the logic in the `_settleAuction()` :

```solidity
if (address(this).balance < reservePrice) {
    // If contract balance is less than reserve price, refund to the last bidder
    if (_auction.bidder != address(0)) {
        _safeTransferETHWithFallback(_auction.bidder, _auction.amount);
    }

    // And then burn the Noun
    verbs.burn(_auction.verbId);
}
```

This will not be fair for the highest bidder who did provide the sufficient ETH amount to win the auction but will not receive the NFT because the `reservePrice` was changed.

## Tools Used

Manual review

## Recommended Mitigation Steps

The `reservePrice` should only be changed when there is no auction ongoing and the contract is paused.


## Assessed type

Context
`AuctionHouse` contract: setting a maximum gas threshold can block the contract
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L74-L75
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/AuctionHouse.sol#L429
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/AuctionHouse.sol#L311


# Vulnerability details

## Impact

- Art pieces are created in the `CultureIndex` contract with an array of creators of a maximum of 100 addresses.

- Users vote on art pieces, and with each vote; the maxHeap is re-arranged to preserve the characteristics of a max heap where the top voted pieces is set at first the top of the tree as parents and the children below each parent represent the pieces with lower votes, the cost of this operation increases as the number of added pieces is increased.

- Then the top voted art piece can be dropped to be auctioned by the `AuctionHouse`; where users can create bids, and the winner bid will win the minted verbs tokens and governance ERC20 tokens.

- The process of creating an auction in the `AuctionHouse` is done only if after settling the previous auction, and when an auction is settled; multiple operations are done to transfer proceeds to the art piece creators and the protocol.

- But it was noticed that the `AuctionHouse` contract limits the gas amount associated with `_createAuction` to be > `MIN_TOKEN_MINT_GAS_THRESHOLD` which equals to `750_000`, and with each external call; it limits the gas to 50_000:

  ```javascript
  success := call(50000, _to, _amount, 0, 0, 0, 0)
  ```

- But setting such limits on gas can be exploited by griefers and blocking the `AuctionHouse`, let's take the following scenario:

  1. Multiple art pieces are created with the maximum number of creators; which is 100 address.
  2. One of these art pieces got the highest votes and dropped to be auctioned, where this art piece
  3. The auction got a bidder, and its dead line is reached so any one can call `settleCurrentAndCreateNewAuction` function to settle and create a new auction by dropping the next top voted art piece.
  4. Settling an auction has multiple operations as transferring ether rewards to the creators array addresses; and with 100 creators and assuming each would consume 50_000 gas, this will total in 500_000 gas for transferring ether only.
  5. And after the auction is settled; `_createAuction` will check if the remaining gas is > `750_000` to proceed; if not the transaction would revert.
  6. But even if the gas left is `> 750_000`; it doesn't account for the operations of extracting the top voted art piece from the max heap which might have a large entries that requires more gas to re-arrange.

- Also, if the above scenario is present where it doesn't revert; the cost of transaction would be hefty (knowing that the protocol is going to be deployed
PUSH0 opcode not supported in all networks
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/AuctionHouse.sol#L24


# Vulnerability details

According to the documentation, the protocol targets Base and Optimism L2s, both built on the OP Stack, which [currently does not support the PUSH0 opcode](https://docs.optimism.io/stack/differences#opcodes). This opcode was introduced in 0.8.20 version of Solidity, so given that the protocol contracts have the version pragma ^0.8.22, the bytecode produced by the compiler might provoke unexpected behavior when deployed on the mentioned L2s.

## Impact

The bytecode produced by the compiler might provoke unexpected behavior when deployed on the mentioned L2s.

## Tools Used

Manual inspection.

## Recommended Mitigation Steps

Change the Solidity version to 0.8.19 of set `evm_version` to `paris` in the `foundry.toml` file.


## Assessed type

Other
A malicious creator can manipulate QuorumVotes in createPiece
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/CultureIndex.sol#L226-L229


# Vulnerability details

## Impact
When ```createPiece()``` in ```CultureIndex.sol``` is called it takes the totalSupply ot tokens in the block
```solidity
newPiece.totalVotesSupply = _calculateVoteWeight(
            erc20VotingToken.totalSupply(),
            erc721VotingToken.totalSupply()
        );
``` 
and calculates the totalVoteSupply by calling the [```_calculateVoteWeight()``` ](https://github.com/code-423n4/2023-12-revolutionprotocol/blob/main/packages/revolution/src/CultureIndex.sol#L284-L286) function. Later on the totalVoteSupply is used to calculate the quroumVotes needed for the piece to be able to be auctioned ```newPiece.quorumVotes = (quorumVotesBPS * newPiece.totalVotesSupply) / 10_000;``` . A malicious creator can back run the createPice transaction and mint himself NontrasferableERC20Votes in the same block the piece is created. Thus the newly minted votes won't count towards the quorumVotes ratio, but he will still be able to vote for that piece because he minted tokens in the same block which the piece was created. For example if at the time of piece creation the tokens supply is 10 and quorumVotesBPS is 60%, that means for the piece to be eligible for auction is should have at least 6 token votes. Now if a malicious piece creator back runs the transaction and mint 6 tokens he can guarantee that his piece will successfully pass the quorumVotes requirement. However his 6 mitned tokens after a piece is created shouldn't be eligible for voting.As well as the correct quorum should be 60% * 16 = 3.75(I have used small integers to better ilustrate the problem, 3.75 wont round down as we are dealing with 1e18 integers, also these are just example values). This can be abused by malicious creators especially in the beginning as they are less total votes, if he is successful in passing the quorum in such a way and his piece is the top voted he will receive the rewards associated with a piece being successfully auctioned. This also breaks an Invarian specified by the protocol : ``Only snapshotted (at art piece creation block) vote weights should be able to update the total vote weight of the art piece. eg: If you received votes after snapshot date on the art piece, you should have 0 votes.``   Keep in mind that transactions are ordered firstly by nonce in the MEV pool, so back running a transaction is not that hard when you first create a ```createPiece()```  transaction followed by calling ```buyToken()``` in the ```ERC20TokenEmitter.sol``` contract.

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

## Tools Used
Manual review
## Recommended Mitigation Steps
Instead of 
```solidity
newPiece.totalVotesSupply = _calculateVoteWeight(
            erc20VotingToken.totalSupply(),
            erc721
PieceIds that have overcome the quorum may never get into the auction
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L313-L322
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L292-L298


# Vulnerability details

## Impact
The order of pieces at the MaxHeap is determined by the number of votes they received. But the required quorum for each pieceId may differ due to different totalSupply at the time of creation. Thus, the zero position can be taken by a pieceId that has more votes, but does not reach a quorum, and other pieceIds with sufficient quorum will not be able to get into the auction.

## Proof of Concept
The `MaxHeap` contract [sorts](https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/MaxHeap.sol#L136) the `pieceId` according to the size of the `value`.
The number of user votes is [used](https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L313-L322) as `value`.
```solidity
        uint256 weight = _getPastVotes(voter, pieces[pieceId].creationBlock);
        require(weight > minVoteWeight, "Weight must be greater than minVoteWeight");

        votes[pieceId][voter] = Vote(voter, weight);
        totalVoteWeights[pieceId] += weight;

        uint256 totalWeight = totalVoteWeights[pieceId];

        // TODO add security consideration here based on block created to prevent flash attacks on drops?
        maxHeap.updateValue(pieceId, totalWeight);
```
Pieces with index zero are included in the auction, i.e. the maximum number of votes from all `pieceId`s. But it is also [checked]() that the play has received enough votes to pass a quorum. This logic is done in the [`CultureIndex.dropTopVotedPiece`](https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L519-L534) function.
```solidity
        ICultureIndex.ArtPiece memory piece = getTopVotedPiece();
        require(totalVoteWeights[piece.pieceId] >= piece.quorumVotes, "Does not meet quorum votes to be dropped.");
```
Quorum is defined as the percentage of the total number of votes at the time of creation of the `pieceId`.
```solidity
        newPiece.quorumVotes = (quorumVotesBPS * newPiece.totalVotesSupply) / 10_000;
```
Therefore, for different `pieceIds`, the quorum size may differ, as well as the maximum number of votes. Accordingly, a situation may occur when a pieceID with a large number of votes, but with insufficient quorum, is located above other pieces, with a smaller number of maximum allowed votes determined at the time of creation.

## Tools Used
Manual review

## Recommended Mitigation Steps
Consider using the ratio of the number of votes to the required quorum for ordering at the MaxHeap b
`NontransferableERC20Votes` does not comply with ERC-20 specification
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/NontransferableERC20Votes.sol#L91-L117


# Vulnerability details

According to the documentation `NontransferableERC20Votes: Should comply with ERC20`.

However, the modifications in the implementation to make the token non-transferrable are not compliant with some of the [ERC-20](https://eips.ethereum.org/EIPS/eip-20) specification requirements. More specifically, the requirements of the `transfer`, `transferFrom` and `approve` functions are not met.

## Impact

The NontransferableERC20Votes token contract is not compliant with the ERC-20 specification.

## Tools Used

Manual inspection.

## Recommended Mitigation Steps

As the token is meant to be non-transferrable, the proposed solution would be acknowledging that the token is not ERC-20 compliant by renaming the contract to `NontransferableTokenVotes` and documenting the differences with the ERC-20 specification.


## Assessed type

ERC20
The NFT token on the auction balance will not participate in voting, but affects the quorum
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L226-L229
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L234


# Vulnerability details

## Impact
Due to the fact that the token on the auction balance is counted in the total number of voting tokens, pieces created before the start of the auction will have a lower required quorum than pieces created after the start of the auction. Considering that the total number of active votes is the same, it will be mathematically more difficult for some pieces to overcome the quorum.
 
## Proof of Concept
At the moment of creation of a new piece of art, the total number of minted tokens is [saved](https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L226-L229).
```solidity
        newPiece.totalVotesSupply = _calculateVoteWeight(
            erc20VotingToken.totalSupply(),
            erc721VotingToken.totalSupply()
        );
```
Based on the total number of issued tokens, the required quorum of votes for the piece is [determined](https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L234).
```solidity
        newPiece.quorumVotes = (quorumVotesBPS * newPiece.totalVotesSupply) / 10_000;
```
But the NFT token that is on the auction balance will not be able to take part in the voting.

## Tools Used
Manual review

## Recommended Mitigation Steps
Consider subtracting the NFT token in the auction balance from the total number of tokens issued.



## Assessed type

Governance
`VerbsToken.tokenURI` does not comply with ERC-721 specification
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/VerbsToken.sol#L194


# Vulnerability details

According to the documentation `VerbsToken: Should comply with ERC721`.

The specification of [ERC-721](https://eips.ethereum.org/EIPS/eip-721) states the following regarding the `tokenURI` function: `Throws if _tokenId is not a valid NFT`.

The `tokenURI` function in `VerbsToken` does not check if the `_tokenId` is a valid NFT, and therefore it is possible to call the function with an invalid `_tokenId` and get a response.

## Impact

The Verbs token contract is not compliant with the ERC-721 specification.

## Tools Used

Manual inspection.

## Recommended Mitigation Steps

```diff
    function tokenURI(uint256 tokenId) public view override returns (string memory) {
+       require(uint8(artPieces[tokenId].metadata.mediaType) > 0, "Invalid tokenId");
        return descriptor.tokenURI(tokenId, artPieces[tokenId].metadata);
    }
```



## Assessed type

ERC721
`CultureIndex.sol:_verifyVoteSignature` does not comply with EIP-712
Audit: 2023-12-revolutionprotocol-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-revolutionprotocol/blob/d42cc62b873a1b2b44f57310f9d4bbfdd875e8d6/packages/revolution/src/CultureIndex.sol#L431


# Vulnerability details


The `CultureIndex.sol` contract implements the `voteForManyWithSig` and `batchVoteForManyWithSig` functions, which are used to vote for multiple proposals at once.

Both functions use the internal `_verifyVoteSignature` function to verify the signature of the voter. This function uses the `EIP712` standard to encode the data that is signed by the voter.

```solidity
431        voteHash = keccak256(abi.encode(VOTE_TYPEHASH, from, pieceIds, nonces[from]++, deadline));
```

However, the array of `pieceIds` is not encoded correctly, as according to the [EIP-712 specification](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#definition-of-encodedata):

`The array values are encoded as the keccak256 hash of the concatenated encodeData of their contents (i.e. the encoding of SomeType[5] is identical to that of a struct containing five members of type SomeType).`

## Impact

The signature verification is not EIP712 compliant, which will result in issues with integrators.

## Tools Used

Manual inspection.

## Recommended Mitigation Steps

```diff
-       voteHash = keccak256(abi.encode(VOTE_TYPEHASH, from, pieceIds, nonces[from]++, deadline));
+       voteHash = keccak256(abi.encode(VOTE_TYPEHASH, from, keccak256(abi.encodePacked(pieceIds)), nonces[from]++, deadline));
```


## Assessed type

Other